閑來無事,做的萬年歷。時間設定、鬧鐘定時功能版本的萬年歷后面再發。
電路原理圖如下:
1.png (76.53 KB, 下載次數: 52)
下載附件
2020-9-18 21:56 上傳
單片機源程序如下:
- #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();
- }
- }
復制代碼
|