|
LCD1602程序仿真正常,實物上顯示不正常,程序在附件里面
TIM截圖20190601163408.png (31.91 KB, 下載次數: 31)
下載附件
2019-6-1 16:35 上傳
IMG_20190601_163436.jpg (2.53 MB, 下載次數: 41)
下載附件
2019-6-1 16:35 上傳
單片機源程序如下:
- #include <reg51.h> //調用含有51專用寄存器的頭文件
- #include<intrins.h>
- #define uchar unsigned char //用uchar代替unsigned char
- #define uint unsigned int //用uint代替unsigned int
- #define yh 0x80 //LCD第一行的初始位置,因為LCD1602字符地址首位D7恒定為1(100000000=80)
- #define er 0x80+0x40 //LCD第二行初始位置(因為第二行第一個字符位置地址是0x40)
- char a,sec,min,hour,day,mouth,temp,n; //定義變量
- sbit rs=P3^0; //液晶指令/數據輸入控制
- sbit en=P3^2; //液晶使能端
- sbit Data=P3^6; //定義數據線
- uchar rec_dat[14]; //用于顯示的接收數據數組
- sbit IO=P3^5; //數據線
- sbit SCLK=P3^4; //時鐘線
- sbit RST=P3^3; //使能
- sbit mode=P1^0; //設置鍵
- sbit s1 =P1^1; //加鍵
- sbit s2 =P1^2; //減鍵
- sbit yes =P1^3; //調整確認鍵
- sbit ACC0=ACC^0; //累加器A低位
- sbit ACC7=ACC^7; //累加器A高位
- uchar code tab1[]={"Tem: Hum: %"}; //時間顯示的固定字符
- uchar code tab2[]={" - : : "}; //時間顯示的固定字符
- /***********************延時子程序********************/
- void delay(uint xms)
- {
- uint x,y;
- for(x=xms;x>0;x--)
- for(y=110;y>0;y--);
- }
- /****************液晶寫入指令函數*******************/
- void write_1602com(uchar com)
- {
- rs=0; //數據/指令選擇置為指令
- P2=com; //送入數據
- delay(1); //看時序圖,可以得出,寫程序需要時間
- en=1; //拉高使能端,為制造有效的下降沿做準備
- delay(1);
- en=0; //en由高變低,產生下降沿,液晶執行命令
- }
- /********************液晶寫入數據函數***************/
- void write_1602dat(uchar dat)
- {
- rs=1; //數據/指令選擇置為數據
- P2=dat; //送入數據
- delay(1);
- en=1; //en置高電平,為制造下降沿做準備
- delay(1);
- en=0; //en由高變低,產生下降沿,液晶執行命令
- }
- /**************液晶初始化函數**********************/
- void lcd_init()
- {
- write_1602com(0x38); //設置液晶工作模式,
- write_1602com(0x0c); //開顯示不顯示光標
- write_1602com(0x06); //整屏不移動,光標自動右移
- write_1602com(0x01); //清顯示
- write_1602com(yh+1); //日歷顯示固定符號從第一行第1個位置之后開始顯示
- for(a=0;a<14;a++)
- {
- write_1602dat(tab1[a]); //向液晶屏寫日歷顯示的固定符號部分
- }
- write_1602com(er+1); //時間顯示固定符號寫入位置,從第2個位置后開始顯示
- for(a=0;a<14;a++)
- {
- write_1602dat(tab2[a]); //寫顯示時間固定符號,兩個冒號
- }
- }
- /***************寫數據********************/
- void write_byte(uchar dat)
- {
- ACC=dat;
- RST=1;
- for(a=8;a>0;a--)
- {
- IO=ACC0;
- SCLK=0;
- SCLK=1;
- ACC=ACC>>1;
- }
- }
- /******************讀數據********************/
- uchar read_byte()
- {
- RST=1;
- for(a=8;a>0;a--)
- {
- ACC7=IO;
- SCLK=1;
- SCLK=0;
- ACC=ACC>>1;
- }
- return (ACC);
- }
- /*********向1302芯片寫函數,指定寫入地址,數據*********/
- void write_1302(uchar add,uchar dat)
- {
- RST=0;
- SCLK=0;
- RST=1;
- write_byte(add);
- write_byte(dat);
- SCLK=1;
- RST=0;
- }
- /*********從1302讀數據函數,指定讀取數據來源地址*******/
- uchar read_1302(uchar add)
- {
- uchar temp;
- RST=0;
- SCLK=0;
- RST=1;
- write_byte(add);
- temp=read_byte();
- SCLK=1;
- RST=0;
- return(temp);
- }
- /****************BCD碼轉十進制函數,輸入BCD,返回十進制*******/
- uchar BCD(uchar m)
- {
- uchar x;
- x=m>>4;
- return(x=x*10+(m&=0x0f));
- }
- /********1302芯片初始化子函數(2019-05-19,16:36:00,week7)********/
- void ds1302_init()
- {
- RST=0;
- SCLK=0;
- write_1302(0x8e,0x00); //允許寫,禁止寫保護
- write_1302(0x8e,0x80); //打開寫保護
- }
- /*****************************月日時分秒顯示子函數*******************************/
- void write_time(uchar add,uchar dat)//向LCD寫時分秒,有顯示位置加、現示數據,兩個參數
- {
- uchar gw,sw;
- gw=dat%10; //取得個位數字
- sw=dat/10; //取得十位數字
- write_1602com(er+add); //er是頭文件寫的值0x80+0x40
- write_1602dat(0x30+sw); //數字+30得到該數字的LCD1602顯示碼
- write_1602dat(0x30+gw); //數字+30得到該數字的LCD1602顯示碼
- }
- /***********************按鍵處理函數**********************/
- void key()
- {
- if(mode==0) //第一次判斷"模式"按鍵按下
- {
- delay(5); //延時消抖
- if(mode==0){TR0=0;n++;}while(!mode);}
- if(n>5) {TR0=1;n=0;} //如果第四次按下mode鍵則繼續計時,并且重新記錄按下的按鍵次數
- /**********************調整+********************************/
- if(n!=0) //當mode按下以后。再按以下鍵才有效(按鍵次數不等于零)
- {
- if(s1==0) //調整+鍵
- {
- delay(30);
- if(s1==0)
- {
- TR0=0;
- switch(n)
- {
- case 1:sec++; //設置鍵按動1次,調秒
- if(sec==60) sec=0; //秒超過59,再加1,就歸零
- write_time(13,sec); //令LCD在正確位置顯示"加"設定好的秒數
- temp=(sec)/10*16+(sec)%10; //十進制轉換成DS1302要求的DCB碼
- write_1302(0x8e,0x00); //允許寫,禁止寫保護
- write_1302(0x80,temp); //向DS1302內寫秒寄存器80H寫入調整后的秒數據BCD碼
- write_1302(0x8e,0x80); //打開寫保護
- write_1602com(er+14); //因為設置液晶的模式是寫入數據后,指針自動+1,需要光標回位
- break;
- case 2:min++; //設置鍵按動2次,調分
- if(min==60) min=0; //分數據加到60時自動變成0
- write_time(10,min); //令LCD在正確位置顯示"加"設定好的分數據
- temp=(min)/10*16+(min)%10; //十進制轉換成DS1302要求的DCB碼
- write_1302(0x8e,0x00); //允許寫,禁止寫保護
- write_1302(0x82,temp); //向DS1302內寫分寄存器82H寫入調整后的分數據BCD碼
- write_1302(0x8e,0x80); //打開寫保護
- write_1602com(er+11);
- break;
- case 3:hour++;
- if(hour==24) hour=0; //時數據加到24時自動變成0
- write_time(7,hour); //令LCD在正確的位置顯示"加"設定好的小時數據
- temp=(hour)/10*16+(hour)%10; //十進制轉換成DS1302要求的DCB碼
- write_1302(0x8e,0x00); //允許寫,禁止寫保護
- write_1302(0x84,temp); //向DS1302內寫小時寄存器84H寫入調整后的小時數據BCD碼
- write_1302(0x8e,0x80); //打開寫保護
- write_1602com(er+8);
- break;
- case 4:day++; //設置鍵按動5次,調天
- if(day==32) day=1; //天數據加到32時自動變成1
- write_time(4,day); //令LCD在正確的位置顯示"加"設定好的日期數據
- temp=(day)/10*16+(day)%10; //十進制轉換成DS1302要求的DCB碼
- write_1302(0x8e,0x00); //允許寫,禁止寫保護
- write_1302(0x86,temp); //向DS1302內寫日期寄存器86H寫入調整后的日期數據BCD碼
- write_1302(0x8e,0x80); //打開寫保護
- write_1602com(er+5);
- break;
- case 5:mouth++; //設置鍵按動6次,調月
- if(mouth>=13) mouth=1; //月數據加到12時自動變成1
- write_time(1,mouth); //令LCD在正確的位置顯示"加"設定好的月份數據
- temp=(mouth)/10*16+(mouth)%10; //十進制轉換成DS1302要求的DCB碼
- write_1302(0x8e,0x00); //允許寫,禁止寫保護
- write_1302(0x88,temp); //向DS1302內寫月份寄存器88H寫入調整后的月份數據BCD碼
- write_1302(0x8e,0x80); //打開寫保護
- write_1602com(er+2);
- break;
- }
- }
- while(!s1);
- }
- }
- /**********************調整-********************************/
- if(n!=0) //當mode按下以后,再按以下鍵才有效
- {
- if(s2==0) //調整-鍵
- {
- delay(30);
- if(s2==0)
- {
- TR0=0; //關閉中斷
- switch(n)
- {
- case 1:sec--; //設置鍵按動1次,調秒
- if(sec==-1) sec=59; //秒數據減到-1時自動變成59
- write_time(13,sec); //令LCD在正確位置顯示"加"設定好的秒數
- temp=(sec)/10*16+(sec)%10; //十進制轉換成DS1302要求的DCB碼
- write_1302(0x8e,0x00); //允許寫,禁止寫保護
- write_1302(0x80,temp); //向DS1302內寫秒寄存器80H寫入調整后的秒數據BCD碼
- write_1302(0x8e,0x80); //打開寫保護
- write_1602com(er+14); //因為設置液晶的模式是寫入數據后,指針自動+1,需要光標回位
- break;
- case 2:min--;
- if(min==-1) min=59; //分數據減到-1時自動變成59
- write_time(10,min); //令LCD在正確位置顯示"加"設定好的分數據
- temp=(min)/10*16+(min)%10; //十進制轉換成DS1302要求的DCB碼
- write_1302(0x8e,0x00); //允許寫,禁止寫保護
- write_1302(0x82,temp); //向DS1302內寫分寄存器82H寫入調整后的分數據BCD碼
- write_1302(0x8e,0x80); //打開寫保護
- write_1602com(er+11);
- break;
- case 3:hour--;
- if(hour==-1) hour=23; //時數據減到-1時自動變成23
- write_time(7,hour); //令LCD在正確的位置顯示"加"設定好的小時數據
- temp=(hour)/10*16+(hour)%10; //十進制轉換成DS1302要求的DCB碼
- write_1302(0x8e,0x00); //允許寫,禁止寫保護
- write_1302(0x84,temp); //向DS1302內寫小時寄存器84H寫入調整后的小時數據BCD碼
- write_1302(0x8e,0x80); //打開寫保護
- write_1602com(er+8);
- break;
- case 4:day--;
- if(day==-1) day=31; //天數據減到-1時自動變成31
- write_time(4,day); //令LCD在正確的位置顯示"加"設定好的日期數據
- temp=(day)/10*16+(day)%10; //十進制轉換成DS1302要求的DCB碼
- write_1302(0x8e,0x00); //允許寫,禁止寫保護
- write_1302(0x86,temp); //向DS1302內寫日期寄存器86H寫入調整后的日期數據BCD碼
- write_1302(0x8e,0x80); //打開寫保護
- write_1602com(er+5);
- break;
- case 5:mouth--;
- if(mouth==-1) mouth=12; //月數據減到-1時自動變成12
- write_time(1,mouth);
- temp=(mouth)/10*16+(mouth)%10; //十進制轉換成DS1302要求的DCB碼
- write_1302(0x8e,0x00); //允許寫,禁止寫保護
- write_1302(0x88,temp); //向DS1302內寫月份寄存器88H寫入調整后的月份數據BCD碼
- write_1302(0x8e,0x80); //打開寫保護
- write_1602com(er+2);
- break;
- }
- }
- while(!s2); //按鍵松開檢測
- }
- }
- if(n!=0)
- {
- if(yes==0) //調整值確認鍵按下,保存設置的參數,直接退出調整狀態,進入走時。
- {
- delay(30);
- if(yes==0)
- {
- n=0,
- write_1602com(0x0c); //設置光標不閃爍
- TR0=1; //打開定時器
- temp=(sec)/10*16+(sec)%10;
- write_1302(0x8e,0x00);
- write_1302(0x80,0x00|temp); //秒數據寫入DS1302
- write_1302(0x8e,0x80);
- }
- while(!yes); //松開按鍵檢測
- }
- }
- }
- //*********************DHT11************************
- void DHT11_delay_us(uchar n)
- {
- while(--n);
- }
- void DHT11_delay_ms(uint z)
- {
- uint i,j;
- for(i=z;i>0;i--)
- for(j=110;j>0;j--);
- }
- void DHT11_start()
- {
- Data=1;
- DHT11_delay_us(2);
- Data=0;
- DHT11_delay_ms(30); //延時18ms以上
- Data=1;
- DHT11_delay_us(30);
- }
- uchar DHT11_rec_byte() //接收一個字節
- {
- uchar i,dat=0;
- for(i=0;i<8;i++) //從高到低依次接收8位數據
- {
- while(!Data); ////等待50us低電平過去
- DHT11_delay_us(8); //延時60us,如果還為高則數據為1,否則為0
- dat<<=1; //移位使正確接收8位數據,數據為0時直接移位
- if(Data==1) //數據為1時,使dat加1來接收數據1
- dat+=1;
- while(Data); //等待數據線拉低
- }
- return dat;
- }
- void DHT11_receive() //接收40位的數據
- {
- uchar R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise;
- DHT11_start();
- if(Data==0)
- {
- while(Data==0); //等待拉高
- DHT11_delay_us(40); //拉高后延時80us
- R_H=DHT11_rec_byte(); //接收濕度高八位
- R_L=DHT11_rec_byte(); //接收濕度低八位
- T_H=DHT11_rec_byte(); //接收溫度高八位
- T_L=DHT11_rec_byte(); //接收溫度低八位
- revise=DHT11_rec_byte(); //接收校正位
- DHT11_delay_us(25); //結束
- if((R_H+R_L+T_H+T_L)==revise) //校正
- {
- RH=R_H;
- RL=R_L;
- TH=T_H;
- TL=T_L;
- }
- /*數據處理,方便顯示*/
- rec_dat[0]='T';
- rec_dat[1]='e';
- rec_dat[2]='m';
- rec_dat[3]=':';
- rec_dat[4]='0'+(TH/10);
- rec_dat[5]='0'+(TH%10);
- rec_dat[6]=' ';
- rec_dat[7]='H';
- rec_dat[8]='u';
- rec_dat[9]='m';
- rec_dat[10]=':';
- rec_dat[11]='0'+(RH/10);
- rec_dat[12]='0'+(RH%10);
- rec_dat[13]='%';
- }
- }
- /****************************主函數**********************/
- void main()
- {
- uchar i;
- TMOD=0x11; //指定定時/計數器的工作方式為3
- TH0=0; //定時器T0的高四位=0
- TL0=0; //定時器T0的低四位=0
- EA=1; //開總中斷
- ET0=1; //允許T0中斷
- TR0=1; //開啟中斷,啟動定時器
- lcd_init(); //調用液晶屏初始化子函數
- ds1302_init(); //調用DS1302時鐘的初始化子函數
- DHT11_delay_ms(100); //DHT11上電后要等待1S以越過不穩定狀態在此期間不能發送任何指令
- DHT11_receive();
- write_1602com(yh+1); //從lcd1602第一行第一個位置開始顯示
- for(i=0;i<14;i++)
- write_1602dat(rec_dat[i]); //顯示數據
-
- while(1)
- {
- key();
- }
-
- }
- void timer0() interrupt 1 //取得并顯示日歷和時間
- {
- /***************************讀取秒時分周日月年七個數據***********************/
- sec = BCD(read_1302(0x81));
- min = BCD(read_1302(0x83));
- hour = BCD(read_1302(0x85));
- day = BCD(read_1302(0x87));
- mouth= BCD(read_1302(0x89));
- /**************************顯示溫度、秒、時、分數據***************************/
- write_time(13,sec); //秒,從第二行第8個字后開始顯示(調用時分秒顯示子函數)
- write_time(10,min); //分,從第二行第5個字符后開始顯示
- write_time(7,hour); //小時,從第二行第2個字符后開始顯示
- write_time(4,day); //日期,從第二行第9個字符后開始顯示
- write_time(1,mouth); //月份,從第二行第6個字符后開始顯示
- }
復制代碼 |
-
-
1302時鐘.zip
2019-6-1 16:36 上傳
點擊文件名下載附件
4.24 KB, 下載次數: 16
|