我做了一個帶日期顯示的溫度計,但是在顯示時1602液晶出現(xiàn)光標漂移的問題,在0xc0+8和9的位置。
那位幫我看看時怎么回事,初學單片機,還請多多指教。
- #include <AT89X52.h>
- #include <Intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- uchar a,count,S1num,xqnum;
- char yue,ri,shi,fen,miao;
- int nian;
- sbit lcdrs=P2^5;
- sbit lcdrw=P2^4; //1602
- sbit lcden=P2^3;
- sbit S1=P3^0; //定義鍵——進入設(shè)置
- sbit S2=P3^1; //定義鍵——增大
- sbit S3=P3^2; //定義鍵——減小
- sbit S4=P3^3; //定義鍵——退出設(shè)置
- sbit ds18b20=P1^7; //DS18B20
- uchar code table0[]="2018-02-13 WED";
- uchar code table1[]="23:59:50 ";
- uchar code xingqi[][3]={"MON","TUE","WED","THU","FRI","SAT","SUN"};
- //---------------------------------------
- //1602液晶寄存器設(shè)置
- //---------------------------------------
- unsigned char temp1;
- unsigned char temp2;
- unsigned char code table[16]={0,0,1,2,2,3,4,4,5,6,6,7,8,8,9,9};
- void delay(uint z)
- {
- unsigned int i;
- while (z--)
- for (i=0;i<125;i++);
- }
- //名稱:復(fù)位DS18B20函數(shù)
- //---------------------------------------
- bit Reset(void)
- {
- unsigned int i;
- bit k;
- ds18b20=0; //拉低DQ總線開始復(fù)位
- i=200; //保持DQ低大約870uS,符合不低于48US的要求
- while(i>0) //保持DQ低大約870uS,符合不低于48US的要求
- i--; //保持DQ低大約870uS,符合不低于48US的要求
- ds18b20=1; //拉高準備接收數(shù)據(jù)
- i=18; //大約80uS后
- while(i>0) //大約80uS后
- i--; //大約80uS后
- k=ds18b20; //讀出數(shù)據(jù)并保存
- i=91; //維持約400US,符合總讀時隙不低于480US的要求
- while(i>0) //維持約400US,符合總讀時隙不低于480US的要求
- i--; //維持約400US,符合總讀時隙不低于480US的要求
- return k; //k=0為復(fù)位成功,k=1為復(fù)位失敗
- }
- //---------------------------------------
- //名稱:讀一字節(jié)函數(shù)
- //---------------------------------------
- unsigned char ReadByte(void)
- {
- unsigned int i;
- unsigned char j,buf=0;
- for(j=0;j<8;j++) //接收8次還原一個字節(jié)數(shù)據(jù)
- {
- buf=buf>>1; //接收前,想將接收緩沖區(qū)右移
- ds18b20=0; //拉低
- _nop_(); //維持2US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持2US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持2US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持2US,符合大于1US小于15US的規(guī)范
- ds18b20=1; //拉高,為讀數(shù)據(jù)做準備
- _nop_(); //維持6US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持6US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持6US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持6US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持6US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持6US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持6US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持6US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持6US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持6US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持6US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持6US,符合大于1US小于15US的規(guī)范
- if(ds18b20==1) buf|=0x80; //讀出1位數(shù)據(jù)保存于buf中
- i=12; //維持約52US,符合總讀時隙不低于60US的要求
- while(i>0) //維持約52US,符合總讀時隙不低于60US的要求
- i--; //維持約52US,符合總讀時隙不低于60US的要求
- }
- return buf; //退出的同時將接收緩沖區(qū)參數(shù)返回
- }
- //---------------------------------------
- //名稱:寫一字節(jié)函數(shù)
- //---------------------------------------
- void WriteByte(unsigned char dat)
- {
- unsigned int i;
- unsigned char j;
- for(j=0;j<8;j++)
- {
- if(dat&0x01) //如果寫1
- {
- ds18b20=0; //拉低
- _nop_(); //維持2US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持2US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持2US,符合大于1US小于15US的規(guī)范
- _nop_(); //維持2US,符合大于1US小于15US的規(guī)范
- ds18b20=1; //拉高
- i=14; //維持約63US,符合不低于60US的要求
- while(i>0) //維持約63US,符合不低于60US的要求
- i--; //維持約63US,符合不低于60US的要求
- }
- else //如果寫0
- {
- ds18b20=0; //拉低
- i=14; //維持約63US,符合不低于60US的要求
- while(i>0) //維持約63US,符合不低于60US的要求
- i--; //維持約63US,符合不低于60US的要求
- ds18b20=1; //拉高
- _nop_(); //維持2US,符合大于1US的規(guī)范
- _nop_(); //維持2US,符合大于1US的規(guī)范
- _nop_(); //維持2US,符合大于1US的規(guī)范
- _nop_(); //維持2US,符合大于1US的規(guī)范
- }
- dat=dat>>1; //寫入字節(jié)右移1位
- }
- }
- //---------------------------------------
- //名稱:DS18B20溫度轉(zhuǎn)換函數(shù)
- //---------------------------------------
- bit Convert(void)
- {
- if(Reset()==0) //復(fù)位DS18B20
- {
- WriteByte(0xcc); //寫入跳過序列號命令字 Skip Rom
- WriteByte(0x44); //寫入溫度轉(zhuǎn)換命令字 Convert T
- return 1; //啟動溫度轉(zhuǎn)換成功
- }
- else
- {
- return 0; //啟動溫度轉(zhuǎn)換失敗
- }
- }
- //---------------------------------------
- //名稱:轉(zhuǎn)換結(jié)束處理函數(shù)
- //---------------------------------------
- void ReadFlash(void)
- {
- unsigned char Lsb,Msb;
- if(Reset()==0) //復(fù)位DS18B20
- {
- WriteByte(0xcc); //寫入跳過序列號命令字 Skip Rom
- WriteByte(0xbe); //寫入讀取數(shù)據(jù)令字 Read Scratchpad
- Lsb=ReadByte(); //讀出第一個字節(jié)暫存于LSB
- Msb=ReadByte(); //讀出第二個字節(jié)暫存于MSB
- temp1=Lsb&0x0f; //temp1內(nèi)裝溫度參數(shù)的小數(shù)部分
- temp2=(Lsb>>4)|(Msb<<4);//temp2內(nèi)裝溫度參數(shù)的整數(shù)部分
- }
- else
- {
- temp1=0; //如果復(fù)位失敗,溫度參數(shù)清零
- temp2=0; //如果復(fù)位失敗,溫度參數(shù)清零
- }
- }
- /**************************************************
- 1602液晶顯示器模塊
- sbit lcdrs=P2^5;
- sbit lcdrw=P2^4;
- sbit lcden=P2^3;
- *************************************************/
- void write_com(uchar com) //液晶寫指令
- {
- lcdrw=0;
- lcdrs=0;
- P0=com;
- delay(5);
- lcden=1;
- delay(5);
- lcden=0;
- }
- void write_data(uchar dat) //液晶寫數(shù)據(jù)
- {
- lcdrw=0;
- lcdrs=1;
- P0=dat;
- delay(5);
- lcden=1;
- delay(5);
- lcden=0;
- }
- /********************************************
- 年月日寫入1602函數(shù)
- ********************************************/
- void write_sfm(uchar add,uchar dat) //寫時分秒函數(shù)
- {
- uchar shi,ge;
- shi=dat/10;
- ge=dat%10;
- write_com(0x80+0x40+add);
- write_data(0x30+shi);
- write_data(0x30+ge);
- }
- void write_yr(uchar add,uchar dat) //寫月日函數(shù)
- {
- uchar shi,ge;
- shi=dat/10;
- ge=dat%10;
- write_com(0x80+add);
- write_data(0x30+shi);
- write_data(0x30+ge);
- }
- void write_nian(uchar add,uint dat) //寫年函數(shù)
- {
- uint qian,bai,shi,ge;
- qian=dat/1000;
- bai=dat%1000/100;
- shi=dat%100/10;
- ge=dat%10;
- write_com(0x80+add);
- write_data(0x30+qian);
- write_data(0x30+bai);
- write_data(0x30+shi);
- write_data(0x30+ge);
- }
- void xwd()
- {
-
- if(Convert()==1) //啟動轉(zhuǎn)換
- {
- ReadFlash(); //讀取溫度
- if(temp2>99) temp2=99;
- if(temp1>15) temp1=0;
- write_com(0xc0+10);
- write_data(temp2/10+'0'); //LCD1602_Disp(0,0,temp2/10+'0'); //溫度整數(shù)部分十位
- write_com(0xc0+11);
- write_data(temp2%10+'0'); //LCD1602_Disp(1,0,temp2%10+'0'); //溫度整數(shù)部分個位
- write_com(0xc0+12);
- write_data('.'); //LCD1602_Disp(2,0,'.'); //.
- write_com(0xc0+13);
- write_data(table[temp1]+'0'); //LCD1602_Disp(3,0,table[temp1]+'0'); //溫度小數(shù)部分
- write_com(0xc0+14);
-
- write_data(0xdf); //LCD1602_Disp(4,0,0xdf); //.
- write_com(0xc0+15);
- write_data(0x43); //LCD1602_Disp(5,0,0x43); //C
- }
- }
- /***************************************************
- 初始化
- ***************************************************/
- void init_lcd() //液晶初始化
- {
- lcden=0;
- nian=2018;
- yue=2;
- ri=13;
- shi=23; //初始shi、fen、miao
- fen=59;
- miao=50;
- write_com(0x38); //設(shè)置16x2顯示,5x7點陣,8位數(shù)據(jù)口
- write_com(0x0c); //設(shè)置開顯示,不顯示光標
- write_com(0x06); //寫一個字符后地址指針加1
- write_com(0x01); //顯示清0,數(shù)據(jù)指針清0
- }
- void init() //初始化函數(shù)
- {
- init_lcd(); //液晶初始化
- write_com(0x80); //設(shè)置顯示初始坐標
- for(a=0;a<14;a++) //顯示年月日初始值
- {
- write_data(table0[a]);
- delay(5);
- }
- write_com(0x80+0x40); //設(shè)置顯示初始坐標
- for(a=0;a<8;a++) //顯示時分秒初始值
- {
- write_data(table1[a]);
- delay(5);
- }
-
- count=0;
- xqnum=0;
- S1num=0; //初始化全局變量count
- TMOD=0x01; //設(shè)置定時器0工作模式1
- TH0=0xdb; //定時器裝初始值
- TL0=0xff;
- EA=1; //開總中斷
- ET0=1; //開定時器0中斷
- TR0=1; //啟動定時器0
- }
- /**************************************************
- 獨立鍵盤
- sbit S1=P3^0; //定義鍵——進入設(shè)置
- sbit S2=P3^1; //定義鍵——增大
- sbit S3=P3^2; //定義鍵——減小
- sbit S4=P3^3; //定義鍵——退出設(shè)置
- 獨立鍵盤已接地
- *************************************************/
- void keyscan()
- {
- if(S1==0)
- {
- delay(5); //確認定義鍵被按下
- if(S1==0)
- {
- S1num++; //定義鍵S1按下次數(shù)記錄
- while(!S1); //釋放按鍵確認
- if(S1num==1) //S1按下一次時
- {
- TR0=0; //關(guān)閉定時器
- write_com(0xc0+7); //光標定位到秒位置
- write_com(0x0f); //光標閃爍
- }
- if(S1num==2) //S1按下兩次時
- {
- write_com(0xc0+4); //光標定位到分位置
- }
- if(S1num==3) //S1按下三次時
- {
- write_com(0xc0+1); //光標定位到時位置
- }
- if(S1num==4) //S1按下四次時
- {
- write_com(0x80+13); //光標定位到星期位置
- }
- if(S1num==5) //S1按下五次時
- {
- write_com(0x80+9); //光標定位到日位置
- }
- if(S1num==6) //S1按下六次時
- {
- write_com(0x80+6); //光標定位到月位置
- }
- if(S1num==7) //S1按下七次時
- {
- write_com(0x80+3); //光標定位到年位置
- }
- if(S1num==8) //S1按下八次時
- {
- S1num=0; //S1記錄按鍵次數(shù)清零
- TR0=1; //開啟定時器
- write_com(0x0c); //取消光標閃爍
- }
- }
- }
- if(S1num!=0) //只有定義鍵按下后S2、S3、S4才有效
- {
- if(S2==0)
- {
- delay(5); //防抖
- if(S2==0) //確認按鍵被按下
- {
- while(!S2); //釋放按鍵確認
- if(S1num==1) //S1按下一次時
- {
- miao++; //調(diào)整秒加1
- if(miao==60) //滿60清零
- miao=0;
- write_sfm(6,miao); //每調(diào)節(jié)一次送液晶顯示一次
- write_com(0x80+0x40+7); //顯示位置重新回到調(diào)節(jié)處
- }
- if(S1num==2) //S1按下兩次時
- {
- fen++; //調(diào)整分加1
- if(fen==60)
- fen=0;
- write_sfm(3,fen);
- write_com(0x80+0x40+4);
- }
- if(S1num==3) //S1按下三次時
- {
- shi++; //調(diào)整時加1
- if(shi==24)
- shi=0;
- write_sfm(0,shi);
- write_com(0xc0+1);
- }
- if(S1num==4) //星期加調(diào)整
- {
- xqnum++;
- if(xqnum==7)
- xqnum=0;
- write_com(0x80+0x0b);
- for(a=0;a<3;a++)
- {
- write_data(xingqi[xqnum][a]);
- delay(5);
-
- }
- }
- if(S1num==5) //日加調(diào)整
- {
- ri++;
- if(yue==2)
- {
- if(nian%400==0)
- {
- if(ri==30)
- {
- ri=1;
- }
- }
- if(nian%400!=0)
- {
- if(ri==29)
- {
- ri=1;
- }
- }
- }
- else if(yue<=7)
- {
- if(yue%2==0&yue!=2)
- {
- if(ri==31)
- {
- ri=1;
- }
- }
- else if(yue%2!=0&yue!=2)
- {
- if(ri==32)
- {
- ri=1;
- }
- }
- }
- else if(yue>=8)
- {
- if(yue%2==0)
- {
- if(ri==32)
- {
- ri=1;
- }
- }
- else if(yue%2!=0)
- {
- if(ri==31)
- {
- ri=1;
- }
- }
- }
- write_yr(8,ri);
- write_com(0x80+9);
- }
- if(S1num==6) //月加調(diào)整
- {
- yue++;
- if(yue==13)
- yue=1;
- write_yr(5,yue);
- write_com(0x80+6);
- }
- if(S1num==7) //年加調(diào)整
- {
- nian++;
- if(nian==2021)
- nian=2018;
- write_nian(0,nian);
- write_com(0x80+3);
- }
- }
- }
- if(S3==0)
- {
- delay(5);
- if(S3==0) //確認按鍵被按下
- {
- while(!S3);
- if(S1num==1)
- {
- miao--; //調(diào)整秒減1
- if(miao==-1) //減到00后再減重新設(shè)置為59
- miao=59;
- write_sfm(6,miao);
- write_com(0x80+0x40+7);
- }
- if(S1num==2)
- {
- fen--; //調(diào)整分減1
- if(fen==-1)
- fen=59;
- write_sfm(3,fen);
- write_com(0x80+0x40+4);
- }
- if(S1num==3)
- {
- shi--; //調(diào)整時減1
- if(shi==-1)
- shi=23;
- write_sfm(0,shi);
- write_com(0x80+0x40+1);
- }
- if(S1num==4)
- {
- xqnum--; //調(diào)整星期減一
- if(xqnum==-1)
- xqnum=6;
- write_com(0x80+0x0b);
- for(a=0;a<3;a++)
- {
- write_data(xingqi[xqnum][a]);
- delay(5);
-
- }
- }
- if(S1num==5) //調(diào)整日
- {
- ri--;
- if(yue==2)
- {
- if(nian%400==0)
- {
- if(ri==0)
- {
- ri=29;
- }
- }
- if(nian%400!=0)
- {
- if(ri==0)
- {
- ri=28;
- }
- }
- }
- else if(yue<=7)
- {
- if(yue%2==0&yue!=2)
- {
- if(ri==0)
- {
- ri=30;
- }
- }
- else if(yue%2!=0&yue!=2)
- {
- if(ri==0)
- {
- ri=31;
- }
- }
- }
- else if(yue>=8)
- {
- if(yue%2==0)
- {
- if(ri==0)
- {
- ri=31;
- }
- }
- else if(yue%2!=0)
- {
- if(ri==0)
- {
- ri=30;
- }
- }
- }
- write_yr(8,ri);
- write_com(0x80+9);
- }
- if(S1num==6) //調(diào)整月
- {
- yue--;
- if(yue==0)
- yue=12;
- write_yr(5,yue);
- write_com(0x80+6);
- }
- if(S1num==7) //調(diào)整年
- {
- nian--;
- if(nian==2017)
- nian=2020;
- write_nian(0,nian);
- write_com(0x80+3);
- }
- }
- }
- if(S4==0) //退出設(shè)置、開啟中斷
- {
- delay(5);
- if(S4==0)
- {
- S1num=0;
- TR0=1;
- write_com(0x0c);
- }
- }
- }
- }
- /**************************************************
- 定時器0
- *************************************************/
- void timer0() interrupt 1 //定時器0中斷服務(wù)程序
- {
- TH0=0xdb; //重裝定時器初始值
- TL0=0xff;
- count++; //中斷次數(shù)累加
- if(count==200) //20次50毫秒即一秒
- {
- count=0;
- miao++;
- if(miao==60) //秒加到60時分進位
- {
- miao=0;
- fen++;
- if(fen==60) //分加到60時時進位
- {
- fen=0;
- shi++;
- if(shi==24) //時加到24時清0
- {
- shi=0;
- xqnum++;
- ri++;
- if(yue==2) //如果是二月
- {
- if(nian%400==0) //閏年判斷
- {
- if(ri==30)
- {
- ri=1;
- yue++;
- write_yr(5,yue);
- }
- }
- if(nian%400!=0) //平年判斷
- {
- if(ri==29)
- {
- ri=1;
- yue++;
- write_yr(5,yue);
- }
- }
- }
- else if(yue<=7&yue!=2) //一月到七月
- {
- if(yue%2==0) //偶數(shù)月(除二月)
- {
- if(ri==31)
- {
- ri=1;
- yue++;
- }
- }
- else if(yue%2!=0) //奇數(shù)月
- {
- if(ri==32)
- {
- ri=1;
- yue++;
- }
- }
- write_yr(5,yue);
- }
- else if(yue>=8) //八月到12月
- {
- if(yue%2==0) //偶數(shù)月(除二月)
- {
- if(ri==32)
- {
- ri=1;
- yue++;
- if(yue==13) //如果判斷月份為12月,則加一后重新定義月份為1
- {
- yue=1;
- nian++;
- write_nian(0,nian);
- }
- write_yr(5,yue);
- }
- }
- else if(yue%2!=0) //奇數(shù)月
- {
- if(ri==31)
- {
- ri=1;
- yue++;
- write_yr(5,yue);
- }
- }
- }
- write_yr(8,ri);
- if(xqnum==7) //星期寫入
- xqnum=0;
- write_com(0x80+0x0b);
- for(a=0;a<3;a++)
- {
- write_data(xingqi[xqnum][a]);
- delay(5);
- }
- }
- write_sfm(0,shi); //重新寫入數(shù)據(jù)
- }
- write_sfm(3,fen); //重新寫入數(shù)據(jù)
- }
- write_sfm(6,miao); //重新寫入數(shù)據(jù)
- }
- }
- /*************************************************
- 主函數(shù)
- *************************************************/
- void main()
- {
- init();
- while(1)
- {
- if(S1num==0)
- {
- xwd();
- }
-
- keyscan(); //不停的檢測按鍵是否被按下
- }
- }
復(fù)制代碼
|