@
前言
參考資料:
YL-47 DHT11 使用說明--.pdf
DHT11說明書最新版--.pdf
DHT11模塊--.pdf
DHT11模塊使用說明書
DS18B20.pdf
ds18b20中文資料詳解
源碼參考:
野火dht11溫濕度傳感器測試實驗
正點原子TFTLCD顯示實驗
正點原子18B20數字溫度傳感器實驗
正點原子按鍵實驗
正點原子蜂鳴器實驗
開發板:正點原子 STM32F103 精英版
語言:C語言
開發環境:Keil5
開發板使用了 LED KEY BEEP TFTLCD USART DHT11模塊 DS18B20模塊
代碼下載:
功能介紹:
1、LED0約2秒一閃,表示程序運行中。
2、LCD和串口顯示實時的溫濕度,2秒一循環。上面一個temp是DS18B20,下面的是DHT11。%RH 相對濕度, CEL 攝氏度(ps:不接入DS18B20的話會循環等待)
3、按鍵都會翻轉LED1,KEY1 開啟報警模式,KEY0關閉報警模式。(按鍵10ms一巡檢)
4、報警模式下:當溫度不低於85攝氏度或者濕度不低於90%RH,蜂鳴器報警。可以通過按下KEY0關閉報警模式。(報警串口會有打印,LCD也會有提示)
接線
DS18B20
VCC -》 3.3V
DQ -》 PG11
GND -》 GND

DHT11
VCC -》 3.3V
DATA -》 PB10
GND -》 GND

效果圖
普通環境
普通版main.c

升級版


哈熱氣
普通版
我這哈了3下

然后持續手扇風

ok,溫濕度降下來了。
升級版

搓手捂熱
手有汗,濕度也上來了
(下圖是舊的,僅供參考)


最后本來應該整個打火機的,可惜沒有。夾咯吱窩下(僅DHT11 舊圖)

最后來個鼻息

