动态扫描led8个c语言编程,ME300实例

ME300实例-LED数码管显示电子钟(汇编、C语言)

演示图片:

4cec194ab34bfc814ce6c516d3eb5ac1.png

源程序

;*  描述:                                                                       *

;*         简易电子时钟,数码管显示                                              *

;*         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  ; 

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 

#include 

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 

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值