51单片机实验报告Word文件下载.docx
《51单片机实验报告Word文件下载.docx》由会员分享,可在线阅读,更多相关《51单片机实验报告Word文件下载.docx(80页珍藏版)》请在冰豆网上搜索。
![51单片机实验报告Word文件下载.docx](https://file1.bdocx.com/fileroot1/2023-2/6/30e70424-8689-405d-a514-60ebc63d151e/30e70424-8689-405d-a514-60ebc63d151e1.gif)
1.时-分-秒(2位-2位-2位)显示
可通过键盘置入时间值(参照电子表设置时间工作模式)。
2.可通过按键控制在LED上从右向左滚动显示年_月_日3次,如:
2012_01_20空空2012_01_20
3.实现每日闹铃提醒功能,闹铃时间可用按键设置。
闹铃采用提示音表示。
4.实现秒表功能。
5.实现定时器功能(预置定时时间,按键启动,倒计时,计到0响提示音。
6.设计实现音乐提示音。
7.设计串行通信程序,使两台实验系统同步显示。
2.硬件环境与工作原理
2.1硬件环境:
2.1.1单片机:
SST89E564RD
图2.1
2.1.2外部设备:
1.八位8段数码管
图2.2
2.一个4x4非编码键盘
图2.3
2.2工作原理:
2.2.1引入选通信号的原因:
由于AT89C51单片机的引脚数目有限,需要采用引脚时分复用技术,因此引入AJ00~AJ07作为选通信号,用于选择当前的输入输出设备。
其中,AJ00~AJ07是A12~A14经过74138译码器后的输出信号(A15为译码器的使能信号)。
2.2.2选通信号产生电路图:
图2.4
2.2.3数码管位选择原理:
1.输出位选信号指令:
MOVA,#SELECT;
SELECT为位选信号对应的数值
MOVDPTR,#8000H
MOV@DPTR,A
2.电路实现原理:
在指令“MOVDPTR,#8000H”中,8000H代表外部存储器的地址,对应于A15=1,Ai=0(i=0~14)。
由图2.4可知,此时74138译码器有效,由A=B=C=0,得:
AJ00=0,AJ0i=1(i=1~7)。
有由于执行指令“MOV@DPTR,A”时,WR=0,因此,由图2.2可知74HC573有效,它将D0~D7信号保持并输入ULN2803,信号经过放大后,作为位选信号驱动8位数码管。
2.2.4数码管段选择原理:
1.输出段选信号指令:
MOVA,#SELECT;
SELECT为段选信号对应的数值
MOVDPTR,#9000H
2.电路实现原理:
在指令“MOVDPTR,#9000H”中,9000H代表外部存储器的地址,对应于A15=1,A12=1,Ai=0(i=0~11,13,14)。
由图2.4可知,此时74138译码器有效,由A=C=0,B=1,得:
AJ01=0,AJ0i=1(i=0,2~7)。
有由于执行指令“MOV@DPTR,A”时,WR=0,因此,由图2.2可知74HC573有效,它将D0~D7信号保持并作为位选信号输入8位数码管。
2.2.54x4键盘控制原理:
由图2.3可知,AJ00=0时,可通过P00~P03向键盘发出扫描信号或读取键盘信号。
具体原理见后续代码。
3.资源使用
3.1RAM的使用情况
ALARMEQU20H.0;
闹钟设置标志
TIME_UPEQU20H.1;
倒计时时间到标志
SOUND_ONEQU20H.2;
声音开关标志
UART_ENEQU20H.3;
处于串口通信状态标志
IS_HOSTEQU20H.4;
是否作为串口通信的主机标志
HOUR_TPEQU2AH
MIN_TPEQU2BH
SEC_TPEQU2CH
MUSIC_SELECTEQU2DH
TIME_BUFEQU2EH;
30~35H连续存放led显示数据
HOUREQU36H;
小时
MINEQU37H;
分钟
SECEQU38H;
秒
COUNTEQU39H;
每0.05s加1
HOUR_ALARMEQU3AH
MIN_ALARMEQU3BH
SEC_ALARMEQU4BH
SEC_OLDEQU3CH;
存放旧的秒数
HOUR_DOWNEQU3DH
MIN_DOWNEQU3EH;
倒数时分钟数
SEC_DOWNEQU3FH;
倒数时间秒钟数
VAR_HOUREQU40H
VAR_MINEQU41H
VAR_SECEQU42H
MSEQU43H;
作用同SEC_OLD
YEAR0EQU44H
YEAR1EQU45H
MONTHEQU46H
DAYEQU47H
MUSIC1EQU48H
MUSIC2EQU49H
MUSIC3EQU4AH
DATE_BUFEQU60H;
以下连续12字节为日期显示数据
3.2系统堆栈使用情况
主程序将SP设置为50H,在50H到60H之间的16字节为堆栈区,由于此工程设计的函数调用层次最多不超过3层且参数主要通过内存变量传递,因此,不会出现堆栈溢出的情况。
此处,更好的方案应该是把DATE_BUF前移并把堆栈放在DATE_BUF之后。
但是,实际操作时发现如果堆栈区包含62H以后的区域,就会出现一个严重的bug,由于这个bug一直没法解释和解决,我只好采用了现在这个方案。
3.3寄存器使用情况:
1.累加器A
2.寄存器B
3.00区的R0~R7寄存器,01~03区的寄存器不曾使用。
3.4定时器计数器使用情况
整个工程用到了定时器T0和T1。
其中T0用于主时钟的计时,优先级最高,不可被软中断中断,且不可被软中断屏蔽。
T1用于控制播放音乐时音调的频率和控制串口通信时的波特率。
4程序原理与框图
4.1主函数
4.1.1主函数框图
T0中断服务:
4.1.2主函数代码:
;
*************************************主函数***********************************************;
***作者:
***日期:
2012226
NAMEMAIN_FUNC
EXTRNCODE(GET_KEY,BEEP,SET_DOWN_TIMER,CONVERT,DISP,SET_TIME,SET_ALARM_TIME)
EXTRNCODE(COUNTER,DATE_ROLLER,MUSIC,INT_T1,UART_INT,UART_HOST,UART_SLAVE,SET_DATE)
蜂鸣器引脚定义
BUZZEREQUP1.6
PROGSEGMENTCODE
CSEGAT0
ORG0H
JMPMAIN
ORG0BH
JMPINT_T0
ORG001BH
JMPINT_T1;
跳转至T1中断服务程序
ORG23H
JMPUART_INT
CSEGAT0050H
RSEGPROG
主程序;
MAIN:
MOVSP,#50H
LCALLINIT;
初始化变量
LCALLINIT_TIMER;
设置定时器
LCALLINIT_SHOW
无穷循环
LOOP:
MOVVAR_HOUR,HOUR
MOVVAR_MIN,MIN
MOVVAR_SEC,SEC
LCALLCONVERT;
先传递参数再调用
LCALLTIME_TEST;
检查闹钟时间
LCALLDISP
LCALLGET_KEY
MOVA,#15
CJNEA,#9,LOOP_TO_10
LCALLBEEP
LCALLSET_TIME
LJMPLOOP
LOOP_TO_10:
CJNEA,#10,LOOP_TO_11
LCALLSET_ALARM_TIME
JMPLOOP
LOOP_TO_11:
CJNEA,#11,LOOP_TO_12
LCALLSET_DOWN_TIMER;
设置倒计时间
LOOP_TO_12:
CJNEA,#12,LOOP_TO_13
LCALLCOUNTER
LOOP_TO_13:
CJNEA,#13,LOOP_TO_14
LCALLDATE_ROLLER
LOOP_TO_14:
CJNEA,#14,LOOP_TO_2
LCALLSET_DATE
LOOP_TO_2:
CJNEA,#2,LOOP_TO_15
JBALARM,ALARM_OFF
SETBALARM
ALARM_OFF:
CLRALARM
NO_KEY:
LOOP_TO_1:
CJNEA,#1,NO_KEY
JNBSOUND_ON,L1
CLRSOUND_ON
LJMPL11
L1:
SETBSOUND_ON
L11:
LOOP_TO_15:
CJNEA,#15,LOOP_TO_16
LCALLUART_HOST
LOOP_TO_16:
CJNEA,#16,LOOP_TO_1
LCALLUART_SLAVE
检查是否启动闹钟
TIME_TEST:
JBALARM,TI3
RET
检查闹钟时间是否到了
TI3:
MOVA,HOUR
MOVB,HOUR_ALARM
CJNEA,B,BK
MOVA,MIN
MOVB,MIN_ALARM
LCALLTIME_OUT;
闹钟时间到了,开始提示
BK:
TIME_OUT:
MOVR0,#1;
#256
;
MOVSEC_OLD,#100
ALARMING:
MOVMUSIC_SELECT,#1;
选择第一首歌曲
LCALLMUSIC
LCALLGET_KEY
CJNEA,#4,AL1;
响铃次数没到,但是用户按K4停止闹钟
LJMPAL2
AL1:
DJNZR0,ALARMING;
响铃的次数到了就停
AL2:
CLRALARM
显示时钟初始值000000
INIT_SHOW:
MOVDPTR,#8000H
MOVA,#B
MOVX@DPTR,A
中断服务程序
INT_T0:
PUSHPSW
PUSHACC
CLREA;
关中断
CLRTR0
MOVA,#7;
加上执行到SETTR0处需要的时间
ADDA,TL0
MOVTL0,A
MOVA,#0DCH
ADDCA,TH0
MOVTH0,A
SETBTR0
INCCOUNT
秒输出
MOVA,COUNT
CJNEA,#100,TT1;
是否一秒到了
MOVCOUNT,#0
INCSEC
MOVA,SEC
CJNEA,#60,TT1;
是否一分钟到了
分输出
INCMIN
MOVSEC,#0
是否一小时到了
时输出
INCHOUR
MOVMIN,#0
CJNEA,#24,TT1
MOVHOUR,#0
MOVA,MONTH
CJNEA,#2,NOT_2
MOVA,YEAR1
CJNEA,#0,NOT_100
MOVA,YEAR0
MOVB,#4
DIVAB
MOVA,B
CJNEA,#0,NOT_2
MOVR0,#28
LJMPDAY_TEST
NOT_100:
MOVR0,#29
LJMPNO1
NOT_2:
MOVDPTR,#(MONTHS-1)
MOVC+DPTR
MOVR0,A
NO1:
TT1:
;
如果放在最后会出现OUTOFRANGE错误!
POPACC
POPPSW
SETBEA;
开中断
RETI
DAY_TEST:
INCDAY
MOVA,DAY
INCR0
MOVB,R0
CJNEA,B,TT1
MOVDAY,#1
INCMONTH
CJNEA,#13,TT1
MOVMONTH,#1
INCYEAR1
CJNEA,#100,TT1
MOVYEAR1,#0
INCYEAR0
MOVYEAR0,#0
JMPTT1
使用定时器T0模式0计时
INIT_TIMER:
MOVTMOD,#01H
MOVIE,#B
MOVTL0,#00H
MOVTH0,#0DCH
SETBTR0;
启动定时器T0
初始化:
计时单元清零
INIT:
CLRALARM;
关闭闹钟功能
MOVHOUR_ALARM,#0
MOVMIN_ALARM,#0
MOVSEC_ALARM,#0
MOVSEC_OLD,#0;
保存的秒值以便对比判断是否过了一秒
MOVHOUR_DOWN,#0
MOVMIN_DOWN,#0
MOVSEC_DOWN,#0
MOVTIME_BUF+2,#B;
显示时分秒之间的分隔符
MOVTIME_BUF+5,#B;
MOVYEAR0,#20
MOVYEAR1,#12
MOVMONTH,#2
MOVDAY,#14
SETBSOUND_ON;
开声音
平年的每月天数表
MONTHS:
DB31D,28D,31D,30D,31D,30D,31D,31D,30D,31D,30D,31D
END
4.2主时钟设置模块:
4.2.1主时钟设置模块代码:
*********************************主时钟设置模块*******************************************;
***外部接口:
SET_TIME
***参数:
无
***日期:
2012220
NAMESETTING_CLOCK
EXTRNCODE(DISP,GET_KEY,CONVER