您好,欢迎来到九壹网。
搜索
您的当前位置:首页电子钟& 温度计制作

电子钟& 温度计制作

来源:九壹网
电子钟&温度计制作

梅林 mlnin@163.com

相信每个学单片机的人都有过做电子钟的经历吧!我曾经在面包板上做过两电子钟,加上这个是第三个了。这个 是从2007年五一劳动节开始做的,大约用了一个星期才做出来。还叫了几个同学来看过,他们都说做的不错,自己也高兴了好一阵子。后来,我去电信系实验室玩,自那以后就高兴不起来了。李秀军和王辉正在做智能车,罗斌正在做单片机和FPGA的实验。曾生伟和赵裴的ARM+UCOS+GUI+CAN也做好了。本来这个文档快做好了,突然之间发现自己做的这个东西太简单了,所以就不好意思再继续写下去了。今天是2007年7月30号,离我毕业只有三天之遥,想来想去,还是决定继续把这个文档做完,就算给自己留个纪念吧,毕竟大学四年真正做出来的东西也就这一样了!

方案是ATC2051+DS1302+DS18B20+74HC1。

ATC2051有15个IO。DS1302用去3个,DS18B20用去1个,数码管动态显示用去6个,按键用去4个,峰鸣器用去1个。正好全部用完。

第一个按键是功能切换,在时间显示和温度显示之间切换。第二个按键在设置时间的时候用来切换时间位。第三个按键是时间加。第四个按键是时间减。

PROTEUS原理图

编写程序

我手头上有一份汇编语言写的DS1302驱动程序,还有一份11.0592hz下的DS18B20驱动程序,还有一个按键处理程序模板。编程工作有:将汇编版的DS1302驱动程序改成C语言版的;将11.0592Mhz版的DS18B20驱动程序改成4M hz版的;写按键处理程序;写主程序。

程序总共有600行,1.7K大小,由于空间不够,所以没有年月日显示功能,也没有闹钟功能。只能显示时间和温度。

程序调试

LED动态显示,按键响应,DS1302驱动,DS18B20驱动,这几个模块我都很顺利的调试成功了,但把它们合并在一起,却花了我三个通宵的时间!程序中有三个与时间相关的地方,DS18B20每隔750MS完成一次转换,LED每隔5MS显示一位,还要每隔10MS扫描一次按键状态。协调这三个模块,花了我不少时间。用的方法也很笨,我用T0中断来控制LED显示,T1中断来扫描按键,用指令延时来控制DS18B20的转换时间(现在我想我只用一个定时器就能完成这些工作了!)。再就是按键处理程序也比较麻烦,要不是有PROTEUS在线仿真,我肯定要累死。

LED板原理图

123456A1G4VCCC11uF14D013D112D211D3109TXD8U2VCCD0D1D2D39TXD74LS1VCCRXDRXDD7D6D5D4GND1234567RXDRXDD7D6D5D4D03D54G35G26D1P14*LED1四个数码管87654321Header 8G1VCCRXDTXDG1G2G3G4A2AFG1G2BR21KG3BBDP71011C12G4DGCED4D3D7D2D6CTitleDrawnbyD1234Date电子钟PART1_DISPBOARDT313_2_12 梅林2007年5月2日56D CPU板原理图

1C230pF4MC330pFR61KRSTC510uFBVCCC4220uFU3VCCP212Header 2CP1VCCRXDTXDG1G2G3G412345678Header 8DP14R51KVCCQ19012U4+-BELLTitleDrawnbyDate12345电子钟PART2_MCUBOARD23456XTAL1RSTRXDTXDG1G2G3G4P37XTAL2XTAL1123671145U1RSTP3.0(RXD)P3.1(TXD)P3.2(INT0)P3.3(INT1)P3.4(T0)P3.5(T1)P3.7XTAL2XTAL1ATC2051VCCGND2010P1.7P1.6P1.5P1.4P1.3P1.2(AIN1)P1.1(AIN0)P1.01918171615141312P17P16P15P14P13P12P11P10VCCVCCVCCSW1R31KR41KR71KR81KP37SW_PBBP12SW_PBSW4P11SW_PBSW3P10SW_PBSW2AAXTAL2VCCVCCVCCVCC1SCLKI/ORST8765P15P16P17P3DS18B20VCCP512Header 2P42132.768kHZ1234VCC2X1X2GNDDS1302123VCCP13R14K7CDT313_2_12 梅林2007年5月2日6

