11.1 實驗簡介
11.1.1 溫度采集方案概述
本實驗采用三種方式來獲取溫濕度值,一種是STM32芯片內部自帶的溫度傳感器,一種是基于單總線協議的DS18B20溫度傳感器,還有一種就是溫濕度傳感器DHT11或者DHT22,但是在成本上DHT22比較高,所以實驗僅使用DHT11,DS18B20和內部溫度傳感器進行。
11.1.2 單線協議
單總線協議是美國的達拉斯公司推出的一款總線通信協議,所謂單線協議,就是通過一根線傳輸所有的數據,通俗地講就是根據低電平的時間來判斷總線上的數據是0還是1,比如拉低總線10us,就認為發送的是1,拉低總線50us,就認為發送的是0,單總線協議中,有3種時序,即寫時序,讀時序和檢測時序。我們在51單片機開發中已經嘗試用51單片機通過單總線協議讀取DS18B20的溫度值,故這里不再詳細描述協議的具體內容。
11.2 傳感器介紹
11.2.1 內部溫度傳感器
STM32F103有一個內部溫度傳感器,可以用于測量CPU以及周圍的溫度,這個溫度傳感器在內部和ADC模塊的通道16相連,這個通道用于將傳感器輸出的電壓值轉換為數字編碼,根據手冊得到推薦的采樣時間是17.1us,STM32內部溫度傳感器支持的溫度范圍為-40~+125℃,精度在±1.5℃左右。
根據手冊提供的電壓與溫度轉換公式如下所示。
其中V25代表傳感器在25℃時候的數值,典型值為1.43
K代表溫度與Vsense曲線的平均斜率,典型值為4.3mV/℃
Vsense代表實際溫度傳感器輸出的數值。
通過上面的公式,我們就可以方便地計算出當前的實際溫度。
11.2.2 DS18B20溫度傳感器
DS18B20是一款測溫范圍在-55~+125℃,精度在±0.5℃的高精度數字式溫度傳感器,可以通過單線接口直接讀取出被測物體的溫度,測溫精度可以通過編程實現,工作電壓3~5.5V。值得一提的是,DS18B20內部具有64位序列號是出廠就被設定的,每一個DS18B20的序列號均不相同,其中前8位是產品家族碼,中間48位是序列號,最后8位是CEC校驗碼,這就可以實現1根總線上掛接多個DS18B20。
(1)復位與應答脈沖
單總線上的所有通信都是以初始化序列開始。主機輸出低電平,保持低電平時間至少480us,以產生復位脈沖。接著主機釋放總線,4.7K的上拉電阻將單總線拉高,延時15~60us,并進入接收模式。接著從設備拉低總線60~240us,以產生低電平應答脈沖,若為低電平,再延時480us。
(2)寫時序
寫時序包括寫0時序和寫1時序。所有寫時序至少需要60us,且在2次獨立的寫時序之間至少需要1us的恢復時間,兩種寫時序均起始于主機拉低總線。寫1時序:主機輸出低電平,延時2us,然后釋放總線,延時60us。寫0時序:主機輸出低電平,延時60us,然后釋放總線,延時2us。
(3)讀時序
必須馬上產生讀時序,以便從機能夠傳輸數據。所有讀時序至少需要60us,且在2次獨立的讀時序之間至少需要1us的恢復時間。每個讀時序都由主機發起,至少拉低總線1us。主機在讀時序期間必須釋放總線,并且在時序起始后的15us之內采樣總線狀態。典型的讀時序過程為:主機輸出低電平延時2us,然后主機轉入輸入模式延時12us,然后讀取單總線當前的電平,然后延時50us。
(4)DS18B20測溫時序
DS18B20的典型溫度讀取過程為:復位->發送跳過ROM讀取命令(0XCC)->發開始轉換命令(0X44)->延時復位->發送跳過ROM讀取命令(0XCC)->發讀存儲器命令(0XBE)->連續讀出兩個字節溫度->結束。
11.2.3 DHT11溫濕度傳感器
DHT11是一款濕溫度一體化的數字傳感器。該傳感器包括一個電阻式測濕元件和一個NTC測溫元件,并與一個高性能8位單片機相連接。通過單片機等微處理器簡單的電路連接就能夠實時的采集本地濕度和溫度。DHT11與單片機之間能采用簡單的單總線進行通信,僅僅需要一個I/O口。傳感器內部濕度和溫度數據40Bit的數據一次性傳給單片機,數據采用校驗和方式進行校驗,有效的保證數據傳輸的準確性。DHT11功耗很低,5V電源電壓下,工作平均最大電流0.5mA。
DHT11的電參數如下所示。
(1)工作電壓:3.3V~5.5V
(2)工作電流:平均0.5mA
(3)測量范圍:濕度2090%RH,溫度050℃
(4)測量精度:濕度±5%,溫度±2%℃
(5)分辨率:濕度1%,溫度1℃
DHT11數字式溫濕度傳感器采用單總線數據格式。即,單個數據引腳端口完成輸入輸出雙向傳輸。其數據包由5個字節組成。數據分小數部分和整數部分,一次完整的數據傳輸為40bit,高位先出。DHT11的數據格式為:8bit濕度整數數據+8bit濕度小數數據+8bit溫度整數數據+8bit溫度小數數據+8bit校驗和。其中校驗和數據為前四個字節相加。傳感器數據輸出的是未編碼的二進制數據。數據(濕度、溫度、整數、小數)之間應該分開處理。
DHT11的 **開始時序** ,即:拉低數據線,保持至少18ms,然后拉高數據線20~40us,然后讀取DHT11的響應,正常的話,DHT11會拉低數據線,保持40~50us,作為響應信號,然后DHT11拉高數據線,保持40~50us后,開始輸出數據。
11.3 STM32片內ADC簡介
11.3.1 內部ADC概述
STM32F103擁有1~3個ADC,這些ADC可以獨立使用,也可以使用雙重模式(提高采樣率)。STM32的ADC是12位逐次逼近型的模擬數字轉換器。它有18個通道,可測量16個外部和2個內部信號源。各通道的A/D轉換可以單次、連續、掃描或間斷模式執行。ADC的結果可以左對齊或右對齊方式存儲在16位數據寄存器中。模擬看門狗特性允許應用程序檢測輸入電壓是否超出用戶定義的高/低閥值。STM32F103系列最少都擁有2個ADC,我們選擇的STM32F103ZET包含有3個ADC。
STM32的ADC最大的轉換速率為1Mhz,也就是轉換時間為1us(在ADCCLK=14M,采樣周期為1.5個ADC時鐘下得到),不要讓ADC的時鐘超過14M,否則將導致結果準確度下降。STM32將ADC的轉換分為2個通道組:規則通道組和注入通道組。規則通道相當于你正常運行的程序,而注入通道就相當于中斷。在程序正常執行的時候,中斷是可以打斷執行的。同這個類似,注入通道的轉換可以打斷規則通道的轉換,在注入通道被轉換完成之后,規則通道才得以繼續轉換。
11.3.2 ADC相關寄存器
(1)ADC控制寄存器1:ADC_CR1
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | AWDEN | AWDENJ | - | FUALMOD[3:0] | |||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
DISCNUM[2:0] | DISCENJ | DISCEN | JAUTO | AWDSGL | SCAN | JEOCIE | AWDIE | EOCIE | AWDCH[4:0] |
Bit 23:在規則通道上開啟模擬看門狗
0:在規則通道上禁用模擬看門狗
1:在規則通道上使用模擬看門狗
Bit 22:在注入通道上開啟模擬看門狗
0:在注入通道上禁用模擬看門狗
1:在注入通道上使用模擬看門狗
Bit 19~Bit16:雙模式選擇
0000:獨立模式
0001:混合的同步規則+注入同步模式
0010:混合的同步規則+交替觸發模式
0011:混合同步注入+快速交叉模式
0100:混合同步注入+慢速交叉模式
0101:注入同步模式
0110:規則同步模式
0111:快速交叉模式
1000:慢速交叉模式
1001:交替觸發模式
Bit 15~Bit 13:間斷模式通道計數
000:1個通道
001:2個通道
……
111:8個通道
Bit 12:在注入通道上的間斷模式
0:注入通道組上禁用間斷模式
1:注入通道組上使用間斷模式
Bit 11:在規則通道上的間斷模式
0:規則通道組上禁用間斷模式
1:規則通道組上使用間斷模式
Bit 10:自動的注入通道組轉換
0:關閉自動的注入通道組轉換
1:開啟自動的注入通道組轉換
Bit 9:掃描模式中在一個單一的通道上使用看門狗
0:在所有的通道上使用模擬看門狗
1:在單一通道上使用模擬看門狗
Bit 8:掃描模式
0:關閉掃描模式
1:使用掃描模式
Bit 7:允許產生注入通道轉換結束中斷
0:禁止JEOC中斷
1:允許JEOC中斷
Bit 6:允許產生模擬看門狗中斷
0:禁止模擬看門狗中斷
1:允許模擬看門狗中斷
Bit 5:允許產生EOC中斷
0:禁止EOC中斷
1:允許EOC中斷
Bit 4~Bit 0:模擬看門狗通道選擇位
00000:ADC模擬輸入通道0
00001:ADC模擬輸入通道1
……
01111:ADC模擬輸入通道15
10000:ADC模擬輸入通道16
10001:ADC模擬輸入通道17
(2)ADC控制寄存器2:ADC_CR2
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | TSVREF | SWSTART | SWSTARTJ | EXTTRIG | EXTSEL[2:0] | - | |||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
JEXTTRIG | JEXTSEL[2:0] | ALIGN | - | DMA | - | RSTCAL | CAL | CONT | ADON |
Bit 23:溫度傳感器和VREFINT使能
0:禁止溫度傳感器和VREFINT
1:啟用溫度傳感器和VREFINT
Bit 22:開始轉換規則通道
0:復位狀態
1:開始轉換規則通道
Bit 21:開始轉換注入通道
0:復位狀態
1:開始轉換注入通道
Bit 20:規則通道的外部觸發轉換模式
0:不用外部事件啟動轉換
1:使用外部事件啟動轉換
Bit 19~Bit 17:選擇啟動規則通道組轉換的外部事件
ADC1和ADC2的觸發配置如下
000:定時器1的CC1事件
001:定時器1的CC2事件
010:定時器1的CC3事件
011:定時器2的CC2事件
100:定時器3的TRGO事件
101:定時器4的CC4事件
110:EXTI線11/TIM8_TRGO事件,僅大容量產品具有TIM8_TRGO功能
111:SWSTART
ADC3的觸發配置如下
000:定時器3的CC1事件
001:定時器2的CC3事件
010:定時器1的CC3事件
011:定時器8的CC1事件
100:定時器8的TRGO事件
101:定時器5的CC1事件
110:定時器5的CC3事件
111:SWSTART
Bit 15:注入通道的外部觸發轉換模式
0:不用外部事件啟動轉換;
1:使用外部事件啟動轉換。
Bit 14~Bit 12:選擇啟動注入通道組轉換的外部事件
ADC1和ADC2的觸發配置如下
000:定時器1的TRGO事件
001:定時器1的CC4事件
010:定時器2的TRGO事件
011:定時器2的CC1事件
100:定時器3的CC4事件
101:定時器4的TRGO事件
110:EXTI線15/TIM8_CC4事件,僅大容量產品具有TIM8_CC4
111:JSWSTART
ADC3的觸發配置如下
000:定時器1的TRGO事件
001:定時器1的CC4事件
010:定時器4的CC3事件
011:定時器8的CC2事件
100:定時器8的CC4事件
101:定時器5的TRGO事件
110:定時器5的CC4事件
111:JSWSTART
Bit 11:數據對齊
0:右對齊
1:左對齊
Bit 8:直接存儲器訪問模式
0:不使用DMA模式
1:使用DMA模式
Bit 3:復位校準
0:校準寄存器已初始化
1:初始化校準寄存器
Bit 2:A/D校準
0:校準完成
1:開始校準
Bit 1:連續轉換
0:單次轉換模式
1:連續轉換模式
Bit 0:開/關A/D轉換器
0:關閉ADC轉換/校準,并進入斷電模式
1:開啟ADC并啟動轉換
(3)ADC采樣事件寄存器1:ADC_SMPR1
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | SMP17[2:0] | SMP16[2:0] | SMP15[2:1] | ||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
SMP15_0 | SMP14[2:0] | SMP13[2:0] | SMP12[2:0] | SMP11[2:0] | SMP10[2:0] |
SMPx[2:0]:選擇通道x的采樣時間
000:1.5周期
001:7.5周期
010:13.5周期
011:28.5周期
100:41.5周期
101:55.5周期
110:71.5周期
111:239.5周期
(4)ADC采樣事件寄存器2:ADC_SMPR2
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | SMP9[2:0] | SMP8[2:0] | SMP7[2:0] | SMP6[2:0] | SMP5[2:1] | ||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
SMP5_0 | SMP4[2:0] | SMP3[2:0] | SMP2[2:0] | SMP1[2:0] | SMP0[2:0] |
SMPx[2:0]:選擇通道x的采樣時間
000:1.5周期
001:7.5周期
010:13.5周期
011:28.5周期
100:41.5周期
101:55.5周期
110:71.5周期
111:239.5周期
(5)ADC規則序列寄存器1:ADC_SQR1
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | L[3:0] | SQ16[4:1] | |||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
SQ16_0 | SQ15[4:0] | SQ14[4:0] | SQ13[4:0] |
Bit 23~Bit 20:規則通道序列長度
0000:1個轉換
0001:2個轉換
……
1111:16個轉換
Bit 19Bit 15:規則序列中的第16個轉換,這些位由軟件定義轉換序列中的第16個轉換通道的編號(017)
Bit 14~Bit 10:規則序列中的第15個轉換
Bit 9~Bit 5:規則序列中的第14個轉換
Bit 4~Bit 0:規則序列中的第13個轉換
(6)ADC規則序列寄存器2:ADC_SQR2
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | SQ12[4:0] | SQ11[4:0] | SQ10[4:0] | ||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
SQ10_0 | SQ9[4:0] | SQ8[4:0] | SQ7[4:0] |
Bit 29~Bit 25:規則序列中的第12個轉換
Bit 24~Bit 20:規則序列中的第11個轉換
Bit 19~Bit 15:規則序列中的第10個轉換
Bit 14~Bit 10:規則序列中的第9個轉換
Bit 9~Bit 5:規則序列中的第8個轉換
Bit 4~Bit 0:規則序列中的第7個轉換
(7)ADC規則序列寄存器3:ADC_SQR3
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | SQ6[4:0] | SQ5[4:0] | SQ4[4:0] | ||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
SQ4_0 | SQ3[4:0] | SQ2[4:0] | SQ1[4:0] |
Bit 29~Bit 25:規則序列中的第6個轉換
Bit 24~Bit 20:規則序列中的第5個轉換
Bit 19~Bit 15:規則序列中的第4個轉換
Bit 14~Bit 10:規則序列中的第3個轉換
Bit 9~Bit 5:規則序列中的第2個轉換
Bit 4~Bit 0:規則序列中的第1個轉換
(8)ADC數據寄存器:ADC_DR和ADC_JDR
數據寄存器分為DR和JDR,其中DR中存儲的是規則序列轉換后的值,JDR存儲的則是注入序列轉換后的值。其中ADC_DR寄存器的結構如下圖所示。
31 | 30 | 29 | 28 | 27 | 26 | 25 | 24 | 23 | 22 | 21 | 20 | 19 | 18 | 17 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ADC2_DATA[15:0] | |||||||||||||||
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
DATA[15:0] |
Bit 31~Bit16:ADC2轉換的數據,在ADC1中:雙模式下,這些位包含了ADC2轉換的規則通道數據
Bit 15~Bit 0:規則轉換的數據:包含了規則通道的轉換結果,數據是左對齊或右對齊
(9)ADC狀態寄存器:ADC_SR
15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
- | STRT | JSTART | JEOC | EOC | AWD |
Bit 4:規則通道開始位
0:規則通道轉換未開始
1:規則通道轉換已開始
Bit 3:注入通道開始位
0:注入通道組轉換未開始
1:注入通道組轉換已開始
Bit 2:注入通道轉換結束位
0:轉換未完成
1:轉換完成
Bit 1:轉換結束位
0:轉換未完成
1:轉換完成
Bit 0:模擬看門狗標志位
0:沒有發生模擬看門狗事件
1:發生模擬看門狗事件
11.4 內部溫度傳感器例程
功能實現:采用內部溫度傳感器讀取溫度顯示在TFTLCD上。
(1)創建adc.h文件,并輸入以下代碼。
#ifndef _ADC_H_
#define _ADC_H_
#include "sys.h"
/*********************************************************************************************************
函 數 列 表
*********************************************************************************************************/
void ADC_Init( void ) ; //初始化ADC1
u16 Get_Adc_Average( u8 ch, u8 times ) ; //獲取通道ch的轉換均值
short Get_Temprate( void ) ; //獲取溫度值
#endif
(2)創建adc.c文件,并輸入以下代碼。
#include "adc.h"
#include "delay.h"
/***************************************************
Name :ADC_Init
Function :初始化ADC1
Paramater :None
Return :None
***************************************************/
void ADC_Init()
{
//先初始化IO口
RCC->APB2ENR |= 1<<2 ; //使能PORTA口時鐘
GPIOA->CRL &= 0XFFFFFF0F ; //PA1 anolog輸入
RCC->APB2ENR |= 1<<9 ; //ADC1時鐘使能
RCC->APB2RSTR |= 1<<9 ; //ADC1復位
RCC->APB2RSTR &= ~( 1<<9 ) ; //復位結束
RCC->CFGR &= ~( 3<<14 ) ; //分頻因子清零
//SYSCLK/DIV2=12M ADC時鐘設置為12M,ADC最大時鐘不能超過14M
RCC->CFGR |= 2<<14 ;
ADC1->CR1 &= 0xF0FFFF ; //工作模式清零
ADC1->CR1 |= 0<<16 ; //獨立工作模式
ADC1->CR1 &= ~( 1<<8 ) ; //非掃描模式
ADC1->CR2 &= ~( 1<<1 ) ; //單次轉換模式
ADC1->CR2 &= ~( 7<<17 ) ;
ADC1->CR2 |= 7<<17 ; //軟件控制轉換
ADC1->CR2 |= 1<<20 ; //使用用外部觸發
ADC1->CR2 &= ~( 1<<11 ) ; //右對齊
ADC1->CR2 |= 1<<23 ; //使能溫度傳感器
ADC1->SQR1 &= ~( 0xF<<20 ) ;
ADC1->SQR1 &= ~( 1<<20 ) ; //1個轉換在規則序列中
//設置通道1的采樣時間
ADC1->SMPR2 &= ~( 3<<0 ) ; //通道1采樣時間清空
ADC1->SMPR2 |= 7<<3 ; //通道1 239.5周期,提高采樣時間可以提高精確度
ADC1->SMPR1 &= ~( 7<<18 ) ; //清除通道16原來的設置
ADC1->SMPR1 |= 7<<18 ; //通道16 239.5周期,提高采樣時間可以提高精確度
ADC1->CR2 |= 1<<0 ; //開啟AD轉換器
ADC1->CR2 |= 1<<3 ; //使能復位校準
while( ( ADC1->CR2&0x08 )==0x08 ) ; //等待校準結束
ADC1->CR2 |= 1<<2 ; //開啟AD校準
while( ( ADC1->CR2&0x04 )==0x04 ) ; //等待校準結束
}
/***************************************************
Name :ADC_Init
Function :獲取通道ch的轉換均值
Paramater :
ch:通道編號
times:獲取次數
Return :通道ch的轉換均值
***************************************************/
u16 Get_Adc_Average( u8 ch, u8 times )
{
u32 temp_val=0 ;
u8 t ;
for( t=0; t
(3)創建main文件,并輸入以下代碼。
#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "adc.h"
int main()
{
short Temp ;
u8 Str[] = "Temperature:+000.00 'C" ;
STM32_Clock_Init( 9 ) ; //STM32時鐘初始化
SysTick_Init( 72 ) ; //SysTick初始化
USART1_Init( 72, 115200 ) ; //初始化串口1波特率115200
LCD_Init() ; //LCD初始化
ADC_Init() ; //ADC初始化
while( 1 )
{
Temp = Get_Temprate() ;
if( Temp<0 )
{
Temp = -Temp ;
Str[ 12 ] = '-' ; //顯示負號
}
else
Str[ 12 ] = ' ' ; //無符號
Str[ 13 ] = 0x30+Temp/10000 ;
Str[ 14 ] = 0x30+Temp%10000/1000 ;
Str[ 15 ] = 0x30+Temp%1000/100 ;
Str[ 17 ] = 0x30+Temp%100/10 ;
Str[ 18 ] = 0x30+Temp%10 ;
LCD_ShowString( 100, 100, Str ) ; //顯示溫度值
delay_ms( 500 ) ;
}
}
11.5 DS18B20例程
功能實現:讀取DS18B20的溫度顯示在TFTLCD上。
(1)創建ds18b20.h文件,并輸入以下代碼。
#ifndef _DS18B20_H_
#define _DS18B20_H_
#include "sys.h"
/*********************************************************************************************************
端 口 分 配
*********************************************************************************************************/
#define DS18B20_DQ_OUT PGout( 11 ) //數據端口
#define DS18B20_DQ_IN PGin( 11 )
/*********************************************************************************************************
函 數 列 表
*********************************************************************************************************/
void DS18B20_Init( void ) ; //初始化DS18B20
short DS18B20_Get_Temp( void ) ; //獲取溫度
#endif
(2)創建ds18b20.c文件,并輸入以下代碼。
#include "ds18b20.h"
#include "delay.h"
/***************************************************
Name :DS18B20_Write_Byte
Function :發送1個字節
Paramater :
Byte:發送的字節
Return :None
***************************************************/
void DS18B20_Write_Byte( u8 Byte )
{
u8 i ;
GPIOG->CRH &= 0xFFFF0FFF ;
GPIOG->CRH |= 0x00003000 ;
for( i=0; i<8; i++ )
{
if( ( Byte&0x01 )==0x01 )
{
DS18B20_DQ_OUT = 0;
delay_us( 2 ) ;
DS18B20_DQ_OUT = 1 ;
delay_us( 60 ) ;
}
else
{
DS18B20_DQ_OUT = 0 ;
delay_us( 60 ) ;
DS18B20_DQ_OUT = 1 ;
delay_us( 2 ) ;
}
Byte >>= 1 ;
}
}
/***************************************************
Name :DS18B20_Read_Byte
Function :讀取1個字節
Paramater :None
Return :讀取的字節
***************************************************/
u8 DS18B20_Read_Byte()
{
u8 i, Byte=0 ;
for( i=0; i<8; i++ )
{
Byte >>= 1 ;
GPIOG->CRH &= 0xFFFF0FFF ;
GPIOG->CRH |= 0x00003000 ;
DS18B20_DQ_OUT = 0 ;
delay_us( 2 ) ;
DS18B20_DQ_OUT = 1 ;
GPIOG->CRH &= 0xFFFF0FFF ;
GPIOG->CRH |= 0x00008000 ;
delay_us( 12 ) ;
if( DS18B20_DQ_IN )
Byte |= 0x80 ;
delay_us( 50 ) ;
}
return Byte ;
}
/***************************************************
Name :DS18B20_Check
Function :等待DS18B20的回應
Paramater :None
Return :None
***************************************************/
void DS18B20_Check()
{
GPIOG->CRH &= 0xFFFF0FFF ;
GPIOG->CRH |= 0x00003000 ;
DS18B20_DQ_OUT = 0 ; //拉低DQ
delay_us( 750 ); //拉低750us
DS18B20_DQ_OUT = 1 ; //DQ=1
delay_us( 15 ) ; //15us
GPIOG->CRH &= 0xFFFF0FFF ;
GPIOG->CRH |= 0x00008000 ;
while( DS18B20_DQ_IN ) ; //等待應答
while( DS18B20_DQ_IN==0 ); //等待應答結束
}
/***************************************************
Name :DS18B20_Init
Function :初始化DS18B20
Paramater :None
Return :None
***************************************************/
void DS18B20_Init()
{
RCC->APB2ENR |= 1<<8 ; //使能PORTG口時鐘
GPIOG->CRH &= 0xFFFF0FFF ; //PORTG.11 推挽輸出
GPIOG->CRH |= 0x00003000 ;
GPIOG->ODR |= 1<<11 ; //輸出1
DS18B20_Check() ;
}
/***************************************************
Name :DS18B20_Get_Temp
Function :得到溫度值
Paramater :None
Return :溫度值
***************************************************/
short DS18B20_Get_Temp()
{
u8 TL,TH;
short temp ;
DS18B20_Check() ;
DS18B20_Write_Byte( 0xCC ) ; //跳過ROM讀取
DS18B20_Write_Byte( 0x44 ) ; //開啟轉換
DS18B20_Check() ;
DS18B20_Write_Byte( 0xCC ) ; //跳過ROM讀取
DS18B20_Write_Byte( 0xBE ) ; //開始轉換
TL = DS18B20_Read_Byte() ; //LSB
TH = DS18B20_Read_Byte() ; //MSB
if( TH>7 )
{
TH = ~TH ;
TL = ~TL ;
}
temp = TH ; //獲得高八位
temp <<= 8 ;
temp += TL ; //獲得低八位
temp = ( float )temp*0.625 ; //轉換
if( TH>7 )
return temp ; //返回溫度值
else
return -temp ;
}
(3)創建1.c文件,并輸入以下代碼。
#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "ds18b20.h"
int main()
{
short Temp ;
u8 Str[] = "Temperature:+000.00 'C" ;
STM32_Clock_Init( 9 ) ; //STM32時鐘初始化
SysTick_Init( 72 ) ; //SysTick初始化
USART1_Init( 72, 115200 ) ; //初始化串口1波特率115200
LCD_Init() ; //LCD初始化
DS18B20_Init() ; //DS18B20初始化
while( 1 )
{
Temp = DS18B20_Get_Temp(); //讀取溫度
if( Temp<0 )
{
Temp = -Temp ;
Str[ 12 ] = '-' ; //顯示負號
}
else
Str[ 12 ] = ' ' ; //無符號
Str[ 13 ] = 0x30+Temp/10000 ;
Str[ 14 ] = 0x30+Temp%10000/1000 ;
Str[ 15 ] = 0x30+Temp%1000/100 ;
Str[ 17 ] = 0x30+Temp%100/10 ;
Str[ 18 ] = 0x30+Temp%10 ;
LCD_ShowString( 100, 100, Str ) ; //顯示溫度值
delay_ms( 500 ) ;
}
}
11.6 DHT11例程
功能實現:讀取DHT11的溫度與濕度數據顯示在TFTLCD上。
(1)創建dht11.h文件,并輸入以下代碼。
#ifndef _DHT11_H_
#define _DHT11_H_
#include "sys.h"
/*********************************************************************************************************
端 口 分 配
*********************************************************************************************************/
#define DHT11_DQ_OUT PGout( 11 ) //數據端口
#define DHT11_DQ_IN PGin( 11 )
/*********************************************************************************************************
函 數 列 表
*********************************************************************************************************/
u8 DHT11_Init( void ) ; //初始化DHT11
u8 DHT11_Get_Data( u8 *temp, u8 *humi ) ; //獲取溫濕度
#endif
(2)創建dht11.c文件,并輸入以下代碼。
#include "dht11.h"
#include "delay.h"
/***************************************************
Name :DHT11_Check
Function :檢查DHT11
Paramater :None
Return :
0:存在
1:不存在
***************************************************/
u8 DHT11_Check()
{
u8 retry ;
GPIOG->CRH &= 0xFFFF0FFF ; //PG11推挽輸出
GPIOG->CRH |= 0x00003000 ;
DHT11_DQ_OUT = 0 ; //拉低DQ
delay_ms( 20 ) ; //拉低至少18ms
DHT11_DQ_OUT = 1 ; //DQ=1
delay_us( 30 ); //主機拉高20~40us
GPIOG->CRH &= 0xFFFF0FFF; //PG11上拉輸入
GPIOG->CRH |= 0x00008000;
//DHT11會拉低40~80us
retry = 0 ;
while( ( DHT11_DQ_IN==1 )&&( retry<100 ) )
{
retry ++ ;
delay_us( 1 ) ;
};
if( retry>=100 )
return 1 ;
else
retry = 0 ;
//DHT11拉低后會再次拉高40~80us
while( ( DHT11_DQ_IN==0 )&&( retry<100 ) )
{
retry ++ ;
delay_us( 1 ) ;
};
if( retry>=100 )
return 1 ;
return 0 ;
}
/***************************************************
Name :DHT11_Read_Byte
Function :讀取1個字節
Paramater :None
Return :讀取的字節
***************************************************/
u8 DHT11_Read_Byte()
{
u8 i, Byte=0;
for (i=0;i<8;i++)
{
Byte <<= 1 ;
while( DHT11_DQ_IN ) ; //等待變為低電平
while( DHT11_DQ_IN==0 ) ; //等待變高電平
delay_us( 40 ) ; //等待40us
if( DHT11_DQ_IN )
Byte |= 0x01 ;
}
return Byte ;
}
/***************************************************
Name :DHT11_Get_Data
Function :獲取溫濕度
Paramater :
temp:溫度值(范圍:0~50°)
humi:濕度值(范圍:20%~90%)
Return :
0:正常
1:讀取失敗
***************************************************/
u8 DHT11_Get_Data( u8 *temp, u8 *humi )
{
u8 i, buf[ 5 ] ;
if( DHT11_Check()==0 )
{
//讀取40位數據
for( i=0; i<5; i++ )
buf[ i ] = DHT11_Read_Byte() ;
if( ( buf[ 0 ]+buf[ 1 ]+buf[ 2 ]+buf[ 3 ] )==buf[ 4 ] )
{
*humi = buf[ 0 ] ;
*temp = buf[ 2 ] ;
}
}
else
return 1 ;
return 0 ;
}
/***************************************************
Name :DHT11_Init
Function :初始化DHT11
Paramater :None
Return :
0:存在
1:不存在
***************************************************/
u8 DHT11_Init()
{
RCC->APB2ENR |= 1<<8 ; //使能PG時鐘
GPIOG->CRH &= 0xFFFF0FFF ; //PG11推挽輸出
GPIOG->CRH |= 0x00003000 ;
GPIOG->ODR |= 1<<11 ; //輸出1
if( DHT11_Check() )
return 1 ;
return 0 ;
}
(3)創建1.c文件,并輸入以下代碼。
#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "dht11.h"
int main()
{
u8 Temp, Humi;
u8 Str1[ 20 ] ;
u8 Str2[ 20 ] ;
STM32_Clock_Init( 9 ) ; //STM32時鐘初始化
SysTick_Init( 72 ) ; //SysTick初始化
USART1_Init( 72, 115200 ) ; //初始化串口1波特率115200
LCD_Init() ; //LCD初始化
while( DHT11_Init() ) //DHT11初始化
{
LCD_ShowString( 100, 100, "DHT11 Error!!!" ) ;
delay_ms( 200 ) ;
LCD_ShowString( 100, 100, " " ) ;
delay_ms( 200 ) ;
}
while( 1 )
{
//讀取溫濕度
if( DHT11_Get_Data( &Temp, &Humi )==0 )
{
sprintf( ( char * )Str1, "Temperature:%02d C", Temp ) ;
LCD_ShowString( 100, 100, Str1 ) ; //顯示溫度值
sprintf( ( char * )Str2, "Humidity:%02d RH%%", Temp ) ;
LCD_ShowString( 100, 116, Str2 ) ; //顯示濕度值
}
delay_ms( 500 ) ;
}
}
-
溫度傳感器
+關注
關注
48文章
2918瀏覽量
155899 -
STM32
+關注
關注
2266文章
10876瀏覽量
354926 -
單總線協議
+關注
關注
1文章
4瀏覽量
1862
發布評論請先 登錄
相關推薦
評論