梅林 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 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 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 C:\\Documents and Settings\\new\\桌面\\ml\\电子钟MY\\DS1302.c #include \"DS1302.h\" #include 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
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- 91gzw.com 版权所有 湘ICP备2023023988号-2
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务