多功能数字时钟 四院三队 李博.docx
《多功能数字时钟 四院三队 李博.docx》由会员分享,可在线阅读,更多相关《多功能数字时钟 四院三队 李博.docx(25页珍藏版)》请在冰豆网上搜索。
多功能数字时钟四院三队李博
多功能数字时钟
设计者:
李博
院别:
四院三队
系统方案
摘要:
本系统的设计电路由实时时钟模块、环境温度检测模块、电压检测模块、人机接口模块等部分组成。
其中实时时钟采用由11.0592M晶振控制单片机STC12C5A60S2内部中断实现,可实现年、月、日、时、分、秒等时间信息的采集和调整功能;温度检测模块由DS18B20集成温度传感器对现场环境温度进行实时检测;电压检测模块由单片机STC12C5A60S2上在P1口集成的AD功能检测等实现对电压的测量;人机接口模块由4*4薄膜键盘和1602液晶组成,可实现题目要求的时间显示、时间调整、环境温度测量、电压显示等功能;外接5V开关稳压电源则是采用MC34063芯片,该芯片既有稳压功能,还能放大电流,作为单片机的驱动。
总体方案比较与论证
方案一:
采用CPLD作为主控制器控制外围电路进行电压、频率测量、时钟控制、温度测量、键盘和LED控制。
此方案逻辑电路复杂,且灵活性较低、不利于各种功能的扩展。
方案二:
采用单片机来实现系统的控制。
键盘采用4*4矩阵薄膜键盘控制,手感良好,反应迅速;时钟采用外部晶振提供的11.0592M控制单片机内部中断和计数器,总体构成数字时钟;温度传感器采用DS18B20;电压信号可通过集成在STC12C5A60S2单片机P1口上的AD直接测得;电源由一个220~12V工频变压器、BPK310整流桥、以及后续由MC34063和外围电路构成的降压电路构成。
此系统硬件简洁,将复杂的硬件功能用软件实现,因此系统控制灵活,能基本满足本题的基本要求和扩展要求。
此方案基本原理框图如图1所示。
故采用方案2。
模块电路设计与比较
1.时钟方案选择
方案一:
因为题目中要求不高,因此可以用门电路组合构成时钟发生器,但此方案硬件复杂,稳定性低,且不易控制。
方案二:
因题目并未要求时钟为高精度,且时钟芯片外接电路复杂,故时钟采用外部晶振提供的11.0592M控制单片机内部中断和计数器,总体构成精度基本满意的数字时钟;
故采用方案2。
2.温度检测方案选择
方案一:
采用热电偶或热敏电阻作感温元件,但热电偶需冷端补偿,电路设计复杂,热敏电阻虽然精度较高,但需要标准稳定电阻匹配才能使用,而且重复性、可靠性都比较差。
方案二:
采用集成温度传感器DS18B20结构简单,不需外接电路,数据传输采用one—wire总线,可用一根I/0数据线既供电又传输数据,在-10~+100摄氏度范围内精度为±0.5摄氏度,能满足题目的要求,且分辨率较高,重复性和可靠性好。
故采用方案2。
3.电压测量方案选择
方案一:
采用0809外接AD转换芯片,精确度高,但是硬件电路搭接复杂,且芯片28脚稳定性能不好。
方案二:
采用STC12C5A60S2单片机集成在P1口上的8路10位高速AD转换器,既节约空间时间,电路简洁明了,又能达到题目要求的0~5V电压。
故采用方案2。
6.显示模块的选择
方案一:
采用数码管显示。
数码管亮度高、体积小、重量轻,但其显示信息简单、有限,在本题目中应用受到很大的限制。
方案二:
采用液晶显示。
液晶显示功耗低、轻便防震。
由于本题显示信息比较复杂,采用液晶显示界面友好清晰,操作方便,显示信息丰富。
7.其他设计的考虑
(1)考虑到最终成品只做出P10的1路电压检测,且题目要求能同时显示的数据越多越好,所以把题目所要求的所有数据都在1602的2行屏幕上显示出来(包括时间、星期、日历、温度、电压)。
理论分析和计算
(1)单片机最小系统组成:
单片机系统是整个硬件系统的核心,它既协调整机工作,又是数据处理器,还是软硬件系统连接的桥梁。
它包括:
单片机STC12C5A60S2,11.0592M晶振,上拉电阻,DS18B20温度模块,并行液晶驱动1602,4*4矩阵键盘,复位电路。
(2)时钟原理:
11.0592M的晶振可以近似看做12M,所以1个机器周期=12个时钟周期=12*(1/12)=1us。
当CPU设置为开启定时功能后,定时器便在晶振的作用下自动开始计时。
考虑时钟的精度,所以TMOD设置为0x20,即采用定时器1的方式2:
8位初值自动重装的8位定时器/计数器。
初值为TH1=56,TL1=56,所以中断一次所需要的时间为256-56=200个机器周期=200us,时钟走1S的所需要1s/200us=5000次中断,换算成11.0592M加上一些系统误差大约是4500次左右。
因此程序中取num==4506,秒++。
(3)测温模块原理:
测温模块采用了DS18B20芯片:
DS18B20引脚定义:
(1)DQ为数字信号输入/输出端;
(2)GND为电源地;
(3)VDD为外接供电电源输入端(在寄生电源接线方式时接地)。
根据DS18B20的通讯协议,主机(单片机)控制DS18B20完成温度转换必须经过三个步骤:
每一次读写之前都要对DS18B20进行复位操作,复位成功后发送一条ROM指令,最后发送RAM指令,这样才能对DS18B20进行预定的操作。
复位要求主CPU将数据线下拉500微秒,然后释放,当DS18B20收到信号后等待16~60微秒左右后发出60~240微秒的存在低脉冲,主CPU收到此信号表示复位成功。
因只采用一个DS18B20,复位成功后,写入跳过ROM,温度转换,读暂存器等命令。
最后得到两个八位的值,取高八位的后四位和低八位的前四位,组成的八位数值即为所要测得温度值的整数部分,低八位的后四位为16进制的小数部分*0.625即得所要测得温度的小数部分。
测试完毕。
(4)电压测试原理:
利用P1口集成的高速8路AD转换实现。
因为上拉电阻的存在,所以需要在电压采集程序的开头赋给P10口低电平,然后调节电位器,使P10口电压变为0.00,作为基准电压。
具体方法为:
先将P1ASF特殊功能寄存器设置为0x01:
即P10口作为模拟AD输入口,再将ADC_CONTR(ADC转换控制寄存器)设置为0x88:
即为允许转换和开始转换;然后检测ADC_CONTR是否变为0x90:
转换完成;如果是,取ADC_RES的全八位和ADC_RESL的低两位,然后舍去ADC_RES里面的高2位,剩下部分与ADC_RESL组成新的八位结果。
根据公式结果Y=1024*VIN/VCC。
VCC是单片实际工作电压,此处为5V,即可求得VIN:
输入电压值。
测试完毕。
(5)稳压电源电路原理:
题目要求做一个从220V~5V的AC-DC开关稳压电源,选用MC34063芯片作为主控芯片。
起始位置为220V~12V的工频变压器,再经过整流桥的整流,输出大概14V的直流电,然后通过3个滤波电容,1个瓷片电容,1个5819,1个电感,MC34063芯片,2个调节输出电压的电阻等构成的特定电路,最终输出1.25*(1+3/1)=5V的DC电压。
因为芯片里面带有放大效应的三极管以及稳压模块,最终得到的电源能够带动外围设备,并成功稳压。
电路及程序设计
单片机核心及其引脚:
:
并行液晶模块:
键盘模块:
4*4:
晶振和复位电路:
温度模块:
ADC模拟:
电源电路:
软件部分
注:
源程序贴于附录部分。
现对软件部分做出一些诠释:
系统软件部分为实现系统功能,系统软件共设五个运行状态(S1-S5)和一个中断处理程序。
各部分功能描述如下:
S1为时钟运行状态,即时钟自动秒时分乃至年月日的累加;
S2为键盘扫描状态,即先检测行列电平再消抖,最后扫描得到一定的键值然后执行相关功能:
包括按2键初始化光标,调整时间有效;按3键光标消失,调整时间无效;按5键光标右移一位(光标只出现在可调节位);按8键,光标所在位组(2位为一位组)数值+1:
即光标在表示分(时、日、月)的位组时,分(时、日、月)+1,在秒位组时秒清零处理,在年的高2位和低2位时同时、分一样处理,且为了防止溢出具有自动循环功能;按9键同理8键,做减1运算。
S3为自动定位光标状态,每隔一定的中断数自动定位到当前光标一次,可以有效消除写数据带来的光标冲突。
S4为实时温度检测状态,利用软件读取DS18B20寄存器中的数值进行转化,然后显示在1602上第二行前4位。
S5为P10口电压检测状态,利用P10口上集成的高速AD转换器测试外接的输入电压Vin,显示在1602的第一行前4位。
S1-S5五种状态全由中断计数器控制刷新频率,能够满足题目的要求。
测试方法与测试结果
(1)时钟测试:
在带有单片机STC12C5A60S2的小系统上,使其在液晶上显示出时分秒年月日和星期,并可以通过键盘控制设定时间。
利用仿真机调试成功后通过编程器将程序写入芯片中调试。
最终测试结果与Casio的电波表(该表采用原子钟的电波,误差可忽略)相比,结果满足时钟基本精度。
时钟测试数据:
(2)温度测试:
利用仿真机通过程序读出温度传感器DS18B20中的温度数据,并且进行了定标,送到液晶显示,并与室内温度计测得的数值相比较,看是否在误差允许范围内。
在实际测量中,我们发现DS18B20在低温和高温时变化比较缓慢,误差相对较大一些,在室温时测量比较正常。
温度测试数据:
(3)电压测试:
调节稳压电源电位器,使电源输出0~5V的电压作为直流信号,先用数字万用表测量电压值,再用设计的电路测量此信号,然后求出误差,反复调整改进到在误差允许的范围内。
电压测试数据:
总结
本系统以STC12C5A60S2为核心部件,利用软件编程,通过键盘控制和液晶显示实现了时钟功能,并完成了对环境温度和电压值的测量显示,能实现题目的基本要求和部分选作部分。
尽量做到硬件电路简单稳定、减小电磁干扰和其他环境干扰,充分发挥软件编程的优点,减小因元器件精度不够引起的误差。
由于时间有限和本身知识水平的限制,我认为本系统还有需要改进和提高的地方,例如选用更高精度的元器件,硬件电路更加精确稳定,软件测量算法进一步地改进与完善等。
参考文献:
(1)谭浩强.C语言设计.北京:
清华大学出版社,1991
(2)宏晶科技STCMicrocontrollerHandbook,2007
(3)郭天祥.51单片机C语言教程.电子工业出版社,2009
(4)周坚.单片机C语言轻松入门.
北京航空航天大学出版社,2006
(5)江志红.51单片机技术应用与应用系统开发案例精选.
清华大学出版社,2008
附录:
源程序:
/*******************************
软件版本:
KeiluV3
CPU:
STC12C5A60S2
时钟:
11.0592M
队别:
四院三队
设计者:
李博
开发时间:
2010/10/1
最后修改时间:
2010/10/14
*******************************/
#include
#defineuintunsignedint
#defineucharunsignedchar
ucharcodedat[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};
ucharcodeLCDCode[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','*','#'};
ucharcodetable[]={'1','2','3','4','5','6','7'};
sfrKey_Port=0x80;
sfrP4SW=0xbb;
sfrP1ASF=0x9d;
sfrADC_CONTR=0xbc;
sfrADC_RES=0xbd;
sfrADC_RESL=0xbe;
sfrAUXR1=0xa2;
sfrP1M1=0x91;
sfrP1M0=0x92;
sbitX=P1^0;
sbitP44=0xc4;
sbitlcdrs=P0^7;
sbitQA=P3^3;
uintnum=0;
intshi=8,fen=0,miao=0,nian=2010,yue=10,ri=17;
charxinqi=6;
charlow2,high2;
uintguangbiao=0;
bitcursor=0;
intm;
bitKeyon=0;
bitFirst_Getkey=0;
bitGetkey=0;
ucharKey_Num=0xff;
ucharKey_NumValid=0xff;
voidInitial();
voidRead_Key();
voidInitialT0();
voidwrite_com(uchar);
voidwrite_data(uchar);
voidinit();
voiddelay(uint);
voiddelayus(longint);
voidDelay_100ns();
voidwrite_clock(uint,uint);
voidwrite_clock2(uint,uint);
voidhand();
voidouto(ucharcom1);
ucharinter(void);
voidADC_Collection();
voidInitial()
{
TMOD=0x20;
TH1=0xFF-200;
TL1=0xFF-200;
EA=1;
ET1=1;
TR1=1;
}
voidinit()
{
P44=0;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80+9);write_data('-');
write_com(0x80+12);write_data('-');
write_com(0x80+0x40+7);write_data('-');
write_com(0x80+0x40+10);write_data('-');
write_clock(11,miao);
write_clock(8,fen);
write_clock(5,shi);
write_clock2(13,ri);
write_clock2(10,yue);
write_clock2(5,high2);
write_clock2(7,low2);
}
voidwrite_clock(uintlocation,uinttime)
{
ucharshi,ge;
shi=time/10;
ge=time%10;
write_com(0x80+0x40+location);
write_data(LCDCode[shi]);
write_data(LCDCode[ge]);
}
voidwrite_clock2(uintlocation,uintcalendar)
{
ucharshi,ge;
shi=calendar/10;
ge=calendar%10;
write_com(0x80+location);
write_data(LCDCode[shi]);
write_data(LCDCode[ge]);
}
voiddelay(uintx)
{
inti,j;
for(i=x;i>0;i--)
for(j=110;j>0;j--);
}
voiddelayus(longintz)
{
while(z--);
}
voidDelay_100ns()
{
uchari;
for(i=0;i<100;i++);
}
voidhand()
{intn=1;
while(n)
{
QA=1;
delayus(8);
QA=0;
delayus(80);
QA=1;
delayus(10);
n=QA;
delayus(10);
}
}
voidouto(ucharcom1)
{
uchari;
for(i=0;i<8;i++)
{
QA=1;
QA=0;
QA=com1&0x01;
delayus(5);
QA=1;
com1>>=1;
}
}
ucharinter(void)
{ucharda=0;
uinti;
for(i=0;i<8;i++)
{
QA=0;
da>>=1;
QA=1;
if(QA)
da|=0x80;
delayus(5);
}
return(da);
}
voidADC_Collection()
{
floatvin;
ucharPd;
uintx,y;
uinta,b;
P1ASF=0x01;
ADC_CONTR=0x88;
Delay_100ns();
Pd=ADC_CONTR;
if(Pd==0x90)
{
X=0;
delay(50);
ADC_CONTR=0x88;
a=ADC_RES;
b=ADC_RESL;
a<<=2;
a=(a|b);
vin=(a*5.0/1024);
x=vin;
y=((vin-x)*100);
write_com(0x80);
write_data(LCDCode[x]);
write_data(0x2e);
write_data(LCDCode[y/10]);
write_data(LCDCode[y%10]);
write_com(0x80+5+guangbiao);
}
}
voidwrite_com(ucharcom)
{
lcdrs=0;
P2=com;
delay(10);
P44=1;
delay(10);
P44=0;
}
voidwrite_data(uchardate)
{
lcdrs=1;
P2=date;
delay(10);
P44=1;
delay(10);
P44=0;
}
voidTimer1_Int()interrupt3
{
num++;
}
voidRead_Key()
{
ucharKey_Sbuf=0;
Key_Port=0x0f;
Key_Sbuf=Key_Port;
if(Key_Sbuf!
=0x0f)
{
if(First_Getkey==0)
{
First_Getkey=1;
}
else
{
if(Keyon==0)
{
Key_Port=0x7f;
Key_Sbuf=Key_Port;
if(Key_Sbuf!
=0x7f)
{
switch(Key_Sbuf)
{
case0x77:
Key_Num=0x01;
break;
case0x7b:
Key_Num=0x02;
break;
case0x7d:
Key_Num=0x03;
break;
}
}
else
{
Key_Port=0xbf;
Key_Sbuf=Key_Port;
if(Key_Sbuf!
=0xbf)
{
switch(Key_Sbuf)
{
case0xb7:
Key_Num=0x04;
break;
case0xbb:
Key_Num=0x05;
break;
case0xbd:
Key_Num=0x06;
break;
}
}
else
{
Key_Port=0xdf;
Key_Sbuf=Key_Port;
if(Key_Sbuf!
=0xdf)
{
switch(Key_Sbuf)
{
case0xd7:
Key_Num=0x07;
break;
case0xdb:
Key_Num=0x08;
break;
case0xdd:
Key_Num=0x09;
break;
}
}
else
{
Key_Port=0xef;
Key_Sbuf=Key_Port;
if(Key_Sbuf!
=0xef)
{
switch(Key_Sbuf)
{
case0xe7:
Key_Num=0x0E;
break;
case0xeb:
Key_Num=0x00;
break;
case0xed:
Key_Num=0x0F;
break;
}
}
}
}
}
Keyon=1;
}
}
}
else
{
Key_Num=0xff;
First_Getkey=0;
Keyon=0;
}
}
voidmain()
{
P4SW=0xff;
low2=nian%100;
high2=nian/100;
init();
Initial();
write_com(0x80+0x40+15);
write_data(table[xinqi]);
while
(1)
{
if(num%350==0)
{
Read_Key();
if(Key_NumValid!
=Key_Num)
{
if(Key_NumValid!
=0xff)
{
switch(Key_NumValid)
{
case0x02:
write_com(0x80+5+guangbiao);write_com(0x0f);cursor=1;break;