分享

ME300实例-LED数码管显示电子

 共同成长888 2021-11-09

演示图片:


源程序
;*  描述:                                                                       *
;*         简易电子时钟,数码管显示                                              *
;*         K1---时调整                                                          *
;*         K2---分调整                                                          *
;*                                                                              *
;*                                                                              *

CODE_SEG SEGMENT CODE 
DATA_SEG SEGMENT DATA 
STACK_SEG SEGMENT IDATA


K1 BIT P1.4
K2 BIT P1.5

 RSEG  DATA_SEG
KEY_S:  DS   1
KEY_V:    DS   1
DIS_DIGIT:    DS   1
SEC:     DS   1
DIS_INDEX:   DS    1
HOUR:    DS    1
MIN:     DS    1
SEC100:    DS    1
DIS_BUF:    DS    8
        
BUF_HOUR_H EQU DIS_BUF  ; 小时十位
BUF_HOUR_L EQU DIS_BUF+1 ; 小时个位
BUF_MIN_H EQU DIS_BUF+3 ; 分十位
BUF_MIN_L EQU DIS_BUF+4 ; 分个位
BUF_SEC_H EQU DIS_BUF+6 ; 秒十位
BUF_SEC_L EQU DIS_BUF+7 ; 秒个位

 RSEG STACK_SEG
STACK: DS 20 
 

;=======================================================

CSEG AT 0000H
 JMP MAIN
 
CSEG AT 0000BH
 LJMP TIMER0 

CSEG AT 0001BH
 LJMP TIMER1

;===================================================


 RSEG  CODE_SEG
MAIN:
 USING 0
 
 MOV SP, #(STACK-1)  ;
 
 
 MOV   P0,#0FFH
 MOV   P2,#0FFH
 MOV   TMOD,#011H  ; 定时器0, 1工作模式1, 16位定时方式
 MOV   TH0,#0FCH
 MOV   TL0,#017H
 MOV   TH1,#0DCH
 CLR   A
 MOV   TL1,A
 
 MOV   HOUR,#12  ; 
 CLR A   ; 
 MOV   MIN,A
 MOV   SEC,A
 MOV   SEC100,A
 
 MOV   A,HOUR
 MOV   B,#10
 DIV   AB
 MOV   DPTR,#DIS_CODE
 MOVC  A,@A+DPTR
 MOV   BUF_HOUR_H,A  ; 时十位
 MOV   A,HOUR
 MOV   B,#10
 DIV   AB
 MOV   A,B
 MOVC  A,@A+DPTR
 MOV   BUF_HOUR_L,A  ; 时个位
 MOV   A,MIN
 MOV   B,#10
 DIV   AB
 MOVC  A,@A+DPTR
 MOV   BUF_MIN_H,A  ; 分十位
 MOV   A,MIN
 MOV   B,#10
 DIV   AB
 MOV   A,B
 MOVC  A,@A+DPTR
 MOV   BUF_MIN_L,A  ; 分个位
 MOV   A,SEC
 MOV   B,#10
 DIV   AB
 MOVC  A,@A+DPTR
 MOV   BUF_SEC_H,A  ; 秒十位
 MOV   A,SEC
 MOV   B,#10
 DIV   AB
 MOV   A,B
 MOVC  A,@A+DPTR
 MOV   BUF_SEC_L,A  ; 秒个位
 
 MOV   BUF_HOUR_H+02H,#0BFH
 MOV   BUF_HOUR_H+05H,#0BFH
 
 MOV   DIS_DIGIT,#0FEH
 CLR A
 MOV   DIS_INDEX,A
 
 MOV   IE,#08AH  ; 使能TImer0,1 中断
 
 SETB TR0
 SETB TR1
 
 MOV   KEY_V,#03H
 
MAIN_LP:
 LCALL SCAN_KEY  ; 键扫描
 JZ   MAIN_LP   ; 无键返回
 
 MOV R7,#10   ; 延时10ms
 LCALL DELAYMS   ; 延时去抖动
 LCALL SCAN_KEY  ; 再次扫描
 JZ MAIN_LP   ; 无键返回
 
 MOV   KEY_V,KEY_S  ; 保存键值
 LCALL PROC_KEY  ; 键处理
 SJMP MAIN_LP   ; 调回主循环


