片机提高WWW.51C51.COM 自学单片机的网站:作中国单片机编程技术普及推广第一站!倚天一出宝刀屠龙返回主页 给我留言 单片机教程 单片机提高  品质技术 单片机网址软件下载  学液晶显示产品介绍 如何购买

;********************************************************************************


;/*******************************************************************************
;* 标题: xl系列单片机实验仪演示程序 数码管秒表计时 *
;* 文件: XLmb.asm *
;* 日期: 2006-1-5 *
;* 版本: 3.0 (试验通过版)可用xl600-xl1000单片机综合试验仪试验 *
;* 邮箱: sxj1974@163.com *
;* 网站: http://www.51c51.com www.8951.com *
;********************************************************************************
;* 描述: *
;* 数码管显示秒表, 分辨率0.01s *
;* K1---控制按钮 *
;* 第一次按下时, 启动开始计时 *
;* 第二次按下时, 停止 *
;* 第三次按下时, 归零 *
;* 引用资源:数码管数据 p0口,数码管控制p2口 控制按钮 p3.2口 *
;* 秒单位,寄存器与数码管对应关系: *
;* *
;* --- 秒单位 ---------- 数码管端口 ---- 缓冲区 --------- 计时BCD码值寄存器 *
;* 十万位 P20 dis_buf[7] sec_bcd[7] *
;* 万位 P21 dis_buf[6] sec_bcd[6] *
;* 千位 P22 dis_buf[5] sec_bcd[5] *
;* 百位 P23 dis_buf[4] sec_bcd[4] *
;* 十位 P24 dis_buf[3] sec_bcd[3] *
;* 个位(1.s) P25 dis_buf[2] sec_bcd[2] *
;* 十分位(0.1s) P26 dis_buf[1] sec_bcd[1] *
;* 百分位(0.01s) P27 dis_buf[0] sec_bcd[0] *
;* *
;********************************************************************************
;* 【版权】 Copyright(C)深圳市学林电子有限公司 www.51c51.com *
;* 【声明】 此程序仅用于学习与参考,引用请注明版权和作者信息! *
;* 【技术支持】请访问http://www.51c51.com/bbs/ 官方论坛 *
;********************************************************************************/
ORG 0080h
CODE_SEG SEGMENTCODE
DATA_SEG SEGMENT DATA 
STACK_SEGSEGMENTIDATA
RSEG DATA_SEG
KEY_S: DS 1
KEY_V: DS 1
DIS_DIGIT: DS 1
DIS_INDEX: DS 1
SEC_BCD: DS 8; 秒计数值, BCD码
KEY_TIMES: DS 1; K1 按下次数 
DIS_BUF: DS 8; 显示缓冲区
RSEGSTACK_SEG
STACK:DS20
K1BITP3.2
;===============================================================================
CSEGAT0000H
LJMPMAIN
CSEGAT0000BH
LJMPTIMER0
CSEGAT0001BH
LJMPTIMER1
;===============================================================================
RSEGCODE_SEG
MAIN:
USING0
MOVSP,#(STACK-1)

