需要先編寫OneWire模塊,再在DS18B20模塊中調用OneWire模塊的函數
先根據原理圖做好端口的聲明:
sbit OneWire_DQ = P3^7;
接下來像之前一樣把時序結構用代碼模擬出來:
unsigned char OneWire_Init(void)
{
unsigned char i;
unsigned char AckBit;
OneWire_DQ = 1;
OneWire_DQ = 0; //總線拉低
//延時500us
i = 227; while (--i);
OneWire_DQ = 1; //釋放總線
//延時70us
i = 29; while (--i);
AckBit = OneWire_DQ;
//延時500us
i = 227; while (--i);
return AckBit;
}
void OneWire_SendBit(unsigned char Bit)
{
unsigned char i;
OneWire_DQ = 0; //總線拉低
//延時10us后直接讀電平
i = 4; while(--i);
OneWire_DQ = Bit;
//延時50us湊滿時間片
i = 22; while(--i);
OneWire_DQ = 1;
}
unsigned char OneWire_ReceiveBit(void)
{
unsigned char i;
unsigned char Bit;
OneWire_DQ = 0;
//延時5us
i = 2; while(--i);
OneWire_DQ = 1;
//延時5us
i = 2; while(--i);
Bit = OneWire_DQ;
//延時50us
i = 22; while(--i);
return Bit;
}
void OneWire_SendByte(unsigned char Byte)
{
unsigned char i;
for(i = 0; i < 8; i ++) {
OneWire_SendBit(Byte & (0x01<<i));
}
}
unsigned char OneWire_ReceiveByte(void)
{
unsigned char i;
unsigned char Byte = 0x00;
for(i = 0; i < 8; i ++) {
if(OneWire_ReceiveBit()) {Byte |= (0x01<<i);}
}
return Byte;
}
至此,OneWire模塊就寫好了,接下來在DS18B20模塊中模擬數據幀:
#include <REGX52.H>
#include "OneWire.h"
#define DS18B20_SKIP_ROM 0xCC
#define DS18B20_CONVERT_T 0x44
#define DS18B20_READ_SCRATCHPAD 0xBE
void DS18B20_ConvertT(void)
{
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_CONVERT_T);
}
float DS18B20_ReadT(void)
{
unsigned char TLSB, TMSB;
int temp;
float T;
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
TLSB = OneWire_ReceiveByte();
TMSB = OneWire_ReceiveByte();
temp = (TMSB<<8) | TLSB;
T = temp / 16.0;
return T;
}
之后只需要在main中調用即可
#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
float T;
void main()
{
LCD_Init();
LCD_ShowString(1, 1, "Temperature!");
while(1)
{
DS18B20_ConvertT();
T = DS18B20_ReadT();
if(T < 0)
{
LCD_ShowChar(2, 1, '-');
T = -T;
}
else
{
LCD_ShowChar(2, 1, '+');
}
LCD_ShowNum(2, 2, T, 3);//整數部分
LCD_ShowChar(2, 5, '.');
LCD_ShowNum(2, 6, (unsigned long)(T *10000) % 10000, 4); //小數部分
}
}
接下來進行一些綜合的應用:溫度報警器,按鍵可調整報警溫度的上下限,且能用AT24C02記錄上下限,掉電不丟失(這里默認所有溫度不會超過DS18B20的芯片范圍)
#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"
#include "AT24C02.h"
#include "Key.h"
#include "Timer0.h"
float T, TShow;
char THigh, TLow;
unsigned char KeyNum;
void main()
{
THigh = AT24C02_ReadByte(0);
TLow = AT24C02_ReadByte(1);
//第一次讀可能是非法值,所以要特判一下
if(THigh > 125 || TLow < - 55 || THigh <= TLow)
{
THigh = 20;
TLow = 15;
}
Timer0_Init();
LCD_Init();
LCD_ShowString(1, 1, "T:");
LCD_ShowString(2, 1, "TH:");
LCD_ShowString(2, 9, "TL:");
LCD_ShowSignedNum(2, 4, THigh, 3);
LCD_ShowSignedNum(2, 12, TLow, 3);
while(1)
{
KeyNum = Key();
/*溫度讀取及顯示*/
DS18B20_ConvertT();
T = DS18B20_ReadT();
if(T < 0)
{
LCD_ShowChar(1, 3, '-');
TShow = -T;
}
else
{
LCD_ShowChar(1, 3, '+');
TShow = T;
}
LCD_ShowNum(1, 4, TShow, 3);
LCD_ShowChar(1, 7, '.');
LCD_ShowNum(1, 8, (unsigned long)(TShow * 100)%100, 2);
/*閾值判斷及顯示*/
if(KeyNum)
{
if(KeyNum == 1) THigh ++;
if(KeyNum == 2) THigh --;
if(KeyNum == 3) TLow ++;
if(KeyNum == 4) TLow --;
LCD_ShowSignedNum(2, 4, THigh, 3);
LCD_ShowSignedNum(2, 12, TLow, 3);
AT24C02_WriteByte(0, THigh);
Delay(5);
AT24C02_WriteByte(1, TLow);
Delay(5);
}
if(T > THigh) LCD_ShowString(1, 13, "OV:H");
else if(T < TLow) LCD_ShowString(1, 13, "OV:L");
else LCD_ShowString(1, 13, " ");
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x66; //設置定時初值
TH0 = 0xFC; //設置定時初值
T0Count ++;
if(T0Count >= 20) //20ms執(zhí)行一次
{
T0Count = 0;
Key_Loop();
}
}
這還沒完,在與定時器的結合中,定時器的中斷會影響OneWire的延時,從而影響其中的時序結構進而影響溫度實時獲取,所以在時序結構編寫的代碼中需要加上屏蔽定時器中斷的代碼:開始時加上EA = 0,最后加上EA = 1,改版后的OneWire模塊如下:文章來源:http://www.zghlxwxcb.cn/news/detail-632577.html
#include <REGX52.H>
sbit OneWire_DQ = P3^7;
unsigned char OneWire_Init(void)
{
unsigned char i;
unsigned char AckBit;
EA = 0; //屏蔽中斷
OneWire_DQ = 1;
OneWire_DQ = 0; //總線拉低
//延時500us
i = 227; while (--i);
OneWire_DQ = 1; //釋放總線
//延時70us
i = 29; while (--i);
AckBit = OneWire_DQ;
//延時500us
i = 227; while (--i);
EA = 1;
return AckBit;
}
void OneWire_SendBit(unsigned char Bit)
{
unsigned char i;
EA = 0; //屏蔽中斷
OneWire_DQ = 0; //總線拉低
//延時10us后直接讀電平
i = 4; while(--i);
OneWire_DQ = Bit;
//延時50us湊滿時間片
i = 22; while(--i);
OneWire_DQ = 1;
EA = 1;
}
unsigned char OneWire_ReceiveBit(void)
{
unsigned char i;
unsigned char Bit;
EA = 0; //屏蔽中斷
OneWire_DQ = 0;
//延時5us
i = 2; while(--i);
OneWire_DQ = 1;
//延時5us
i = 2; while(--i);
Bit = OneWire_DQ;
//延時50us
i = 22; while(--i);
EA = 1;
return Bit;
}
void OneWire_SendByte(unsigned char Byte)
{
unsigned char i;
for(i = 0; i < 8; i ++) {
OneWire_SendBit(Byte & (0x01<<i));
}
}
unsigned char OneWire_ReceiveByte(void)
{
unsigned char i;
unsigned char Byte = 0x00;
for(i = 0; i < 8; i ++) {
if(OneWire_ReceiveBit()) {Byte |= (0x01<<i);}
}
return Byte;
}
但是這樣雖然能維護好單總線的通信,但這樣直接屏蔽中斷卻會影響定時器的計時準確度,從而對定時器控制的其他模塊造成影響,這也就是單總線的一大缺點,不過在這個實例中,按鍵的定時器準度要求并不高,所以這樣控制影響不大文章來源地址http://www.zghlxwxcb.cn/news/detail-632577.html
到了這里,關于51單片機學習--DS18B20溫度讀取&溫度報警器的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!