一、環(huán)境介紹
編程軟件: keil5
操作系統(tǒng): win10
MCU型號: STM32F103C8T6
STM32編程方式: 寄存器開發(fā) (方便程序移植到其他單片機)
溫度傳感器: DS1820
DS18B20是一個數(shù)字溫度傳感器,采用的是單總線時序與主機通信,只需要一根線就可以完成溫度數(shù)據(jù)讀??;
DS18B20內(nèi)置了64位產(chǎn)品序列號,方便識別身份,在一根線上可以掛接多個DS18B20傳感器,通過64位身份驗證,可以分別讀取來至不同傳感器采集的溫度信息。
二、DS18B20介紹
2.1 DS18B20 的主要特征
1. 全數(shù)字溫度轉(zhuǎn)換及輸出。
2. 先進的單總線數(shù)據(jù)通信。
3. 最高 12 位分辨率,精度可達土 0.5 攝氏度。
4. 12 位分辨率時的最大工作周期為 750 毫秒。
5. 可選擇寄生工作方式。
6. 檢測溫度范圍為–55° C ~+125° C (–67° F ~+257° F)
7. 內(nèi)置 EEPROM,限溫報警功能。
8. 64位光刻 ROM,內(nèi)置產(chǎn)品序列號,方便多機掛接。
2.2 DS18B20 引腳功能
GND 電壓地
DQ 單數(shù)據(jù)總線
NC 空引腳
2.3 DS18B20 工作原理及應用
DS18B20 的溫度檢測與數(shù)字數(shù)據(jù)輸出全集成于一個芯片之上,從而抗干擾力更強。其一個工作周期可分為兩個部分,即溫度檢測和數(shù)據(jù)處理。
18B20 共有三種形態(tài)的存儲器資源,它們分別是:ROM 只讀存儲器,用于存放 DS18B20ID 編碼,其前 8 位是單線系列編碼(DS18B20 的編碼是19H),后面 48 位是芯片唯一的序列號,最后 8 位是以上 56 的位的 CRC 碼(冗余校驗)。數(shù)據(jù)在出產(chǎn)時設置不由用戶更改,DS18B20 一共有 64 位 ROM。
RAM 數(shù)據(jù)暫存器,用于內(nèi)部計算和數(shù)據(jù)存取,數(shù)據(jù)在掉電后丟失, DS18B20 共 9 個字節(jié) RAM,每個字節(jié)為 8 位。第 1、 2 個字節(jié)是溫度轉(zhuǎn)換后的數(shù)據(jù)值信息,第 3、 4 個字節(jié)是用戶 EEPROM(常用于溫度報警值儲存)的鏡像。在上電復位時其值將被刷新。第 5 個字節(jié)則是用戶第 3 個 EEPROM的鏡像。第 6、 7、 8 個字節(jié)為計數(shù)寄存器,是為了讓用戶得到更高的溫度分辨率而設計的,同樣也是內(nèi)部溫度轉(zhuǎn)換、計算的暫存單元。第 9 個字節(jié)為前 8 個字節(jié)的 CRC 碼。 EEPROM 非易失性記憶體,用于存放長期需要保存的數(shù)據(jù),上下限溫度報警值和校驗數(shù)據(jù),DS18B20 共 3 位 EEPROM,并在 RAM 都存在鏡像,以方便用戶操作。
DS18B20默認工作在12位分辨率模式,轉(zhuǎn)換后得到的12位數(shù)據(jù),存儲在DS18B20的兩個8比特的RAM中(最前面的兩個字節(jié)),二進制中的前面5位是符號位,如果測得的溫度大于0,這5位為0,只要將測到的數(shù)值乘于0.0625即可得到實際溫度;如果溫度小于0,這5位為1,測到的數(shù)值需要取反加1再乘于0.0625即可得到實際溫度?;蛘呤褂梦贿\算方式提取溫度: ?小數(shù)位是占用的是低4位,高位是整數(shù)位(不考慮負數(shù)情況)。
2.4?DS18B20 芯片 ROM 指令表
1.?? ?Read ROM(讀 ROM) [33H] (方括號中的為 16 進制的命令字)
這個命令允許總線控制器讀到 DS18B20 的 64 位 ROM。只有當總線上只存在一個 DS18B20 的時候才可以使用此指令,如果掛接不只一個,當通信時將會發(fā)生數(shù)據(jù)沖突
2.?? ?atch ROM(指定匹配芯片) [55H]
這個指令后面緊跟著由控制器發(fā)出了 64 位序列號,當總線上有多只 DS18B20 時,只有與控制發(fā)出的序列號相同的芯片才可以做出反應,其它芯片將等待下一次復位。這條指令適應單芯片和多芯片掛接。
3.?? ?Skip ROM(跳躍 ROM 指令) [CCH]
這條指令使芯片不對 ROM 編碼做出反應,在單總線的情況之下,為了節(jié)省時間則可以選用此指令。如果在多芯片掛接時使用此指令將會出現(xiàn)數(shù)據(jù)沖突,導致錯誤出現(xiàn)。
4.?? ?Search ROM(搜索芯片) [F0H]
在芯片初始化后,搜索指令允許總線上掛接多芯片時用排除法識別所有器件的 64 位 ROM。
5.?? ?Alarm Search(報警芯片搜索) [ECH]
在多芯片掛接的情況下,報警芯片搜索指令只對附合溫度高于 TH 或小于 TL 報警條件的芯片做出反應。只要芯片不掉電,報警狀態(tài)將被保持,直到再一次測得溫度什達不到報警條件為止。
6.?? ?Write Scratchpad (向 RAM 中寫數(shù)據(jù)) [4EH]
這是向 RAM 中寫入數(shù)據(jù)的指令,隨后寫入的兩個字節(jié)的數(shù)據(jù)將會被存到地址 2(報警 RAM 之 TH)和地址 3(報警 RAM 之 TL)。寫入過程中可以用復位信號中止寫入。
7.?? ?Read Scratchpad (從 RAM 中讀數(shù)據(jù)) [BEH]
此指令將從 RAM 中讀數(shù)據(jù),讀地址從地址 0 開始,一直可以讀到地址 9,完成整個 RAM 數(shù)據(jù)的讀出。芯片允許在讀過程中用復位信號中止讀取,即可以不讀后面不需要的字節(jié)以減少讀取時間。
8.?? ?Copy Scratchpad (將 RAM 數(shù)據(jù)復制到 EEPROM 中) [48H]
此指令將 RAM 中的數(shù)據(jù)存入 EEPROM 中,以使數(shù)據(jù)掉電不丟失。此后由于芯片忙于 EEPROM 儲存處理,當控制器發(fā)一個讀時間隙時,總線上輸出“0”,當儲存工作完成時,總線將輸出“1”。
在寄生工作方式時必須在發(fā)出此指令后立刻超用強上拉并至少保持 10MS,來維持芯片工作。
9.?? ?Convert T(溫度轉(zhuǎn)換) [44H]
收到此指令后芯片將進行一次溫度轉(zhuǎn)換,將轉(zhuǎn)換的溫度值放入 RAM 的第 1、 2 地址。此后由于芯片忙于溫度轉(zhuǎn)換處理,當控制器發(fā)一個讀時間隙時,總線上輸出“0”,當儲存工作完成時,總線將輸出“1”。在寄生工作方式時必須在發(fā)出此指令后立刻超用強上拉并至少保持 500MS,來維持芯片工作。
10.?? ?Recall EEPROM(將 EEPROM 中的報警值復制到 RAM) [B8H]
此指令將 EEPROM 中的報警值復制到 RAM 中的第 3、 4 個字節(jié)里。由于芯片忙于復制處理,當控制器發(fā)一個讀時間隙時,總線上輸出“0”,當儲存工作完成時,總線將輸出“1”。另外,此指令將在芯片上電復位時將被自動執(zhí)行。這樣 RAM 中的兩個報警字節(jié)位將始終為 EEPROM 中數(shù)據(jù)的鏡像。
11.?? ?Read Power Supply(工作方式切換) [B4H]
此指令發(fā)出后發(fā)出讀時間隙,芯片會返回它的電源狀態(tài)字,“0”為寄生電源狀態(tài),“1”為外部電源狀態(tài)。
2.5 DS18B20時序圖
2.5.1 DS18B20 復位及應答關系示意圖
每一次通信之前必須進行復位,復位的時間、等待時間、回應時間應嚴格按時序編程。
DS18B20 讀寫時間隙:DS18B20的數(shù)據(jù)讀寫是通過時間隙處理位和命令字來確認信息交換的。
2.5.2? 向DS18B20寫數(shù)據(jù)0和數(shù)據(jù)1
在寫數(shù)據(jù)時間隙的前 15uS 總線需要是被控制器拉置低電平,而后則將是芯片對總線數(shù)據(jù)的采樣時間,采樣時間在 15~60uS,采樣時間內(nèi)如果控制器將總線拉高則表示寫“1”,如果控制器將總線拉低則表示寫“0”。
每一位的發(fā)送都應該有一個至少 15uS的低電平起始位,隨后的數(shù)據(jù)“0”或“1”應該在 45uS 內(nèi)完成。
整個位的發(fā)送時間應該保持在 60~120uS,否則不能保證通信的正常。
注意: ?DS18B20讀寫數(shù)據(jù)都是從低位開始傳輸。
2.5.3 從DS18B20讀數(shù)據(jù)0和數(shù)據(jù)1
讀時間隙時控制時的采樣時間應該更加的精確才行,讀時間隙時也是必須先由主機產(chǎn)生至少1uS的低電平,表示讀時間的起始。隨后在總線被釋放后的 15uS 中 DS18B20 會發(fā)送內(nèi)部數(shù)據(jù)位,這時控制如果發(fā)現(xiàn)總線為高電平表示讀出“1”,如果總線為低電平則表示讀出數(shù)據(jù)“0”。每一位的讀取之前都由控制器加一個起始信號。
注意:必須在讀間隙開始的 15uS 內(nèi)讀取數(shù)據(jù)位才可以保證通信的正確。
在通信時是以 8 位“0”或“1”為一個字節(jié),字節(jié)的讀或?qū)懯菑牡臀婚_始的。
2.5.4? 讀取一次溫度的順序(總線上只有單個DS18B20情況)
1. 發(fā)送復位信號
2. 檢測回應信號
3. 發(fā)送0xCC
4. 發(fā)送0x44
5. 發(fā)送復位信號
6. 檢測回應信號
7. 寫0xcc
8. 寫0xbe
9. 循環(huán)8次讀取溫度低字節(jié)
10. 循環(huán)8次讀取溫度高字節(jié)
11. 合成16位溫度數(shù)據(jù),處理
三、驅(qū)動代碼
3.1 DS18B20.c
#include "ds18b20.h"
/*
函數(shù)功能: DS18B20初始化
硬件連接: PB15
*/
void DS18B20_Init(void)
{
RCC->APB2ENR|=1<<3; //PB
GPIOB->CRH&=0x0FFFFFFF;
GPIOB->CRH|=0x30000000;
GPIOB->ODR|=1<<15; //上拉
}
/*
函數(shù)功能: 檢測DS18B20設備是否存在
返回值 : 1表示設備不存在 0表示設備正常
*/
u8 DS18B20_CheckDevice(void) //包含了復位脈沖、檢測存在脈沖
{
DS18B20_OUTPUT_MODE();//初始化為輸出模式
DS18B20_OUT=0; //產(chǎn)生復位脈沖
DelayUs(750); //產(chǎn)生750us的低電平
DS18B20_OUT=1; //釋放總線
DelayUs(15); //等待DS18B20回應
if(DS18B20_CleckAck())//檢測存在脈沖
{
return 1;
}
return 0;
}
/*
函數(shù)功能: 檢測DS18B20設備的存在脈沖
返回值 : 1表示錯誤 0表示正常
*/
u8 DS18B20_CleckAck(void)
{
u8 cnt=0;
DS18B20_INPUT_MODE();//初始化為輸入模式
while(DS18B20_IN&&cnt<200) //等待DS18B20響應存在脈沖
{
DelayUs(1);
cnt++;
}
if(cnt>=200)return 1; //錯誤
cnt=0;
while((!DS18B20_IN)&&cnt<240) //等待DS18B20釋放總線
{
DelayUs(1);
cnt++;
}
if(cnt>=240)return 1; //錯誤
return 0;
}
/*
函數(shù)功能: 寫一個字節(jié)
首先學會如何寫一個位。
*/
void DS18B20_WriteByte(u8 cmd)
{
u8 i;
DS18B20_OUTPUT_MODE(); //初始化為輸出模式
for(i=0;i<8;i++)
{
DS18B20_OUT=0; //產(chǎn)生寫時間間隙(寫開始)
DelayUs(2);
DS18B20_OUT=cmd&0x01; //發(fā)送實際的數(shù)據(jù)位
DelayUs(60); //等待寫完成
DS18B20_OUT=1; //釋放總線,準備下一次發(fā)送
cmd>>=1; //繼續(xù)發(fā)送下一位數(shù)據(jù)
}
}
/*
函數(shù)功能: 讀一個字節(jié)
首先學會如何讀一個位。
*/
u8 DS18B20_ReadByte(void)
{
u8 i,data=0;
for(i=0;i<8;i++)
{
DS18B20_OUTPUT_MODE(); //初始化為輸出模式
DS18B20_OUT=0; //產(chǎn)生讀時間間隙(讀開始)
DelayUs(2);
DS18B20_OUT=1; //釋放總線
DS18B20_INPUT_MODE(); //初始化為輸入模式
DelayUs(8); //等待DS18B20的數(shù)據(jù)輸出
data>>=1; //高位補0,默認以0為準
if(DS18B20_IN) data|=0x80;
DelayUs(60);
DS18B20_OUT=1; //釋放總線,等待讀取下一位數(shù)據(jù)
}
return data;
}
/*
函數(shù)功能: 讀取一次DS18B20的溫度數(shù)據(jù)
返 回 值: 讀取的溫度數(shù)據(jù)
考慮的情況: 總線上只是接了一個DS18B20的情況
*/
u16 DS18B20_ReadTemp(void)
{
u16 temp=0;
u8 temp_H,temp_L;
DS18B20_CheckDevice(); //發(fā)送復位脈沖、檢測存在脈沖
DS18B20_WriteByte(0xCC); //跳過ROM序列檢測
DS18B20_WriteByte(0x44); //啟動一次溫度轉(zhuǎn)換
//等待溫度轉(zhuǎn)換完成
while(DS18B20_ReadByte()!=0xFF){}
DS18B20_CheckDevice(); //發(fā)送復位脈沖、檢測存在脈沖
DS18B20_WriteByte(0xCC); //跳過ROM序列檢測
DS18B20_WriteByte(0xBE); //讀取溫度
temp_L=DS18B20_ReadByte(); //讀取的溫度低位數(shù)據(jù)
temp_H=DS18B20_ReadByte(); //讀取的溫度高位數(shù)據(jù)
temp=temp_L|(temp_H<<8); //合成溫度
return temp;
}
3.2 DS18B20.h
#ifndef DS18B20_H
#define DS18B20_H
#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"
#include "ds18b20.h"
#include "usart.h"
/*封裝接口*/
//初始化DS18B20為輸入模式
#define DS18B20_INPUT_MODE() {GPIOB->CRH&=0x0FFFFFFF;GPIOB->CRH|=0x80000000;}
//初始化DS18B20為輸出模式
#define DS18B20_OUTPUT_MODE(){GPIOB->CRH&=0x0FFFFFFF;GPIOB->CRH|=0x30000000;}
//DS18B20 IO口輸出
#define DS18B20_OUT PBout(15)
//DS18B20 IO口輸入
#define DS18B20_IN PBin(15)
//函數(shù)聲明
u8 DS18B20_CleckAck(void);
u8 DS18B20_CheckDevice(void);
void DS18B20_Init(void);
u16 DS18B20_ReadTemp(void);
u8 DS18B20_ReadByte(void);
void DS18B20_WriteByte(u8 cmd);
#endif
3.3 延時函數(shù)
/*
函數(shù)功能: 延時us單位
*/
void DelayUs(int us)
{
#ifdef _SYSTICK_IRQ_
int i,j;
for(i=0;i<us;i++)
for(j=0;j<72;j++);
#else
u32 tmp;
SysTick->VAL=0; //CNT計數(shù)器值
SysTick->LOAD=9*us; //9表示1us
SysTick->CTRL|=1<<0; //開啟定時器
do
{
tmp=SysTick->CTRL; //讀取狀態(tài)
}while((!(tmp&1<<16))&&(tmp&1<<0));
SysTick->VAL=0; //CNT計數(shù)器值
SysTick->CTRL&=~(1<<0); //關閉定時器
#endif
}
3.4 main.c 調(diào)用DS18B20讀取溫度打印到串口
#include "stm32f10x.h"
#include "ds18b20.h"
u8 DS18B20_ROM[8]; //存放DS18B20的64為ROM編碼
int main(void)
{
u16 temp;
USARTx_Init(USART1,72,115200);//串口1的初始化
DS18B20_Init(); //DS18B20初始化
/*1. 讀取DS18B20的64位ROM編碼*/
//發(fā)送復位脈沖、檢測存在脈沖
while(DS18B20_CheckDevice())
{
printf("DS18B20設備不存在!n");
DelayMs(500);
}
//發(fā)送讀取64為ROM編碼的命令
DS18B20_WriteByte(0x33);
//循環(huán)讀取64位ROM編碼
for(i=0;i<8;i++)
{
DS18B20_ROM[i]= DS18B20_ReadByte();
printf("DS18B20_ROM[%d]=0x%Xn",i,DS18B20_ROM[i]);
}
while(1)
{
/*2. 同時操作總線上所有的DS18B20開始轉(zhuǎn)換溫度*/
DS18B20_CheckDevice(); //發(fā)送復位脈沖、檢測存在脈沖
DS18B20_WriteByte(0xCC); //跳過ROM序列檢測
DS18B20_WriteByte(0x44); //啟動一次溫度轉(zhuǎn)換(讓總線上所有的DS18B20都轉(zhuǎn)換溫度)
DelayMs(500); //等待線上所有的DS18B20溫度轉(zhuǎn)換完成
/*3. 單個針對性讀取每個DS18B20的溫度*/
DS18B20_CheckDevice(); //發(fā)送復位脈沖、檢測存在脈沖
DS18B20_WriteByte(0x55); //發(fā)送匹配ROM的命令
for(i=0;i<8;i++) //發(fā)送64位編碼
{
DS18B20_WriteByte(DS18B20_ROM[i]);
}
DS18B20_WriteByte(0xBE); //讀取溫度
temp=DS18B20_ReadByte(); //讀取的溫度低位數(shù)據(jù)
temp|=DS18B20_ReadByte()<<8; //讀取的溫度高位數(shù)據(jù)
printf("temp1=%d.%dn",temp>>4,temp&0xF);
printf("temp2=%fn",temp*0.0625);
DelayMs(500);
}
}
下面公眾號里有全套QT、51單片機、Python、C++、Linux基礎教程,歡迎關注:?