;=======================================================
SCAN_KEY:
; 扫键扫描子程序
; 保存按键状态到key_s
; 返回: A --- 按键是否按下(BOOL)

 CLR A
 
 MOV   C,K1   ; 读按键K1
 MOV ACC.0,C
 MOV C,K2   ; 读按键K2
 MOV ACC.1,C
 
 MOV KEY_S,A   ;  保存按键状态到key_s
 XRL   A,KEY_V
 RET   

;========================================================
PROC_KEY:
; 键处理子程序
; 传入参数: KEY_V --- 按键值
; 返回值: 无

 CLR   EA
 
 MOV   A,KEY_V
 JNB ACC.0,PROC_K1
 JNB ACC.1,PROC_K2
 SJMP END_PROC_KEY
 
PROC_K1:    ; 按键k1处理
 LCALL INC_HOUR  ; 小时加1
 SJMP  END_PROC_KEY

PROC_K2:    ; 按键K2处理
 INC   MIN   ; 分钟加1
 
 MOV   A,MIN   ; 
 SETB  C
 SUBB  A,#59 
 JC    K2_UPDATE_MIN  ; 如果分钟等于60,则分清0,小时加1
 
 CLR   A   ; 
 MOV   MIN,A

K2_UPDATE_MIN:    ; 更新分显示缓冲区
 MOV   A,MIN
 MOV   B,#10
 DIV   AB   ; A = MIN / 10 
 MOV   DPTR,#DIS_CODE
 MOVC  A,@A+DPTR
 MOV   BUF_MIN_H,A  ; 更新分十位
 
 MOV   A,MIN
 MOV   B,#10
 DIV   AB
 MOV   A,B   ; A = MIN % 10
 MOVC  A,@A+DPTR
 MOV   BUF_MIN_L,A  ; 更新分个位 
 
END_PROC_KEY:
 SETB  EA
 RET   

;========================================================

 USING 0
TIMER0:
; 定时器0中断服程序, 用于数码管的动态扫描
; DIS_INDEX --- 显示索引, 用于标识当前显示的数码管和缓冲区的偏移量
; DIS_DIGIT --- 位选通值, 传送到P2口用于选通当前数码管的数值, 如等于0xfe时,
;  选通P2.0口数码管
; DIS_BUF   --- 显于缓冲区基地址  

 PUSH  ACC
 PUSH  PSW
 PUSH  AR0
 
 MOV   TH0,#0FCH
 MOV   TL0,#017H
 
 MOV   P2,#0FFH  ; 先关闭所有数码管
 
 MOV   A,#DIS_BUF  ; 获得显示缓冲区基地址
 ADD   A,DIS_INDEX  ; 获得偏移量
 MOV   R0,A   ; R0 = 基地址 + 偏移量
 MOV   A,@R0   ; 获得显示代码
 MOV   P0,A   ; 显示代码传送到P0口
 
 MOV   P2,DIS_DIGIT

 MOV A,DIS_DIGIT  ; 位选通值左移, 下次中断时选通下一位数码管
 RL A
 MOV DIS_DIGIT,A
 
 INC DIS_INDEX  ; DIS_INDEX加1, 下次中断时显示下一位
 ANL DIS_INDEX,#0x07  ; 当DIS_INDEX等于8(0000 1000)时, 清0

 POP   AR0
 POP   PSW
 POP   ACC
 
 RETI  

;==================================================
 USING 0
TIMER1:
; 定时器1中断服务程序, 产生时基信号10ms

;
 PUSH PSW
 PUSH  ACC
 PUSH  B
 PUSH  DPH
 PUSH  DPL
 
 MOV   TH1,#0DCH
 
 INC   SEC100
 
 MOV   A,SEC100
 CLR   C
 SUBB  A,#100   ; 是否中断100次(达到1s)
 JC    END_TIMER1  ; < 1S
 
 MOV   SEC100,#00H  ; 达到1s 
 LCALL INC_SEC   ; 秒加1 
 
END_TIMER1:
 POP   DPL
 POP   DPH
 POP   B
 POP   ACC
 POP PSW
 
 RETI     ; 

;========================================================
INC_SEC:
 INC   SEC
 
 MOV   A,SEC
 SETB  C
 SUBB  A,#59   ; 
 JC    UPDATE_SEC
 
 CLR   A
 MOV   SEC,A
 LCALL INC_MIN
 
