闲来无事,做的万年历。时间设定、闹钟定时功能版本的万年历后面再发。
电路原理图如下:
单片机源程序如下:
- #include "reg52.h"
- #include "intrins.h"
- #define uint unsigned int
- #define uchar unsigned char
- sbit Dat=P2^0;
- sbit RS=P2^6;
- sbit RW=P2^5;
- sbit EN=P2^7;
- sbit CE=P3^5;
- sbit DSIO=P3^4;
- sbit SCL=P3^6;
- uchar code talble[]="0123456789";
- uchar read[]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; //存放秒、分、小时、日期、月份、周、年的读寄存器命令字
- uchar time[]={0x21,0x53,0x15,0x18,0x09,0x05,0x20}; //放置初始的秒、分、小时、日期、月份、周、年的BCD码
- uchar num0=0,num1=0,num2=0;
- void delayms(uint z) //12MHz时,z=1约为1ms
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=122;y>0;y--);
- }
- void delayus(uchar z) //12MHz时,z=1约为17us
- {
- while(z--);
- }
- /************************************按键*************************************/
- //待写
- /******************************DHT11温湿度传感器********************************/
- uchar Read_Byte()
- {
- uchar m,n,sum;
- for(m=0;m<8;m++)
- {
- while(!Dat); //每个数据前面会有一个50us的低电平,等待50us结束
- delayus(3); //延时50us后检测电平
- sum<<=1; //循环左移,左移放在判断数据是0或者1的前面,数据读出正确
- n=Dat; //读数据
- if(n==1)
- {
- sum=sum|0x01;
- while(!Dat); //等待高电平结束
- }
- else
- {
- sum=sum|0x00;
- }
- delayus(3);
- }
- return (sum);
- }
- void dht11()
- {
- uchar m0,m1,m2,m3,m4;
- Dat=1;
- delayms(1);
- Dat=0; //拉低单总线
- delayms(20); //至少保持18ms
- Dat=1; //拉高总线,等待接收DHT11应答信号
- delayus(3); //主机发送开始信号后,等待20~40u后,检测DHT11应答信号
- if(Dat==0) //检测DHT11是否有应答信号,当DHT11检测到信号后,首先将总线拉低约80us,然后再拉高80us作为应答信号
- {
- while(!Dat); //检测到应答信号,等待应答信号结束
- while(Dat); //发送响应信号后,再把总线拉高约80us,准备发送数据,这里是等待开始
- m0=Read_Byte(); //读取湿度整数数据
- m1=Read_Byte(); //读取湿度小数数据
- m2=Read_Byte(); //读取温度整数数据
- m3=Read_Byte(); //读取温度小数数据
- m4=Read_Byte(); //读取校验和
- }
- if(m4==(m0+m1+m2+m3)) //校验数据,正确的话更新数据,错误的话保持数据不变
- {
- num0=m0;
- num1=m2;
- }
- else
- {
- num0=num0;
- num1=num1;
- }
- }
- /************************************DS1302*************************************/
- void Ds1302_Write_Byte(uchar addr,uchar dat) //向某个地址写入一个字节数据
- {
- uchar i;
- CE=0; //CE引脚为低,数据传送中指
- SCL=0; //清零时钟总线
- CE=1; //CE为高,逻辑控制有效
- for(i=0;i<8;i++) //发送地址,循环8次移位
- {
- DSIO=addr&0x01; //每次传输低位字节
- addr>>=1; //数据位右移1位
- SCL=1; //上升沿将数据送入DS1302
- _nop_();
- SCL=0;
- _nop_();
- }
- for(i=0;i<8;i++) //发送数据位
- {
- DSIO=dat&0x01;
- dat>>=1;
- SCL=1;
- _nop_();
- SCL=0;
- _nop_();
- }
- CE=0;
- }
- uchar Ds1302_Read_Byte(uchar addr) //读取某个地址的数据
- {
- uchar i,dat0,dat1;
- CE=0; //CE置低电平,初始化
- SCL=0; //SCL置低电平,初始化
- CE=1; //启动DS1302总线,CE拉高
- for(i=0;i<8;i++)
- {
- DSIO=addr&0x01; //按位与运算,取出addr的最低位,并将其赋给DSIO
- addr>>=1; //将地址右移一位,低位抛弃,高位补0
- SCL=1; //开始SCL为低电平,现在置高,产生一个上升沿,数据被写入DS1302,数据要先写入,然后再发送
- _nop_();
- SCL=0; //将SCL置低,为下次写入数据做准备
- _nop_();
- }
- for(i=0;i<8;i++)
- {
- dat0=DSIO;
- dat1=(dat1>>1)|(dat0<<7);
- SCL=1;
- _nop_();
- SCL=0;
- _nop_();
- }
- CE=0;
- SCL=1;
- DSIO=0;
- DSIO=1;
- return dat1;
- }
- void DS1302_Init()
- {
- Ds1302_Write_Byte(0x8e,0x00); //关闭写保护寄存器
- Ds1302_Write_Byte(0x80,0x21); //秒位初始化
- Ds1302_Write_Byte(0x82,0x53); //分钟初始化
- Ds1302_Write_Byte(0x84,0x15); //小时初始化
- Ds1302_Write_Byte(0x86,0x18); //日期初始化
- Ds1302_Write_Byte(0x88,0x09); //月份初始化
- Ds1302_Write_Byte(0x8a,0x05); //周初始化
- Ds1302_Write_Byte(0x8c,0x20); //年初始化
- Ds1302_Write_Byte(0x8e,0x80); //允许写保护
- }
- void Read_time()
- {
- uchar i;
- for(i=0;i<7;i++)
- {
- time[i]=Ds1302_Read_Byte(read[i]);
- }
- }
- /************************************闹钟*************************************/
- //待写
- /**********************************1602液晶*************************************/
- bit Busy()
- {
- bit bsy;
- RS=0;
- RW=1;
- EN=1;
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- bsy=(bit)(P0&0x80);
- EN=0;
- return (bsy);
- }
- void Wr_com(uchar com)
- {
- while(Busy());
- RS=0;
- RW=0;
- P0=com;
- delayus(1);
- EN=1;
- EN=0;
- }
- void Wr_dat(uchar dat)
- {
- while(Busy());
- RS=1;
- RW=0;
- P0=dat;
- delayus(1);
- EN=1;
- EN=0;
- }
- void LCD_Init()
- {
- Wr_com(0x38);
- Wr_com(0x0C);
- Wr_com(0x06);
- Wr_com(0x01);
- }
- void display()
- {
- Wr_com(0x80);
- Wr_dat('2');
- Wr_dat('0');
- Wr_dat('0'+time[6]/16); //年
- Wr_dat('0'+(time[6]&0x0f));
- Wr_dat('-'); //-
- Wr_dat('0'+time[4]/16); //月
- Wr_dat('0'+(time[4]&0x0f));
- Wr_dat(0xb0); //-
- Wr_dat('0'+time[3]/16); //日
- Wr_dat('0'+(time[3]&0x0f));
- Wr_com(0x80+0x0b);
- Wr_dat('0'+(time[5]&0x0f)); //星期
- Wr_com(0x80+0x0d);
- Wr_dat(talble[num0/10]); //湿度
- Wr_dat(talble[num0%10]);
- Wr_dat(0x25); //%
- Wr_com(0xC0);
- Wr_dat('0'+time[2]/16); //时
- Wr_dat('0'+(time[2]&0x0f));
- Wr_dat(0x3a); //:
- Wr_dat('0'+time[1]/16); //分
- Wr_dat('0'+(time[1]&0x0f));
- Wr_dat(0x3a); //:
- Wr_dat('0'+time[0]/16); //秒
- Wr_dat('0'+(time[0]&0x0f));
-
- Wr_com(0xC0+0x0a);
- Wr_dat(talble[num1/10]); //温度
- Wr_dat(talble[num1%10]);
- Wr_dat(0x2e); //.
- Wr_dat(talble[0]);
- Wr_dat(0xdf); //
- Wr_dat(0x43); //C
- }
- void main()
- {
- uint a;
- LCD_Init();
- DS1302_Init();
- while(1)
- {
- a++;
- if(a==20)
- {
- a=0;
- dht11();
- }
- Read_time();
- display();
- }
- }
复制代码
|