基于51的电子闹钟设计报告附原理图PCB图程序Word文档下载推荐.docx
《基于51的电子闹钟设计报告附原理图PCB图程序Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《基于51的电子闹钟设计报告附原理图PCB图程序Word文档下载推荐.docx(44页珍藏版)》请在冰豆网上搜索。
按键未按下时,IO口为高电平,按键按下后IO口被拉低。
1.2.3蜂鸣器驱动电路
发音部分是通过三极管放大驱动蜂鸣器工作,当IO口输出低电平时,三极管导通,蜂鸣器响。
1.2.4数码管驱动电路
由于点亮数码管所需电流较大,对单片机IO口连接上拉电阻,提高IO口的电流输出能力。
1.2.5电源电路
由于系统需要在7~12V的供电下正常工作,故采用了78M05三段稳压芯片。
78M05能将7~35V的直流电源转换成5V直流电压。
1.3软件部分的设计
1.3.1主程序部分的设计
程序部分主要采用了程序结构的模块化设计,避免了一些函数的不必要的重复书写,使程序变得单间易懂。
程序在执行时,主程序要须通过调用子函数就可完成相应的功能。
1.3.2中断计时器及时间进位
数字电子钟设计中主要使用定时器T0中断ET0,利用ET0中断进行计时时间的自增,从而实现计时功能。
STC89C51RC有两个通用定时/计数器。
两者均可配置为定时器或事件计数器。
另外增加了定时器T0/T1,溢出时T0/T1脚自动翻转的功能选项。
用作“定时器”功能时,每经过一个机器周期,寄存器值加1。
用作“计数器”功能时,寄存器在对应的外部输入管脚T0/T1上每发生一次1到0的跳变时加1。
使用该功能时,外部输入每个机器周期被采样一次。
设计中采用了中断方式1作为定时中断,其定时计数初值的设置可由以下公式计算得到。
1.3.3闹钟子函数
闹钟时间的判别主要是通过设定时间与实时时间对逐位对比确定是否进行闹铃。
1.3.4按键扫描
这些函数主要是判断是否有按键按下,并根据相应按键按下的情况调用相关函数执行。
1.3.5时钟闹钟设置
此部分主要是通过判断flag_sw、flag_set在不同值时通过调用加1、减1子函数对时间和闹钟进行设置。
1.3.6显示数字函数
函数通过判断需要显示的数字及显示的位置进行相应显示。
1.3.7显示界面函数
函数通过判断标志位flag_sw判断需要显示的界面。
1.3.8闹钟记录及读取
STC89C51RC单片机内部集成了的EEPROM是与程序空间是分开的,利用ISP/IAP技术可将内部DataFlash当EEPROM,擦写次数在10万次以上。
EEPROM可分为若干个扇区,每个扇区包含512字节。
使用时,建议同一次修改的数据放在同一个扇区,不是同一次修改的数据放在不同的扇区,不一定要用满。
数据存储器的擦除操作是按扇区进行的。
EEPROM可用于保存一些需要在应用过程中修改并且掉电不丢失的参数数据。
在用户程序中,可以对EEPROM进行字节读/字节编程/扇区擦除操作。
IAP及EEPROM新增特殊功能寄存器介绍
符号
描述
地址
位地址及符号
MSBLSB
复位值
ISP_DATA
ISP/IAPFlashDataRegister
E2H
11111111B
ISP_ADDRH
ISP/IAPFlashAddressHigh
E3H
00000000B
ISP_ADDRL
ISP/IAPFlashAddressLow
E4H
ISP_CMD
ISP/IAPFlashCommandRegister
E5H
------MS1MS0
xxxxxx00B
ISP_TRIG
ISP/IAPFlashCommandTrigger
E6H
xxxxxxxxB
ISP_CONTR
ISP/IAPControlRegister
E7H
ISPENSWBSSWRST--WT2WT1WT0
000xx000B
1.ISP/IAP数据寄存器ISP_DATA
ISP_DATA:
ISP/IAP操作时的数据寄存器。
ISP/IAP从Flash读出的数据放在此处,向Flash写的数据也需放在此处
2.ISP/IAP地址寄存器ISP_ADDRH和ISP_ADDRL
ISP_ADDRH:
ISP/IAP操作时的地址寄存器高八位。
该寄存器地址为E3H,复位后值为00H.
ISP_ADDRL:
ISP/IAP操作时的地址寄存器低八位。
该寄存器地址为E4H,复位后值为00H.
3.ISP/IAP命令寄存器ISP_CMD
ISP/IAP命令寄存器IAP_CMD格式如下:
SFRname
Address
bit
B7
B6
B5
B4
B3
B2
B1
B0
name
-
MS1
MS0
MS2
命令/操作模式选择
Standby待机模式,无ISP操作
1
从用户的应用程序区对"
DataFlash/EEPROM区"
进行字节读
进行字节编程
进行扇区擦除
程序在系统ISP程序区时可以对用户应用程序区/数据Flash区(EEPROM)进行字节读/字节编程/扇区擦除;
程序在用户应用程序区时,仅可以对数据Flash区(EEPROM)进行字节读/字节编程/扇区擦除。
已经固化有ISP引导码,并设置为上电复位进入ISP
4.ISP/IA命令触发寄存器ISP_TRIG
ISP_TRIG:
ISP/IAP操作时的命令触发寄存器。
在ISPEN(ISP_CONTR.7)=1时,对ISP_TRIG先写入46h,再写入B9h,ISP/IAP命令才会生效。
ISP/IAP操作完成后,ISP地址高八位寄存器ISP_ADDRH、ISP地址低八位寄存器ISP_ADDRL和ISP命令寄存器ISP_CMD的内容不变。
如果接下来要对下一个地址的数据进行ISP/IAP操作,需手动将该地址的高8位和低8位分别写入ISP_ADDRH和ISP_ADDRL寄存器。
每次ISP操作时,都要对ISP_TRIG先写入46H,再写入B9H,ISP/IAP命令才会生效。
5.ISP/IAP命令寄存器ISP_CONTR
ISP/IAP控制寄存器IAP_CONTR格式如下:
SFRname
Address
bit
B7
B6
B5
B4
B3
B2
B0
IAP_CONTR
E7H
name
ISPEN
SWBS
SWRST
-
WT2
WT0
ISPEN:
ISP/IAP功能允许位。
0:
禁止IAP/ISP读/写/擦除DataFlash/EEPROM
1:
允许IAP/ISP读/写/擦除DataFlash/EEPROM
SWBS:
软件选择从用户应用程序区启动(送0),还是从系统ISP监控程序区启动(送1)。
要与SWRST直接配合才可以实现
SWRST:
0:
不操作;
1:
产生软件系统复位,硬件自动复位。
设置等待时间
CPU等待时间(机器周期),(1个机器周期=12个CPU工作时钟)
WT1
Read/读
Program/编程
(=72uS)
SectorErase
扇区擦除
(=13.1304ms)
RecommendedSystemClock
跟等待参数对应的推荐系统时钟
0
1
6个机器周期
30个机器周期
5471个机器周期
5MHz
11个机器周期
60个机器周期
10942个机器周期
10MHz
22个机器周期
120个机器周期
21885个机器周期
20MHz
43个机器周期
240个机器周期
43769个机器周期
40MHz
STC89C51RC/RD+系列单片机EEPROM空间大小及地址
STC89C51RC/RD+系列单片机内部可用EEPROM的地址与程序空间是分开的:
程序在用户应用程序区时,可以对EEPROM行IAP/ISP操作。
具体某个型号单片机内部EEPROM大小及详细地址请参阅:
1.STC89C51RC/RD+系列单片机内部EEPROM详细地址表
2.STC89C51RC/RD+系列单片机内部EEPROM空间大小选型一览表
STC89C51RC系列单片机内部EEPROM详细地址表
具体某型号有多少扇区的EEPROM,参照前面的EEPROM空间大小选型一览表,每个扇区0.5K字节
第一扇区
第二扇区
第三扇区
第四扇区
起始地址
结束地址
2000h
21FFh
2200h
23FFh
2400h
25FFh
2600h
27FFh
第五扇区
第六扇区
第七扇区
第八扇区
2800h
29FFh
2A00h
2BFFh
2C00h
2DFFh
2E00h
2FFFh
每个扇区512字节,建议同一次修改的数据放在同一扇区,不是同一次修改的数据放在不同的扇区,不必用满,当然可全用。
2.硬件调试
PCB制作完成后,为检测其能否正常工作,我编写了将数码管全部点亮,蜂鸣器控制口置低电平的程序。
发现如下问题:
1.某一数码管右侧的所有数码管的相同段不亮;
2.数码管的小数点全部不亮;
3.蜂鸣器负极直接单片机IO口,蜂鸣器声音微小。
经检查后发现原因如下:
1.数码管板底层走线较细,钻孔时被打断,由于两块PCB已焊接到一起,拆解修补困难,故在数码管板顶层直接飞线;
2.PCB布局失误,使得固定螺丝与排孔引脚接错,而螺丝接地,使得该线路与GND短路;
3.单片机灌电流过小,使得电流无法驱动蜂鸣器,再加上三极管扩流后,问题得到了解决。
附录A:
电路原理图
附录B:
电路PCB图
附录C:
源程序
#include<
reg51.h>
intrins.h>
#definedp10
charsec,min,h,date=1,mon=1,year=12;
charh_ala=0,min_ala=1,sw_ala=1;
charflag_set,flag_sw;
charcount;
sbitnum1=P0^0;
sbitnum2=P0^4;
sbitnum3=P2^7;
sbitnum4=P2^3;
sbitnum5=P2^0;
sbitnum6=P2^1;
sbitbell=P2^2;
sbitkey_set=P3^0;
sbitkey_sw=P3^1;
sbitkey_l=P3^2;
sbitkey_down=P3^3;
sbitkey_ok=P3^4;
sbitkey_up=P3^5;
sbitkey_r=P3^6;
voidDelay(unsignedintz);
voiddisplay_num(charnum,charpo);
voiddisplay_sec(void);
voiddisplay_min(void);
voiddisplay_h(void);
voiddisplay_year(void);
voiddisplay_mon(void);
voiddisplay_date(void);
voiddisplay_time(void);
voiddisplay_dates(void);
voiddisplay_h_ala(void);
voiddisplay_min_ala(void);
voiddisplay_sw_ala(void);
voiddisplay_alarm(void);
voiddisplay(void);
voidcarry(void);
voidkey_swscan(void);
voidkey_setscan(void);
voidset(void);
voidalarm(void);
voidInitTimer0(void);
#defineRdCommand0x01//定义ISP的操作命令
#definePrgCommand0x02
#defineEraseCommand0x03
#defineError1
#defineOk0
#defineWaitTime0x01//定义CPU等待时间
sfrISP_DATA=0xe2;
sfrISP_ADDRH=0xe3;
sfrISP_ADDRL=0xe4;
sfrISP_CMD=0xe5;
sfrISP_TRIG=0xe6;
sfrISP_CONTR=0xe7;
voidISP_IAP_enable(void);
voidISP_IAP_disable(void);
voidISPgoon(void);
unsignedcharbyte_read(unsignedintbyte_addr);
voidSectorErase(unsignedintsector_addr);
voidbyte_write(unsignedintbyte_addr,unsignedcharoriginal_data);
voidread_ala(void);
voidrecord_ala(void);
voidmain(void)
{
read_ala();
//读取闹铃
InitTimer0();
//定时器0初始化
while
(1)
{
carry();
//进位
display();
//显示
alarm();
//闹钟
key_swscan();
//切换界面按键扫描
key_setscan();
//设置按键(改变设置标志位)扫描
if(flag_set!
=0)//设置标志位不为'
0'
,开始设置
{
set();
}
}
}
//================延时函数================
voidDelay(unsignedintz)
unsignedintx,y;
for(x=z;
x>
0;
x--)
for(y=120;
y>
0;
y--);
//================显示数字================
voiddisplay_num(charnum,charpo)
unsignedcharcodeTab[]={0x77,0x14,0xB3,0xB6,0xD4,0xE6,0xE7,0x34,0xF7,0xF6,0x08};
if(!
(num==0&
&
(po==1||po==3||po==5))||(flag_sw==1&
po==1))
switch(po)
case1:
P1=Tab[num];
num1=0;
Delay
(1);
num1=1;
break;
case2:
num2=0;
num2=1;
case3:
num3=0;
num3=1;
case4:
num4=0;
num4=1;
case5:
num5=0;
num5=1;
default:
num6=0;
num6=1;
//================显示秒================
voiddisplay_sec(void)
if(flag_set==3&
count>
10||flag_set!
=3)
display_num(sec/10,5);
display_num(sec%10,6);
//================显示分================
voiddisplay_min(void)
if(flag_set==2&
=2)
display_num(min/10,3);
display_num(min%10,4);
display_num(dp,4);
//================显示时================
voiddisplay_h(void)
if(flag_set==1&
=1)
display_num(h/10,1);
display_num(h%10,2);
display_num(dp,2);
//================显示日================
voiddisplay_date(void)
display_num(date/10,5);
display_num(date%10,6);
//================显示月================
voiddisplay_mon(void)
display_num(mon/10,3);
display_num(mon%10,4);
//================显示年================
voiddisplay_year(void)
display_num(year/10,1);
display_num(year%10,2);
//================显示时间================
voiddisplay_time(void)
display_sec();
display_min();
display_h();
//================显示日期================
voiddisplay_dates(void)
display_date();
display_mon();
display_year();
//================显示闹钟时================
voiddisplay_h_ala(void)
display_num(h_ala/10,1);
display_num(h_ala%10,2);
displ