核心代碼
普通版main.c
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "bsp_dht11.h"
#include "ds18b20.h"
DHT11_Data_TypeDef DHT11_Data;
/*
DS18B20
供電電壓:3 - 5.5V
接線:DQ -》 PG11 (IO口)
DHT11
供電電壓:3.3 - 5V
接線:DATA -》 PB10 (IO口)
*/
int main(void)
{
u8 str[100] = {0};
// DS18B20用變量
short temperature;
delay_init(); //延時函數初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置NVIC中斷分組2:2位搶占優先級,2位響應優先級
uart_init(115200); //串口初始化為115200
LED_Init(); //LED端口初始化
LCD_Init(); // LCD初始化
DHT11_GPIO_Config(); // 初始化DTT11的引腳 DATA -> PB10
LED0 = 0;
POINT_COLOR = WHITE;
BACK_COLOR = BLACK;
LCD_Clear(BLACK);
while(DS18B20_Init()) //DS18B20初始化
{
LCD_ShowString(10,70,200,16,16,"DS18B20 Error");
delay_ms(200);
LCD_Fill(10,70,239,130+16,WHITE);
delay_ms(200);
}
LCD_ShowString(10,90,200,16,16,"Temp: . CEL");
while(1)
{
POINT_COLOR = WHITE;
// DS18B20
temperature = DS18B20_Get_Temp();
if(temperature < 0)
{
LCD_ShowChar(10+40, 90, '-', 16, 0); //顯示負號
temperature = -temperature; //轉為正數
}else LCD_ShowChar(10+40,90,' ', 16, 0); //去掉負號
LCD_ShowNum(10+40+8, 90, temperature/10, 2, 16); //顯示正數部分
LCD_ShowNum(10+40+32, 90,temperature%10, 1, 16); //顯示小數部分
printf("溫度為 %u.%u℃ \r\n",temperature/10, temperature%10);
// DHT11
// 調用Read_DHT11讀取溫濕度,若成功則輸出該信息
if( Read_DHT11(&DHT11_Data) == SUCCESS)
{
printf("濕度為%d.%d %RH ,溫度為 %d.%d℃ \r\n", DHT11_Data.humi_int, DHT11_Data.humi_deci, DHT11_Data.temp_int, DHT11_Data.temp_deci);
sprintf((char*)str, "HUM: %d.%d%%RH ", DHT11_Data.humi_int, DHT11_Data.humi_deci);
LCD_ShowString(10,130,200,24,24, str);
sprintf((char*)str, "TEMP: %d.%dCEL ", DHT11_Data.temp_int, DHT11_Data.temp_deci);
LCD_ShowString(10,170,200,24,24, str);
//printf("\r\n 濕度:%d,溫度:%d \r\n" ,DHT11_Data.humi_int,DHT11_Data.temp_int);
}
else
{
printf("Read DHT11 ERROR!\r\n");
}
LED0 = !LED0;
// 采樣周期不得低於1秒,否則會讀取失敗
delay_ms(1000);
delay_ms(1000);
}
}
升級版main.c
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "bsp_dht11.h"
#include "ds18b20.h"
#include "key.h"
#include "beep.h"
DHT11_Data_TypeDef DHT11_Data;
/*
DS18B20
供電電壓:3 - 5.5V
接線:DQ -》 PG11 (IO口)
DHT11
供電電壓:3.3 - 5V
接線:DATA -》 PB10 (IO口)
*/
int main(void)
{
u8 str[100] = {0};
// 蜂鳴器報警標志位
u8 flag = 0;
// 報警模式
u8 mode = 0;
vu8 key = 0;
// 循環計數
u8 time = 0;
// DS18B20用變量
short temperature;
delay_init(); //延時函數初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置NVIC中斷分組2:2位搶占優先級,2位響應優先級
uart_init(115200); //串口初始化為115200
LED_Init(); //LED端口初始化
LCD_Init(); // LCD初始化
KEY_Init(); // KEY初始化
BEEP_Init(); // BEEP初始化
DHT11_GPIO_Config(); // 初始化DTT11的引腳 DATA -> PB10
LED0 = 0;
LED1 = 0;
POINT_COLOR = WHITE;
BACK_COLOR = BLACK;
LCD_Clear(BLACK);
while(DS18B20_Init()) //DS18B20初始化
{
LCD_ShowString(10,70,200,16,16,"DS18B20 Error");
delay_ms(200);
LCD_Fill(10,70,239,130+16, BLACK);
delay_ms(200);
}
LCD_ShowString(10,90,200,16,16,"Temp: . CEL");
LCD_ShowString(10,220,220,12,12,"TOUCH KEY0 CLOSE ALARM MODE");
LCD_ShowString(10,240,220,12,12,"TOUCH KEY1 OPEN ALARM MODE");
POINT_COLOR = RED;
LCD_ShowString(10,260,100,12,12,"ALARM MODE: OFF");
POINT_COLOR = WHITE;
while(1)
{
flag = 2;
POINT_COLOR = WHITE;
key = KEY_Scan(0); //得到鍵值
if (key)
{
switch (key)
{
case WKUP_PRES:
LED1 = !LED1;
break;
// KEY1 按下 開啟報警模式
case KEY1_PRES:
mode = 1;
LED1 = !LED1;
LCD_ShowString(80,260,100,12,12,"ON ");
printf("開啟報警模式\r\n");
break;
// KEY1 按下 關閉報警模式
case KEY0_PRES:
mode = 0;
LED1 = !LED1;
LCD_ShowString(80,260,100,12,12,"OFF ");
printf("關閉報警模式\r\n");
break;
}
}
// 約2秒一次
if(time % 200 == 0)
{
// DS18B20
temperature = DS18B20_Get_Temp();
if(temperature < 0)
{
LCD_ShowChar(10+40, 90, '-', 16, 0); //顯示負號
temperature = -temperature; //轉為正數
}else LCD_ShowChar(10+40,90,' ', 16, 0); //去掉負號
LCD_ShowNum(10+40+8, 90, temperature/10, 2, 16); //顯示正數部分
LCD_ShowNum(10+40+32, 90,temperature%10, 1, 16); //顯示小數部分
printf("溫度為 %u.%u℃ \r\n",temperature/10, temperature%10);
// DHT11
// 調用Read_DHT11讀取溫濕度,若成功則輸出該信息 采樣周期不得低於1秒,否則會讀取失敗
if( Read_DHT11(&DHT11_Data) == SUCCESS)
{
printf("濕度為%d.%d %RH ,溫度為 %d.%d℃ \r\n", DHT11_Data.humi_int, DHT11_Data.humi_deci, DHT11_Data.temp_int, DHT11_Data.temp_deci);
sprintf((char*)str, "HUM: %d.%d%%RH ", DHT11_Data.humi_int, DHT11_Data.humi_deci);
LCD_ShowString(10,130,200,24,24, str);
sprintf((char*)str, "TEMP: %d.%dCEL ", DHT11_Data.temp_int, DHT11_Data.temp_deci);
LCD_ShowString(10,170,200,24,24, str);
//printf("\r\n 濕度:%d,溫度:%d \r\n" ,DHT11_Data.humi_int,DHT11_Data.temp_int);
}
else
{
printf("Read DHT11 ERROR!\r\n");
}
// 判斷溫度是否不低於85攝氏度
if(temperature >= 850 || DHT11_Data.temp_int >= 85)
{
printf("溫度過高!!!\r\n");
flag++;
}
else
{
flag--;
}
// 判斷濕度是否高於90%RH
if(DHT11_Data.humi_int >= 90)
{
printf("濕度過高!!!\r\n");
flag++;
}
else
{
flag--;
}
// 判斷是否需要報警
if(flag >= 2 && mode == 1)
{
LCD_ShowString(10,200,200,16,16,"BEEP!!!(>__<)");
printf("BEEP!!!(>__<)\r\n");
BEEP = 1;
}
if(flag < 2)
{
LCD_ShowString(10,200,200,16,16," (- v -) ");
BEEP = 0;
}
// 重新置零
time = 0;
LED0 = !LED0;
}
if(mode == 0)
{
LCD_ShowString(10,200,200,16,16," (- v -) ");
BEEP = 0;
}
time++;
delay_ms(10);
}
}
bsp_dht11.h
#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f10x.h"
#include "delay.h"
#define HIGH 1
#define LOW 0
#define DHT11_CLK RCC_APB2Periph_GPIOB
#define DHT11_PIN GPIO_Pin_10
#define DHT11_PORT GPIOB
//帶參宏,可以像內聯函數一樣使用,輸出高電平或低電平
#define DHT11_DATA_OUT(a) if (a) \
GPIO_SetBits(GPIOB,GPIO_Pin_10);\
else \
GPIO_ResetBits(GPIOB,GPIO_Pin_10)
//讀取引腳的電平
#define DHT11_DATA_IN() GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)
typedef struct
{
uint8_t humi_int; //濕度的整數部分
uint8_t humi_deci; //濕度的小數部分
uint8_t temp_int; //溫度的整數部分
uint8_t temp_deci; //溫度的小數部分
uint8_t check_sum; //校驗和
}DHT11_Data_TypeDef;
void DHT11_GPIO_Config(void);
static void DHT11_Mode_IPU(void);
static void DHT11_Mode_Out_PP(void);
uint8_t Read_DHT11(DHT11_Data_TypeDef *DHT11_Data);
static uint8_t Read_Byte(void);
#endif /* __DHT11_H */
bsp_dht11.c
#include "bsp_dht11.h"
/*
* 函數名:DHT11_GPIO_Config
* 描述 :配置DHT11用到的I/O口
* 輸入 :無
* 輸出 :無
*/
void DHT11_GPIO_Config(void)
{
/*定義一個GPIO_InitTypeDef類型的結構體*/
GPIO_InitTypeDef GPIO_InitStructure;
/*開啟DHT11_PORT的外設時鍾*/
RCC_APB2PeriphClockCmd(DHT11_CLK, ENABLE);
/*選擇要控制的DHT11_PORT引腳*/
GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
/*設置引腳模式為通用推挽輸出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*設置引腳速率為50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*調用庫函數,初始化DHT11_PORT*/
GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
/* 拉高GPIOB10 */
GPIO_SetBits(DHT11_PORT, GPIO_Pin_10);
}
/*
* 函數名:DHT11_Mode_IPU
* 描述 :使DHT11-DATA引腳變為上拉輸入模式
* 輸入 :無
* 輸出 :無
*/
static void DHT11_Mode_IPU(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*選擇要控制的DHT11_PORT引腳*/
GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
/*設置引腳模式為浮空輸入模式*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
/*調用庫函數,初始化DHT11_PORT*/
GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
}
/*
* 函數名:DHT11_Mode_Out_PP
* 描述 :使DHT11-DATA引腳變為推挽輸出模式
* 輸入 :無
* 輸出 :無
*/
static void DHT11_Mode_Out_PP(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*選擇要控制的DHT11_PORT引腳*/
GPIO_InitStructure.GPIO_Pin = DHT11_PIN;
/*設置引腳模式為通用推挽輸出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*設置引腳速率為50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*調用庫函數,初始化DHT11_PORT*/
GPIO_Init(DHT11_PORT, &GPIO_InitStructure);
}
/*
* 從DHT11讀取一個字節,MSB先行
*/
static uint8_t Read_Byte(void)
{
uint8_t i, temp=0;
for(i=0;i<8;i++)
{
/*每bit以50us低電平標置開始,輪詢直到從機發出 的50us 低電平 結束*/
while(DHT11_DATA_IN()==Bit_RESET);
/*DHT11 以26~28us的高電平表示“0”,以70us高電平表示“1”,
*通過檢測 x us后的電平即可區別這兩個狀 ,x 即下面的延時
*/
delay_us(40); //延時x us 這個延時需要大於數據0持續的時間即可
if(DHT11_DATA_IN()==Bit_SET)/* x us后仍為高電平表示數據“1” */
{
/* 等待數據1的高電平結束 */
while(DHT11_DATA_IN()==Bit_SET);
temp|=(uint8_t)(0x01<<(7-i)); //把第7-i位置1,MSB先行
}
else // x us后為低電平表示數據“0”
{
temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0,MSB先行
}
}
return temp;
}
/*
* 一次完整的數據傳輸為40bit,高位先出
* 8bit 濕度整數 + 8bit 濕度小數 + 8bit 溫度整數 + 8bit 溫度小數 + 8bit 校驗和
*/
uint8_t Read_DHT11(DHT11_Data_TypeDef *DHT11_Data)
{
/*輸出模式*/
DHT11_Mode_Out_PP();
/*主機拉低*/
DHT11_DATA_OUT(LOW);
/*延時18ms*/
delay_ms(18);
/*總線拉高 主機延時30us*/
DHT11_DATA_OUT(HIGH);
delay_us(30); //延時30us
/*主機設為輸入 判斷從機響應信號*/
DHT11_Mode_IPU();
/*判斷從機是否有低電平響應信號 如不響應則跳出,響應則向下運行*/
if(DHT11_DATA_IN() == Bit_RESET)
{
/*輪詢直到從機發出 的80us 低電平 響應信號結束*/
while(DHT11_DATA_IN()==Bit_RESET);
/*輪詢直到從機發出的 80us 高電平 標置信號結束*/
while(DHT11_DATA_IN()==Bit_SET);
/*開始接收數據*/
DHT11_Data->humi_int= Read_Byte();
DHT11_Data->humi_deci= Read_Byte();
DHT11_Data->temp_int= Read_Byte();
DHT11_Data->temp_deci= Read_Byte();
DHT11_Data->check_sum= Read_Byte();
/*讀取結束,引腳改為輸出模式*/
DHT11_Mode_Out_PP();
/*主機拉高*/
DHT11_DATA_OUT(HIGH);
/*檢查讀取的數據是否正確*/
if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)
return SUCCESS;
else
return ERROR;
}
else
{
return ERROR;
}
}
ds18b20.h
#ifndef __DS18B20_H
#define __DS18B20_H
#include "sys.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序只供學習使用,未經作者許可,不得用於其它任何用途
//ALIENTEK戰艦STM32開發板
//DS18B20驅動代碼
//正點原子@ALIENTEK
//技術論壇:www.openedv.com
//修改日期:2012/9/12
//版本:V1.0
//版權所有,盜版必究。
//Copyright(C) 廣州市星翼電子科技有限公司 2009-2019
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////
//IO方向設置
#define DS18B20_IO_IN() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;}
#define DS18B20_IO_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;}
////IO操作函數
#define DS18B20_DQ_OUT PGout(11) //數據端口 PA0
#define DS18B20_DQ_IN PGin(11) //數據端口 PA0
u8 DS18B20_Init(void);//初始化DS18B20
short DS18B20_Get_Temp(void);//獲取溫度
void DS18B20_Start(void);//開始溫度轉換
void DS18B20_Write_Byte(u8 dat);//寫入一個字節
u8 DS18B20_Read_Byte(void);//讀出一個字節
u8 DS18B20_Read_Bit(void);//讀出一個位
u8 DS18B20_Check(void);//檢測是否存在DS18B20
void DS18B20_Rst(void);//復位DS18B20
#endif
ds18b20.c
#include "ds18b20.h"
#include "delay.h"
//////////////////////////////////////////////////////////////////////////////////
//本程序只供學習使用,未經作者許可,不得用於其它任何用途
//ALIENTEK精英STM32開發板
//DS18B20驅動代碼
//正點原子@ALIENTEK
//技術論壇:www.openedv.com
//修改日期:2012/9/12
//版本:V1.0
//版權所有,盜版必究。
//Copyright(C) 廣州市星翼電子科技有限公司 2009-2019
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////
//復位DS18B20
void DS18B20_Rst(void)
{
DS18B20_IO_OUT(); //SET PG11 OUTPUT
DS18B20_DQ_OUT=0; //拉低DQ
delay_us(750); //拉低750us
DS18B20_DQ_OUT=1; //DQ=1
delay_us(15); //15US
}
//等待DS18B20的回應
//返回1:未檢測到DS18B20的存在
//返回0:存在
u8 DS18B20_Check(void)
{
u8 retry=0;
DS18B20_IO_IN(); //SET PG11 INPUT
while (DS18B20_DQ_IN&&retry<200)
{
retry++;
delay_us(1);
};
if(retry>=200)return 1;
else retry=0;
while (!DS18B20_DQ_IN&&retry<240)
{
retry++;
delay_us(1);
};
if(retry>=240)return 1;
return 0;
}
//從DS18B20讀取一個位
//返回值:1/0
u8 DS18B20_Read_Bit(void)
{
u8 data;
DS18B20_IO_OUT(); //SET PG11 OUTPUT
DS18B20_DQ_OUT=0;
delay_us(2);
DS18B20_DQ_OUT=1;
DS18B20_IO_IN(); //SET PG11 INPUT
delay_us(12);
if(DS18B20_DQ_IN)data=1;
else data=0;
delay_us(50);
return data;
}
//從DS18B20讀取一個字節
//返回值:讀到的數據
u8 DS18B20_Read_Byte(void)
{
u8 i,j,dat;
dat=0;
for (i=1;i<=8;i++)
{
j=DS18B20_Read_Bit();
dat=(j<<7)|(dat>>1);
}
return dat;
}
//寫一個字節到DS18B20
//dat:要寫入的字節
void DS18B20_Write_Byte(u8 dat)
{
u8 j;
u8 testb;
DS18B20_IO_OUT(); //SET PG11 OUTPUT;
for (j=1;j<=8;j++)
{
testb=dat&0x01;
dat=dat>>1;
if (testb)
{
DS18B20_DQ_OUT=0; // Write 1
delay_us(2);
DS18B20_DQ_OUT=1;
delay_us(60);
}
else
{
DS18B20_DQ_OUT=0; // Write 0
delay_us(60);
DS18B20_DQ_OUT=1;
delay_us(2);
}
}
}
//開始溫度轉換
void DS18B20_Start(void)
{
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc); // skip rom
DS18B20_Write_Byte(0x44); // convert
}
//初始化DS18B20的IO口 DQ 同時檢測DS的存在
//返回1:不存在
//返回0:存在
u8 DS18B20_Init(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
DS18B20_Rst();
return DS18B20_Check();
}
//從ds18b20得到溫度值
//精度:0.1C
//返回值:溫度值 (-550~1250)
short DS18B20_Get_Temp(void)
{
u8 temp;
u8 TL,TH;
short tem;
DS18B20_Start (); // ds1820 start convert
DS18B20_Rst();
DS18B20_Check();
DS18B20_Write_Byte(0xcc); // skip rom
DS18B20_Write_Byte(0xbe); // convert
TL=DS18B20_Read_Byte(); // LSB
TH=DS18B20_Read_Byte(); // MSB
if(TH>7)
{
TH=~TH;
TL=~TL;
temp=0; //溫度為負
}else temp=1; //溫度為正
tem=TH; //獲得高八位
tem<<=8;
tem+=TL; //獲得底八位
tem=(float)tem*0.625; //轉換
if(temp)return tem; //返回溫度值
else return -tem;
}
參考用圖
DHT11




DS18B20





