【制作】基於金沙灘51單片機的單點測溫程序


基於金沙灘51單片機的單點測溫程序

之前學51單片機的時候做了一個單點測溫程序,現在分享一下。
用的是金沙灘的51單片機開發板,這個很好,推薦一下。

零、完成功能

本項目完成以下功能:

  1. 單點溫度測量
  2. 測溫范圍 10℃-40℃
  3. 分辨率 1℃
  4. 兩位溫度顯示
  5. 超出上下限(18℃-25℃)蜂鳴器響起警報

壹、硬件電路圖

貳、軟件代碼

代碼的注釋很詳細,程序很簡單,就不一一介紹了。

#include <reg52.h>
#include <intrins.h>
#define T_MAX 25 // 最大溫度限定值
#define T_MIN 18 // 最小溫度限定值

sbit BUZZ = P1^6;
//_nop_()函數所在頭文件


/*----------------音樂函數申明------------------------------*/
void InitBuzz();
bit isBuzz = 0; //蜂鳴器是否在響


/*----------------溫度傳感器申明----------------------------*/
bit Start18B20();			//初始化DS18B20
bit Get18B20Temp(int *temp);//讀取溫度
bit isGetTemp = 0;		   //是否在獲取溫度


/*----------------LCD1602顯示模塊申明------------------------*/
void InitLcd1602();			//LCD1602初始化函數
void display();			//顯示控制模塊

/*-------------------LCD1602顯示緩存-------------------------*/
//LCD1602函數調用申明
void LcdShowStr(unsigned char x, unsigned char y,unsigned char *str, unsigned char len);
unsigned char strbuff[4];//格式:“25°C”
unsigned char code waringStrHot[] = "      Hot!      ";//報警顯示文字
unsigned char code waringStrCol[] = "      Cold!     ";//報警顯示文字
unsigned char code striswaring[] = "            ";//取消報警顯示文字


/*----------------------其他全局變量-------------------------*/
int Temp = 0;		//讀取到的當前溫度值(16bit二進制)
int intT;			//溫度值的整數和小數部分
bit iswaring = 0;	//是否報警標志位


void main()
{
//	int n = 0;
//	char s[1];
	bit isReay = 0;
	bit sta;				//是否成功讀取標志
	unsigned int cnt = 0;	//檢測標志,主要用於控制檢測溫度的頻率
	
	InitBuzz();					//蜂鳴器初始化
	Start18B20();			//啟動DS18B20
    InitLcd1602();      	//初始化LCD1602液晶模塊
	
	while(1)
	{
		if(isReay == 0)
		{
			cnt++;
		}

		if((cnt>28000&&isBuzz == 0)||(cnt>14000&&isBuzz == 1)) 				//大約0.8s(仿真得到) DS18B20最多750ms轉化好
		{
			cnt = 0;
			isReay = 1;
		}
		  
		if(isReay == 1 && isBuzz == 0)
		{
//			n++;
//			s[0] = n+'0';
//			LcdShowStr(0, 0,s, 1);
			isGetTemp = 1;
			sta = Get18B20Temp(&Temp);	//讀取當前溫度
			isGetTemp = 0;
			if (sta)					//讀取成功時,刷新當前溫度顯示
			{
				intT = Temp >> 4;		//分離出溫度值整數部分
			}
			Start18B20();					//重新啟動下一次轉換
	
			if(intT > T_MAX || intT < T_MIN)
			{
				iswaring = 1;
			}else{
				iswaring = 0;
			}

			isReay = 0;
		}

		display();//顯示
	}
}

/*-----------------------以下是LCD1602顯示驅動------------------*/
//定義LCD1602顯示相關的IO接口
#define LCD1602_DB  P0
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_E  = P1^5;