UPDATE_SEC:
 MOV   A,SEC
 MOV   B,#10
 DIV   AB   ; A = SEC / 10
 MOV   DPTR,#DIS_CODE
 MOVC  A,@A+DPTR  ; 
 MOV   BUF_SEC_H,A  ; 
 
 MOV   A,SEC
 MOV   B,#10
 DIV   AB
 MOV   A,B   ; A = SEC % 10
 MOVC  A,@A+DPTR
 MOV   BUF_SEC_L,A
 RET   

;========================================================

INC_MIN:
 INC   MIN   ; 分钟加1
 
 MOV   A,MIN   ; 
 SETB  C
 SUBB  A,#59 
 JC    UPDATE_MIN  ; 如果分钟等于60,则分清0,小时加1
 
 CLR   A   ; 
 MOV   MIN,A
 LCALL INC_HOUR  ; 小时加1
 
UPDATE_MIN:    ; 更新分显示缓冲区
 MOV   A,MIN
 MOV   B,#10
 DIV   AB   ; A = MIN / 10 
 MOV   DPTR,#DIS_CODE
 MOVC  A,@A+DPTR
 MOV   BUF_MIN_H,A  ; 更新分十位
 
 MOV   A,MIN
 MOV   B,#10
 DIV   AB
 MOV   A,B   ; A = MIN % 10
 MOVC  A,@A+DPTR
 MOV   BUF_MIN_L,A  ; 更新分个位
 
 RET   

;===========================================================

INC_HOUR:
 INC   HOUR   ; 小时加1 
 MOV   A,HOUR
 SETB  C
 SUBB  A,#24
 JC    UPDATE_HOUR  ; 如果小时等于24,则小时清0
 
 CLR   A
 MOV   HOUR,A   ; 小时清0 
 
UPDATE_HOUR:
 MOV   A,HOUR
 SETB  C
 SUBB  A,#9
 JC    UPDATE_HOUR1  ; 如果小时小于10,则十位0不显示
 
 MOV   A,HOUR
 MOV   B,#10
 DIV   AB
 MOV   DPTR,#DIS_CODE
 MOVC  A,@A+DPTR  ; 
 MOV   BUF_HOUR_H,A
 SJMP  UPDATE_HOUR2
 
UPDATE_HOUR1:
 MOV   BUF_HOUR_H,#0FFH
 
UPDATE_HOUR2:
 MOV   A,HOUR
 MOV   B,#10
 DIV   AB
 MOV   A,B
 MOV   DPTR,#DIS_CODE
 MOVC  A,@A+DPTR
 MOV   BUF_HOUR_L,A
 RET   

;=================================================

DELAYMS:
; 延时子程序
; 传入参数:R7 --- 延时值(MS) 
; 返回值:无

 MOV A,R7
 JZ END_DLYMS 
DLY_LP1:
 MOV R6,#185
DLY_LP2:
 NOP
 NOP
 NOP
 DJNZ R6,DLY_LP2
 DJNZ R7,DLY_LP1

END_DLYMS:
 RET 
 
; END OF DELAYMS  

;======================================================

DIS_CODE:
 DB 0C0H
 DB 0F9H
 DB 0A4H
 DB 0B0H
 DB 099H
 DB 092H
 DB 082H
 DB 0F8H
 DB 080H
 DB 090H
 DB 0FFH

 END


=========================
源程序(C语言)
*  描述:                                                                       *
*                 简易电子时钟,LED数码管显示                                  *
*                 K1---时调整                                                  *
*                 K2---分调整                                                  *
*                                                                              *
*                 上电时初始化显示:  12-00-00                                  *
*                                                                              *
*           *    ****          ****    ****          ****    ****              *
*           *        *        *    *  *    *        *    *  *    *             *
*           *        *        *    *  *    *        *    *  *    *             *
*           *    ****  ****** *    *  *    * ****** *    *  *    *             *
*           *   *             *    *  *    *        *    *  *    *             *
*           *   *             *    *  *    *        *    *  *    *             *
*           *    ****          ****    ****          ****    ****              *
*                                                                              *
*                                                                              *

#include <reg51.h>
#include <intrins.h>

unsigned char data dis_digit;
unsigned char key_s, key_v;

unsigned char code dis_code[11]={0xc0,0xf9,0xa4,0xb0, // 0, 1, 2, 3
    0x99,0x92,0x82,0xf8,0x80,0x90, 0xff};// 4, 5, 6, 7, 8, 9, off 
