DS18B20 是由 DALLAS 半導體公司推出的一種的“一線總線”接口的溫度傳感器。與傳
統的熱敏電阻等測溫元件相比,它是一種新型的體積小、適用電壓寬、與微處理器接口簡單的
數字化溫度傳感器。一線總線結構具有簡潔且經濟的特點,可使用戶輕松地組建傳感器網絡,
從而為測量系統的構建引入全新概念,測量溫度范圍為-55~+125℃ ,精度為±0.5℃。現場溫
度直接以“一線總線”的數字方式傳輸,大大提高了系統的抗干擾性。它能直接讀出被測溫度,
並且可根據實際要求通過簡單的編程實現 9~l2 位的數字值讀數方式。它工作在 3—5. 5 V 的電
壓范圍,采用多種封裝形式,從而使系統設計靈活、方便,設定分辨率及用戶設定的報警溫度
存儲在 EEPROM 中,掉電后依然保存
其內部結構如下所示

DS18B20的通訊方式是單總線的,一般而言,我們遇到的封裝都是如下

其中DQ就是主要的通訊線路,對DS的讀取和寫入都需要主機來控制DQ線路的DQ高低電平的時間來確定,具體如下
一般而言,DQ線需要接一個上拉電阻,所以,才寫操作的最后一步都需要將總線拉高

向DS寫0需要總線拉低至少60US最多120US就算完成,也就是說,1-->0(持續60-120us)-->1 寫入了0
像DS寫入1需要總線拉低最少1us最多15US,然后總線拉高,拉高時間至少15us,一般40us以上即可 1->0(1-15us,推薦5us)-->1(持續15us以上,推薦40us)
由此可見,DS的總線采樣實在總線拉低之后的15us開始的

讀取DS分別為讀取1和讀取0,但是這兩者時序是統一的
首先總線拉低至少1us,最多15us,還是選擇2us,然后釋放總線(也就是說進入輸入模式),等待15us以上的事件,然后采樣,高電平為1低電平為0
1-->0(持續2us,最多15us)-->等待15us以上60us以下-->采樣總線電平,得到1或者0,記得采樣完成之后切換到輸出模式將總線拉高便於下一次使用
DS18B20的命令
DS1820有三個主要數字部件:1)64位激光ROM,2)溫度傳感器,3)非易失性溫度報警觸發器TH和TL



啟動溫度轉換的命令是0X44,讀取命令是0XBE
所以一般而言,對於DS的驅動包含以下幾步
復位-->發 SKIP ROM 命令(0XCC)-->發開始轉換命令(0X44)-->延時-->復
位-->發送 SKIP ROM 命令(0XCC)-->發讀存儲器命令(0XBE)-->連續讀出兩個字節數據(即
溫度)-->結束
我們在讀取的時候只讀取兩個字節的原因在於DS的存儲器布局

前兩個就是我們需要的溫度,當然也可以讀取全部的,擴展驅動達到其他目的
以下是驅動代碼,STM32驅動代碼中使用了位段操作
#ifndef __Ds18b20H
#define __Ds18b20H
#include "ioremap.h"
#include "delay.h"
#include "uart.h"
//IO方向設置
#define Ds18b20IO_IN() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;}
#define Ds18b20IO_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;}
////IO操作函數
#define Ds18b20DQ_OUT PGout(11) //數據端口 PG11
#define Ds18b20DQ_IN PGin(11) //數據端口 PG11
u8 Ds18b20Init(void); //初始化DS18B20
short Ds18b20GetTemp(void); //獲取溫度
void Ds18b20Start(void); //開始溫度轉換
void Ds18b20WriteByte(u8 dat);//寫入一個字節
u8 Ds18b20ReadByte(void); //讀出一個字節
u8 Ds18b20ReadBit(void); //讀出一個位
u8 Ds18b20Check(void); //檢測是否存在DS18B20
void Ds18b20Rst(void); //復位DS18B20
void Ds18b20Show(void);
#endif
#include "ds18b20.h"
//復位DS18B20
void Ds18b20Rst(void)
{
Ds18b20IO_OUT(); //SET PA0 OUTPUT
Ds18b20DQ_OUT=0; //拉低DQ
DelayUs(750); //拉低750us
Ds18b20DQ_OUT=1; //DQ=1
DelayUs(15); //15US
}
//等待DS18B20的回應
//返回1:未檢測到DS18B20的存在
//返回0:存在
u8 Ds18b20Check(void)
{
u8 retry=0;
Ds18b20IO_IN();//SET PA0 INPUT
while (Ds18b20DQ_IN&&retry<200)
{
retry++;
DelayUs(1);
};
if(retry>=200)return 1;
else retry=0;
while (!Ds18b20DQ_IN&&retry<240)
{
retry++;
DelayUs(1);
};
if(retry>=240)return 1;
return 0;
}
//從DS18B20讀取一個位
//返回值:1/0
u8 Ds18b20ReadBit(void) // read one bit
{
u8 data;
Ds18b20IO_OUT();//SET PA0 OUTPUT
Ds18b20DQ_OUT=0;
DelayUs(2);
Ds18b20DQ_OUT=1;
Ds18b20IO_IN();//SET PA0 INPUT
DelayUs(12);
if(Ds18b20DQ_IN)data=1;
else data=0;
DelayUs(50);
return data;
}
//從DS18B20讀取一個字節
//返回值:讀到的數據
u8 Ds18b20ReadByte(void) // read one byte
{
u8 i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=Ds18b20ReadBit();
dat=(j<<7)|(dat>>1);
}
return dat;
}
//寫一個字節到DS18B20
//dat:要寫入的字節
void Ds18b20WriteByte(u8 dat)
{
u8 j;
u8 testb;
Ds18b20IO_OUT();//SET PA0 OUTPUT;
for (j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if (testb)
{
Ds18b20DQ_OUT=0;// Write 1
DelayUs(2);
Ds18b20DQ_OUT=1;
DelayUs(60);
}
else
{
Ds18b20DQ_OUT=0;// Write 0
DelayUs(60);
Ds18b20DQ_OUT=1;
DelayUs(2);
}
}
}
//開始溫度轉換
void Ds18b20Start(void)// ds1820 start convert
{
Ds18b20Rst();
Ds18b20Check();
Ds18b20WriteByte(0xcc);// skip rom
Ds18b20WriteByte(0x44);// convert
}
//初始化DS18B20的IO口 DQ 同時檢測DS的存在
//返回1:不存在
//返回0:存在
u8 Ds18b20Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE); //使能PORTG口時鍾
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; //PORTG.11 推挽輸出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOG, &GPIO_InitStructure);
GPIO_SetBits(GPIOG,GPIO_Pin_11); //輸出1
Ds18b20Rst();
return Ds18b20Check();
}
//從ds18b20得到溫度值
//精度:0.1C
//返回值:溫度值 (-550~1250)
short Ds18b20GetTemp(void)
{
u8 temp;
u8 TL,TH;
short tem;
Ds18b20Start (); // ds1820 start convert
Ds18b20Rst();
Ds18b20Check();
Ds18b20WriteByte(0xcc);// skip rom
Ds18b20WriteByte(0xbe);// convert
TL=Ds18b20ReadByte(); // LSB
TH=Ds18b20ReadByte(); // MSB
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0;//溫度為負
}else temp=1;//溫度為正
tem=TH; //獲得高八位
tem<<=8;
tem+=TL;//獲得底八位
tem=(short)((float)tem*0.625);//轉換
if(temp)return tem; //返回溫度值
else return -tem;
}
void Ds18b20Show(void)
{
short t = 0;
t = Ds18b20GetTemp();
printf("ds18b20 temp is %d\r\n",t);
}