MOV P0,#0FFH; 初始化端口
MOV P2,#0FFH
MOV TMOD,#011H; 
MOV TH1,#0DCH
CLR A
MOV TL1,A
MOV TH0,#0FCH
MOV TL0,#017H
LCALLCLR_TIME; 清零计时值
MOV DIS_DIGIT,#07FH; 上电时选通P27数码管
CLR A
MOV DIS_INDEX,A
MOV KEY_TIMES,A
MOV KEY_V,#01H 
MOV IE,#08AH; 使能timer0, timer1中断
SETB TR0
CLR TR1 
MAIN_LP:
LCALLSCAN_KEY; 键扫描
JZ MAIN_LP; 无键返回 
MOVR7,#10; 延时10ms
LCALLDELAYMS; 延时去抖动
LCALLSCAN_KEY; 再次扫描
JZMAIN_LP; 无键返回 
MOV KEY_V,KEY_S; 保存键值
LCALLPROC_KEY; 键处理
SJMPMAIN_LP; 调回主循环
;===============================================================================
CLR_TIME: 
CLR A
MOV SEC_BCD,A; 清零所有计时值
MOV SEC_BCD+01H,A
MOV SEC_BCD+02H,A
MOV SEC_BCD+03H,A
MOV SEC_BCD+04H,A
MOV SEC_BCD+05H,A
MOV SEC_BCD+06H,A
MOV SEC_BCD+07H,A
LJMP UPDATE_DISBUF; 更新显示缓冲区 
;===============================================================================
SCAN_KEY:
CLR A
MOV KEY_S,A
MOV C,K1; 读按键状态
RLC A
ORL KEY_S,A
MOV A,KEY_S
XRL A,KEY_V; 
RET 
;===============================================================================
PROC_KEY:
MOV A,KEY_V
JB ACC.0,END_PROC_KEY 
INC KEY_TIMES
MOV A,KEY_TIMES
CJNE A,#01H,PROC_KEY1 
SETB TR1; KEY_TIMES =1,第一次按下K1, 启动开始计时 
RET 
PROC_KEY1:
MOV A,KEY_TIMES 
CJNE A,#02H,PROC_KEY2 
CLR TR1; KEY_TIMES =2, 第二次按下K1, 停止计时 
RET 
PROC_KEY2:
LCALLCLR_TIME; 第三次按下K1, 清零计时值 
CLR A
MOV KEY_TIMES,A; 清零KEY_TIMES 
END_PROC_KEY:
RET 
;===============================================================================
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; 
MOVA,DIS_DIGIT; 位选通值右移(P20<-P27), 下次中断时选通下一位数码管
RRA
MOVDIS_DIGIT,A 
INCDIS_INDEX; DIS_INDEX加1, 下次中断时显示下一位
ANLDIS_INDEX,#0x07; 当DIS_INDEX等于8(0000 1000)时, 清0
POP AR0
POP PSW
POP ACC 
RETI 
;===============================================================================
TIMER1:
PUSH ACC
PUSH B
PUSH DPH
PUSH DPL
PUSHPSW
PUSHAR7
ORL TH1,#0DCH; 恢复定时器初值
CLR A
MOV R7,A 
MOV A,#LOW (SEC_BCD) 
MOV R0,A; 计时值寄存器地址到R0 
TIMER_INC:; 
INC @R0; 计时值加1
MOV A,@R0
CLR C
SUBB A,#10; 
JC END_INC; 如果低位不满10, 则结束
MOV @R0,#00H; 低位满10, 清零低位
INCR0; 指向高位
INC R7; 
CJNE R7,#08H,TIMER_INC; 如果达到最高位, 则结束 
END_INC:
LCALLUPDATE_DISBUF
POPAR7 
POPPSW
POP DPL
POP DPH
POP B
POP ACC
RETI 
;===============================================================================
UPDATE_DISBUF:
; 根据计时寄存器的值更新显示缓冲区
MOV DPTR,#DIS_CODE; 保存表格地址 
MOV A,sec_bcd
MOV DPTR,#dis_code
MOVC A,@A+DPTR; 获得显示代码
MOV dis_buf,A; 更新显示缓冲区
MOV A,sec_bcd+01H
MOVC A,@A+DPTR
MOV dis_buf+01H,A
MOV A,sec_bcd+02H
MOVC A,@A+DPTR
ANL A,#07FH; 显示小数点
MOV dis_buf+02H,A
MOV A,sec_bcd+03H
MOVC A,@A+DPTR
MOV dis_buf+03H,A
MOV A,sec_bcd+04H
MOVC A,@A+DPTR
MOV dis_buf+04H,A
MOV A,sec_bcd+05H
MOVC A,@A+DPTR
MOV dis_buf+05H,A
MOV A,sec_bcd+06H
MOVC A,@A+DPTR
MOV dis_buf+06H,A
MOV A,sec_bcd+07H
MOVC A,@A+DPTR
MOV dis_buf+07H,A
RET 
; END OF UPDATE_DISBUF 
;===============================================================================
DELAYMS:
; 延时子程序
; 传入参数:R7 --- 延时值(MS) 
; 返回值:无
MOVA,R7
JZEND_DLYMS 
DLY_LP1:
MOVR6,#185
DLY_LP2:
NOP
NOP
NOP
DJNZR6,DLY_LP2
DJNZR7,DLY_LP1
END_DLYMS:
RET 
;===============================================================================
DIS_CODE:
db 28h,7eh,0a2h,62h,74h,61h,21h,7ah,20h,60h,0ffh
END