>[success] **技術支持說明:**
>**1**.一般以自主學習為主
> **2**.可到官方問答社區中提問:[**去提問**](https://bbs.csdn.net/forums/nb-iot)
> **3**.工程師**會盡快**解答社區問題,但他們是一線開發,【**難以保證**】解答時效,解答辛苦,感謝理解!
<br/>
STM32主板中內置了一個奧松 DHT20溫濕度傳感器,如圖所示。

本節課將講解如何使用DHT20溫濕度傳感器來感知環境溫濕度,并且把數據在屏幕中顯示出來。許多傳感器的使用方法都是類似的,通過學習使用DHT20,相信讀者可以做到舉一反三,能夠使用更多種類的傳感器。
<br/>
## **DHT20 簡介**
DHT20是奧松電子精心打造的一款溫濕度傳感器,是DHT11的全新升級版本。傳感器內配置一顆全新設計的專用芯片、經過改進的半導體電容式濕度傳感元件和一個溫度傳感元件。全面改良后,DHT20在降低功耗、降低成本的同時,在測量精度、測量范圍、響應時間、穩定性等方面的性能都有大幅提升,其主要技術參數如圖所示。

<br/>
## **項目架構設計**
基于前述的SDK設計思想,筆者把使用溫濕度傳感器的代碼分為3個部分,分別是HAL的DHT20驅動程序、服務層的傳感器服務和任務層的傳感器任務,如圖所示。

###
打開本節課配套的工程可以找到與這3個部分對應的文件,如圖所示。

###
其中的hal\_dht11.h/c是DHT20驅動程序,svc\_sensor.h/c是傳感器服務,task\_sensor.h/c是傳感器任務。
<br/>
## **DHT20驅動程序**
hal\_dht20.h文件中有兩個重要的函數,代碼如下:
###
```
/**
* @fn halDht20Init
*
* @brief 初始化函數,使用DHT20前必須先調用此函數
*/
#define halDht20Init() AHT20_Init()
/**
* @fn halDht20GetData
*
* @brief 獲取DHT20的溫濕度數據
*
* @return 溫濕度數據值
*/
#define halDht20GetData() AHT20GetData()
```
halDht20GetData()函數的返回值是一個結構體,定義代碼如下:
```
/** @brief 用于表示DHT20溫濕度數據 */
typedef struct {
unsigned char ok;//ok的值非0時溫濕度數據才有效
float temp;//溫度值
float humi;//濕度值
} AHT20Data_t;
```
<br/>
## **傳感器服務**
傳感器服務的作用是抽象各種傳感器驅動程序,為上層提供統一的接口。
打開svc\_sensor.h文件,代碼如下:
```
#ifndef __SVC_SENSOR_H__
#define __SVC_SENSOR_H__
/**
* 初始化溫濕度傳感器
*/
void svcSensorInit(void);
/**
* 獲取溫度值
* @param value用于存放溫度值
* @return 0表示獲取成功,非0表示獲取失敗
*/
int svcSensorGetTemp(float *value);
/**
* 獲取濕度值
* @param value用于存放濕度值
* @return 0表示獲取成功,非0表示獲取失敗
*/
int svcSensorGetHumi(float *value);
#endif /* __SVC_SENSOR_H__ */
```
###
打開svc\_sensor.c文件,代碼如下:
```
#include "svc_sensor.h"
#include "hal_dht20.h"
/**
* 初始化溫濕度傳感器
*/
void svcSensorInit()
{
}
/**
* 獲取溫度值
* @param value用于存放溫度值
* @return 0表示獲取成功,非0表示獲取失敗
*/
int svcSensorGetTemp(float *value)
{
/* 調用DHT20驅動程序獲取數據 */
AHT20Data_t data = halDht20GetData();
if (!data.ok) return -1;
*value = data.temp;
return 0;
}
/**
* 獲取濕度值
* @param value用于存放濕度值
* @return 0表示獲取成功,非0表示獲取失敗
*/
int svcSensorGetHumi(float *value)
{
/* 調用DHT20驅動程序獲取數據 */
AHT20Data_t data = halDht20GetData();
if (!data.ok) return -1;
*value = data.humi;
return 0;
}
```
<br/>
## **傳感器任務:task_sensor**
傳感器任務實現了每隔1.5秒獲取溫濕度,并在顯示屏上顯示。打開task\_sensor.c文件,代碼如下:
###
```
#include "task_sensor.h"
#include "svc_plugins.h"
#include "svc_sensor.h"
#include "svc_task.h"
#include "svc_log.h"
#include <stdio.h>
static void taskSensorRunner(uint8_t, void *);
/*
* 傳感器任務初始化
*/
void taskSensorInit()
{
/* 啟動一個1.5秒的周期性任務 */
svcTaskAdd(
1500,//1.5秒
1,//重復執行
taskSensorRunner,//任務內容
0);//任務參數
}
/*
* 任務內容
*/
void taskSensorRunner(uint8_t id, void *args)
{
char str[32];
float temp, humi;
/* 獲取溫度,顯示在第三行 */
if (svcSensorGetTemp(&temp) == 0) {
sprintf(str, "temp: %.1f C", temp);
svcPluginsLcdWrite(0, 0, (uint8_t *)str, 0);
}
/* 獲取濕度,顯示在第四行 */
if (svcSensorGetHumi(&humi) == 0) {
sprintf(str, "humi: %.1f %%", humi);
svcPluginsLcdWrite(0, 0, 0, (uint8_t *)str);
}
}
```
<br/>
## **編寫Main函數**
打開main.c文件,代碼如下:
```
#include "main.h"
#include "task_sensor.h"
#include "task_input.h"
#include "task_lcd.h"
#include "task_uart.h"
#include "task_led.h"
#include "task_test.h"
#include "svc_sensor.h"
#include "svc_button.h"
#include "svc_plugins.h"
#include "svc_log.h"
#include "svc_task.h"
#include "hal_dht20.h"
#include "hal_button.h"
#include "hal_oled12864.h"
#include "hal_led.h"
#include "hal_uart.h"
#include "hal_system.h"
static void halInit(void);
static void svcInit(void);
static void taskInit(void);
int main(void)
{
halInit();//HAL初始化
svcInit();//服務層初始化
taskInit();//任務層初始化
/* 每隔1毫秒查看有沒有任務需要執行*/
while (1) {
halSystemDelayUs(1000);//延時1毫秒
svcTaskPoll(1);//查看有沒有任務需要執行
}
}
/* HAL初始化 */
void halInit()
{
halSystemInit();//系統初始化
halUartInit(115200);//串口初始化
halLedInit();//LED初始化
halOLED12864Init();//顯示器初始化
halButtonInit(0);//按鈕初始化
halDht20Init();//DHT20溫濕度傳感器初始化
}
/* Services層初始化*/
void svcInit()
{
svcTaskInit();//任務管理服務初始化
svcLogInit();//日志服務初始化
svcPluginsInit();//插件服務初始化
svcButtonInit();//按鈕服務初始化
svcSensorInit();//傳感器服務初始化
}
/* Tasks */
void taskInit()
{
taskTestInit();//測試任務初始化
taskLedInit();//LED任務初始化
taskLcdInit();//顯示器任務初始化
taskUartInit();//串口任務初始化
taskInputInit();//輸入任務初始化
taskSensorInit();//傳感器任務初始化
}
```
<br/>
## **代碼測試**
* 把開發板的第1、2、3和4打到右邊,第5和6位打到左邊,如圖所示。

###
* 編譯鏈接工程代碼,把生成的Hex文件燒錄到開發板中。
###
* 程序運行后,可以在屏幕上看到溫濕度,如圖所示。

<br/>
<br/>
## **商務合作**
如有以下需求,可掃碼添加管理員好友,注明“**商務合作**”
* 項目定制開發,技術范圍:**NB-IoT**、**CATn(4G)**、**WiFi**、**ZigBee**、**BLE Mesh**以及**STM32**、**嵌入式Linux**等;
* 入駐平臺,成為講師;
* 接項目賺外快;
* 善學坊官網:[www.sxf-iot.com](https://www.sxf-iot.com/)

(非商務合作**勿擾**,此處**非**技術支持)
- 課程簡介
- 配套資源下載
- 配套開發套件簡介
- 簡介
- 硬件組成 & 技術參數
- STM32 Pro 主板 原理圖 & PCB圖
- STM32 Std 主板 原理圖 & PCB圖
- 板載設備使用說明
- STM32開發指南
- 1. 搭建開發環境
- 1.1 Keil MDK簡介與安裝
- 1.2 STM32 Pack 簡介與安裝
- 1.3 CH34x 驅動簡介與安裝
- 1.4 ISP 串口下載工具
- 1.5 串口調試工具
- 2. STM32 開發基礎
- 2.1 新建工程
- 2.2 實現第1個程序
- 2.3 Hex 文件燒錄詳解
- 3. 移植官方標準工程模板
- 4. GPIO實驗:LED
- 5. 系統延時應用
- 6. GPIO實驗:按鍵
- 7. GPIO中斷實驗——按鍵觸發實驗
- 8. 使用定時器TIM3
- 9. 串口通信實驗
- 10. ADC 實驗
- 11. OLED顯示器實驗
- 12. SDK 設計思想
- 13. SDK 架構解析
- 14. 多任務應用實驗
- 15. 輸入型任務:按鍵輸入實驗
- 16. 輸入型任務:串口接收實驗
- 17. 高精度溫濕度傳感器實驗
- 進階課程