這是我學習單片機制作的,設計參數主要有: 1.溫度傳感器采用DS18B20芯片;
2.LCD1602液晶模塊作為顯示器;
3.能夠實現按鍵調整溫度上下限; 4.能夠顯示年月日。
里面有電路仿真圖,c程序等,希望能夠幫助到大家。
1.png (72.33 KB, 下載次數: 59)
下載附件
2020-7-4 18:44 上傳
- #include<reg51.h> //將AT89X52.h頭文件包含到主程序
- #include<intrins.h> //將intrins.h頭文件包含到主程序(調用其中的_nop_()空操作函數延時)
- #define uint unsigned int //變量類型宏定義,用uint表示無符號整形(16位)
- #define uchar unsigned char //變量類型宏定義,用uchar表示無符號字符型(8位)
- sbit lcdrs=P2^4;
- sbit lcdrw=P2^5;
- sbit lcden=P2^6;
- sbit ds=P1^3;
- sbit k1=P3^0;//設置按鍵
- sbit k2=P3^1;//加1按鍵
- sbit k3=P3^2;//減1按鍵
- //sbit k4=P3^3;//關蜂鳴器按鍵
- sbit D1=P1^0;
- sbit D2=P1^1;
- uchar flag,num;
- uint aa,bb;
- uchar miao,fen,shi,ri=3,month=7,year=18,num11;
- long uint temp,biaozhi; //參數temp一定要聲明為 int 型
- //延時函數
- void Tempdelay11(uchar us) //經驗表明,這里us=1時約等于6.9us
- {
- while(us--);
- }
- void delay11(uint count) //延時子函數,當count=1是,延時大概2ms
- {
- uint i;
- while(count)
- {
- i=200;
- while(i>0)
- i--;
- count--;
- }
- }
- void delay(uint z)
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=110;y>0;y--);
- }
- /******************lcd液晶程序部分**************************/
- void write_com(uchar com) //lcd寫指令
- {
- lcdrs=0;
- lcdrw=0;
- P0=com;
- lcden=1;
- delay(5);
- lcden=0;
- }
- void write_date(uchar date) //lcd寫數據
- {
- lcdrs=1;
- lcdrw=0;
- P0=date;
- lcden=1;
- delay(5);
- lcden=0;
- }
- void init() //lcd初始化
- {
- lcdrw=0;
- write_com(0x38); //lcd液晶 顯示模式設置
- write_com(0x0c); //lcd液晶 開顯示 關光標 關閃爍
- write_com(0x06); //讀一個字節 光標指針加一 不整屏移動
- write_com(0x01); //清屏
- write_com(0x80); //設置數據指針
- }
- void key()
- {
- if(k1==0)//判斷k1按鍵是否按下
- {
- delay(10);//延時,消抖
- if(k1==0)//再次判斷k1按鍵是否按下
- {
- while(k1==0);//按鍵松手檢測
- num++;
- if(num==1)
- {
- write_com(0x80+9);
- write_com(15);
- }
- if(num==2)
- {
- write_com(0x80+15);
- }
- if(num==3)
- {
- num=0;
- write_com(12);
- }
- }
- }
- if(num!=0)
- {
- if(k2==0)//判斷k1按鍵是否按下
- {
- delay(10);//延時,消抖
- if(k2==0)//再次判斷k1按鍵是否按下
- {
- while(k2==0);//按鍵松手檢測
- if(num==1)
- {
- aa++;
- if(aa==1000)
- aa=0;
- write_com(0x80+6);
- write_date(48+aa/100);
- write_com(0x80+7);
- write_date(48+aa/10%10);
- write_com(0x80+9);
- write_date(48+aa%10);
- write_com(0x80+8);
- write_date('.');
- }
- if(num==2)
- {
- if(bb<aa)
- bb++;
- if(bb==1000)
- bb=0;
- write_com(0x80+12);
- write_date(48+bb/100);
- write_date(48+bb/10%10);
- write_com(0x80+15);
- write_date(48+bb%10);
- write_com(0x80+14);
- write_date('.');
- }
- }
- }
- if(k3==0)//判斷k1按鍵是否按下
- {
- delay(10);//延時,消抖
- if(k3==0)//再次判斷k1按鍵是否按下
- {
- while(k3==0);//按鍵松手檢測
- if(num==1)
- {
- if(aa>0)
- aa--;
- if(aa==-1)
- aa=999;
- write_com(0x80+6);
- write_date(48+aa/100);
- write_date(48+aa/10%10);
- write_com(0x80+9);
- write_date(48+aa%10);
- write_com(0x80+8);
- write_date('.');
- }
- if(num==2)
- {
- if(bb>0)
- bb--;
- if(bb==-1)
- bb=999;
- write_com(0x80+12);
- write_date(48+bb/100);
- write_date(48+bb/10%10);
- write_com(0x80+15);
- write_date(48+bb%10);
- write_com(0x80+14);
- write_date('.');
- }
- }
- }
- }
- }
- //LCD1602液晶的顯示
- void display(uint temp)
- {
- uchar bai,shi,ge;
- bai=temp/100;
- shi=temp/10%10;
- ge=temp%10;
- if(num==0)
- {
- if(biaozhi==1)
- {
- biaozhi=0;
- }
- write_com(0x80);
- write_date(48+bai);
- write_date(48+shi);
- write_date('.');
- write_date(48+ge);
- write_date(' ');
- write_date('H');
- write_date(48+aa/100);
- write_date(48+aa/10%10);
- write_date('.');
- write_date(48+aa%10);
- write_date(' ');
- write_date('L');
- write_date(48+bb/100);
- write_date(48+bb/10%10);
- write_date('.');
- write_date(48+bb%10);
- if(temp>aa)
- {
- D1=0;
- }
- else
- D1=1;
- if(temp<bb)
- D2=0;
- else
- D2=1;
- }
- write_com(0xc0+3);
- write_date('2');
- write_date('0');
- write_date(48+year/10);
- write_date(48+year%10);
- write_date('-');
- write_date(48+month/10);
- write_date(48+month%10);
- write_date('-');
- write_date(48+ri/10);
- write_date(48+ri%10);
- }
- /*****************************************
- 時序:初始化時序、讀時序、寫時序。
- 所有時序都是將主機(單片機)作為主設備,單總
- 線器件作為從設備。而每一次命令和數據的傳輸
- 都是從主機主動啟動寫時序開始,如果要求單總
- 線器件回送數據,在進行寫命令后,主機需啟動
- 讀時序完成數據接收。數據和命令的傳輸都是低
- 位在先。
- 初始化時序:復位脈沖 存在脈沖
- 讀;1 或 0時序
- 寫;1 或 0時序
- 只有存在脈沖信號是從18b20(從機)發出的,其
- 它信號都是由主機發出的。
- 存在脈沖:讓主機(總線)知道從機(18b20)已
- 經做好了準備。
- ******************************************/
- /*--------------------------------------------------------------------------------------------------------------------
- 初始化:檢測總線控制器發出的復位脈沖
- 和ds18b20的任何通訊都要從初始化開始
- 初始化序列包括一個由總線控制器發出的復位脈沖
- 和跟在其后由從機發出的存在脈沖。
- 初始化:復位脈沖+存在脈沖
- 具體操作:
- 總線控制器發出(TX)一個復位脈沖 (一個最少保持480μs 的低電平信號),然后釋放總線,
- 進入接收狀態(RX)。單線總線由5K 上拉電阻拉到高電平。探測到I/O 引腳上的上升沿后
- DS1820 等待15~60μs,然后發出存在脈沖(一個60~240μs 的低電平信號)。
- 具體看18b20 單線復位脈沖時序和1-wire presence detect "的時序圖
- -------------------------------------------------------------------------------------------------------------------*/
- void ds_reset()
- {
- ds=1;
- _nop_(); //1us
- ds=0;
- Tempdelay11(80); //當總線停留在低電平超過480us,總線上所以器件都將被復位,這里
- //延時約530us總 線停留在低電平超過480μs,總線上的所有器件都將被復位。
- _nop_();
- ds=1; //產生復位脈沖后,微處理器釋放總線,讓總線處于空閑狀態,原因查
- //18b20中文資料
- Tempdelay11(5); //釋放總線后,以便從機18b20通過拉低總線來指示其是否在線,
- //存在檢測高電平時間:15~60us, 所以延時44us,進行1-wire presence //detect(單線存在檢測)
- _nop_();
- _nop_();
- _nop_();
- if(ds==0)
- flag=1; //detect 18b20 success
- else
- flag=0; //detect 18b20 fail
- Tempdelay11(20); //存在檢測低電平時間:60~240us,所以延時約140us
- _nop_();
- _nop_();
- ds=1; //再次拉高總線,讓總線處于空閑狀態
- }
- /*----------------------------------------
- 讀/寫時間隙:
- DS1820 的數據讀寫是通過時間隙處理
- 位和命令字來確認信息交換。
- ------------------------------------------*/
- bit ds_read_bit() //讀一位
- {
- bit dat;
- ds=0; //單片機(微處理器)將總線拉低
- _nop_(); //讀時隙起始于微處理器將總線拉低至少1us
- ds=1; //拉低總線后接著釋放總線,讓從機18b20能夠接管總線,輸出有效數據
- _nop_();
- _nop_(); //小延時一下,讀取18b20上的數據 ,因為從ds18b20上輸出的數據
- //在讀"時間隙"下降沿出現15us內有效
- dat=ds; //主機讀從機18b20輸出的數據,這些數據在讀時隙的下降沿出現15us內有效
- Tempdelay11(10); //所有讀"時間隙"必須60~120us,這里77us
- return(dat); //返回有效數據
- }
- uchar ds_read_byte() //讀一字節
- {
- uchar value,i,j;
- value=0; //一定別忘了給初值
- for(i=0;i<8;i++)
- {
- j=ds_read_bit();
- value=(j<<7)|(value>>1); //這一步的說明在一個word文檔里面
- }
- return(value); //返回一個字節的數據
- }
- void ds_write_byte(uchar dat) //寫一個字節
- {
- uchar i;
- bit onebit; //一定不要忘了,onebit是一位
- for(i=1;i<=8;i++)
- {
- onebit=dat&0x01;
- dat=dat>>1;
- if(onebit) //寫 1
- {
- ds=0;
- _nop_();
- _nop_(); //看時序圖,至少延時1us,才產生寫"時間隙"
- ds=1; //寫時間隙開始后的15μs內允許數據線拉到高電平
- Tempdelay11(5); //所有寫時間隙必須最少持續60us
- }
- else //寫 0
- {
- ds=0;
- Tempdelay11(8); //主機要生成一個寫0 時間隙,必須把數據線拉到低電平并保持至少60μs,這里64us
- ds=1;
- _nop_();
- _nop_();
- }
- }
- }
- /*****************************************
- 主機(單片機)控制18B20完成溫度轉換要經過三個步驟:
- 每一次讀寫之前都要18B20進行復位操作,復位成功后發送
- 一條ROM指令,最后發送RAM指令,這樣才能對DS18b20進行
- 預定的操作。
- 復位要求主CPU將數據線下拉500us,然后釋放,當ds18B20
- 受到信號后等待16~60us,后發出60~240us的存在低脈沖,
- 主CPU收到此信號表示復位成功
- ******************************************/
- /*----------------------------------------
- 進行溫度轉換:
- 先初始化
- 然后跳過ROM:跳過64位ROM地址,直接向ds18B20發溫度轉換命令,適合單片工作
- 發送溫度轉換命令
- ------------------------------------------*/
- void tem_change()
- {
- ds_reset();
- delay11(1); //約2ms
- ds_write_byte(0xcc);
- ds_write_byte(0x44);
- }
- /*----------------------------------------
- 獲得溫度:
- ------------------------------------------*/
- uint get_temperature()
- {
- float wendu;
- uchar a,b;
- ds_reset();
- delay11(1); //約2ms
- ds_write_byte(0xcc);
- ds_write_byte(0xbe);
- a=ds_read_byte();
- b=ds_read_byte();
- temp=b;
- temp<<=8;
- temp=temp|a;
- /*if((b&0x80)==0x80)
- {
- biaozhi=1;//設置溫度正負的標志
- temp=0xffff-temp;
- temp=temp+1;
- }*/
- wendu=temp*0.0625; //得到真實十進制溫度值,因為DS18B20
- //可以精確到0.0625度,所以讀回數據的最低位代表的是0.0625度
- temp=wendu*10.0+0.5; //放大十倍,這樣做的目的將小數點后第一位
- //也轉換為可顯示數字,同時進行一個四舍五入操作。
- return temp;
- }
- void main()
- {
- aa=500;
- bb=50;
- EA=1;
- ET0=1;
- TMOD=0x01;
- TH0=(65536-50000)/256;
- TL0=(65536-50000)%256;
- TR0=1;
- init();
- while(1)
- {
- key();
- if(num==0)
- {
- tem_change(); //開始轉換12位轉換時間最大為750ms
- get_temperature();//000000000000
- }
- display(temp);
- }
- }
- //定時器0中斷子函數
- void t0() interrupt 1
- {
- TH0=(65536-50000)/256;
- TL0=(65536-50000)%256;
- num11++;
- if(num11==20)
- {
- num11=0;
- miao++;
- if(miao==60)
- {
- miao=0;
- fen++;
- if(fen==60)
- {
- fen=0;
- shi++;
- if(shi==24)
- {
- shi=0;
- fen=0;
- miao=0;
- ri++;
- if(ri==29)
- if((year%4!=0)&&(month==2))
- {
- ri=1;
- month++;
- if(month==13)
- {
- month=1;
- year++;
- }
- }
- if(ri==30)
- if((year%4==0)&&(month==2))
- {
- ri=1;
- month++;
- if(month==13)
- {
- month=1;
- year++;
- }
- }
- if(ri==31)
- if((month==4)||(month==6)||(month==9)||(month==11))
- {
- ri=1;
- month++;
- if(month==13)
- {
- month=1;
- year++;
- }
- }
- if(ri==32)
- if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12))
- {
- ri=1;
- month++;
- if(month==13)
- {
- month=1;
- year++;
- }
- }
- }
- }
- }
- }
- }
復制代碼全部資料51hei下載地址:
基于DS18B20的溫度計.zip
(79.31 KB, 下載次數: 132)
2020-7-4 18:47 上傳
點擊文件名下載附件
基于DS18B20的溫度計 下載積分: 黑幣 -5
|