在完成RA-Eco-RA6M4开发板的串口通信与OLED显示功能调试后,本次实践将进一步集成DHT11温湿度传感器,通过单总线通信实现环境温湿度的数据采集,并将采集到的信息同步通过OLED屏幕可视化展示与串口打印输出,完整实现“传感器采集-数据处理-多端呈现”的闭环功能。
DHT11是一款低成本、数字输出的温湿度复合传感器,其核心通信依赖单总线协议,仅需一根数据线即可完成主机与从机的数据交互,硬件连接简单但对通信时序要求严格。
DHT11一次通信传输40位二进制数据,采用“高位先出”格式,具体组成如下:8位湿度整数数据 + 8位湿度小数数据 + 8位温度整数数据 + 8位温度小数数据 + 8位校验位
本次硬件搭建以RA6M4开发板为核心,联动DHT11、OLED模块与串口,具体接线如下表所示,重点确保DHT11的DATA线时序稳定性。
| 器件 | 引脚/接口 | RA6M4开发板引脚 | 辅助元件 |
|---|---|---|---|
| DHT11 | VCC | 3.3V | - |
| DHT11 | GND | GND | - |
| DHT11 | DATA | P301(GPIO) | 4.7kΩ上拉电阻 |
| OLED(I2C) | SCL | P100 | - |
| OLED(I2C) | SDA | P101 | 10K上拉电阻×2 |
| OLED | VCC/GND | 3.3V/GND | - |
| 串口模块 | TX/RX | 对应UART9引脚 | - |
注意:DHT11的DATA线切勿直接接5V引脚,RA6M4的GPIO口耐受3.3V电压,错接可能损坏芯片;上拉电阻需紧贴DATA线与3.3V之间,减少信号衰减。
本次开发使用e2studio IDE,结合瑞萨FSP(Flexible Software Package)配置工具,完成引脚定义、模块初始化等基础配置,核心步骤如下:
在原有“串口+OLED”项目基础上,新增DHT11相关驱动文件,形成模块化结构,便于维护:
DHT11_demo/
├─ src/
│ ├─ dht11/ // DHT11驱动目录
│ │ ├─ bsp_dht11.c // 驱动实现(时序控制、数据读取)
│ │ └─ bsp_dht11.h // 函数声明、宏定义
│ ├─ oled/ // OLED驱动(复用原有代码)
│ ├─ uart/ // UART9驱动(复用原有代码)
│ └─ hal_entry.c // 主函数(逻辑调度)
└─ ra_cfg/ // FSP配置文件(自动生成)
通过e2studio的“Pin Selection”工具配置P301引脚(DHT11的DATA线),参数如下:
配置完成后,点击“Generate Project Content”生成引脚配置代码(g_bsp_pin_cfg)。
无需额外启用FSP的专用模块,仅通过GPIO的电平翻转与延时函数模拟单总线时序,因此重点确保以下基础模块已初始化:
UART9_Init());R_BSP_SoftwareDelay()实现微秒级/毫秒级延时(单总线时序核心)。代码设计遵循“模块化”原则:bsp_dht11.c封装DHT11的底层时序操作,hal_entry.c实现整体逻辑调度(初始化-采集-显示)。
核心功能是通过GPIO模拟单总线时序,实现“主机发起请求-从机应答-数据接收-校验”的完整流程,关键函数如下:
为简化代码,定义DATA线的电平读写宏,便于后续时序调整:
#include "hal_data.h"
// 定义DHT11的DATA引脚(P301)
#define DHT11_DATA_PORT BSP_IO_PORT_03
#define DHT11_DATA_PIN BSP_IO_PIN_01
// 电平设置宏
#define DHT11_DATA_HIGH() R_IOPORT_PinWrite(&g_ioport_ctrl, DHT11_DATA_PIN, BSP_IO_LEVEL_HIGH)
#define DHT11_DATA_LOW() R_IOPORT_PinWrite(&g_ioport_ctrl, DHT11_DATA_PIN, BSP_IO_LEVEL_LOW)
#define DHT11_DATA_READ() R_IOPORT_PinRead(&g_ioport_ctrl, DHT11_DATA_PIN)
// 函数声明
fsp_err_t DHT11_Init(void); // 初始化DHT11(发送启动信号)
fsp_err_t DHT11_ReadData(uint8_t *hum_int, uint8_t *hum_dec, uint8_t *temp_int, uint8_t *temp_dec); // 读取温湿度数据
主机通过拉低DATA线至少18ms,发起启动信号,随后释放总线等待传感器应答:
fsp_err_t DHT11_Init(void)
{
// 1. 主机拉低总线18ms以上
DHT11_DATA_LOW();
R_BSP_SoftwareDelay(20, BSP_DELAY_UNITS_MILLISECONDS); // 延时20ms,满足启动要求
// 2. 释放总线(外部上拉为高电平)
DHT11_DATA_HIGH();
R_BSP_SoftwareDelay(30, BSP_DELAY_UNITS_MICROSECONDS); // 等待30us,准备接收应答
// 3. 检测传感器应答(从机拉低总线80us)
if(DHT11_DATA_READ() == BSP_IO_LEVEL_LOW)
{
// 4. 等待应答结束(从机拉高总线80us)
while(DHT11_DATA_READ() == BSP_IO_LEVEL_LOW);
while(DHT11_DATA_READ() == BSP_IO_LEVEL_HIGH);
return FSP_SUCCESS; // 初始化成功
}
return FSP_ERR_INVALID_STATE; // 无应答,初始化失败
}
解析传感器返回的40位数据,按格式提取温湿度,并通过校验位验证有效性:
// 读取1位二进制数据(单总线位时序解析)
static uint8_t DHT11_ReadBit(void)
{
uint8_t bit = 0;
// 主机拉低5us,触发从机发送位信号
DHT11_DATA_LOW();
R_BSP_SoftwareDelay(5, BSP_DELAY_UNITS_MICROSECONDS);
DHT11_DATA_HIGH();
// 等待从机拉低总线(位起始信号)
while(DHT11_DATA_READ() == BSP_IO_LEVEL_HIGH);
// 延时26-28us:若仍为低电平,则为0;若为高电平,则为1
R_BSP_SoftwareDelay(27, BSP_DELAY_UNITS_MICROSECONDS);
if(DHT11_DATA_READ() == BSP_IO_LEVEL_HIGH) bit = 1;
// 等待位信号结束(总线拉低)
while(DHT11_DATA_READ() == BSP_IO_LEVEL_LOW);
return bit;
}
// 读取1字节数据(8位拼接)
static uint8_t DHT11_ReadByte(void)
{
uint8_t byte = 0;
for(uint8_t i=0; i<8; i++)
{
byte <<= 1; // 高位先出,左移补位
byte |= DHT11_ReadBit(); // 拼接当前位
}
return byte;
}
// 读取完整温湿度数据
fsp_err_t DHT11_ReadData(uint8_t *hum_int, uint8_t *hum_dec, uint8_t *temp_int, uint8_t *temp_dec)
{
uint8_t buf[5] = {0}; // 存储40位数据(5字节)
// 1. 先初始化(发起请求)
if(DHT11_Init() != FSP_SUCCESS)
return FSP_ERR_IO;
// 2. 读取5字节数据
for(uint8_t i=0; i<5; i++)
{
buf[i] = DHT11_ReadByte();
}
// 3. 校验数据有效性
if(buf[0] + buf[1] + buf[2] + buf[3] == buf[4])
{
*hum_int = buf[0]; // 湿度整数
*hum_dec = buf[1]; // 湿度小数
*temp_int = buf[2]; // 温度整数
*temp_dec = buf[3]; // 温度小数
return FSP_SUCCESS;
}
return FSP_ERR_DATA_CORRUPT; // 校验失败,数据无效
}
主函数负责统筹各模块初始化,通过循环实现“LED闪烁提示-温湿度采集-OLED显示-串口打印”的周期性执行:
#include "hal_data.h"
#include "bsp_dht11.h"
#include "bsp_oled.h" // OLED驱动头文件
#include "bsp_uart9.h" // UART9驱动头文件
// 全局变量:存储温湿度数据
uint8_t hum_int = 0, hum_dec = 0;
uint8_t temp_int = 0, temp_dec = 0;
void hal_entry(void)
{
// 1. 初始化GPIO(默认高电平,避免DHT11误触发)
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_03_PIN_01, BSP_IO_LEVEL_HIGH);
R_BSP_SoftwareDelay(1000, BSP_DELAY_UNITS_MILLISECONDS); // 系统稳定延时
// 2. 模块初始化
UART9_Init(); // 串口初始化
LED_Init(); // LED初始化(状态提示)
OLED_Init(); // OLED初始化
OLED_Clear(); // 清屏
// 3. OLED初始显示(标题)
OLED_ShowChinese(0, 0, 9); // 显示“瑞”
OLED_ShowChinese(16, 0, 10); // 显示“萨”
OLED_ShowString(32, 0, "RA6M4", 16); // 开发板型号
OLED_ShowString(0, 2, "TEMP: ", 16); // 温度标签
OLED_ShowString(0, 4, "HUMD: ", 16); // 湿度标签
// 4. 串口提示信息
printf("RA6M4 + DHT11 温湿度采集系统启动!\r\n");
R_BSP_SoftwareDelay(2, BSP_DELAY_UNITS_SECONDS); // 等待模块就绪
// 5. 主循环:周期性采集与显示
while(1)
{
// LED闪烁提示系统运行
LED1_ON;
LED2_ON;
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);
LED1_OFF;
LED2_OFF;
// 读取温湿度数据
if(DHT11_ReadData(&hum_int, &hum_dec, &temp_int, &temp_dec) == FSP_SUCCESS)
{
// 串口打印数据
printf("湿度:%d.%d %%RH | 温度:%d.%d ℃\r\n", hum_int, hum_dec, temp_int, temp_dec);
// OLED更新显示(仅显示整数位,简化界面)
OLED_ShowNum(64, 2, temp_int, 2, 16); // 温度整数位
OLED_ShowString(80, 2, "℃", 16);
OLED_ShowNum(64, 4, hum_int, 2, 16); // 湿度整数位
OLED_ShowString(80, 4, "%", 16);
}
else
{
printf("数据采集失败,请检查DHT11连接或时序!\r\n");
}
R_BSP_SoftwareDelay(2, BSP_DELAY_UNITS_SECONDS); // 2秒采集一次
}
#if BSP_TZ_SECURE_BUILD
R_BSP_NonSecureEnter();
#endif
}
串口调试助手持续打印有效数据,无校验失败提示,示例如下:
RA6M4 + DHT11 温湿度采集系统启动!
湿度:51.0 %RH | 温度:25.0 ℃
湿度:51.0 %RH | 温度:25.0 ℃
湿度:52.0 %RH | 温度:25.0 ℃
屏幕清晰显示“瑞萨RA6M4”标题,以及实时更新的“TEMP: 25℃”和“HUMD: 51%”,无乱码或闪烁现象。
LED1与LED2每1秒同步闪烁一次,表明系统正常运行;若DHT11连接松动,串口会打印“数据采集失败”提示,便于故障排查。
R_BSP_SoftwareDelay()延时不准(如优化等级过高),可改用定时器中断实现微秒级延时;DHT11是一款低成本、数字输出的温湿度复合传感器,其核心通信依赖单总线协议,仅需一根数据线即可完成主机与从机的数据交互,硬件连接简单但对通信时序要求严格。
DHT11一次通信传输40位二进制数据,采用“高位先出”格式,具体组成如下:8位湿度整数数据 + 8位湿度小数数据 + 8位温度整数数据 + 8位温度小数数据 + 8位校验位
本次硬件搭建以RA6M4开发板为核心,联动DHT11、OLED模块与串口,具体接线如下表所示,重点确保DHT11的DATA线时序稳定性。
| 器件 | 引脚/接口 | RA6M4开发板引脚 | 辅助元件 |
|---|---|---|---|
| DHT11 | VCC | 3.3V | - |
| DHT11 | GND | GND | - |
| DHT11 | DATA | P301(GPIO) | 4.7kΩ上拉电阻 |
| OLED(I2C) | SCL | P100 | - |
| OLED(I2C) | SDA | P101 | 10K上拉电阻×2 |
| OLED | VCC/GND | 3.3V/GND | - |
| 串口模块 | TX/RX | 对应UART9引脚 | - |
注意:DHT11的DATA线切勿直接接5V引脚,RA6M4的GPIO口耐受3.3V电压,错接可能损坏芯片;上拉电阻需紧贴DATA线与3.3V之间,减少信号衰减。
本次开发使用e2studio IDE,结合瑞萨FSP(Flexible Software Package)配置工具,完成引脚定义、模块初始化等基础配置,核心步骤如下:
在原有“串口+OLED”项目基础上,新增DHT11相关驱动文件,形成模块化结构,便于维护:
DHT11_demo/
├─ src/
│ ├─ dht11/ // DHT11驱动目录
│ │ ├─ bsp_dht11.c // 驱动实现(时序控制、数据读取)
│ │ └─ bsp_dht11.h // 函数声明、宏定义
│ ├─ oled/ // OLED驱动(复用原有代码)
│ ├─ uart/ // UART9驱动(复用原有代码)
│ └─ hal_entry.c // 主函数(逻辑调度)
└─ ra_cfg/ // FSP配置文件(自动生成)
通过e2studio的“Pin Selection”工具配置P301引脚(DHT11的DATA线),参数如下:
配置完成后,点击“Generate Project Content”生成引脚配置代码(g_bsp_pin_cfg)。
无需额外启用FSP的专用模块,仅通过GPIO的电平翻转与延时函数模拟单总线时序,因此重点确保以下基础模块已初始化:
UART9_Init());R_BSP_SoftwareDelay()实现微秒级/毫秒级延时(单总线时序核心)。代码设计遵循“模块化”原则:bsp_dht11.c封装DHT11的底层时序操作,hal_entry.c实现整体逻辑调度(初始化-采集-显示)。
核心功能是通过GPIO模拟单总线时序,实现“主机发起请求-从机应答-数据接收-校验”的完整流程,关键函数如下:
为简化代码,定义DATA线的电平读写宏,便于后续时序调整:
#include "hal_data.h"
// 定义DHT11的DATA引脚(P301)
#define DHT11_DATA_PORT BSP_IO_PORT_03
#define DHT11_DATA_PIN BSP_IO_PIN_01
// 电平设置宏
#define DHT11_DATA_HIGH() R_IOPORT_PinWrite(&g_ioport_ctrl, DHT11_DATA_PIN, BSP_IO_LEVEL_HIGH)
#define DHT11_DATA_LOW() R_IOPORT_PinWrite(&g_ioport_ctrl, DHT11_DATA_PIN, BSP_IO_LEVEL_LOW)
#define DHT11_DATA_READ() R_IOPORT_PinRead(&g_ioport_ctrl, DHT11_DATA_PIN)
// 函数声明
fsp_err_t DHT11_Init(void); // 初始化DHT11(发送启动信号)
fsp_err_t DHT11_ReadData(uint8_t *hum_int, uint8_t *hum_dec, uint8_t *temp_int, uint8_t *temp_dec); // 读取温湿度数据
主机通过拉低DATA线至少18ms,发起启动信号,随后释放总线等待传感器应答:
fsp_err_t DHT11_Init(void)
{
// 1. 主机拉低总线18ms以上
DHT11_DATA_LOW();
R_BSP_SoftwareDelay(20, BSP_DELAY_UNITS_MILLISECONDS); // 延时20ms,满足启动要求
// 2. 释放总线(外部上拉为高电平)
DHT11_DATA_HIGH();
R_BSP_SoftwareDelay(30, BSP_DELAY_UNITS_MICROSECONDS); // 等待30us,准备接收应答
// 3. 检测传感器应答(从机拉低总线80us)
if(DHT11_DATA_READ() == BSP_IO_LEVEL_LOW)
{
// 4. 等待应答结束(从机拉高总线80us)
while(DHT11_DATA_READ() == BSP_IO_LEVEL_LOW);
while(DHT11_DATA_READ() == BSP_IO_LEVEL_HIGH);
return FSP_SUCCESS; // 初始化成功
}
return FSP_ERR_INVALID_STATE; // 无应答,初始化失败
}
解析传感器返回的40位数据,按格式提取温湿度,并通过校验位验证有效性:
// 读取1位二进制数据(单总线位时序解析)
static uint8_t DHT11_ReadBit(void)
{
uint8_t bit = 0;
// 主机拉低5us,触发从机发送位信号
DHT11_DATA_LOW();
R_BSP_SoftwareDelay(5, BSP_DELAY_UNITS_MICROSECONDS);
DHT11_DATA_HIGH();
// 等待从机拉低总线(位起始信号)
while(DHT11_DATA_READ() == BSP_IO_LEVEL_HIGH);
// 延时26-28us:若仍为低电平,则为0;若为高电平,则为1
R_BSP_SoftwareDelay(27, BSP_DELAY_UNITS_MICROSECONDS);
if(DHT11_DATA_READ() == BSP_IO_LEVEL_HIGH) bit = 1;
// 等待位信号结束(总线拉低)
while(DHT11_DATA_READ() == BSP_IO_LEVEL_LOW);
return bit;
}
// 读取1字节数据(8位拼接)
static uint8_t DHT11_ReadByte(void)
{
uint8_t byte = 0;
for(uint8_t i=0; i<8; i++)
{
byte <<= 1; // 高位先出,左移补位
byte |= DHT11_ReadBit(); // 拼接当前位
}
return byte;
}
// 读取完整温湿度数据
fsp_err_t DHT11_ReadData(uint8_t *hum_int, uint8_t *hum_dec, uint8_t *temp_int, uint8_t *temp_dec)
{
uint8_t buf[5] = {0}; // 存储40位数据(5字节)
// 1. 先初始化(发起请求)
if(DHT11_Init() != FSP_SUCCESS)
return FSP_ERR_IO;
// 2. 读取5字节数据
for(uint8_t i=0; i<5; i++)
{
buf[i] = DHT11_ReadByte();
}
// 3. 校验数据有效性
if(buf[0] + buf[1] + buf[2] + buf[3] == buf[4])
{
*hum_int = buf[0]; // 湿度整数
*hum_dec = buf[1]; // 湿度小数
*temp_int = buf[2]; // 温度整数
*temp_dec = buf[3]; // 温度小数
return FSP_SUCCESS;
}
return FSP_ERR_DATA_CORRUPT; // 校验失败,数据无效
}
主函数负责统筹各模块初始化,通过循环实现“LED闪烁提示-温湿度采集-OLED显示-串口打印”的周期性执行:
#include "hal_data.h"
#include "bsp_dht11.h"
#include "bsp_oled.h" // OLED驱动头文件
#include "bsp_uart9.h" // UART9驱动头文件
// 全局变量:存储温湿度数据
uint8_t hum_int = 0, hum_dec = 0;
uint8_t temp_int = 0, temp_dec = 0;
void hal_entry(void)
{
// 1. 初始化GPIO(默认高电平,避免DHT11误触发)
R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_03_PIN_01, BSP_IO_LEVEL_HIGH);
R_BSP_SoftwareDelay(1000, BSP_DELAY_UNITS_MILLISECONDS); // 系统稳定延时
// 2. 模块初始化
UART9_Init(); // 串口初始化
LED_Init(); // LED初始化(状态提示)
OLED_Init(); // OLED初始化
OLED_Clear(); // 清屏
// 3. OLED初始显示(标题)
OLED_ShowChinese(0, 0, 9); // 显示“瑞”
OLED_ShowChinese(16, 0, 10); // 显示“萨”
OLED_ShowString(32, 0, "RA6M4", 16); // 开发板型号
OLED_ShowString(0, 2, "TEMP: ", 16); // 温度标签
OLED_ShowString(0, 4, "HUMD: ", 16); // 湿度标签
// 4. 串口提示信息
printf("RA6M4 + DHT11 温湿度采集系统启动!\r\n");
R_BSP_SoftwareDelay(2, BSP_DELAY_UNITS_SECONDS); // 等待模块就绪
// 5. 主循环:周期性采集与显示
while(1)
{
// LED闪烁提示系统运行
LED1_ON;
LED2_ON;
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS);
LED1_OFF;
LED2_OFF;
// 读取温湿度数据
if(DHT11_ReadData(&hum_int, &hum_dec, &temp_int, &temp_dec) == FSP_SUCCESS)
{
// 串口打印数据
printf("湿度:%d.%d %%RH | 温度:%d.%d ℃\r\n", hum_int, hum_dec, temp_int, temp_dec);
// OLED更新显示(仅显示整数位,简化界面)
OLED_ShowNum(64, 2, temp_int, 2, 16); // 温度整数位
OLED_ShowString(80, 2, "℃", 16);
OLED_ShowNum(64, 4, hum_int, 2, 16); // 湿度整数位
OLED_ShowString(80, 4, "%", 16);
}
else
{
printf("数据采集失败,请检查DHT11连接或时序!\r\n");
}
R_BSP_SoftwareDelay(2, BSP_DELAY_UNITS_SECONDS); // 2秒采集一次
}
#if BSP_TZ_SECURE_BUILD
R_BSP_NonSecureEnter();
#endif
}
串口调试助手持续打印有效数据,无校验失败提示,示例如下:
RA6M4 + DHT11 温湿度采集系统启动!
湿度:51.0 %RH | 温度:25.0 ℃
湿度:51.0 %RH | 温度:25.0 ℃
湿度:52.0 %RH | 温度:25.0 ℃
屏幕清晰显示“瑞萨RA6M4”标题,以及实时更新的“TEMP: 25℃”和“HUMD: 51%”,无乱码或闪烁现象。
LED1与LED2每1秒同步闪烁一次,表明系统正常运行;若DHT11连接松动,串口会打印“数据采集失败”提示,便于故障排查。
R_BSP_SoftwareDelay()延时不准(如优化等级过高),可改用定时器中断实现微秒级延时;本次实践基于RA-Eco-RA6M4开发板,成功集成DHT11温湿度传感器,核心收获包括:
后续可进一步拓展功能,如通过蓝牙模块将温湿度数据上传至手机,或添加阈值报警(当温度超过30℃时LED常亮提示)。DHT11供电波动可能导致数据跳变,可在VCC与GND间并联100nF电容滤波。
本次实践基于RA-Eco-RA6M4开发板,成功集成DHT11温湿度传感器,核心收获包括:
后续可进一步拓展功能,如通过蓝牙模块将温湿度数据上传至手机,或添加阈值报警(当温度超过30℃时LED常亮提示)。
更多回帖