//顯示控制模塊
void display()
{
	static int intTb;	//溫度值的整數部分備份
	static bit isBuzzb;

	if(isBuzzb != isBuzz)
	{
		if(isBuzz == 0 && iswaring == 1)
		{
			if(intT > T_MAX)
			{
				LcdShowStr(0,1,waringStrHot,16);
			}else{
				LcdShowStr(0,1,waringStrCol,16);
			}
			
		}else{
			LcdShowStr(0,1,striswaring,11);
		}
		isBuzzb = isBuzz;
	}

	if(intTb != intT)//如果有變化
	{
		/*備份當前值*/
		intTb = intT;
		
		if((intT/10) == 0)strbuff[0] = ' ';else strbuff[0] = ((intT/10)%10)+0x30;//十位
		strbuff[1] = ((intT/1)%10)+0x30;//個位

		LcdShowStr(6,0,strbuff,4);	//顯示,初始位置隨意,只要能顯示完整就好
	}
}

//等待液晶准備好
void LcdWaitReady()
{
    unsigned char sta;
     
    LCD1602_DB = 0xFF;
    LCD1602_RS = 0;
    LCD1602_RW = 1;
    do {
        LCD1602_E = 1;      //使能LCD1602
        sta = LCD1602_DB;   //讀取狀態字
        LCD1602_E = 0;      //避免干擾其他器件
    } while (sta & 0x80);   //第七位等於1表示液晶正忙,重復檢測直到第七位等於0為止
}
//向LCD1602液晶寫入一字節命令,cmd為待寫入命令值
void LcdWriteCmd(unsigned char cmd)
{
    LcdWaitReady();
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DB = cmd;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
//向LCD1602液晶寫入一字節數據,dat為待寫入數據值
void LcdWriteDat(unsigned char dat)
{
    LcdWaitReady();
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DB = dat;
    LCD1602_E  = 1;
    LCD1602_E  = 0;
}
//設置顯示RAM起始地址,亦即光標位置,(x,y)對應屏幕上的字符的坐標
void LcdSetCursor(unsigned char x, unsigned char y)
{
    unsigned char addr;
     
    if (y == 0)  			//由輸入的屏幕坐標計算顯示RAM的地址
        addr = 0x00 + x;	//第一行字符地址從0x00起始
    else
        addr = 0x40 + x;	//第二行字符地址從0x40起始
    LcdWriteCmd(addr | 0x80);	//設置RAM地址
}
//在液晶上顯示字符串,(x,y)-對應屏幕上的起始坐標,
//str-字符串指針,len-需顯示的字符長度
void LcdShowStr(unsigned char x, unsigned char y,unsigned char *str, unsigned char len)
{
    LcdSetCursor(x, y);   //設置起始地址
    while (len--)         //連續寫入len個字符數據
    {
        LcdWriteDat(*str++);  //先取str指向的數據,然后str自加1
    }
}

void InitLcd1602()//初始化1602液晶
{
	strbuff[2] = 0XDF;
	strbuff[3] = 'C';

    LcdWriteCmd(0x38);  //16*2顯示,5*7點陣,8位數據接口
    LcdWriteCmd(0x0C);  //顯示器開,光標關閉
    LcdWriteCmd(0x06);  //文字不動,地址自動+1
    LcdWriteCmd(0x01);  //清屏
}


/*-----------------------以下是溫度傳感器驅動------------------*/
//DS18B20通信引腳
sbit IO_18B20 = P3^2;
void DelayX10us(unsigned char t)
{
    do {
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
    } while (--t);
    /*_nop_()函數在12M晶振中延遲1us,為什么這里是8個_nop_()
	因為while和--t也是需要時間的,這里不一定是准確的10us/循環
	只是大致的時間*/
}
bit Get18B20Ack() //DS18B20存在檢測函數 
{
	bit ack;

	EA = 0;				//關中斷 
	IO_18B20 = 0;		//拉低引腳 
	DelayX10us(50);		//延時500us(480us - 960us) 
	IO_18B20 = 1;		//釋放總線 
	DelayX10us(6);		//延時60us(15us - 60us) 
	ack = IO_18B20;		//讀取響應(60us - 240us) 
	while(!IO_18B20);	//等待DS18B20釋放總線 (60us - 240us) 
	EA = 1;				//取消關中斷 

	return ack;			//返回是否存在 (0:存在 1:不存在) 
}

void  Write18B20(unsigned char dat) //寫DS18B20 
{
	unsigned char mask;			//臨時變量定義 
	EA = 0;						//關中斷 
	for(mask=0x01; mask!= 0; mask<<=1)	//循環發送單個bit位 
	{
		IO_18B20 = 0;			//拉低(請求讀寫操作) 
		_nop_();				//延時(1us < time <= 15us) 
		_nop_();
		if((mask&dat) == 0)		//按位讀取dat 
			IO_18B20 = 0;		//本位是0,拉低 
		else
			IO_18B20 = 1;		//本位是1,拉高 
			//上面這個操作DS18B20讀取(最小時間 0us<time<15us,
			//典型時間 15us,最大時間45us) 
		DelayX10us(6);			//等待60us(足夠DS18B20讀取) 
		IO_18B20 = 1;			//釋放總線 
	}
	EA = 1;						//取消關中斷 
}

unsigned char Read18B20()		//讀DS18B20 
{
	unsigned char dat;			//數據緩存變量 
	unsigned char mask;			//臨時變量 

	EA = 0;						//關中斷 
	for(mask=0x01; mask!=0; mask<<=1)//同上循環按位操作 
	{
		IO_18B20 = 0;			//讀寫請求 
		_nop_();				//等待(1us < time < 15us) 
		_nop_();
		IO_18B20 = 1;			//初始化讀操作 
		_nop_();				//等待DS18B20輸出 
		_nop_();
		if(!IO_18B20)			//讀 
			dat &= ~mask;		//“0” 
		else
			dat |= mask;		//“1” 
		DelayX10us(6);			//等待DS18B20釋放總線 
	}
	EA = 1;						//取消關中斷 

	return dat;					//返回數據 
}

bit Start18B20()		//初始化DS18B20 
{
	bit ack;			//存在標志 

	ack = Get18B20Ack();//檢測存在 
	if(ack == 0)		//存在 
	{					//寫命令使工作
		Write18B20(0xCC); 	//跳過ROM檢測 
		Write18B20(0x44);	//啟動溫度轉換 
	}
	return ~ack;		//返回是否成功(1是,0否) 
}

bit Get18B20Temp(int *temp)	//獲取DS18B20溫度存於temp 
{
	bit ack;				//存在標志 
	unsigned char LSB, MSB;	//數據低/高位 

	ack = Get18B20Ack();	//檢測存在 
	if(ack == 0)			//存在 
	{						//寫指令 
		Write18B20(0xCC);	//跳過ROM檢測 
		Write18B20(0xBE);	//讀寄存器 
		LSB = Read18B20();	//讀低位 
		MSB = Read18B20();	//讀高位 
		*temp = ((int)MSB<<8) + LSB;	//合並 
	}
	return ~ack;			//返回結果(1成功,0失敗) 
}

//下面是蜂鳴器
void InterruptTimer0() interrupt 1
{
	static unsigned int timer;
	TH0 = 0x00;
	TL0 = 0x00;
	timer++;
	if(iswaring)
	{
		if(timer>3000)
		{
			isBuzz = 1;

			if(timer%5==1)
			{
				BUZZ = ~BUZZ;
			}

			if(timer>6000)
			{
				timer = 0;	
			}
		}else{
			isBuzz = 0;
		}
	}else{
		isBuzz = 0;
	}
}

void InitBuzz()
{
	TMOD = 0x02;
	TR0 = 1;
	ET0 = 1;	
}

叄、運行效果

視頻演示:https://www.bilibili.com/video/BV1Fy4y1y7BP/

成功完成以上功能,哈哈~
喜歡的小伙伴支持一下吧


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM