主要參考學習資料:B站【普中官方】51單片機手把手教學視頻
開發資料下載鏈接:http://www.prechin.cn/gongsixinwen/208.html
單片機套裝:普中STC51單片機開發板A4標準版套餐7
目錄
- DS18B20介紹
- 主要特性
- 內部結構
- 控制時序
- 初始化時序
- 寫時序
- 讀時序
- 硬件設計
- 實驗15 DS18B20溫度傳感器
- DS18B20驅動
- 數碼管驅動
- 主函數
DS18B20介紹
主要特性
DS18B20是達拉斯半導體公司推出的單總線接口的傳感器,與傳統的熱敏電阻測溫元件相比,它是一種新型的體積小、工作范圍寬、與微處理器接口簡單的數字化溫度傳感器,具體特點如下:
①工作電壓范圍為3.0V~5.5V,除了依靠電源管腳供電,也可采用寄生電源方式(DQ數據線管腳供電)。
②采用單線接口方式,與微處理器只需要一根線即可實現數據通信。
③支持多點組網功能,多個DS18B20可以同時并聯在單總線上。
④不需要外圍元器件,所有傳感器和轉換電路都集成在DS18B20中。
⑤工作溫度范圍為-55℃~125℃,在-10℃~85℃的精度為±0.5℃。
⑥分辨率(測量數據的細微程度)設置范圍為912bit,即0.50.0625,分辨率越高,最大轉換時間越慢。DS18B20默認分辨率為12bit,最大轉換時間750ms。
⑦測量結果直接以數字通過DQ串行輸出給CPU,同時可傳輸CRC校驗碼,具有較強的抗干擾能力。
⑧具有負壓特性,GND和VDD反接時DS18B20不會因發熱而燒毀,但不能正常工作。
內部結構
ROM:刻有64位序列號,可以看作是地址序列號,含有8位產品類型標號(28H)、48位DS18B20自身序列號和8位針對前56位的CRC校驗碼。每個DS18B20的序列號都不相同,以便實現單總線的多點組網。
高速緩存存儲器:包括一個高速暫存器RAM和一個EEPROM,后者存放高/低溫觸發器TH、TL和結構寄存器。
高速暫存存儲器:由9個字節組成:
寄存器內容 | 字節地址 |
---|---|
溫度值低位LS Byte | 0 |
溫度值高位MS Byte | 1 |
高溫限值TH | 2 |
低溫限值TL | 3 |
配置寄存器 | 4 |
保留 | 5 |
保留 | 6 |
保留 | 7 |
CRC校驗值 | 8 |
當溫度轉換命令44H發布后,經轉換所得溫度值以二進制補碼形式存放在存儲器MS和LS中,MS的高5位為符號位,若溫度非負,則符號位均為0,將測得的數值乘以分辨率即為實際溫度;溫度為負時,符號位均為1,測得的數值需先取反后加一再乘以分辨率。
配置寄存器:高3位依次為TM、R1、R0,低5位均為1。TM為測試模式位,用于設置DS18B20在工作模式還是測試模式,在出廠時已被設置為1(工作模式),不宜改動。R1和R0用于設置分辨率,默認均為1,如下表所示:
R1 | R0 | 精度 | 最大轉換時間 |
---|---|---|---|
0 | 0 | 9bit | 93.75ms |
0 | 1 | 10bit | 187.5ms |
1 | 0 | 11bit | 375ms |
1 | 1 | 12bit | 750ms |
控制時序
單總線器件需要嚴格的信號時序來保證數據的完整性,DS18B20的時序包括初始化時序、寫時序、讀時序。DS18B20發送命令和數據的字節均是低位在前。
初始化時序
單總線的所有通信均以初始化時序開始。①主機將總線先置高后拉低,保持480960μs。②主機釋放總線,電阻上拉,等待DS18B20在1560μs后響應。③DS18B20拉低總線,保持60~240μs。④主機讀取到低電平后繼續延時,延時時間從釋放總線算起至少480μs。
寫時序
寫時序包括寫0和寫1,所有寫時序的過程至少需要60μs,且兩次獨立的寫時序之間至少需要1μs的恢復時間。寫時序均起始于主機拉低總線,若寫0則延時60μs后拉高總線并繼續延時2μs;若寫1則延時大概2μs后拉高總線并繼續延時60μs。
讀時序
單總線器件僅在主機發出讀時序后才向主機發送數據,所以在主機發出讀取命令之后必須馬上產生讀時序。讀時序的過程也至少需要60μs,兩次獨立的讀時序之間至少需要1μs的恢復時間。讀時序均由主機產生至少1μs的低電平發起,隨后釋放總線,并在其后的15μs之間采集總線狀態,低電平則讀0,高電平則讀1。
DS18B20典型的溫度讀取過程:復位(初始化時序)→發動SKIP ROM命令(0XCC)→發送開始轉換命令(0X44)→延時→復位→發送SKIP ROM命令(0XCC)→發送讀存儲器命令(0XBE)→連續讀出兩個字節的溫度數據→結束。
硬件設計
本實驗板載DS18B20傳感器的數據總線綁定到P3.7IO口管腳。
實驗15 DS18B20溫度傳感器
實現功能:插上DS18B20溫度傳感器,數碼管顯示檢測的溫度值。
DS18B20驅動
按照實驗14中的多文件工程框架,在App>ds18b20中創建:
ds18b20.h
#ifndef _DS18B20_H
#define _DS18B20_H#include "public.h"//定義IO管腳
sbit DS18B20_PORT = P3^7;//聲明主函數需要的源文件函數
u8 ds18b20_init(void);
float ds18b20_read_temperature(void);#endif
ds18b20.c
#include "ds18b20.h"
//通過intrins.h調用延時2μs需要用到的nop函數
#include "intrins.h"//復位函數
void ds18b20_reset(void)
{DS18B20_PORT = 0;delay_10us(75);DS18B20_PORT = 1;delay_10us(2);
}/*
檢測DS18B20函數是否存在
若一直為高電平或低電平則不存在,返回1,否則返回0
*/
u8 ds18b20_check(void)
{//計時器變量u8 time_temp = 0;//檢測低電平while(DS18B20_PORT && time_temp<20){time_temp++;delay_10us(1);}//若等待超時則返回1,否則重置計時器if(time_temp >= 20)return 1;else time_temp = 0;//檢測高電平while((!DS18B20_PORT) && (time_temp<20)){time_temp++;delay_10us(1);}//若等待超時則返回1,否則返回0if(time_temp >= 20)return 1;return 0;
}//初始化同時檢測存在
u8 ds18b20_init(void)
{ds18b20_reset();return ds18b20_check();
}//寫字節函數
void ds18b20_write_byte(u8 dat)
{//8位輸入循環控制變量u8 i = 0;//存儲準備輸入的位的變量u8 temp = 0;//從低到高按位輸入for(i=0;i<8;i++){//和00000001進行與運算提取最低位temp = dat & 0X01;//字節右移將次低位移到最低位dat >>= 1;//根據temp寫1或寫0if(temp){//拉低總線DS18B20_PORT = 0;//延時2μs,nop函數延時1個機器周期,12MHz下即為1μs_nop_();_nop_();//寫入1DS18B20_PORT = 1;//延時60μsdelay_10us(6);}else{//拉低總線寫入0DS18B20_PORT = 0;//延時60μsdelay_10us(6);//釋放總線DS18B20_PORT = 1;//延時2μs_nop_();_nop_();}}
}//讀取一個位
u8 ds18b20_read_bit(void)
{//存儲讀取數據的變量u8 dat = 0;//拉低總線DS18B20_PORT = 0;//延時2μs_nop_();_nop_();//釋放總線后讀取DS18B20_PORT = 1;if(DS18B20_PORT)dat = 1;else dat = 0;delay_10us(5);return dat;
}//讀取一字節
u8 ds18b20_read_byte(void)
{//8位讀取循環控制變量u8 i = 0;//存儲讀取到的每一位的變量u8 temp = 0;//將每一位存儲進字節的變量u8 dat = 0;//從低到高按位讀取for(i=0;i<8;i++){//讀取一位temp = ds18b20_read_bit();//字節右移一位并將新位存儲到最高位dat >>= 1;//或運算防止其他位被擦除dat |= temp << 7;}return dat;
}//溫度讀取函數
float ds18b20_read_temperature(void)
{//存儲高八位數值u8 dath = 0;//存儲低八位數值u8 datl = 0;//存儲完整十六位數值u16 value = 0;//存儲轉換得到的實際溫度float temp = 0;//參照讀時序介紹中的溫度讀取過程ds18b20_reset();ds18b20_check();ds18b20_write_byte(0XCC);ds18b20_write_byte(0X44);ds18b20_reset();ds18b20_check();ds18b20_write_byte(0XCC);ds18b20_write_byte(0XBE);//先讀低八位,后讀高八位datl = ds18b20_read_byte();dath = ds18b20_read_byte();//高八位移到十六位中的高八位再與低八位結合得到完整的十六位數值value = (dath << 8) + datl;//和1111100000000000與運算檢測符號位if((value&&0XF800) == 0XF800){//符號位均為1則取反加一得到正值value = (~value) + 1;//計算實際溫度temp = value * (-0.0625);}else temp = value * 0.0625;return temp;
}
數碼管驅動
數碼管驅動延用實驗14,但為了數碼管顯示更加自定義,可以顯示負號、小數點等符號,段碼值轉換功能將移到函數外部來完成,即參數dat直接傳入段碼值,以下是smg.c修改后的程序:
#include "smg.h"u8 gseg_code[16] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};void seg_display(u8 dat[], u8 pos)
{u8 i = 0;u8 pos_temp = pos - 1;for(i = pos_temp;i < 8;i++){switch(i){case 0: LSC = 1;LSB = 1;LSA = 1;break;case 1: LSC = 1;LSB = 1;LSA = 0;break;case 2: LSC = 1;LSB = 0;LSA = 1;break;case 3: LSC = 1;LSB = 0;LSA = 0;break;case 4: LSC = 0;LSB = 1;LSA = 1;break;case 5: LSC = 0;LSB = 1;LSA = 0;break;case 6: LSC = 0;LSB = 0;LSA = 1;break;case 7: LSC = 0;LSB = 0;LSA = 0;break;}//此處刪去gesg_code[]SEG_A_DP_PORT = dat[i-pos_temp];delay_10us(100);SEG_A_DP_PORT = 0x00;}
}
主函數
#include "public.h"
#include "smg.h"
#include "ds18b20.h"void main()
{//讀取溫度間隔的延時控制變量u8 i = 0;//本實驗對溫度保留一位小數處理,方法為先乘十后提取整數部分,在數碼管上添加小數點顯示int temp_value = 0;//存儲每一位供數碼管顯示的段碼值,溫度測量結果最高占用5位數碼管u8 temp_buf[5];//初始化ds18b20_init();while(1){//計時器累加i++;//計時器延時50ms后讀取,可自行調整if(i%50 == 0)temp_value = ds18b20_read_temperature() * 10;//判斷溫度正負if(temp_value < 0){//若溫度為負,將溫度轉為正以便拆解數位,并使第一個數碼管顯示負號temp_value = -temp_value;temp_buf[0] = 0X40;}else//若溫度為正,第一個數碼管不顯示temp_buf[0] = 0X00;//將溫度拆解數位并轉換為段碼值依次存儲temp_buf[1] = gseg_code[temp_value / 1000];temp_buf[2] = gseg_code[temp_value % 1000 / 100];temp_buf[3] = gseg_code[temp_value % 100 / 10] | 0X80;temp_buf[4] = gseg_code[temp_value % 10];//將溫度顯示在數碼管后5位上seg_display(temp_buf, 4);}
}