基于AT89C51單片機、DHT11傳感器、LCD、蜂鳴器設計的數字電子鐘,通過按鍵初始化當前時刻和鬧鐘,并顯示年月日星期時分秒、溫濕度顯示、整點報時、鬧鐘、播放音樂(小星星)、記憶時刻,內容包括:Proteus工程和Keil
LM041L大屏幕顯示
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
單片機源程序如下:
- #include<reg51.h>
- #include<intrins.h>
- #define uint unsigned int
- #define uchar unsigned char
- #define port P0
- sbit rst=P3^0; // 復位
- sbit sclk=P3^1; // 時鐘
- sbit io=P3^2; // 輸入輸出口
- sbit e=P2^2; // 使能
- sbit rw=P2^1; // 讀寫
- sbit rs=P2^0; // 數據/命令
- sbit busy=P0^7; // 檢測忙
- sbit BUZZ=P2^3; // 蜂鳴器
- sbit DHT11=P1^0;// DHT11
- sbit START=P1^1;
- sbit NEXT=P1^3;
- sbit JIA=P1^5;
- sbit JIAN=P1^7;
- uchar setup[10]={20,1,1,1,0,0,0,0,0,0};
- uint M_sec,M_min,M_hour;
- uint t;
- uchar t_H,t_L;
- uchar H_1,H_2,T_1,T_2;
- code unsigned int toneH[7]={ //音調對應的定時器計數值的高8位 中音1,2,3,4,5,6,7
- 0XF9,0XF9,0XFA,0XFA,0XFB,0XFB,0XFC
- };
- code unsigned int toneL[7]={ //音調對應的定時器計數值的低8位
- 0X21,0XE1,0X8C,0XD8,0X68,0XE9,0X5B
- };
- code unsigned int soundtone[42]={ //小星星樂譜-音調
- 1,1,5,5,6,6,5,4,4,3,3,2,2,1,
- 5,5,4,4,3,3,2,5,5,4,4,3,3,2,
- 1,1,5,5,6,6,5,4,4,3,3,2,2,1
- };
- code unsigned int soundlong[42]={ //小星星樂譜-節拍
- 1,1,1,1,1,1,2,1,1,1,1,1,1,2,
- 1,1,1,1,1,1,2,1,1,1,1,1,1,2,
- 1,1,1,1,1,1,2,1,1,1,1,1,1,2
- };
- /*************************************************
- 函數名:send()
- 說明:發送一個字節uchar數據
- 入口參數:txd(發送的數據)
- 返回值:無
- **************************************************/
- void send(uchar txd)
- {
- uchar i;
- for(i=0;i<8;i++)
- {
- sclk=0;
- io=txd&0x01; // 取第一位
- txd>>=1; // 左移一位
- sclk=1; // 上升沿有效
- }
- }
- /*************************************************
- 函數名:write()
- 說明:寫地址、數據
- 入口參數:addr(DS1302地址);dat(寫入的數據)
- 返回值:無
- **************************************************/
- void write(uchar addr,uchar dat)
- {
- rst=0;sclk=0;rst=1;
- send(addr); // 發送地址
- send(dat); // 發送數據
- rst=1;
- }
- /*************************************************
- 函數名:receive()
- 說明:接收1個字節uchar數據
- 入口參數:無
- 返回值:dat
- **************************************************/
- uchar receive()
- {
- uchar i;
- uchar dat=0;
- for(i=0;i<8;i++)// 循環8次
- {
- sclk=1;
- dat>>=1;
- sclk=0; // 下降沿讀取
- io=1; // 讀引腳前置1
- if(io==1)dat|=0x80;
- } // 此時dat為16進制比如0x10
- dat=(dat/16)*10+dat%16;
- // 轉化為10進制,現在是10;
- return(dat); // 返回值
- }
- /*************************************************
- 函數名:read()
- 說明:讀時鐘
- 入口參數:addr(地址)
- 返回值:dat(接受到的一字節uchar數據)
- **************************************************/
- uchar read(uchar addr)
- {
- uchar dat=0;
- rst=0;sclk=0;rst=1;
- send(addr); // 發送地址
- dat=receive(); // 接收
- rst=0;
- return(dat);
- }
- /*************************************************
- 函數名:delay()
- 說明:延時函數
- 入口參數:n
- 返回值:無
- **************************************************/
- void delay(uint n)
- {
- uint i;
- for(;n>0;n--)
- for(i=200;i>0;i--);
- }
- /*************************************************
- 函數名:check()
- 說明:判斷LCD是否忙
- 入口參數:無
- 返回值:無
- **************************************************/
- void check()
- {
- rs=0;
- rw=1; // 讀 e=1;
- port=0x00;
- e=1;
- while(busy);
- e=0;
- }
- /*************************************************
- 函數名:sendcommand()
- 說明:LCD寫指令
- 入口參數:command(一個字節uchar的指令)
- 返回值:無
- **************************************************/
- void sendcommand(uchar command)
- {
- check();
- rs=0; // 指令
- rw=0; // 寫 e=0;
- port=command;
- e=1;
- _nop_();_nop_();
- e=0; // 寫入指令
- }
- /*************************************************
- 函數名:writedata()
- 說明:LCD寫數據
- 入口參數:dat(一個字節uchar數據)
- 返回值:無
- **************************************************/
- void writedata(uchar dat)
- {
- check();
- rs=1; // 數據
- rw=0;
- port=dat;
- e=1;
- _nop_();_nop_();
- e=0;
- }
- /*************************************************
- 函數名:pos()
- 說明:設置LCD光標位置
- 入口參數:p(一個字節的無符號整型)
- 返回值:無
- **************************************************/
- void pos(uint p)
- {
- sendcommand(p|0x80);// 第一行第一個 0x80;
- }
- /*************************************************
- 函數名:init()
- 說明:初始化LCD
- 入口參數:無
- 返回值:無
- **************************************************/
- void init()
- {
- sendcommand(0x38); // 8 位數據,雙列, 5*7 字形
- delay(1);
- sendcommand(0x0c); // 開 0x08 關
- delay(1);
- sendcommand(0x06);// 地址增加一
- delay(1);
- sendcommand(0x01);// 清屏
- delay(1);
- }
- /*************************************************
- 函數名:welcome_setup()
- 說明:設置時的LCD初始界面
- 入口參數:無
- 返回值:無
- **************************************************/
- void welcome_setup()
- {
- int i=0;
- uchar Date[]="Date:";
- uchar Time[]="Time:";
- uchar Week[]="Week:";
- uchar Alarm[]="Alarm:";
- init();delay(10);
- pos(0x00);delay(1);
- while(Date[i]!='\0') {writedata(Date[i++]);delay(1); }
- i=0;delay(10);
- pos(0x10);delay(1);
- while(Week[i]!='\0') {writedata(Week[i++]);delay(1); }
- i=0;delay(10);
- pos(0x40);delay(1);
- while(Time[i]!='\0') {writedata(Time[i++]);delay(1); }
- i=0;delay(10);
- pos(0x50);delay(1);
- while(Alarm[i]!='\0') {writedata(Alarm[i++]);delay(1);}
- }
- /*************************************************
- 函數名:welcome()
- 說明:LCD初始界面
- 入口參數:無
- 返回值:無
- **************************************************/
- void welcome()
- {
- int i=0;
- uchar Date[]="Date:";
- uchar Time[]="Time:";
- uchar Week[]="Week:";
- uchar H[]="H:";
- uchar T[]="T:";
- init();delay(10);
- pos(0x00);delay(1);
- while(Date[i]!='\0') {writedata(Date[i++]);delay(1); }
- i=0;delay(10);
- pos(0x10);delay(1);
- while(Week[i]!='\0') {writedata(Week[i++]);delay(1); }
- i=0;delay(10);
- pos(0x40);delay(1);
- while(Time[i]!='\0') {writedata(Time[i++]);delay(1); }
- i=0;delay(10);
- pos(0x50);delay(1);
- while(H[i]!='\0') {writedata(H[i++]);delay(1);}
- i=0;delay(10);
- pos(0x57);delay(1);
- while(T[i]!='\0') {writedata(T[i++]);delay(1);}
- }
- /*************************************************
- 函數名:showLCD()
- 說明:讀取時間和日期并在LCD上顯示
- 入口參數:無
- 返回值:無
- **************************************************/
- void showLCD()
- {
- uchar num[]="0123456789";
- uchar sign=':';
- uchar note='-';
- delay(5);pos(0x05);
- delay(1);writedata(num[setup[0]/10]);
- delay(1);writedata(num[setup[0]%10]);
- delay(1);writedata(note);
- delay(1);writedata(num[setup[1]/10]);
- delay(1);writedata(num[setup[1]%10]);
- delay(1);writedata(note);
- delay(1);writedata(num[setup[2]/10]);
- delay(1);writedata(num[setup[2]%10]);
- delay(5);pos(0x15);
- delay(1);writedata(num[setup[3]%10]);
- delay(5);pos(0x45);
- delay(1);writedata(num[setup[4]/10]);
- delay(1);writedata(num[setup[4]%10]);
- delay(1);writedata(sign);
- delay(1);writedata(num[setup[5]/10]);
- delay(1);writedata(num[setup[5]%10]);
- delay(1);writedata(sign);
- delay(1);writedata(num[setup[6]/10]);
- delay(1);writedata(num[setup[6]%10]);
- delay(5);pos(0x56);
- delay(1);writedata(num[setup[7]/10]);
- delay(1);writedata(num[setup[7]%10]);
- delay(1);writedata(sign);
- delay(1);writedata(num[setup[8]/10]);
- delay(1);writedata(num[setup[8]%10]);
- delay(1);writedata(sign);
- delay(1);writedata(num[setup[9]/10]);
- delay(1);writedata(num[setup[9]%10]);
- }
- /*************************************************
- 函數名:writeLCD()
- 說明:讀取時間和日期并在LCD上顯示
- 入口參數:無
- 返回值:無
- **************************************************/
- void writeLCD()
- {
- uchar num[]="0123456789";
- uchar sign=':';
- uchar note='-';
- delay(5);pos(0x05);
- delay(1);writedata(num[read(0x8d)/10]);
- delay(1);writedata(num[read(0x8d)%10]);
- delay(1);writedata(note);
- delay(1);writedata(num[read(0x89)/10]);
- delay(1);writedata(num[read(0x89)%10]);
- delay(1);writedata(note);
- delay(1);writedata(num[read(0x87)/10]);
- delay(1);writedata(num[read(0x87)%10]);
- delay(5);pos(0x15);
- delay(1);writedata(num[read(0x8B)%10]);
- delay(1);writedata(' ');
- delay(1);writedata(num[M_hour/10]);
- delay(1);writedata(num[M_hour%10]);
- delay(1);writedata(sign);
- delay(1);writedata(num[M_min/10]);
- delay(1);writedata(num[M_min%10]);
- delay(1);writedata(sign);
- delay(1);writedata(num[M_sec/10]);
- delay(1);writedata(num[M_sec%10]);
- delay(5);pos(0x45);
- delay(1);writedata(num[read(0x85)/10]);
- delay(1);writedata(num[read(0x85)%10]);
- delay(1);writedata(sign);
- delay(1);writedata(num[read(0x83)/10]);
- delay(1);writedata(num[read(0x83)%10]);
- delay(1);writedata(sign);
- delay(1);writedata(num[read(0x81)/10]);
- delay(1);writedata(num[read(0x81)%10]);
- delay(5);pos(0x52);
- delay(1);writedata(num[H_1]);
- delay(1);writedata(num[H_2]);
- delay(1);writedata('R');
- delay(1);writedata('H');
- delay(5);pos(0x59);
- delay(1);writedata(num[T_1]);
- delay(1);writedata(num[T_2]);
- delay(1);writedata(0XDF);
- delay(1);writedata(0X43);
- }
- /*************************************************
- 函數名:Delay_us()/Delay_ms()
- 說明:DHT11延時程序
- 入口參數:無
- 返回值:無
- **************************************************/
- void Delay_us(unsigned char n)//n us延時函數 精度 ±4us
- {
- n=n/2;
- while(--n);
- }
- void Delay_ms(unsigned int n)//n毫秒延時
- {
- unsigned char j;
- while(n--)
- {
- for(j=0;j<125;j++);
- }
- }
- /*************************************************
- 函數名:COM()
- 說明:接收DHT11數據
- 入口參數:無
- 返回值:comdata數據
- **************************************************/
- uchar COM(void)
- {
- uchar i,temp,comdata;
- for(i=0;i<8;i++)
- {
- while(!DHT11); //表示讀取的高電位延時大于20多us 則讀取的是1 否則讀取的是0
- Delay_us(35); //通過FLAG,可判斷DHT11顯示數據的脈長
- temp=0;
- if(DHT11)temp=1;
- while(DHT11);
- comdata<<=1;
- comdata|=temp;
- }
- return comdata;
- }
- /*************************************************
- 函數名:getDHT11()
- 說明:主機發送起始信號,獲取溫、濕度值并校驗
- 入口參數:無
- 返回值:無
- **************************************************/
- void getDHT11(void)
- {
- uchar T_data_H,T_data_L,RH_data_H,RH_data_L,checkdata;
- //主機拉低18ms
- GO1:DHT11=0;
- Delay_ms(18);
- DHT11=1;
- //總線由上拉電阻拉高 主機延時20us
- Delay_us(20);
- //主機設為輸入 判斷從機響應信號
- //判斷從機是否有低電平響應信號 如不響應則跳出,響應則向下運行
- if(!DHT11)
- {
- while(!DHT11); //wait DHT goto high
- while(DHT11);
- //數據接收狀態
- RH_data_H=COM();
- RH_data_L=COM();
- T_data_H=COM();
- T_data_L=COM();
- checkdata=COM();
- DHT11=1;
- //數據校驗
- if((T_data_H+T_data_L+RH_data_H+RH_data_L)!=checkdata) //if check wrong,read again
- goto GO1;
- }
- H_1=RH_data_H/10;
- H_2=RH_data_H%10;
- T_1=T_data_H/10;
- T_2=T_data_H%10;
- }
- /*************************************************
- 函數名:Count_Time()
- 說明:計時
- 入口參數:無
- 返回值:無
- **************************************************/
- void init_Ex1() {
- EA = 1; //開啟總中斷
- EX1 = 1; //開啟0號外部中斷
- IT1 = 0; //設置外部中斷觸發方式
- //0 - 低電平觸發
- //1 - 負跳變觸發
- }
- void ex1_intr() interrupt 2 {
- M_sec=read(0x81); //讀秒寄存器
- M_min=read(0x83); //讀分寄存器
- M_hour=read(0x85);//讀時寄存器
- }
- /*************************************************
- 函數名:init_T0()
- 說明:初始化定時器0
- 入口參數:無
- 返回值:無
- **************************************************/
- void init_T0(void)
- {
- TMOD|= 0x01; //使用方式1,16位定時器
- TH0=0x00; //給TH0和TL0賦初值,計數器由0開始計數,到65535溢出
- TL0=0x00;
- EA=1; //總中斷打開
- ET0=1; //定時器中斷打開
- TR0=0; //關閉定時器
- }
- /*************************************************
- 函數名:T0_ISR()
- 說明:定時器0中斷服務程序
- 入口參數:無
- 返回值:無
- **************************************************/
- void T0_ISR(void) interrupt 1
- {
- TH0=t_H; //給TH0和TL0重新賦值
- TL0=t_L;
- BUZZ=~BUZZ; //BUZZ的值取反,改變蜂鳴器的狀態。
- }
- /*************************************************
- 函數名:alarm()
- 說明:鬧鈴
- 入口參數:h(小時),m(分鐘),s(秒)
- 返回值:無
- **************************************************/
- void alarm(int h,int m,int s)
- {
- int sec,min,hour;
- sec=read(0x81); //讀秒寄存器
- min=read(0x83); //讀分寄存器
- hour=read(0x85);//讀時寄存器
- if((sec==0)&(min==0))
- {
- t_H=0XFC;
- t_L=0X5B;
- TR0=1; //打開定時器,蜂鳴器發聲
- Delay_ms(50);
- BUZZ=0; //蜂鳴器不發聲,停頓片刻
- TR0=0;
- }
- if((hour==h)&(min==m)&(sec==s))
- for(t=0;t<42;t++)
- {
- getDHT11();
- writeLCD();
- t_H=toneH[soundtone[t]];//提取音調對應的定時器初始值
- t_L=toneL[soundtone[t]];//提取音調對應的定時器初始值
- TH0=t_H; //給TH0和TL0賦值
- TL0=t_L;
- TR0=1; //打開定時器,蜂鳴器發聲
- Delay_ms(soundlong[t]*200); //延時soundlong[t]指定的時間長度
- BUZZ=0; //蜂鳴器不發聲,停頓片刻
- TR0=0;
- Delay_ms(1);
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
Keil代碼與Proteus仿真下載:
數字電子鐘.7z
(62.8 KB, 下載次數: 88)
2022-11-9 18:25 上傳
點擊文件名下載附件
|