unsigned char data dis_buf[8];
unsigned char data dis_index;
unsigned char hour,min,sec;
unsigned char sec100; 

sbit K1 = P1^4;
sbit K2 = P1^5;

bit scan_key();
void proc_key();
void inc_sec();
void inc_min();
void inc_hour();
void display();
void delayms(unsigned char ms);

void main(void)
{
 P0 = 0xff;
 P2 = 0xff;
 TMOD = 0x11;  // 定时器0, 1工作模式1, 16位定时方式
 TH1 = 0xdc;
 TL1 = 0;

 TH0 = 0xFC;
 TL0 = 0x17;
 
 hour = 12;
 min = 00;
 sec = 00;

 sec100 = 0;
 
 dis_buf[0] = dis_code[hour / 10];  // 时十位
 dis_buf[1] = dis_code[hour % 10];  // 时个位
 dis_buf[3] = dis_code[min / 10];  // 分十位
 dis_buf[4] = dis_code[min % 10];  // 分个位
 dis_buf[6] = dis_code[sec / 10];  // 秒十位
 dis_buf[7] = dis_code[sec % 10];  // 秒个位
 dis_buf[2] = 0xbf;      // 显示"-"
 dis_buf[5] = 0xbf;      // 显示"-"
   
 dis_digit = 0xfe;
 dis_index = 0;
 
 TCON = 0x01;
 IE = 0x8a;    // 使能timer0,1 中断
 
 TR0 = 1;
 TR1 = 1;

 key_v = 0x03;

 while(1)
 {
  if(scan_key())
  {
   delayms(10);
   if(scan_key())
   {
    key_v = key_s;
    proc_key();
   }
  }
  
 }
}

bit scan_key()
{
 key_s = 0x00;
 key_s |= K2;
 key_s <<= 1;
 key_s |= K1;
 return(key_s ^ key_v); 
}

void proc_key()
{
 EA = 0;
 if((key_v & 0x01) == 0)  // K1
 {
  inc_hour();
 }
 else if((key_v & 0x02) == 0) // K2
 {
  min++;
  if(min > 59)
  {
   min = 0;
  }
  dis_buf[3] = dis_code[min / 10];  // 分十位
  dis_buf[4] = dis_code[min % 10];  // 分个位
 }

 EA = 1;
}

void timer0() interrupt 1
// 定时器0中断服务程序, 用于数码管的动态扫描
// dis_index --- 显示索引, 用于标识当前显示的数码管和缓冲区的偏移量
// dis_digit --- 位选通值, 传送到P2口用于选通当前数码管的数值, 如等于0xfe时,
//    选通P2.0口数码管
// dis_buf   --- 显于缓冲区基地址 
{
 TH0 = 0xFC;
 TL0 = 0x17;
 
 P2 = 0xff;       // 先关闭所有数码管
 P0 = dis_buf[dis_index];   // 显示代码传送到P0口
 P2 = dis_digit;      // 

 dis_digit = _crol_(dis_digit,1); // 位选通值左移, 下次中断时选通下一位数码管
 dis_index++;      // 
     
 dis_index &= 0x07;   // 8个数码管全部扫描完一遍之后,再回到第一个开始下一次扫描


void timer1() interrupt 3
{
 TH1 = 0xdc;
 
 sec100++;
 
 if(sec100 >= 100)
 {
  sec100 = 0;
  inc_sec();
 }
}

void inc_sec()
{
 sec++;
 if(sec > 59)
 {
  sec = 0;
  inc_min();
 }
 dis_buf[6] = dis_code[sec / 10];  // 秒十位
 dis_buf[7] = dis_code[sec % 10];  // 秒个位 
}

void inc_min()
{
 min++;
 if(min > 59)
 {
  min = 0;
  inc_hour();
 }
 dis_buf[3] = dis_code[min / 10];  // 分十位
 dis_buf[4] = dis_code[min % 10];  // 分个位
}

void inc_hour()
{
 hour++;
 if(hour > 23)
 {
  hour = 0;
 }
 if(hour > 9)
  dis_buf[0] = dis_code[hour / 10];  // 时十位
 else
  dis_buf[0] = 0xff;     // 当小时的十位为0时不显示
 dis_buf[1] = dis_code[hour % 10];  // 时个位

}


void delayms(unsigned char ms) 
// 延时子程序
{      
 unsigned char i;
 while(ms--)
 {
  for(i = 0; i < 120; i++);
 }
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章