1. 程式人生 > >(微控制器原理與應用)智慧溫度監測系統(設計)

(微控制器原理與應用)智慧溫度監測系統(設計)

中文摘要

智慧溫度檢測系統是通過硬體電路設計和軟體程式設計驅動的結合方式,實現0℃~99℃範圍內的溫度智慧監測。可通過LCD實時顯示實際溫度和預設溫度,當溫度超出預設範圍時及時報警,而且報警聲用電子樂曲或音樂音符實現。

關鍵字

溫度檢測、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的溫度並顯示出來,當採集的溫度超過系統所設定的上限或者下限的時候,系統自動報警,開關閉合,顯示報警溫度的上限值和下限值。綜合模擬圖如圖六所示:


系統的優點與不足

優點:軟體可以實時檢測溫度值,並顯示,當溫度超出預設範圍時及時報警,並且還可以檢測並顯示零下溫度。

缺點:只是做到了模擬程式,沒有具體的硬體實現,系統執行時預設溫度不能改動。

參考文獻

1.《微控制器C語言程式設計實訓100例—基於8051+Proteus模擬》彭偉編著

附錄程式碼

#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);
		}
	}
}