部落客福利:100G+電子設計學習資源包!
http://mp.weixin.qq.com/mp/homepage?__biz=MzU3OTczMzk5Mg==&hid=7&sn=ad5d5d0f15df84f4a92ebf72f88d4ee8&scene=18#wechat_redirect --------------------------------------------------------------------------------------------------------------------------
智能溫度檢測系統是通過硬體電路設計和軟體程式設計驅動的結合方式,實作0℃~99℃範圍内的溫度智能監測。可通過LCD實時顯示實際溫度和預設溫度,當溫度超出預設範圍時及時報警,而且報警聲用電子樂曲或音樂音符實作。
前言
本次設計的主要思路是利用51系列單片機,數字溫度傳感器DS18B20和1602LCD液晶顯示,構成實作溫度檢測與顯示的單片機控制系統,即數字溫度計。通過對單片機編寫相應的程式,達到能夠實時檢測周圍溫度的目的。 通過對本課題的設計能夠熟悉數字溫度計的工作原理及過程,了解各功能器件(單片機、DS18B20、LCD)的基本原理與應用,掌握各部分電路的硬體連線與程式編寫,最終完成對數字溫度計的總體設計。其具體的要求如下: 1、根據設計要求,選用AT89C51單片機為核心器件; 2、溫度檢測器件采用DS18B20數字式溫度傳感器,利用單總線式連接配接方式與單片機的串行接口P3.3引腳相連; 3、顯示電路采用1602LCD液晶顯示溫度值,此類液晶子產品不僅可以顯示數字、字元,還可以顯示各種圖形符号以及少量自定義符号,人機界面友好,使用操作也更加靈活、友善,使其日益成為各種儀器儀表等裝置的首選。
系統的開發過程
本設計主要介紹了用單片機和數字溫度傳感器DS18B20相結合的方法來實作溫度的采集,以單片機AT89C51晶片為核心,溫度傳感器DS18B20和1602LCD液晶顯示,構成了一個多功能單片機數字溫度計。其主要研究内容包括兩方面,一是對系統硬體部分的設計,包括溫度采集電路和顯示電路;二是對系統軟體部分的設計,應用C語言實作溫度的采集與顯示。通過利用數字溫度傳感器DS18B20進行設計,能夠滿足實時檢測溫度的要求,同時通過1602LCD的顯示功能,可以實作不間斷的溫度顯示。其總體設計框圖一如下:
圖一:總體設計框圖
第一節AT89C51簡介
AT89C51是美國ATMEL公司生産的低功耗,高性能CMOS8位單片機,片内含4kbytes的可程式設計的Flash隻讀程式存儲器,相容标準8051指令系統及引腳,并內建了 Flash 程式存儲器,既可線上程式設計(ISP),也可用傳統方法進行程式設計,是以,低價位AT89C51單片機可應用于許多高成本效益的場合,可靈活應用于各種控制領域,對于簡單的測溫系統已經足夠。單片機AT89C51具有低電壓供電和體積小等特點,四個端口隻需要兩個口就能滿足電路系統的設計需要,很适合便攜手持式産品的設計使用系統可用二節電池供電。晶片AT89C51的引腳排列如圖二所示:
圖二:AT89C51單片機引腳圖
第二節晶振電路的設計
單片機晶振電路的設計如圖三所示。XTAL1(X1)為反向振蕩放大器的輸入及内部時鐘工作電路的輸入。按照理論上AT89C51使用的是12MHz的晶振,但實測使用11.0592MHz。是以設計者通常用的是11.0592MHz。
圖三:單片機晶振電路
第三節溫度采集電路的設計
DALLAS 最新單線數字溫度傳感器DS18B20是一種新型的“一線器件”,其體積更小、更适用于多種場合、且适用電壓更寬、更經濟。DALLAS 半導體公司的數字化溫度傳感器DS18B20是世界上第一片支援“一線總線”接口的溫度傳感器。溫度測量範圍為-55~+125 攝氏度,可程式設計為9~12 位轉換精度,測溫分辨率可達0.0625攝氏度,分辨率設定參數以及使用者設定的報警溫度存儲在EEPROM 中,掉電後依然儲存。被測溫度用符号擴充的16位數字量方式串行輸出;其工作電源既可以在遠端引入,也可以采用寄生電源方式産生;多個DS18B20可以并聯到3 根或2 根線上,CPU隻需一根端口線就能與諸多DS18B20 通信,占用微處理器的端口較少,可節省大量的引線和邏輯電路。是以用它來組成一個測溫系統,具有線路簡單,在一根通信線,可以挂很多這樣的數字溫度計,十分友善。本設計的溫度采集電路如圖四所示。
圖四:溫度采集電路圖
第五節溫度顯示電路的設計
顯示器常用作單片機最簡單的輸出裝置,用以顯示單片機的運作結果和運作狀态等。常用的顯示器主要有LED和LCD,它們都具有耗電少、成本低、線路簡單、壽命長等優點,廣泛應用于單片機顯示數字量的場合。設計中采用LCD顯示器。液晶顯示器(LCD)具有功耗低、體積小、品質輕、功耗小的特點。點陣字元型液晶顯示器把LCD控制器、點陣驅動器、字元存儲器內建在一塊印刷電路闆上,構成便于應用的液晶子產品。此類液晶子產品不僅可以顯示數字、字元,還可以顯示各種圖形符号以及少量自定義符号,并且可以實作螢幕的上下左右滾動、文字的閃爍等功能,人機界面友好,使用操作也更加靈活、友善,使其日益成為各種儀器儀表等裝置的首選。圖五為本設計的顯示電路圖。
圖五:顯示電路圖
第六節應用軟體介紹
本設計主要用Proteus仿真軟體和Keil編譯軟體。
本設計主要用Proteus仿真軟體和Keil編譯軟體 4.1.1 Proteus的介紹
Proteus軟體是英國Labcenter electronics公司出版的EDA工具軟體。它不僅具有其它EDA工具軟體的仿真功能,還能仿真單片機及外圍器件,它是目前最好的仿真單片機及外圍器件的工具,雖然目前國内推廣剛起步,但已受到單片機愛好者、從事單片機教學教師、緻力于單片機開發應用的科技工作者的青睐。Proteus是世界上著名的EDA工具(仿真軟體),從原理布圖、代碼調試到單片機與外圍電路協同仿真,一鍵切換發到PCB設計,真正實作了從 概念到産品的完整設計。是目前世界上唯一将電路仿真軟體、PCB設計軟體和虛拟模型仿真軟體三合一的設計平台,其處理器模型支援8051、HC11、PIC10/12/16/18/24/30/DsPIC33、AVR、ARM、8086HE MSP430等,2010年即将增加Cortex和DSP系列處理器,并持續增加其他系列處理器模型。在編譯方面,它也支援IAR、Keil和MPLAB等多種編譯器。
Keil C51是美國Keil Software公司出品的51系列相容單片機C語言軟體開發系統,與彙編相比,C語言在功能上、結構性、可讀性、可維護性上有明顯的優勢,因而易學易用。Keil提供了包括C編譯器、宏彙編、連接配接器、庫管理和一個功能強大的仿真調試器等在内的完整開發方案,通過一個內建開發環境(uVision)将這些部分組合在一起。運作Keil軟體需要WIN98、NT、WIN2000、WINXP等作業系統。如果你使用C語言程式設計,那麼Keil幾乎就是你的不二之選,即使不使用C語言而僅用彙編語言程式設計,其友善易用的內建環境、強大的軟體仿真調試工具也會令你事半功倍。
系統測試情況
進入測試,開關不閉合,系統預設顯示1602LCD顯示目前采集的溫度,當溫度變化時,系統實時采集DS18B20的溫度并顯示出來,當采集的溫度超過系統所設定的上限或者下限的時候,系統自動報警,開關閉合,顯示報警溫度的上限值和下限值。綜合仿真圖如圖六所示:
系統的優點與不足
優點:軟體可以實時檢測溫度值,并顯示,當溫度超出預設範圍時及時報警,并且還可以檢測并顯示零下溫度。
缺點:隻是做到了仿真程式,沒有具體的硬體實作,系統運作時預設溫度不能改動。
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit DQ=P3^3;//DS18B20資料線
sbit BEEP=P3^7;//報警器
sbit LCD_RS=P2^0;
sbit LCD_RW=P2^1;
sbit LCD_EN=P2^2;
sbit K1=P1^7;
uchar code Temp_Disp_Title[]={" Current Temp : "};
uchar Current_Temp_Display_Buffer[]={"TEMP: "};
uchar code Alarm_Temp[]={"ALARM TEMP Hi Lo"};
uchar Alarm_HI_LO_STR[]={"Hi: Lo: "};
uchar code df_Table[]={0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9};//溫度小數位對照表
char Alarm_Temp_HL[2]={100,0};
uchar CurrentT=0;//目前讀取的溫度整數部分
uchar Temp_Value[]={0x00,0x00};//從DS18B20讀取的溫度值
uchar Display_Digit[]={0,0,0,0};//待顯示的各溫度數位
bit HI_Alarm=0,LO_Alarm=0;//高溫低溫報警标志
bit DS18B20_IS_OK=1;//傳感器正常标志
uint Time0_Count=0;//定時器延時累加
//延時
void DelayMS(uint x){
uchar i;
while(x--)for(i=0;i<120;i++);
}
//讀LCD狀态
uchar Read_LCD_State(){
uchar state;
LCD_RS=0;LCD_RW=1;LCD_EN=1;DelayMS(1);state=P0;LCD_EN=0;DelayMS(1);
return state;
}
//忙等待
void LCD_Busy_Wait(){
while((Read_LCD_State()&0x80)==0x80);
DelayMS(5);
}
//寫LCD指令
void Write_LCD_Command(uchar cmd){
LCD_Busy_Wait();
LCD_RS=0;LCD_RW=0;LCD_EN=0;P0=cmd;LCD_EN=1;DelayMS(1);LCD_EN=0;
}
//向LCD寫資料
void Write_LCD_Data(uchar dat){
LCD_Busy_Wait();
LCD_RS=1;LCD_RW=0;LCD_EN=0;P0=dat;LCD_EN=1;DelayMS(1);LCD_EN=0;
}
//延時
void DelayXus(int x){
uchar i;
while(x--)for(i=0;i<200;i++);
}
//延時
void Delay(uint num){
while(--num);
}
//初始化DS18B20
uchar Init_DS18B20(){
uchar status;
DQ=1;Delay(8);
DQ=0;Delay(90);
DQ=1;Delay(8);
status=DQ;
Delay(100);
DQ=1;
return status;//初始化成功傳回0
}
//讀一位元組
uchar ReadOneByte(){
uchar i,dat=0;
DQ=1;_nop_();
for(i=0;i<8;i++){
DQ=0;dat>>=1;DQ=1;_nop_();_nop_();
if(DQ)dat|=0x80;Delay(30);DQ=1;
}
return dat;
}
//寫一個位元組
void WriteOneByte(uchar dat){
uchar i;
for(i=0;i<8;i++){
DQ=0;DQ=dat&0x01;Delay(5);DQ=1;dat>>=1;
}
}
//讀取溫度值
void Read_Temperature(){
if(Init_DS18B20()==1)//DS18B20故障
DS18B20_IS_OK=0;
else{
WriteOneByte(0xcc);//跳過序列号
WriteOneByte(0x44);//啟動溫度轉換
Init_DS18B20();
WriteOneByte(0xcc);//跳過序列号
WriteOneByte(0xbe);//讀取溫度寄存器
Temp_Value[0]=ReadOneByte();//讀取低8位
Temp_Value[1]=ReadOneByte();//溫度高8位
Alarm_Temp_HL[0]=ReadOneByte();//報警TH
Alarm_Temp_HL[1]=ReadOneByte();//報警TL
DS18B20_IS_OK=1;
}
}
//設定DS18B20溫度報警值
void Set_Alarm_Temp_Value(){
Init_DS18B20();
WriteOneByte(0xcc);//跳過序列号
WriteOneByte(0x4e);//将設定的溫度報警值寫入DS18B20
WriteOneByte(Alarm_Temp_HL[0]);//寫TH
WriteOneByte(Alarm_Temp_HL[1]);//寫TL
WriteOneByte(0x7f);//12位精度
Init_DS18B20();
WriteOneByte(0xcc);//跳過序列号
WriteOneByte(0x48);//将設定的溫度報警值寫入DS18B20
}
//設定液晶顯示位置
void Set_LCD_POS(uchar p){
Write_LCD_Command(p|0x80);
}
//在LCD上顯示目前溫度
void Display_Temperature(){
uchar i;
uchar t=150;//延時值
uchar ng=0;//負數标志
char Signed_Current_Temp;//如果為負數則取反加1,并設定負數辨別
if((Temp_Value[1]&0xf8)==0xf8){
Temp_Value[1]=~Temp_Value[1];
Temp_Value[0]=~Temp_Value[0]+1;
if(Temp_Value[0]==0x00)Temp_Value[1]++;
ng=1;//設負數辨別
}
//查表得到溫度小數部分
Display_Digit[0]=df_Table[Temp_Value[0]&0x0f];
//擷取溫度整數部分(無符号)
CurrentT=((Temp_Value[0]&0xf0)>>4)|((Temp_Value[1]&0x07)<<4);
//有符号的目前溫度值,注意此處定義為char,其值可為-128~+127
Signed_Current_Temp=ng?-CurrentT:CurrentT;
//高低溫報警标志設定(與定義為char類型的Alarm_Temp_HL比較,這樣可區分正負比較)
HI_Alarm=Signed_Current_Temp>=Alarm_Temp_HL[0]?1:0;
LO_Alarm=Signed_Current_Temp<=Alarm_Temp_HL[1]?1:0;
//将整數部分分解為三位待顯示數字
Display_Digit[3]=CurrentT/100;
Display_Digit[2]=CurrentT%100/10;
Display_Digit[1]=CurrentT%10;
//重新整理LCD顯示緩沖
Current_Temp_Display_Buffer[11]=Display_Digit[0]+'0';
Current_Temp_Display_Buffer[10]='.';
Current_Temp_Display_Buffer[9]=Display_Digit[1]+'0';
Current_Temp_Display_Buffer[8]=Display_Digit[2]+'0';
Current_Temp_Display_Buffer[7]=Display_Digit[3]+'0';
//高位為0時不顯示
if(Display_Digit[3]==0)Current_Temp_Display_Buffer[7]=' ';
//高位為0且次高位為0時,次高位不顯示
if(Display_Digit[2]==0&&Display_Digit[3]==0)
Current_Temp_Display_Buffer[8]=' ';
//負數符号顯示在恰當位置
if(ng)
{
if(Current_Temp_Display_Buffer[8]==' ')
Current_Temp_Display_Buffer[8]='-';
else if(Current_Temp_Display_Buffer[7]==' ')
Current_Temp_Display_Buffer[7]='-';
else Current_Temp_Display_Buffer[6]='-';
}
//在第一行顯示标題
Set_LCD_POS(0x00);
for(i=0;i<16;i++)Write_LCD_Data(Temp_Disp_Title[i]);
//在第二行顯示目前溫度
Set_LCD_POS(0x40);
for(i=0;i<16;i++)Write_LCD_Data(Current_Temp_Display_Buffer[i]);
//顯示溫度符号
Set_LCD_POS(0x4d);Write_LCD_Data(0x00);
Set_LCD_POS(0x4e);Write_LCD_Data('C');
}
//定時器中斷,控制警報聲音
void T0_INT()interrupt 1{
TH0=-1000/256;
TL0=-1000%256;
BEEP=!BEEP;
if(++Time0_Count==400){
Time0_Count=0;
TR0=0;
}
}
//顯示報警溫度
void Disp_Alarm_Temperature(){
uchar i,ng;
//顯示Alarm_Temp_HL數組中的報警溫度值
//由于Alarm_Temp_HL類型為char,故可以直接進行正負比較
//高溫報警值
ng=0;
if(Alarm_Temp_HL[0]<0)//如果為負數則取反加1
{
Alarm_Temp_HL[0]=~Alarm_Temp_HL[0]+1;
ng=1;
}
//分解高溫各數位到待顯示串中
Alarm_HI_LO_STR[4]=Alarm_Temp_HL[0]/100+'0';
Alarm_HI_LO_STR[5]=Alarm_Temp_HL[0]/10%10+'0';
Alarm_HI_LO_STR[6]=Alarm_Temp_HL[0]%10+'0';
//屏蔽高位不顯示
if(Alarm_HI_LO_STR[4]=='0')Alarm_HI_LO_STR[4]=' ';
if(Alarm_HI_LO_STR[4]==' '&&Alarm_HI_LO_STR[5]=='0')
Alarm_HI_LO_STR[5]=' ';
//"-"符号顯示
if(ng){
if(Alarm_HI_LO_STR[5]==' ')Alarm_HI_LO_STR[5]='-';
else if(Alarm_HI_LO_STR[4]==' ')Alarm_HI_LO_STR[4]='-';
else Alarm_HI_LO_STR[3]='-';
}
//低溫報警值
ng=0;
if(Alarm_Temp_HL[1]<0)//如果為負數則取反加1
{
Alarm_Temp_HL[1]=~Alarm_Temp_HL[1]+1;
ng=1;
}
//分解高溫各數位到待顯示串中
Alarm_HI_LO_STR[12]=Alarm_Temp_HL[1]/100+'0';
Alarm_HI_LO_STR[13]=Alarm_Temp_HL[1]/10%10+'0';
Alarm_HI_LO_STR[14]=Alarm_Temp_HL[1]%10+'0';
//屏蔽高位不顯示
if(Alarm_HI_LO_STR[12]=='0')Alarm_HI_LO_STR[12]=' ';
if(Alarm_HI_LO_STR[12]==' '&&Alarm_HI_LO_STR[13]=='0')
Alarm_HI_LO_STR[13]=' ';
//"-"符号顯示
if(ng){
if(Alarm_HI_LO_STR[13]==' ')Alarm_HI_LO_STR[13]='-';
else if(Alarm_HI_LO_STR[12]==' ')Alarm_HI_LO_STR[12]='-';
else Alarm_HI_LO_STR[11]='-';
}
//顯示高低溫報警溫度值
Set_LCD_POS(0x00);//顯示标題
for(i=0;i<16;i++)Write_LCD_Data(Alarm_Temp[i]);
Set_LCD_POS(0x40);//顯示高低溫
for(i=0;i<16;i++)Write_LCD_Data(Alarm_HI_LO_STR[i]);
}
void LCD_Initialise(){
Write_LCD_Command(0x38);DelayXus(5);
Write_LCD_Command(0x01);DelayXus(5);
Write_LCD_Command(0x06);DelayXus(5);
Write_LCD_Command(0x0c);DelayXus(5);
}
void main(){
LCD_Initialise();
IE=0x82;
TMOD=0x01;
TH0=-1000/256;
TL0=-1000%256;
TR0=0;
K1=1;
Set_Alarm_Temp_Value();
Read_Temperature();
Delay(50000);
Delay(50000);
while(1){
if(K1==0)
{
//顯示報警溫度上下限
Read_Temperature();
Disp_Alarm_Temperature();
DelayXus(100);
}else
{
//正常顯示目前溫度,越界時報警
Read_Temperature();
if(DS18B20_IS_OK){
if(HI_Alarm==1||LO_Alarm==1)TR0=1;
else TR0=0;
Display_Temperature();
}
DelayXus(100);
}
}
}