基於金沙灘51單片機的單點測溫程序
之前學51單片機的時候做了一個單點測溫程序,現在分享一下。
用的是金沙灘的51單片機開發板,這個很好,推薦一下。
零、完成功能
本項目完成以下功能:
- 單點溫度測量
- 測溫范圍 10℃-40℃
- 分辨率 1℃
- 兩位溫度顯示
- 超出上下限(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/

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