LED板PCB图

顶层的线我都布在了LED方框内,这样在安装的时候就可以把这些线都藏起来。 顶层总有11根线,图中画出来的只有10根线,还有1根线,在焊接的时候再加上。 请仔细看!!!我觉得这块板子很经典。

CPU板PCB图

LED板打印的PCB图形

CPU板打印的PCB图形

打印出来的图纸

显影液和腐蚀液

爆光台

显影过程

腐蚀过程

做好的LED显示板和CPU板

实物照片

仔细观察会发现实物的CPU板和上图的CPU板不一样。

这是我最初做的一块板子。上面的那块是改进后的板子,和实物图中的这块板子相比,它作了两处调整。1.将按键的位置换到了电池盒的后面,这样能方便操作。2.敷铜与焊盘的连接方式也作了调整,没有采用直接相连的方式,因为直接相连的话,在焊接的时候焊点很难看(从下面两副图中可以看出来)。

原本我想的是用电池供电的,没想到LED耗电量有这么大,一个星期电就用完了。所以我就没有用电池来供电了,电池盒现在成了个摆设。

由于缺少元件,改进后的板子我没有做出实物。所以只好照了一张最初的实物了。右边两块板子也是这学期做的,顺便也照出来了。右上方的那块是2051的IO板。LED板的测试,DS18B20的测试我都是先在这块板子上完成的。右下方是一块D12的板子,我在网上找了好几个程序测试,但主机都无法识别,就要毕业了,又没心思去弄个究竟,所以暂时把它扔在了一边。

这块板子生锈的比较厉害,那是因为板子焊好后,我又花了三天时间写程序,程序写好后才涂的指甲油,三天时间就锈成这个样子了。

C:\\Documents and Settings\\new\\桌面\\ml\\电子钟MY\\Clock.c

#include #include \"DS1302.h\" #include \"DS18B20.h\" #include \"Key.h\" #define uchar unsigned char #define BEEP P1_4 code unsigned char ucLedData[12]={0x3f,0x06,0x5b,0x4f,0x66,0x6d, 0x7d,0x07,0x7f,0x6f,0x00,0x40}; uchar ucDispData[8]={ 0,0,0,0, //要显示的时间数据初值 0x80,0x80,0x80,0x80 //\"....\要显示的温度数据初 }; TIME time,newtime; uchar ucFunction=0; //0显示时间,1显示温度 bit bSetTimeFlag=0; uchar ucSXCounter=0; //数码管闪烁时间控制,<128灭,>128亮 uchar ucSXPosition=0; //数码管闪烁位置控制 uchar BinToBCD(uchar ucBin) //小于100的数二进制转BCD { return ( ((ucBin/10)<<4) | (ucBin%10) ); } uchar BCDToBin(uchar ucBcd) //小于100的数BCD转二进制 { return ( (((ucBcd&0xf0)>>4)*10) + (ucBcd&0x0f) ); } void Key1Proc(void) { ucFunction=(++ucFunction)%2; ucSXPosition=0; } void Key2Proc(void) { if(ucFunction==0) { ucSXPosition=(++ucSXPosition)%4; ucSXCounter=0; if(ucSXPosition==0) { newtime.hour=time.hour; newtime.minute_h=time.minute_h; newtime.minute_l=time.minute_l; bSetTimeFlag=1; } } } void Key3Proc(void) { if( (ucFunction==0) && (ucSXPosition!=0) ) switch(ucSXPosition) { case 1: if( (time.hour&0x1f) != 0x12 ) time.hour=BinToBCD(BCDToBin(time.hour&0x1f)+1); else time.hour=0x01; break; case 2: if(time.minute_h!=5) ++time.minute_h; else 值 Page 1

C:\\Documents and Settings\\new\\桌面\\ml\\电子钟MY\\Clock.c

time.minute_h=0; break; case 3: if(time.minute_l!=9) ++time.minute_l; else time.minute_l=0; break; default: break; } ?end switch ucSXPosition ? } ?end Key3Proc ? void Key4Proc(void) { if( (ucFunction==0) && (ucSXPosition!=0) ) switch(ucSXPosition) { case 1: if( (time.hour&0x1f) != 0x01 ) time.hour=BinToBCD(BCDToBin(time.hour&0x1f)-1); else time.hour=0x12; break; case 2: if(time.minute_h!=0) --time.minute_h; else time.minute_h=5; break; case 3: if(time.minute_l!=0) --time.minute_l; else time.minute_l=9; break; default: break; } ?end switch ucSXPosition ? } ?end Key4Proc ? void main(void) { SCON=0x00; //数码管的数据采用串转并传送,使用74LS1 TMOD=0x11; //T0用来扫描数码管,T1用来扫描键盘,默认优先级T0>T1 TH0=0xf9; //T0,5ms,4MHz TL0=0x7d; TH1=0xf2; //T1,10ms,4MHz TL1=0xfa; EA=1; ET0=1; ET1=1; TR0=1; TR1=1; DS1302Init(); while(1) { if(bSetTimeFlag) { SetTime(newtime); bSetTimeFlag=0; } if(ucSXPosition==0) { time=GetTime(); ucDispData[0]=ucLedData[time.minute_l]; ucDispData[1]=ucLedData[time.minute_h]; ucDispData[2]=ucLedData[time.hour_l] | 0x80; //0x80是小数点 if(time.hour_h==0) //时间高位灭0 ucDispData[3]=0; else Page 2

C:\\Documents and Settings\\new\\桌面\\ml\\电子钟MY\\Clock.c

ucDispData[3]=0x06;

} else //设置时间的时候,时间不刷新 { ucDispData[0]=ucLedData[time.minute_l]; ucDispData[1]=ucLedData[time.minute_h]; ucDispData[2]=ucLedData[time.hour&0x0f] | 0x80; //0x80是小数点 if( ((time.hour&0x10)>>4)==0) //时间高位灭0 ucDispData[3]=0; else ucDispData[3]=0x06; } if(ucFunction==1) //在显示时间的时候不测温度 { if( !GetTemp() ) //如果获取温度失败(18B20被拔掉了),会显示 ucDispData[4]=ucDispData[5]=ucDispData[6]=ucDispData[7]=0x40; else { ucDispData[4]=ucLedData[ucTempData[0]]; ucDispData[5]=ucLedData[ucTempData[1]] | 0x80; if( (ucTempData[2]==0)&&(ucTempData[3]==0) )//为0的位,不显示,但中间有0,如103,则0要显示 ucDispData[6]=0; else ucDispData[6]=ucLedData[ucTempData[2]]; if(ucTempData[3]==0) ucDispData[7]=0; else ucDispData[7]=ucLedData[ucTempData[3]]; } } ?end if ucFunction==1 ? } ?end while 1 ? } ?end main ?

T0ISR_Disp() interrupt 1 using 1 { static uchar p=0; //控制LED扫描显示 if(bKeyScanEn) //按键响应 KeyDeal(); SBUF=0; TH0=0xf9; TL0=0x7d; //************显示模式判断,闪烁OR不闪烁************* //设置时间的时候,相应的数码管闪烁,想了一夜!!! if( (ucSXPosition!=0)&&(ucFunction==0) ) { if(ucSXPosition==1) //LED3,LED4一起闪烁

P3=( ~( 0x01 << ( (p%4)+2) ) ) | ( (ucSXCounter+=2)<128 ? 0xc0>>(ucSXPosition+1):0 ); else //LDE1,LED2单独闪烁 P3=( ~( 0x01 << ( (p%4)+2) ) ) | ( (ucSXCounter+=2)<128 ? 0x80>>(ucSXPosition+2):0 );

\"----\"

P3=( ~( 0x01 << ( (p%4)+2) ) ); //数码管位选择P32,P33,P34,P35

//*************显示内容判断,时间OR温度OR...********* if(ucFunction==0) //显示时间 SBUF=ucDispData[p%4]; else if(ucFunction==1) //显示温度 SBUF=ucDispData[(p%4)+4]; p++;

} ?end T0ISR_Disp ?

} else

Page 3

C:\\Documents and Settings\\new\\桌面\\ml\\电子钟MY\\DS18B20.h

#include #include #define uchar unsigned char #define uint unsigned int #define DQ P1_3 uchar ucOriginTempData[2]={0x00,0x00}; //原始温度数据, uchar ucTempData[5]; //处理过的温度数据 uchar ucTempConvertOver=0; code uchar ucXS[16]={0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04, 0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09}; void DS18B20Delay(uint unNum) { while( --unNum ); } //由于DS18B20读写时序要求严格,所以在读写的 bit DS18B20Init(void) //初始化ds1820 { static bit bExistFlag; EA=0; DQ=1; DS18B20Delay(2); DQ=0; DS18B20Delay(25); //精确延时 大于 480us DQ=1; DS18B20Delay(2); bExistFlag=!DQ; DS18B20Delay(30); DQ=1; EA=1; return(bExistFlag); //返回信号,1存在,0不存在 } ?end DS18B20Init ? DS18B20Read(void) { uchar i=0; uchar ucData=0; EA=0; for (i=8; i > 0; i--) { DQ=0; ucData >>= 1; DQ=1; if(DQ) ucData |= 0x80; DS18B20Delay(1); } EA=1; return(ucData); } 时候都关了中断 Page 1

C:\\Documents and Settings\\new\\桌面\\ml\\电子钟MY\\DS18B20.h

DS18B20Write(uchar ucData) //写一个字节 { uchar i=0; EA=0; for (i=8; i > 0; i--) { DQ=0; DQ=ucData&0x01; DS18B20Delay(1); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); DQ=1; ucData >>= 1; } EA=1; } ?end DS18B20Write ? bit GetTemp(void) { if(!DS18B20Init()) return 0; else { DS18B20Write(0xCC); // 跳过读序号列号的操作 DS18B20Write(0x44); // 启动温度转换 DS18B20Delay(32000); //750ms,4Mhz DS18B20Init(); DS18B20Write(0xCC); //跳过读序号列号的操作 DS18B20Write(0xBE); //读取温度寄存器 ucOriginTempData[0]=DS18B20Read(); //温度低8位 ucOriginTempData[1]=DS18B20Read(); //温度高8位 ucTempData[4]=ucOriginTempData[0]&0x0f; ucTempData[0]=ucXS[ucTempData[4]]; //查表得小数位的值 ucTempData[4]=((ucOriginTempData[0]&0xf0)>>4) | ((ucOriginTempData[1]&0x0f)<<4); ucTempData[3]=ucTempData[4]/100; ucTempData[1]=ucTempData[4]%100; ucTempData[2]=ucTempData[1]/10; ucTempData[1]=ucTempData[1]%10; } ?end else ? return 1; } ?end GetTemp ? Page 2

C:\\Documents and Settings\\new\\桌面\\ml\\电子钟MY\\DS1302.h

#include #define uchar unsigned char #define SCLK P1_5 #define RST P1_7 #define IODATA P1_6 typedef struct _TIME { uchar hour; uchar minute; uchar second; uchar hour_h; uchar hour_l; uchar hour_m; //AM PM // bit hour_m; ***结构体 uchar minute_h; uchar minute_l; uchar second_h; uchar second_l; } TIME; /*typedef struct _DATE { uchar year; uchar month; uchar day; } DATE;*/ extern DS1302WriteOneChar(uchar ucData); extern uchar DS1302ReadOneChar(void); extern DS1302Rst(void); 中不能有位变量??? extern DS1302Write(uchar ucAddr,uchar ucCmd); extern uchar DS1302Read(uchar ucAddr); extern DS1302Init(void); extern SetTime(TIME); extern TIME GetTime(void); Page 1

C:\\Documents and Settings\\new\\桌面\\ml\\电子钟MY\\DS1302.c

