89C52单片机+DS1302时钟芯片+DS18B20+74HC138译码器 17位数码管万年历制作关键字:51单片机、数码管、万年历、DS1302本文介绍使用STC89C52单片机,DS1302时钟芯片提供时钟信号,DS18B20提供温度信号,74HC138译码器+S8550三极管驱动17位共阳极数码管,才用3个按键对万年历进行调整。
实物图如下:Proteus仿真如下:图中采用4个红色LED模拟时间分隔符,当功能键按下一次后秒开始闪烁,此时可以按下第二键和第三键进行加和减的操作,再按一次功能键进入分钟的调节,依次类推,最后跳出调整状态。
STC89C52介绍:STC89C52是STC公司生产的一种低功耗、高性能CMOS8位微控制器,具有8K 在系统可编程Flash存储器。
STC89C52使用经典的MCS-51内核,但做了很多的改进使得芯片具有传统51单片机不具备的功能。
在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。
具有以下标准功能: 8k 字节Flash ,512字节RAM , 32 位I/O 口线,看门狗定时器,内置4KB EEPROM ,MAX810复位电路,3个16 位定时器/计数器,4个外部中断,一个7向量4级中断结构(兼容传统51的5向量2级中断结构),全双工串行口。
另外 STC89C52 可降至0Hz 静态逻辑操作,支持2种软件可选择节电模式。
空闲模式下,CPU 停止工作,允许RAM 、定时器/计数器、串口、中断继续工作。
掉电保护方式下,RAM 内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。
最高运作频率35MHz ,6T/12T 可选。
器件参数:1. 增强型8051单片机,6 时钟/机器周期和12 时钟/机器周期可以任意 选择,指令代码完全兼容传统8051.[2]2. 工作电压:5.5V ~3.3V (5V 单片机)/3.8V ~2.0V (3V 单片机)3.工作频率范围:0~40MHz ,相当于普通8051 的0~80MHz ,实际工作 频率可达48MHz4. 用户应用程序空间为8K 字节5. 片上集成512 字节RAM6. 通用I/O 口(32 个),复位后为:P0/P1/P2/P3 是准双向口/弱上拉, P0 口是漏极开路输出,作为总线扩展用时,不用加上拉电阻,作为 I/O 口用时,需加上拉电阻。
7. ISP (在系统可编程)/IAP (在应用可编程),无需专用编程器,无 需专用仿真器,可通过串口(RxD/P3.0,TxD/P3.1)直接下载用户程 序,数秒即可完成一片8. 具有EEPROM 功能9. 共3 个16 位定时器/计数器。
即定时器T0、T1、T2 10.外部中断4 路,下降沿中断或低电平触发电路,Power Down 模式可 由外部中断低电平触发中断方式唤醒11. 通用异步串行口(UART ),还可用定时器软件实现多个UART12. 工作温度范围:-40~+85℃(工业级)/0~75℃(商业级)13. PDIP 封装DS1302介绍:DS1302 是美国DALLAS 公司推出的一种高性能、低功耗、带RAM 的实时时钟电路,它可以对年、月、日、周、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V ~5.5V 。
采用三线接口与CPU 进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM 数据。
DS1302内部有一个31×8的用于临时性存放数据的RAM 寄存器。
DS1302是DS1202的升级产品,与DS1202兼容,但增加了主电源/后备电源双电源引脚,同时提供了对后备电源进行涓细电流充电的能力。
DS1302的引脚排列,其中Vcc2为主电源,VCC1为后备电源。
在主电源关闭的情况下,也能保持时钟的连续运行。
DS1302由Vcc1或Vcc2两者中的较大者供电。
当Vcc2大于Vcc1+0.2V 时,Vcc2给DS1302供电。
当Vcc2小于Vcc1时,DS1302由Vcc1供电。
X1和X2是振荡源,外接32.768kHz 晶振。
RST 是复位/片选线,通过把RST 输入驱动置高电平来启动所有的数据传送。
RST 输入有两种功能:首先,RST 接通控制逻辑,允许地址/命令序列送入移位寄存器;其次,RST 提供终止单字节或多字节数据传送的方法。
当RST 为高电平时,所有的数据传送被初始化,允许对DS1302进行操作。
如果在传送过程中RST 置为低电平,则会终止此次数据传送,I/O 引脚变为高阻态。
上电运行时,在Vcc>2.0V 之前,RST必须保持低电平。
只有在SCLK 为低电平时,才能将RST 置为高电平。
I/O 为串行数据输入输出端(双向),后面有详细说明。
SCLK 为时钟输入端。
DS18B20介绍:DS18B20数字温度传感器接线方便,封装成后可应用于多种场合,如管道式,螺纹式,磁铁吸附式,不锈钢封装式,型号多种多样,有LTM8877,LTM8874等等。
主要根据应用场合的不同而改变其外观。
封装后的DS18B20可用于电缆沟测温,高炉水循环测温,锅炉测温,机房测温,农业大棚测温,洁净室测温,弹药库测温等各种非极限温度场合。
耐磨耐碰,体积小,使用方便,封装形式多样,适用于各种狭小空间设备数字测温和控制领域。
1: 技术性能描述①、 独特的单线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯。
② 、测温范围 -55℃~+125℃,固有测温误差(注意,不是分辨率,这里之前是错误的)1℃。
③、支持多点组网功能,多个DS18B20可以并联在唯一的三线上,最多只能并联8个,实现多点测温,如果数量过多,会使供电电源电压过低,从而造成信号传输的不稳定。
④、工作电源: 3.0~5.5V/DC (可以数据线寄生电源)⑤ 、在使用中不需要任何外围元件⑥、 测量结果以9~12位数字量方式串行传送⑦ 、不锈钢保护管直径 Φ6⑧ 、适用于DN15~25, DN40~DN250各种介质工业管道和狭小空间设备测温⑨、 标准安装螺纹 M10X1, M12X1.5, G1/2”任选⑩ 、PVC 电缆直接出线或德式球型接线盒出线,便于与其它电器设备连接。
74HC138介绍:74HC138是一款高速CMOS器件,74HC138引脚兼容低功耗肖特基TTL (LSTTL)系列。
74HC138译码器可接受3位二进制加权地址输入(A0, A1和A2),并当使能时,提供8个互斥的低有效输出(Y0至Y7)。
74HC138特有3个使能输入端:两个低有效(E1和E2)和一个高有效(E3)。
除非E1和E2置低且E3置高,否则74HC138将保持所有输出为高。
利用这种复合使能特性,仅需4片74HC138芯片和1个反相器,即可轻松实现并行扩展,组合成为一个1-32(5线到32线)译码器。
任选一个低有效使能输入端作为数据输入,而把其余的使能输入端作为选通端,则74HC138亦可充当一个8输出多路分配器,未使用的使能输入端必须保持绑定在各自合适的高有效或低有效状态。
74HC138与74HC238逻辑功能一致,只不过74HC138为反相输出。
CD74HC138 ,CD74HC238和CD74HCT138 ,CD74HCT238是高速硅栅CMOS 解码器,适合内存地址解码或数据路由应用。
74HC138 作用原理于高性能的存贮译码或要求传输延迟时间短的数据传输系统,在高性能存贮器系统中,用这种译码器可以提高译码系统的效率。
将快速赋能电路用于高速存贮器时,译码器的延迟时间和存贮器的赋能时间通常小于存贮器的典型存取时间,这就是说由肖特基钳位的系统译码器所引起的有效系统延迟可以忽略不计。
HC138 按照三位二进制输入码和赋能输入条件,从8 个输出端中译出一个低电平输出。
两个低电平有效的赋能输入端和一个高电平有效的赋能输入端减少了扩展所需要的外接门或倒相器,扩展成24 线译码器不需外接门;扩展成32 线译码器,只需要接一个外接倒相器。
在解调器应用中,赋能输入端可用作数据输入端。
复合使能输入,轻松实现扩展兼容JEDEC标准no.7A 存储器芯片译码选择的理想选择低有效互斥输出ESD保护HBM EIA/JESD22-A114-C超过2000 V MM EIA/JESD22-A115-A超过200 V 温度范围-40~+85 ℃-40~+125 ℃多路分配功能。
三极管8550介绍:三极管8550是一种常用的普通三极管。
它是一种低电压,大电流,小信号的PNP型硅三极管。
各模块如下:程序源代码如下:(如果本文对您有用请下载此文档贡献一下您宝贵的财富值,本文不贵,予人玫瑰手有余香,愿单片机爱好者都能学好学会)主函数:(main.h)#include<temp.h>#include<intrins.h>#define uchar unsigned char#define uint unsigned intsbit wela=P3^3;sbit A=P2^7;sbit b=P2^6;sbit C=P2^5;sbit SCLK=P3^5; //DS1302通讯线定义sbit DIO=P3^6;sbit RST=P3^7;sbit k1=P1^0;sbit k2=P1^1;sbit k3=P1^4;sbit w1=P2^4;sbit w2=P2^3;uchar code smgw[]={0,1,2,3,4,5,6,7};uchar code smgd[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88};uchar tab1[9];uchar tab2[9];float tp;int temp;uchar nian,yue,ri,zhou,shi,fen,miao,a,shan,tt,shan;uchar knum;void delay(uint z){u int x,y;f or(x=z;x>0;x--)for(y=110;y>0;y--);}void write(uchar date) //写入DS1302一个字节{u char temp,i;R ST=1;S CLK=0;t emp=date;f or(i=0;i<8;i++){SCLK=0;if(temp&0x01)DIO=1;elseDIO=0;SCLK=1;temp>>=1;}}uchar read() //读出DS1302一个字节{u char a,temp;R ST=1;f or(a=8;a>0;a--){temp>>=1;SCLK=1;_nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_();SCLK=0;if(DIO){temp=temp|0x80;}else{temp=temp|0x00;}}r eturn (temp);}void write_1302(uchar add,uchar dat) //写DS1302数据{R ST=0;S CLK=0;R ST=1;w rite(add);w rite(dat);S CLK=1;R ST=0;}uchar read_1302(uchar add) //读DS1302数据{u char dat1,dat2;R ST=0;S CLK=0;R ST=1;w rite(add);d at1=read();S CLK=1;R ST=0;d at1=ACC; ///?????dat2=dat1/16; //数据进制转换 dat1=dat1%16; //十六进制转十进制 dat1=dat1+dat2*10;r eturn(dat1);}void ds1302_init() //1302初始化{R ST=0;S CLK=0;w rite_1302(0x8e,0x00); //允许写入/* write_1302(0x84,0x00); //24小时制w rite_1302(0x80,0x00);//设置初始值SECw rite_1302(0x82,0x59);//设置初始值MINw rite_1302(0x84,0x23);//设置初始值HRw rite_1302(0x86,0x26);//设置初始值DATEw rite_1302(0x88,0x04);//设置初始值MONTHw rite_1302(0x8A,0x03);//设置初始值DAYw rite_1302(0x8C,0x09);//设置初始值YEAR*/w rite_1302(0x90,0xa5);//启动充电功能w rite_1302(0x8e,0x80);}void display(){miao=read_1302(0x81); //读秒fen=read_1302(0x83); //读分shi=read_1302(0x85);//&0x3f; //读时ri=read_1302(0x87); //读日yue=read_1302(0x89); //读月nian=read_1302(0x8d); //读年zhou=read_1302(0x8B); //读星期 */i f(temp< 0) //当温度值为负数{temp=temp-1;temp=~temp;tp=temp;temp=tp*0.0625*100+0.5;}else{tp=temp;temp=tp*0.0625*100+0.5;}w ela=0;i f(knum==7){wela=0;A=0;b=0;C=0; //年P0=0xa4|shan;delay(1);P0=0xff;A=1;b=0;C=0;P0=0xc0|shan;delay(1);P0=0xff;A=0;b=1;C=0;P0=smgd[nian/10]|shan;delay(1);P0=0xff;A=1;b=1;C=0;P0=smgd[nian%10]|shan;delay(1);P0=0xff;}e lse{wela=0;A=0;b=0;C=0; //年P0=0xa4;delay(1);P0=0xff;A=1;b=0;C=0;P0=0xc0;delay(1);P0=0xff;A=0;b=1;C=0;P0=smgd[nian/10];delay(1);P0=0xff;A=1;b=1;C=0;P0=smgd[nian%10];delay(1);P0=0xff;}i f(knum==6){A=0;b=0;C=1; // 月P0=smgd[yue/10]|shan;delay(1);P0=0xff;A=1;b=0;C=1;P0=smgd[yue%10]|shan;delay(1);P0=0xff;}e lse{A=0;b=0;C=1; // 月P0=smgd[yue/10];delay(1);P0=0xff;A=1;b=0;C=1;P0=smgd[yue%10];delay(1);P0=0xff;}i f(knum==5){A=0;b=1;C=1; // 星期P0=smgd[zhou%10]|shan;delay(1);P0=0xff;}e lse{A=0;b=1;C=1; // 星期P0=smgd[zhou%10];delay(1);P0=0xff;}w ela=1;i f(knum==4){wela=1;A=0;b=0;C=0; // 日P0=smgd[ri/10]|shan;delay(1);P0=0xff;A=1;b=0;C=0;P0=smgd[ri%10]|shan;delay(1);P0=0xff;}e lse{wela=1;A=0;b=0;C=0; // 日P0=smgd[ri/10];delay(1);P0=0xff;A=1;b=0;C=0;P0=smgd[ri%10];delay(1);P0=0xff;}i f(knum==3){A=1;b=1;C=0; // 时P0=smgd[shi/10]|shan;delay(1);P0=0xff;A=0;b=1;C=0;P0=smgd[shi%10]|shan;delay(1);P0=0xff;}e lse{A=1;b=1;C=0; // 时P0=smgd[shi/10];delay(1);P0=0xff;A=0;b=1;C=0;P0=smgd[shi%10];delay(1);P0=0xff;}i f(knum==2){A=0;b=0;C=1; // 分P0=smgd[fen/10]|shan;delay(1);P0=0xff;A=1;b=0;C=1;P0=smgd[fen%10]|shan;delay(1);P0=0xff;}e lse{A=0;b=0;C=1; // 分P0=smgd[fen/10];delay(1);P0=0xff;A=1;b=0;C=1;P0=smgd[fen%10];delay(1);P0=0xff;}i f(knum==1){A=0;b=1;C=1; // 秒P0=smgd[miao/10]|shan;delay(1);P0=0xff;A=1;b=1;C=1;P0=smgd[miao%10]|shan;delay(1);P0=0xff;}e lse{A=0;b=1;C=1; //秒P0=smgd[miao/10];delay(1);P0=0xff;A=1;b=1;C=1;P0=smgd[miao%10];delay(1);P0=0xff;}/* w1=0;P0 = smgd[temp / 10000];d elay(1);P0=0xff;w1=1;w2=0;P0 = smgd[temp % 10000 / 1000];d elay(1);P0=0xff;w2=1; */}void key(){ //u char temp;// display();i f(k1==0){delay(20);if(k1==0){while(!k1);knum++;if(knum==1){temp=(miao)/10*16+(miao)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x80,0x80|temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护}if(knum==8){knum=0;write_1302 (0x8e,0X00); //禁止写保护write_1302 (0x80,0x7f&temp); //时钟恢复write_1302 (0x8e,0x80); //允许写保护write_1302(0x8e,0x00);write_1302(0x80,0x00|temp);//miao数据写入DS1302write_1302(0x8e,0x80);}}}if(knum!=0){if(k2==0){delay(20);if(k2==0){while(!k2);switch(knum){case 1:miao++;if(miao==60)miao=0;temp=(miao)/10*16+(miao)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x80,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护break;case 2:fen++;if(fen==60)fen=0;temp=(fen)/10*16+(fen)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x82,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护}break;case 3:shi++;if(shi==24)shi=0;temp=(shi)/10*16+(shi)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x84,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护break;case 4:ri++;switch(yue){case 1:case 3:case 5:case 7:case 8:case 10:case 12:if(ri==32)ri=1;break;case 4:case 6:case 9:case 11:if(ri==31)ri=1;break;case 2:if(nian%4==0||nian%400==0){if(ri==30)ri=1;}else{if(ri==29)ri=1;}break;}temp=(ri)/10*16+(ri)%10;//十进制转换成DS1302要求的DCB 码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x86,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护break;case 5:zhou++;if(zhou==8)zhou=1;temp=(zhou)/10*16+(zhou)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x8a,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护break;case 6:yue++;if(yue==13)yue=1;temp=(yue)/10*16+(yue)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x88,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护break;case 7:nian++;if(nian==99)nian=0;temp=(nian)/10*16+(nian)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x8c,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护break;}}}if(k3==0){delay(20);if(k3==0){while(!k3);switch(knum){case 1:miao--;if(miao==-1)miao=59;temp=(miao)/10*16+(miao)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x80,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护break;case 2:fen--;if(fen==-1)fen=59;temp=(fen)/10*16+(fen)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x82,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护}break;case 3:shi--;if(shi==-1)shi=23;temp=(shi)/10*16+(shi)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x84,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护break;case 4:ri--;switch(yue){case 1:case 3:case 5:case 7:case 8:case 10:case 12:if(ri==0)ri=31;break;case 4:case 6:case 9:case 11:if(ri==0)ri=30;break;case 2:if(nian%4==0||nian%400==0){if(ri==0)ri=29;}else{if(ri==0)ri=28;}break;}temp=(ri)/10*16+(ri)%10;//十进制转换成DS1302要求的DCB 码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x86,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护break;case 5:zhou--;if(zhou==0)zhou=7;temp=(zhou)/10*16+(zhou)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x8a,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护break;case 6:yue--;if(yue==0)yue=12;temp=(yue)/10*16+(yue)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x88,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护break;case 7:nian--;if(nian==-1)nian=99;temp=(nian)/10*16+(nian)%10;//十进制转换成DS1302要求的DCB码write_1302(0x8e,0x00); //允许写,禁止写保护write_1302(0x8c,temp); //向DS1302内写秒寄存器80H写入调整后的秒数据BCD码write_1302(0x8e,0x80); //打开写保护break;}}}}}void main(){d s1302_init();T MOD=1;T H0=(65536-50000)/256;T L0=(65536-50000)%256;E A=1;E T0=1;T R0=1;s han=0x00;w hile(1){key();//Ds18b20ReadTemp();display();}}void time0() interrupt 1{T H0=(65536-50000)/256;T L0=(65536-50000)%256;t t++;i f(tt==9){tt=0;shan=~shan;}}温度函数:(temp.h)#include"temp.h"/****************************************************************************** * 函数名 : Delay1ms* 函数功能 : 延时函数* 输入 : 无* 输出 : 无*****************************************************************************/void Delay1ms(uint y){u int x;f or( ; y>0; y--){for(x=110; x>0; x--);}}/****************************************************************************** * 函数名 : Ds18b20Init* 函数功能 : 初始化* 输入 : 无* 输出 : 初始化成功返回1,失败返回0******************************************************************************/uchar Ds18b20Init(){u char i;D SPORT = 0; //将总线拉低480us~960usi = 70;w hile(i--);//延时642usD SPORT = 1; //然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低i = 0;w hile(DSPORT) //等待DS18B20拉低总线{Delay1ms(1);i++;if(i>5)//等待>5MS{return 0;//初始化失败}}r eturn 1;//初始化成功}/****************************************************************************** * 函数名 : Ds18b20WriteByte* 函数功能 : 向18B20写入一个字节* 输入 : com* 输出 : 无******************************************************************************/void Ds18b20WriteByte(uchar dat){u int i, j;f or(j=0; j<8; j++){DSPORT = 0; //每写入一位数据之前先把总线拉低1usi++;DSPORT = dat & 0x01; //然后写入一个数据,从最低位开始i=6;while(i--); //延时68us,持续时间最少60usDSPORT = 1; //然后释放总线,至少1us给总线恢复时间才能接着写入第二个数值dat >>= 1;}}/****************************************************************************** * 函数名 : Ds18b20ReadByte* 函数功能 : 读取一个字节* 输入 : com* 输出 : 无******************************************************************************/uchar Ds18b20ReadByte(){u char byte, bi;u int i, j;f or(j=8; j>0; j--){DSPORT = 0;//先将总线拉低1usi++;DSPORT = 1;//然后释放总线i++;i++;//延时6us等待数据稳定bi = DSPORT; //读取数据,从最低位开始读取/*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。