@
目录
前言
参考资料:
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℃
",temperature/10, temperature%10);
// DHT11
// 调用Read_DHT11读取温湿度,若成功则输出该信息
if( Read_DHT11(&DHT11_Data) == SUCCESS)
{
printf("湿度为%d.%d %RH ,温度为 %d.%d℃
", 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("
湿度:%d,温度:%d
" ,DHT11_Data.humi_int,DHT11_Data.temp_int);
}
else
{
printf("Read DHT11 ERROR!
");
}
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("开启报警模式
");
break;
// KEY1 按下 关闭报警模式
case KEY0_PRES:
mode = 0;
LED1 = !LED1;
LCD_ShowString(80,260,100,12,12,"OFF ");
printf("关闭报警模式
");
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℃
",temperature/10, temperature%10);
// DHT11
// 调用Read_DHT11读取温湿度,若成功则输出该信息 采样周期不得低于1秒,否则会读取失败
if( Read_DHT11(&DHT11_Data) == SUCCESS)
{
printf("湿度为%d.%d %RH ,温度为 %d.%d℃
", 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("
湿度:%d,温度:%d
" ,DHT11_Data.humi_int,DHT11_Data.temp_int);
}
else
{
printf("Read DHT11 ERROR!
");
}
// 判断温度是否不低于85摄氏度
if(temperature >= 850 || DHT11_Data.temp_int >= 85)
{
printf("温度过高!!!
");
flag++;
}
else
{
flag--;
}
// 判断湿度是否高于90%RH
if(DHT11_Data.humi_int >= 90)
{
printf("湿度过高!!!
");
flag++;
}
else
{
flag--;
}
// 判断是否需要报警
if(flag >= 2 && mode == 1)
{
LCD_ShowString(10,200,200,16,16,"BEEP!!!(>__<)");
printf("BEEP!!!(>__<)
");
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