#include \"DS1302.h\" #include DS1302WriteOneChar(uchar ucData) { uchar i=0; for (i=8; i > 0; i--) { SCLK=0; _nop_(); _nop_(); IODATA=ucData&0x01; _nop_(); _nop_(); SCLK=1; _nop_(); _nop_(); ucData>>=1; } SCLK=0; } uchar DS1302ReadOneChar(void) //读一{ uchar i=0; uchar ucData=0; for (i=8; i > 0; i--) { SCLK=0; _nop_(); _nop_(); ucData>>=1; if(IODATA) ucData|=0x80; _nop_(); _nop_(); SCLK=1; _nop_(); _nop_(); } RST=0; return (ucData); } ?end DS1302ReadOneChar ? DS1302Rst(void) { RST=0; SCLK=0; _nop_(); _nop_(); RST=1; } DS1302Write(uchar ucAddr,uchar ucCmd) { SCLK=0; _nop_(); _nop_(); RST=1; _nop_(); DS1302WriteOneChar(ucAddr); _nop_(); _nop_(); DS1302WriteOneChar(ucCmd); RST=0; _nop_(); _nop_(); } 个字节 Page 1

C:\\Documents and Settings\\new\\桌面\\ml\\电子钟MY\\DS1302.c

uchar DS1302Read(uchar ucAddr) { SCLK=0; _nop_(); _nop_(); RST=1; _nop_(); _nop_(); DS1302WriteOneChar(ucAddr); return(DS1302ReadOneChar()); } DS1302Init(void) { DS1302Rst(); DS1302Write(0x8E,0x00); DS1302Write(0x90,0xaa); if( (DS1302Read(0x85)&0x1f) == 0 ) { DS1302Write(0x84,0x92); DS1302Write(0x82,0x34); DS1302Write(0x80,0x56); } DS1302Write(0x80,DS1302Read(0x81)&0x7f); DS1302Write(0x8E,0x80); } TIME GetTime(void) { TIME time; time.hour=DS1302Read(0x85)&0xbf; time.minute=DS1302Read(0x83); time.second=DS1302Read(0x81)&0x7f; time.hour_h=( time.hour & 0x10 )>>4; time.hour_l=( time.hour & 0x0f ); time.hour_m=( time.hour & 0x20 )==0 ? 0:1; time.minute_h=( time.minute & 0x70 )>>4; time.minute_l=( time.minute & 0x0f ); time.second_h=( time.second & 0x70 )>>4; time.second_l=( time.second & 0x0f ); return time; } ?end GetTime ? SetTime(TIME time) { DS1302Rst(); DS1302Write(0x8E,0x00); time.hour_l=time.hour&0x0f; time.hour_h=(time.hour&0x10)>>4; time.hour_m=(time.hour&0x20)>>5; // time.minute_l=time.minute&0x0f; // time.minute_h=(time.minute&0xf0)>>4; DS1302Write(0x84,time.hour_l | time.hour_h<<4 | time.hour_m<<5 | 0x80); //0x80,12小时 DS1302Write(0x82,time.minute_l | time.minute_h<<4 ); DS1302Write(0x80,0x00); DS1302Write(0x8E,0x80); } 模式 Page 2

C:\\Documents and Settings\\new\\桌面\\ml\\电子钟MY\\Key.h

#include #define uchar unsigned char uchar ucKeyNum=0x00; uchar ucKeyBackup=0x00; bit bKeyDealFlag=0; bit bKeyScanEn=0; extern void Key1Proc(void); //功extern void Key2Proc(void); //设extern void Key3Proc(void); //时 能置间切时数换,显间,位值+ 示时间切换 或者温度 extern void Key4Proc(void); //时间数值- void KeyAction (void) { switch(ucKeyNum) { case 0x07://key1 Key1Proc(); break; case 0x86://key2 Key2Proc(); break; case 0x85://key3 Key3Proc(); break; case 0x83://key4 Key4Proc(); break; default: break; } ?end switch ucKeyNum ? } ?end KeyAction ? void KeyDeal(void) { bKeyScanEn=0; P3_7=1; P1 |= 0x07; ucKeyNum=(P3&0x80) | (P1&0x07); //获取键值 if( (ucKeyNum!=0x87) && (ucKeyNum==ucKeyBackup) ) { if(!bKeyDealFlag) { KeyAction(); bKeyDealFlag=1; } } else { ucKeyBackup=ucKeyNum; bKeyDealFlag=0; } } ?end KeyDeal ? T1ISR_KeyScan() interrupt 3 { TH1=0xf2; TL1=0xfa; bKeyScanEn=1; } Page 1

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 91gzw.com 版权所有 湘ICP备2023023988号-2

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务