标题:
单片机数码管单片机时钟实验 C语言和汇编语言2个程序 还带Proteus仿真
[打印本页]
作者:
51黑电子happy
时间:
2017-3-30 01:41
标题:
单片机数码管单片机时钟实验 C语言和汇编语言2个程序 还带Proteus仿真
基于51单片机数码管显示的
单片机时钟
仿真原理图(proteus工程文件可到本帖附件下载):
0.png
(32.25 KB, 下载次数: 50)
下载附件
2017-3-30 01:38 上传
单片机汇编语言程序:
;-----------------------------------------------------------------
;文件名称: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黑下载附件…………
复制代码
0.png
(53.93 KB, 下载次数: 39)
下载附件
2017-3-30 01:41 上传
该系列源码包含有很多非常经典,代码风格十分规范,而且注释详细的单片机例程,还带仿真,对于MCU学习特别是初学者是很有帮助的,全部源码下载(共25个项目):
http://www.51hei.com/bbs/dpj-79328-1.html
本例程下载(含proteus仿真工程文件与源码):
单片机数码管单片机时钟实验.rar
(62.5 KB, 下载次数: 59)
2017-3-30 01:40 上传
点击文件名下载附件
下载积分: 黑币 -5
作者:
基地五十
时间:
2017-3-30 10:16
学习一下
作者:
idealize
时间:
2017-6-17 21:39
好资料
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1