一、固件库模板
见博客:stm32f103c8t6新建固件库模板(可自取)
二、准备资料
-
固件库模板
-
MDK5开发环境
-
stm32参考手册
-
利用固件库模板点灯工程(下面第三行,手动狗头)
-
OLED模块资料
-
DHT11数据手册
-
利用固件库模板点灯工程(下面第三行,手动狗头)
-
CH340 USB→TTL模块
实验程序已经发布到百度网盘,本文末有链接可以自取
stm32参考手册
串口协议查看这篇博客USART串口协议
stm32中断概念STM32中断应用概括
DHT11模块资料:DHT11
IIC协议查看这篇博客IIC协议
OLED数据手册查看SSD1306Z
字模链接 链接:https://pan.baidu.com/s/1k_ay03xnAdGChirlTpTIVA
提取码:OLED
串口调试工具 :https://pan.baidu.com/s/1V-jRJzb0INDXDLo9I4CJ6A 提取码:0000
三、DHT11 简介
DHT11是一款有已校准数字信号输出的温湿度传感器
。 其精度湿度±5%RH, 温度±2℃,量程湿度5~95%RH, 温度-20~+60℃
查看数据手册在这:DHT11
下面的解释也都是引用数据手册内容,大家可以试着自己来阅读手册,当然想快速上手看下文即可,
1. 引脚定义
标号 | PIN | 引脚说明 |
---|---|---|
1 | GND | 模块电源地 |
2 | VCC | 模块电源正 |
3 | DATA | 数据引脚 |
2. DHT11 数据结构
DHT11数字湿温度传感器采用单总线数据
格式。即,单个数据引脚端口完成输入输出双向传输。其数据包由5Byte( 40Bit)组成。数据分小数部分和整数部分,具体格式在下面说明。
一次完整的数据传输为40bit,高位先出。
数据格式:8bit湿度整数数据
+8bit湿度小数数据
+8bit温度整数数据
+8bit温度小数数据
+8bit校验和
校验和数据为前四个字节相加。
传感器数据输出的是未编码的二进制数据。数据(湿度、温度、整数、小数)之间应该分开处理。如果,某次从传感器中读取如下5Byte数据:
由以上数据就可得到湿度和温度的值,计算方法:
humi (湿度)= byte4. byte3=45.0 (%RH)
temp (温度)= byte2. byte1=28.0 (℃ )
jiaoyan(校验)= byte4+ byte3+ byte2+ byte1=73(=humi+temp)(校验正确)
注意: DHT11一次通讯时间最大3ms,主机连续采样间隔建议不小于100ms。
3. DHT11的传输时序
3.1 DHT11 开始发送数据流程
通讯过程
用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主 机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集, 用户可选择读取部分数据.从模式下,DHT11接收到开始信号触发一次温湿度采集, 如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集.
主机
发送开始信号后,延时等待 20us-40us
后读取 DHT11 的回应信号
,读取总线为低电平
,说明 DHT11 发送响应信号
, DHT11 发送响应信号后,再把总线拉高
,准备发送数据
,每一 bit 数据都以低电平开始
,格式见下面图示。如果读取响应信号为高电平,则 DHT11 没有响应,请检查线路是否连接正常。
3.2 主机复位信号和 DHT11 响应信号
3.3 数字‘ 0’信号表示方法
3.4 数字‘ 1’信号表示方法
四、OLED显示温湿度实验
1.硬件设计
GND接GND
VCC接3.3
OLED的SCL接stm32的B6(模拟IIC)
OLED的SDA接stm32的B7(模拟IIC)
DHT11的DATA接stm32的A11(普通GPIO口即可)
切记尽量避免使用PB3、PB4,具体看stm32f103c8t6使用PB3和PB4做普通GPIO使用时发现异常
硬件IIC请查看IIC协议
2.软件设计
-
使能 I2C 外设和A11的时钟;
-
配置 I2C 外设的参数并使能 I2C 外设,使能A11;
-
编写OLED初始化指令
-
编写DHT11获取数据函数
-
初始化SysTick系统定时器
2.1 复制工程 固件库模板
六、stm32-OLED
五、stm32-SysTick(系统定时器)
复制上面两个文件夹,不知道的同学可以去博客查阅
2.2 新建DHT11文件(打开工程)
2.3 编写代码
oled.c(模拟IIC)
OLED和SysTick的代码这里就不说了,相信关注我的都会手动狗头
oledfont.h
这里把使用到的中文字库也发一下吧
{0x10,0x60,0x02,0x8C,0x00,0x00,0xFE,0x92,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,0x00},
{0x04,0x04,0x7E,0x01,0x40,0x7E,0x42,0x42,0x7E,0x42,0x7E,0x42,0x42,0x7E,0x40,0x00},/*"温",0*/
{0x00,0x00,0xFC,0x24,0x24,0x24,0xFC,0x25,0x26,0x24,0xFC,0x24,0x24,0x24,0x04,0x00},
{0x40,0x30,0x8F,0x80,0x84,0x4C,0x55,0x25,0x25,0x25,0x55,0x4C,0x80,0x80,0x80,0x00},/*"度",1*/
{0x10,0x60,0x02,0x8C,0x00,0xFE,0x92,0x92,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,0x00},
{0x04,0x04,0x7E,0x01,0x44,0x48,0x50,0x7F,0x40,0x40,0x7F,0x50,0x48,0x44,0x40,0x00},/*"湿",2*/
{0x00,0x00,0xFC,0x24,0x24,0x24,0xFC,0x25,0x26,0x24,0xFC,0x24,0x24,0x24,0x04,0x00},
{0x40,0x30,0x8F,0x80,0x84,0x4C,0x55,0x25,0x25,0x25,0x55,0x4C,0x80,0x80,0x80,0x00},/*"度",3*/
{0x00,0x00,0x0C,0x12,0x12,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"°",4*/
dht11.c
#include "dht11.h"
#include "delay.h"
static void DHT11_GPIO_Config ( void );
static void DHT11_Mode_IPU ( void );
static void DHT11_Mode_Out_PP ( void );
static uint8_t DHT11_ReadByte ( void );
/**
* @brief DHT11 初始化函数
* @param 无
* @retval 无
*/
void DHT11_Init ( void )
{
DHT11_GPIO_Config ();
DHT11_Dout_1; // 拉高GPIOA11
}
/*
* 函数名:DHT11_GPIO_Config
* 描述 :配置DHT11用到的I/O口
* 输入 :无
* 输出 :无
*/
static void DHT11_GPIO_Config ( void )
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
/*开启DHT11_Dout_GPIO_PORT的外设时钟*/
DHT11_Dout_SCK_APBxClock_FUN ( DHT11_Dout_GPIO_CLK, ENABLE );
/*选择要控制的DHT11_Dout_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化DHT11_Dout_GPIO_PORT*/
GPIO_Init ( DHT11_Dout_GPIO_PORT, &GPIO_InitStructure );
}
/*
* 函数名:DHT11_Mode_IPU
* 描述 :使DHT11-DATA引脚变为上拉输入模式
* 输入 :无
* 输出 :无
*/
static void DHT11_Mode_IPU(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的DHT11_Dout_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
/*设置引脚模式为浮空输入模式*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
/*调用库函数,初始化DHT11_Dout_GPIO_PORT*/
GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);
}
/*
* 函数名:DHT11_Mode_Out_PP
* 描述 :使DHT11-DATA引脚变为推挽输出模式
* 输入 :无
* 输出 :无
*/
static void DHT11_Mode_Out_PP(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*选择要控制的DHT11_Dout_GPIO_PORT引脚*/
GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化DHT11_Dout_GPIO_PORT*/
GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);
}
static uint8_t DHT11_ReadByte(void)
{
uint8_t i, temp = 0;
for(i = 0; i < 8; i++)
{
/*每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束*/
while(DHT11_Dout_IN() == Bit_RESET);
/*DHT11 会持续26~28us的高电平表示“0”,持续70us高电平表示“1”,
*通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时
*/
Delay_us(40);
//如果40us后持续高电平
if(DHT11_Dout_IN() == Bit_SET)
{
//将高电平持续结束
while(DHT11_Dout_IN() == Bit_SET);
temp |= 0x01 << (7 - i); //把第7-i位置1,MSB先行
}
else // x us后为低电平表示数据“0”,将第7-i位置0
{
temp &= ~0x01 << (7 - i); //把第7-i位置0,MSB先行
}
}
return temp;
}
/*
* 函数名:DHT11_Read_TempAndHumidity
* 描述 :DTH11读取温湿度
* 一次完整的数据传输为40bit,高位先出
* 8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和
* 输入 :DHT11_Data
* 返回 :状态值
* 调用 :调用
*/
uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{
/********************************************************************************
* 先主机为输出模式,拉低至少18ms的信号
* 然后主机拉高20~40us的信号
* 再主机(DHT11)转为输入模式,等待响应
* 先将响应低电平通过while过滤
* 再将响应高电平通过while过滤
* 最后通过DHT11_ReadByte函数读取数据
********************************************************************************/
//输出模式
DHT11_Mode_Out_PP();
//主机拉低
DHT11_Dout_0;
//延时18MS
Delay_ms(20);
//拉高
DHT11_Dout_1;
//延时30us
Delay_us(30);
/*主机设为输入 判断从机响应信号*/
DHT11_Mode_IPU();
/*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/
if(DHT11_Dout_IN() == Bit_RESET)
{
/*轮询直到从机发出 的80us 低电平 响应信号结束*/
while(DHT11_Dout_IN() == Bit_RESET);
/*轮询直到从机发出的 80us 高电平 标置信号结束*/
while(DHT11_Dout_IN() == Bit_SET);
//8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和
DHT11_Data->humi_int = DHT11_ReadByte();
DHT11_Data->humi_deci = DHT11_ReadByte();
DHT11_Data->temp_int = DHT11_ReadByte();
DHT11_Data->temp_deci = DHT11_ReadByte();
DHT11_Data->check_sum = DHT11_ReadByte();
//读取结束将引脚改为输出模式
DHT11_Mode_Out_PP();
DHT11_Dout_1;
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;
}
dht11.h
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __DHT11_H_
#define __DHT11_H_
#include "stm32f10x.h"
#include "sys.h"
/************************** DHT11 数据类型定义********************************/
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;
#define DHT11_Dout_SCK_APBxClock_FUN RCC_APB2PeriphClockCmd
#define DHT11_Dout_GPIO_CLK RCC_APB2Periph_GPIOA
#define DHT11_Dout_GPIO_PORT GPIOA
#define DHT11_Dout_GPIO_PIN GPIO_Pin_11
/************************** DHT11 函数宏定义********************************/
#define DHT11_Dout_0 GPIO_ResetBits ( DHT11_Dout_GPIO_PORT, DHT11_Dout_GPIO_PIN )
#define DHT11_Dout_1 GPIO_SetBits ( DHT11_Dout_GPIO_PORT, DHT11_Dout_GPIO_PIN )
//读取io引脚电平
#define DHT11_Dout_IN() GPIO_ReadInputDataBit ( DHT11_Dout_GPIO_PORT, DHT11_Dout_GPIO_PIN )
/************************** DHT11 函数声明 ********************************/
void DHT11_Init ( void );
uint8_t DHT11_Read_TempAndHumidity ( DHT11_Data_TypeDef *DHT11_Data );
#endif
/******************************** END OF FILE *********************************/
main.c
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "stm32f10x.h"
#include "dht11.h"
#include "oled.h"
#include "sysTick.h"
extern int read_dht11_finish;
DHT11_Data_TypeDef DHT11_Data;
int humi_int, humi_deci, temp_int, temp_deci; //时间变量
int main()
{
/********************************************************************************
* Delay_init(); //本实验使用的是SysTick时钟
* CPU_TS_TmrInit(); //已经使能宏,不需要初始化
* uart1_init(115200); //串口初始化为115200,需要在usart.h中使能
* uart3_init(115200); //串口初始化为115200
********************************************************************************/
char cStr [ 100 ] = { 0 };
/* 初始化 */
uart1_init(115200);
DHT11_Init();
OLED_Init();
OLED_Clear();
OLED_ShowString(30, 0, "DHT11 ", 16); //输出字符
OLED_ShowCHinese(0, 4, 0); //
OLED_ShowCHinese(16, 4, 1); //
OLED_ShowString (32, 4, ":", 16); //显示温度
OLED_ShowString(48, 4, "--", 16);
OLED_ShowString (64, 4, ".", 16);
OLED_ShowCHinese(87, 4, 4); //
OLED_ShowString (93, 4, "C", 16);
OLED_ShowCHinese(0, 6, 2); //
OLED_ShowCHinese(16, 6, 3); //
OLED_ShowString (32, 6, ":", 16); //显示湿度
OLED_ShowString(48, 6, "--", 16);
OLED_ShowString(64, 6, ".", 16);
OLED_ShowString(87, 6, "%", 16);
SysTick_Init();
while(1)
{
//先去中断判断read_dht11_finish
if( read_dht11_finish ) // read_dht11_finish == 1 or read_dht11_finish == -1
{
sprintf ( cStr, "\r\n\r\n读取DHT11成功!\r\n 温度为%d.%d %,温度为 %d.%d℃ \r\n",
DHT11_Data.humi_int, DHT11_Data.humi_deci, DHT11_Data.temp_int, DHT11_Data.temp_deci );
printf ( "%s", cStr ); //打印读取 DHT11 温湿度信息
humi_int=DHT11_Data.humi_int;
humi_deci=DHT11_Data.humi_deci;
temp_int=DHT11_Data.temp_int;
temp_deci=DHT11_Data.temp_deci;
OLED_ShowNum (48, 4, temp_int, 2, 16); //显示温度
OLED_ShowNum (66, 4, temp_deci, 2, 16);
OLED_ShowNum (48, 6, humi_int, 2, 16);
OLED_ShowNum (66, 6, humi_deci, 2, 16); //显示湿度
read_dht11_finish = 0; // 清零标志位
}
}
}
3. 编译
编译成功
4. 选择烧录工具并配置MDK
本文选择的是ST_Link烧录工具
如果没有ID号看博客:ST-Link V2烧录问题(已解决)
5. 成品
文章来源:https://www.toymoban.com/news/detail-789567.html
工程链接
链接:https://pan.baidu.com/s/1FfgYGIyLy51hpx2BfJrg3g 提取码:0000文章来源地址https://www.toymoban.com/news/detail-789567.html
到了这里,关于十一、DHT11 温湿度检测(OLED显示)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!