|
基于51单片机数码管显示的单片机时钟仿真原理图(proteus工程文件可到本帖附件下载):
单片机汇编语言程序:
- ;-----------------------------------------------------------------
- ;文件名称:SZ10-3.ASM
- ;程序功能:带倒计时的闹钟
- ;----------------------------------------------------------------
- ;******************* 闹钟(含插入倒计时)程序部分 *******************
- ;----- -------- 程序初始化 -------------
- ; 定义存放计时单元地址
- ALB EQU 20H.0 ;闹铃设置标志
- BUF EQU 30H ;30~33H 连续4个字节存放显示器数据
- HOUR EQU 34H ;存放小时变量
- MIN EQU 35H ;存放分钟变量
- SEC EQU 36H ;存放秒钟变量
- DEDA EQU 37H ;存放5ms计数值
- HH EQU 38H ;闹铃设置小时变量
- MM EQU 39H ;闹铃设置分钟变量
- ;………………………………
- SEC0 EQU 3AH ;存放旧的秒数
- MM_D EQU 3BH ;倒数时间分钟数
- SS_D EQU 3CH ;倒数时间秒钟数
- ;………………………………
- ;按键输入引脚定义
- K1 EQU P2.4 ;按键K1引脚定义
- K2 EQU P2.5 ;按键K2引脚定义
- K3 EQU P2.6 ;按键K3引脚定义
- K4 EQU P2.7 ;按键K4引脚定义
-
- ;蜂鸣器和指示灯引脚定义
- SPK EQU P3.7 ;蜂鸣器控制信号引脚定义
- WLED EQU P3.0 ;工作指示灯引脚定义
-
- ;程序开始执行地址
- ORG 0H ;程序代码由地址0开始
- JMP MAIN
- ORG 0BH ;定时器T0中断地址设置
- JMP TO_SRV
- ;-------------- 主 程 序 ------------
-
- MAIN: ;主程序
- CLR ALB ;清除闹铃标志
- ACALL BZ ;蜂鸣器连续两次鸣响
- ACALL BZ
- ACALL LED_BL ;LED 闪动,表示程序开始执行
- ACALL INIT ;初始变化量
- ACALL INIT_TIMER ;设置定时器
-
- ;加载显示器初值数据
- MOV A, #0C0H
- MOV P0, A
-
- ;无穷循环
- LOOP:
- ACALL CONV
- ACALL TIME_PRO ;检查闹铃时间
- ACALL DISP ;扫描显示
- ;设置走时时间
- JB K1, M1 ;未按下K1键,则继续扫描
- ACALL LED_BL ;LED闪动
- ACALL SET_TIME ;设置目前时间
- JMP LOOP ;跳转到LOOP处运行
-
- ;设置闹铃时间
- M1: JB K2, M2 ;未按下K2键,则继续扫描
- ACALL LED_BL
- ACALL SET_ATIME ;设置闹铃时间
- JMP LOOP ;跳转到LOOP处运行
-
- ;设置倒计时间
- M2: JB K3, M3 ;未按下K3键,则继续扫描
- ;…………………………
- ACALL LED_BL
- ACALL DOWN_ATIME ;设置倒计时间
- ;…………………………
- JMP LOOP ;跳转到LOOP处运行
-
- M3: JB K4, M4 ;未按下K4键,则继续扫描
- CPL ALB
- JNB ALB, M31
-
- ;闹铃启动连续3次发出响声
- ACALL BZ
- ACALL BZ
- ACALL BZ
- JMP LOOP ;跳转到LOOP处运行
- M31:
- ACALL BZ ;闹铃停止,发出一声响
- JMP LOOP ;跳转到LOOP处运行
- M4:
- JMP LOOP ;跳转到LOOP处运行
-
- ;----------- 实现走时功能的子程序 ----------
- ;使用定时器T0模式0计时
- INIT_TIMER: ;初始化定时器,使用定时器T0模式0计时
- MOV TMOD,#00000000B ;设置定时器T0工作模式0
- MOV IE, #10000010B ;启用定时器T0中断产生
- MOV TL0, #(8192-4900)MOD 32 ;加载初始化数据
- MOV TH0, #(8192-4900)/32
- SETB TR0 ;启动定时器0开始计时
- RET
- ;-----------―――
- ;中断服务程序
- TO_SRV: ;定时器T0计时中断程序每隔5ms中断一次
- PUSH ACC ;将A值压入堆栈
- MOV TL0, #(8192-4900)MOD 32 ;重加载初始化数据
- MOV TH0, #(8192-4900)/32
- INC DEDA ;加1
- ;秒输出
- MOV A, DEDA
- CJNE A,#200,TT1 ;是否1s到了
- MOV DEDA, #0 ;计数值清0
- CPL WLED ;LED灯亮灭变换
- INC SEC ;秒计数加1
- MOV A, SEC
- CJNE A, #60, TT1 ;是否1min到了
- ;分输出
- INC MIN ;分计数加1
- MOV SEC, #0 ;秒计数清0
- MOV A, MIN
- CJNE A, #60, TT1 ;是否1h到了
- ;小时输出
- INC HOUR ;小时计数加1
- MOV MIN, #0 ;分计数清0
- MOV A, HOUR
- CJNE A, #24, TT1 ;是否24h到了
- MOV SEC, #0 ;秒钟变量清0
- MOV MIN, #0 ;分钟变量清0
- MOV HOUR, #0 ;小时变量清0
- TT1:
- POP ACC ;将A值由堆栈取出
- RETI
- ;------------- 实现显示功能的子程序 ---------
-
- CONV:
- ;转换小时数据
- MOV A, HOUR
- MOV B, #10
- DIV AB
- MOV DPTR,#TABLE ;查表转换
- MOVC A, @A+DPTR
- MOV BUF, A
- MOV A, B
- MOVC A, @A+DPTR
- MOV BUF+1, A
- ;转换分钟数据
- MOV A, MIN
- MOV B, #10
- DIV AB
- MOV DPTR,#TABLE ;查表转换
- MOVC A, @A+DPTR
- MOV BUF+2, A
- MOV A, B
- MOVC A, @A+DPTR
- MOV BUF+3, A
- RET
-
- ;字型数据编码表
- TABLE:
- DB 0C0H,0F9H,0A4H,0B0H
- DB 99H,92H,82H,0F8H
- DB 80H,90H,88H,83H
- DB 0C6H,0A1H,86H,8EH
-
- ;-------------- 扫描显示子程序 -----------
- ;扫描显示
- DISP:
- MOV R0, #BUF ;指向显示器显示缓冲区起始地址
- MOV R2, #4 ;循环执行4次
- MOV ACC, #11110111b ;加载扫描信号初值11110111B
- S1:
- PUSH ACC
- MOV A, @R0 ;取出显示器数据
- MOV P0, A ;由P0送出一位显示器数据
- POP ACC
- MOV P2, ACC ;由P2送出扫描输出信号
- MOV R5, #2 ;延迟一段时间
- ACALL DELAY
- ;改变扫描码 EX:XXXX1011
- RR A ;累加器A向右移动一位
- INC R0 ;显示器显示缓冲区地址加1
- DJNZ R2, S1 ;判断是否继续执行循环
- RET
-
- ;------------- 实现调整时间子程序 -----------
- ;设置目前时间
- SET_TIME:
- CLR TR0 ;定时器工作暂停
- MOV SEC, #0 ;秒钟变量清0
- L0:
- ACALL DISP ;扫描显示
-
- JB K2, L1 ;未按下K2键,则继续扫描
- JNB K2, $ ;按下,则等待放开
- ;K2小时调整
- INC HOUR ;小时计数加1
- MOV A, HOUR
- CJNE A,#24, L11 ;是否24h到了
- MOV HOUR, #0 ;小时变量清0
- L11:
- ACALL CONV ;转换显示数据
- ACALL DISP ;扫描显示
- JMP L0 ;跳转到L0处执行
-
- L1: JB K3, L2 ;未按下K3键,则继续扫描
- JNB K3,$ ;按下,则等待放开
- ;K3分钟调整
- INC MIN ;分钟计数加1
- MOV A, MIN
- CJNE A,#60, L21 ;是否60min到了
- MOV MIN, #0 ;分钟变量清0
- L21:
- ACALL CONV ;转换显示数据
- ACALL DISP ;扫描显示
- JMP L0 ;跳转到L0处运行
-
- L2: JB K4,L0 ;未按下K4键,则继续扫描
- JNB K4, $ ;按下,则等待放开
- ACALL BZ ;蜂鸣器鸣响一声
- ;K4设置完成
- ACALL LED_BL ;LED闪动
- SETB TR0 ;启动定时器
- RET
- ;------------- 计时单元清0子程序 ----------
- ;计时单元清0
- INIT:
- MOV DEDA, #0 ;5ms计数值清0
- MOV SEC, #0 ;秒钟变量清0
- MOV MIN, #0 ;分钟变量清0
- MOV HOUR, #0 ;小时变量清0
- RET
- ; ------------―蜂鸣器鸣响一声子程序 ----------
- ;蜂鸣器
- BZ: ;蜂鸣器鸣响一声
- MOV R6, #250
- B1: ACALL DEX
- CPL SPK
- DJNZ R6, B1
- MOV R5, #50
- ACALL DELAY
- RET
-
- ;-------------工作指示灯闪烁子程序 ----------
- ;工作指示
- LED_BL: ;工作指示灯闪烁
- MOV R4, #6
- LE1: CPL WLED ;位反向
- MOV R5,#25
- ACALL DELAY ;延迟50ms
- DJNZ R4, LE1
- RET
- ;-------------- 延时子程序 -------------
- ;延时子程序
- DELAY: ;总延迟时间R5 2ms
- MOV R6,#10
- D1: MOV R7,#100
- DJNZ R7,$
- DJNZ R6, D1
- DJNZ R5, DELAY
- RET
- ;------------ 蜂鸣器短暂延时子程序-----------
- ; 蜂鸣器
- DEX: MOV R7, #180 ;短暂延时
- DE1: NOP
- DJNZ R7, DE1
- RET
- ;******************** 增加定时闹铃程序部分 *********************
- ; ----------- 设置闹铃时间子程序 ------------
- ;设置闹铃时间
- SET_ATIME:
- MOV HH, #0
- MOV MM, #0
- ACALL CONVA ;加载闹铃时间数据
- N0:
- ACALL DISP
- ;-----------
- JB K2, N1 ;未按下K2键,则继续扫描
- JNB K2, $ ;按下,则等待放开
- ;K2调整小时
- INC HH ;小时数加1
- MOV A, HH
- CJNE A, #24, N11 ;是否24h到了
- MOV HH, #0 ;小时数清0
- N11:
- ACALL CONVA ;加载闹铃时间数据
- ACALL DISP ;扫描显示
- JMP N0 ;跳转到N0处运行
- ;------------
- N1: JB K3, N2 ;未按下K3键,则继续扫描
- JNB K3, $ ;按下,则等待放开
- ;K3调整分钟
- INC MM ;调整分钟数
- MOV A, MM ;分钟数加1
- CJNE A, #60, N21 ;是否60min到了
- MOV MM, #0 ;分钟数清0
- N21:
- ACALL CONVA ;加载闹铃时间数据
- ACALL DISP ;扫描显示
- JMP N0 ;跳转到N0处运行
- ;------------
- N2: JB K4, N0 ;未按下K4键,则继续扫描
- JNB K4, $ ;等K4键放开
- ;K4设置完成
- ACALL LED_BL ;LED闪动
- ACALL CONV ;加载现在时间数据
- RET
- ; ----------- 加载闹铃时间数据子程序 ----------
-
- CONVA:
- ;转换小时数据
- MOV A, HH
- MOV B, #10
- DIV AB
- ;-----------
- MOV DPTR,#TABLE ;查表转换
- MOVC A, @A+DPTR
- MOV BUF, A
- ;-----------
- MOV A, B
- MOVC A, @A+DPTR
- MOV BUF+1, A
- ;转换分钟数据
- MOV A, MM
- MOV B, #10
- DIV AB
- ;-----------
- MOV DPTR, #TABLE ;查表转换
- MOVC A, @A+DPTR
- MOV BUF+2, A
- ;-----------
- MOV A, B
- MOVC A, @A+DPTR
- MOV BUF+3, A
- RET
-
- ; ---------- 检查闹铃时间处理子程序 ----------
- ;检查是否启动闹铃
- TIME_PRO:
- JB ALB, TI3
- RET
- ; --------------
- ;检查闹铃时间是否到了
- TI3:
- MOV A, HOUR
- MOV B, HH
- CJNE A, B, BK ;检查闹铃小时时间
- ;-----------
- MOV A, MIN
- MOV B, MM
- CJNE A, B, BK ;检查闹铃分钟时间
- ;-----------
- ACALL TIME_OUT ;调用执行检查闹铃时间处理子程序
- BK:
- RET
- ;---------- 执行闹铃时间处理子程序 -----------
- TIME_OUT: ;所设置的闹铃数据到了
- X1: ACALL LED_BL ;LED闪动
- ACALL BZ ;蜂鸣器发声
- ;按下K4键停止闹铃
- JB K4, X1 ;等待是否按下K4键
- JNB K4,$ ;若按下键,则等待按键放开
- ACALL LED_BL ;LED闪动
- CLR ALB ;清除闹铃位
- RET
- ; -----------------------------------
-
- ;******************** 增加倒计时程序部分 ***********************
- ;----------- 设置倒计时时间子程序 ----------
- ;设置倒计时时间
- DOWN_ATIME:
- CLR TR0 ;定时器工作暂停
- MOV HH, #0
- MOV MM, #0
- MOV SS_D, #1 ;秒钟变量为1
- S0:
- ACALL DISP ;扫描显示
- ;-----------
- ;按K2分钟数增加
- JB K2, S12 ;未按下K2,则继续扫描
- JNB K2, $ ;按下,则等待放开
-
- INC MM_D ;分钟数加1
- MOV A, MM_D
- CJNE A, #60, S11 ;是否60min到了
- MOV MM_D, #0 ;分钟变量清0
- S11:
- ACALL DOWN_CONV ;显示倒数的时间
- ACALL DISP ;扫描显示
- JMP S0 ;跳转到S0处运行
- ;------------
- ;按K3分钟数减少
- S12: JB K3, S2 ;未按下K3,则继续扫描
- JNB K3, $ ;按下,则等待放开
- DEC MM_D ;分钟数减少1
- MOV A, MM_D
- CJNE A, #0,S21 ;判断是否为0
- MOV MM_D, #60 ;分钟数赋值为60
- S21:
- ACALL DOWN_CONV ;加载倒数时间数据
- ACALL DISP ;扫描显示
- JMP S0 ;循环执行
- ;------------
- S2: JB K4, S0 ;未按下K4键,则继续扫描
- JNB K4, $ ;等K4键放开
- ;K4设置完成
- ACALL BZ ;响4声
- ACALL BZ
- ACALL BZ
- ACALL BZ
-
- ACALL LED_BL ;LED闪动
- SETB TR0 ;启动定时器
-
- S3:
- ACALL DOWN_TIME ;检查倒计时
- ACALL DOWN_CONV ;加载倒数时间数据
- ACALL DISP ;扫描显示
- JMP S3
- RET
-
- ; ---------- 加载倒计时时间子程序 ---------
- ;显示倒数的分钟数
- DOWN_CONV:
- MOV A, MM_D
- MOV B, #10 ;设置被除数
- DIV AB ;除法运算,结果A存商数,B存余数
- MOV DPTR, #TABLE ;查表转换
- MOVC A, @A+DPTR
- MOV BUF+2, A ;商数存入BUF+2
- MOV A, B ;余数暂存入A
- MOVC A, @A+DPTR ;查表转换
- MOV BUF+3, A ;余数存入BUF+3
- RET
-
- ;------------- 检查倒计时子程序 ------------
- ;检查倒计时
- DOWN_TIME: ;检查是否倒数终止
- MOV A,SEC ;加载现在秒数
- MOV B, SEC0 ;载入旧秒数
- CJNE A, B, D01 ;是否过了1s
- RET
- ; -----------
- D01:
- MOV SEC0, SEC ;记录旧的秒数
- DEC SS_D ;秒数减1
- MOV A, SS_D
- CJNE A, #0, D11 ;秒钟数是否为0
- MOV A, MM_D
- CJNE A, #0, D12 ;分钟数是否为0
- ;秒钟数为0且分钟数为0,则倒数终止
- ACALL TIME_OUT ;倒数终了处理程序
- JMP LOOP
- RET
- ;-----------
- D12:
- MOV SS_D,#59 ;秒钟数赋值为59
- DEC MM_D ;分钟数减1
-
- D11:
- ACALL DOWN_CONV ;显示倒计时时间
- RET
- ;----------------------------------
- END
- ;-----------------------------------------------------------------
复制代码
单片机c语言源程序:
- // --------------------------------------------------------------------------------------
- // 文件名称:SZ10-1.c
- // 程序功能:单片机时钟
- // --------------------------------------------------------------------------------------
- #include <reg51.h> // 包含器件配置文件
- #define uchar unsigned char
- #define uint unsigned int
- char DATA_7SEG[10]={0xC0,0xF9,0xA4,0xB0,0x99,
- 0x92,0x82,0xF8,0x80,0x90}; // 0~9的数码管段码
- uchar hour=0,min=0,sec=0; // 时、分、秒单元清0
- uchar deda=0; // 5ms计数单元清0
- bit d_05s=0; // 0.5s标志
- uchar set=0; // 模式设定标志
- uchar m=0;
- uchar flag=0; // RAM掉电标志
- void delay(uint k); // 延时函数
- void conv(); // 走时单元转换
- void disp(); // 走时时间显示函数
- //-----------------------
- sbit K1=P2^4; // 按键K1引脚定义
- sbit K2=P2^5; // 按键K2引脚定义
- sbit K3=P2^6; // 按键K3引脚定义
- sbit K4=P2^7; // 按键K4引脚定义
- //-----------------------
- sbit SPK=P3^7; // 蜂鸣器引脚定义
- sbit SET_2=P2^2;
- sbit M_D=P0^7;
- // ---------------------------- 定时器初始化函数----------------------------
- // 定时器T0初始化
- void init_timer()
- {
- TMOD=0x01; // 设置定时器T0工作模式为1
- TH0=-(4800/256); // 加载高字节计数初值
- TL0=-(4800%256); // 加载低字节计数初值
- IE=0x82; // 启用定时器T0中断产生
- TR0=1; // 启动定时器T0开始计时
- }
- // ------------------------------- 中断T0函数 ------------------------------
-
- // 5ms定时中断
- void T0_srv(void) interrupt 1
- {
- TH0=-(4800/256); // 重置定时器计时初始值
- TL0=-(4800%256);
- deda++; // 计数单元deda 值递增
- }
-
- // ----------------------------- 走时单元转换函数 -------------------------
- // 时、分、秒单元及走时单元转换
- void conv()
- {
- if(deda<=100)d_05s=0; // 秒位标志,每秒的后0.5s置0
- else d_05s=1; // 秒位标志,每秒的前0.5s置1
- if(deda>=200){sec++;deda=0;} // 中断200次秒加1,deda清0
- if(sec==60){min++;sec=0;} // 秒满60次后,分加1,秒清0
- if(min==60){hour++;min=0;} // 分满60次后,时加1,分清0
- if(hour==24){hour=0;} // 小时满24后,小时清0 */
- }
- // ------------------------------ 走时时间显示函数 ------------------------
- // 走时时间显示
- void disp()
- {
- P0=DATA_7SEG[hour/10];P2=0xf7;delay(2);
- P0=DATA_7SEG[hour%10];P2=0xfb;delay(2);
- if(d_05s==1){if(SET_2==0)M_D=0;else M_D=1;}
- delay(2);
- P0=DATA_7SEG[min/10];P2=0xfd;delay(2);
- P0=DATA_7SEG[min%10];P2=0xfe;delay(2);
- }
- // ----------------------------- 调整走时时间函数 -------------------------
- /* 调整走时时间 */
- void set_time()
- {
- uchar m;
- //TR0=0;
- if(K2==0)delay(1); // 按下K2键,消除抖动
- if(K2==0)hour++; // 小时数递增
- if(hour==24)hour=0; // 小时数到24,从0开始
- for(m=0;m<30;m++) // 循环30次
- {
- disp(); // 调用disp()显示函数
- if(SET_2==0)M_D=0; // 点亮U2小数点(秒点)
- else M_D=1;
- delay(1); // 调用delay(1)延时函数
- }
- if(K3==0)delay(1); // 按下K3键,消除抖动
- if(K3==0)min++; // 分钟数递增
- if(min==60)min=0; // 分钟数到60,从0开始
- for(m=0;m<30;m++) // 循环30次
- {
- disp(); // 调取disp()显示函数
- if(SET_2==0)M_D=0; // 点亮U2小数点(秒点)
- else M_D=1;
- delay(1); // 调取delay(1)延时函数
- }
- }
- // ------------------------------ 走时函数 ---------------------------------
- //走时
- void time()
- {
- conv(); // 走时单元转换
- disp(); // 走时时间显示函数
- }
- // ----------------------------- 按键模式函数 ------------------------------
- // 扫描按键次数
- void scan_key()
- {
- delay(1); // 调用延时函数
- if(K1==0) set++; // 按一下K1键,set 加1
- if(set>=2)set=0; // 按两次K1键,set 为0
- if(set==1)flag=0x55; // set =1,flag等于55H
- F0:if(K1==0)goto F0; // 按键未释放,在此等候
- }
- //------------------------------ 延时函数 ---------------------------------
- //延时
- void delay(uint k) // 总延时时间:1ms k
- {
- uint i,j; // 定义局部变量i、j
- for(i=0;i<k;i++){ // 外层循环
- for(j=0;j<121;j++) // 内层循环
- {;}}
- }
- //------------------------------- 发声函数 --------------------------------
-
- // 发声
- void fs_d ()
- {
- unsigned int j,y; // 声明无符号整型变量j, y
- {
- for(y=0;y<1000;y++) // 循环1000次,嘀响0.5s
- {
- SPK=~SPK; // 反相输出
- for(j=0;j<50;j++); // 延时500μs
- }
- delay(200); // 停0.2s
- }
- }
-
- //--------------------------------- 主函数 --------------------------------
- //主函数
- void main()
- {
- init_timer(); // 定时器T0初始化
- while(1) // 无限循环
- {
- if(K1==0)
- {
- scan_key(); // 有按键,调用按键扫描函数
- fs_d ();
- }
- switch(set) // 根据set键值散转
- {
- case 0:time(); break; // 走时时间程序
- case 1: set_time();break; // 走时时间调整
- default:break; // 其他,退出
- }
- if(flag!=0x55) // 判断掉电标志
- {
- P0=0xc0; P2=0xc0; delay(200); // 点亮4个数码管
- P2=0xff; delay(400); // 熄灭 4个数码管
- }
- }
- }
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
该系列源码包含有很多非常经典,代码风格十分规范,而且注释详细的单片机例程,还带仿真,对于MCU学习特别是初学者是很有帮助的,全部源码下载(共25个项目):http://www.51hei.com/bbs/dpj-79328-1.html
本例程下载(含proteus仿真工程文件与源码):
单片机数码管单片机时钟实验.rar
(62.5 KB, 下载次数: 59)
|
|