【瑞萨RA-eco-RA6M4评测】FreeRTOS+NSHT30温湿度采集
本帖最后由 yinwuqing 于 2026-8-9 22:53 编辑承接上期的https://www.eefocus.com/forum/thread-236031-1-1.html 驱动LCD屏篇,实现了FreeRTOS下的线程创建。本期分享一下,在原工程中增加一个线程,对外扩展板上的NSHT30温湿度传感器进行室内温湿度值的采样。并将采样的结果实时显示在LCD彩屏上。本次采用IIC硬件驱动方式驱动NSHT30传感器。
同样的,首先咱们直接上实物连接示意图。
NSHT30温湿度传感器是基于IIC通信接口,在扩展板上的电路原理图如下:
RA-Eco-RA6M4 v2.0开发板上的接口原理图如下:
由上图可知,P113连接SCL2,P112连接SDA2,可通过杜邦线连接GPIO2_02与GPIO2_03引脚。硬件接口连接关系如下:
硬件接口连接确定后,接下来在原“FreeRTOS_Project”工程中,通过Keil中添加调用FSP的入口,打开FSP工具。
然后将P113、P112配置成IIC2的信号脚,并在Stacks中添加SCI I2C Master驱动,回调函数名设置为“sci_i2c_master_callback”,另外添加一个线程。部分设置信息如下:
点击生成代码后,关闭FSP,再回到Keil工程中,再次编译时,提示是否更新代码进行编译,选择“是”。
结合FSP中配置的接口信息,完善IIC驱动代码与应用逻辑处理函数。
new_thread2_entry.c
#include "new_thread2.h"
#include "lcd_init.h"
#include "lcd.h"
#include "nsht30.h"
FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER
fsp_err_t err;
int timeout_ms = 10000;
i2c_master_event_t i2c_event;
/* I2C callback function */
void sci_i2c_master_callback(i2c_master_callback_args_t *p_args)
{
i2c_event = I2C_MASTER_EVENT_ABORTED;
if (NULL != p_args) {
i2c_event = p_args->event;
}
}
/* New Thread entry function */
/* pvParameters contains TaskHandle_t */
void new_thread2_entry(void * pvParameters)
{
FSP_PARAMETER_NOT_USED(pvParameters);
uint8_t ret;
NSHT30_Init();
/* TODO: add your own code here */
while(1)
{
/* 读取温湿度数据 */
ret = NSHT30_ReadData();
if (ret == 1) {
LCD_ShowFloatNum1(88,74,nsht30_temperature,4,RED,WHITE,12);
LCD_ShowFloatNum1(88,94,nsht30_humidity,4,RED,WHITE,12);
} else {
LCD_ShowString(84,74,(uint8_t *)"GetFail",RED,WHITE,12,0);
LCD_ShowString(84,94,(uint8_t *)"GetFail",RED,WHITE,12,0);
}
vTaskDelay(400);
}
}nsht30.h
#ifndef NSHT30_H
#define NSHT30_H
#include <stdint.h>
#define NSHT30_I2C_ADDR 0x44 // 7位地址
#define NSHT30_CMD_MEASURE 0x2400 // 单次测量,高重复性
#define NSHT30_MEASURE_DELAY_MS 20 // 转换等待时间 (典型 1.5ms)
extern float nsht30_temperature;
extern float nsht30_humidity;
void NSHT30_Init(void);
uint8_t NSHT30_ReadData(void); // 返回1成功,0失败
#endif
nsht30.c
#include "nsht30.h"
#include "hal_data.h"
#include <string.h>
/* 引用全局变量 */
extern int timeout_ms;
extern i2c_master_event_t i2c_event;
float nsht30_temperature = 0.0f;
float nsht30_humidity = 0.0f;
static uint8_t rx_buf = {0};
/**
* @brief 发送I2C命令
*/
static uint8_t NSHT30_SendCmd(uint16_t cmd)
{
fsp_err_t err;
uint8_t buf;
buf = (cmd >> 8) & 0xFF;
buf = cmd & 0xFF;
i2c_event = I2C_MASTER_EVENT_ABORTED;
R_SCI_I2C_SlaveAddressSet(&g_i2c2_ctrl, NSHT30_I2C_ADDR, I2C_MASTER_ADDR_MODE_7BIT);
err = R_SCI_I2C_Write(&g_i2c2_ctrl, buf, 2, false);
if (err != FSP_SUCCESS) {
return 0;
}
/* 等待发送完成,带超时 */
timeout_ms = 10000;
while ((i2c_event != I2C_MASTER_EVENT_TX_COMPLETE) && (timeout_ms > 0)) {
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
timeout_ms--;
}
if (i2c_event == I2C_MASTER_EVENT_ABORTED || timeout_ms == 0) {
i2c_event = I2C_MASTER_EVENT_ABORTED;
return 0;
}
i2c_event = I2C_MASTER_EVENT_ABORTED;
return 1;
}
/**
* @brief 读取I2C数据
*/
static uint8_t NSHT30_ReadBytes(uint8_t *data, uint8_t len)
{
fsp_err_t err;
/* 复位事件标志 */
i2c_event = I2C_MASTER_EVENT_ABORTED;
/* 再次设置地址 */
R_SCI_I2C_SlaveAddressSet(&g_i2c2_ctrl, NSHT30_I2C_ADDR, I2C_MASTER_ADDR_MODE_7BIT);
err = R_SCI_I2C_Read(&g_i2c2_ctrl, data, len, false);
if (err != FSP_SUCCESS) {
return 0;
}
timeout_ms = 10000;
while ((i2c_event != I2C_MASTER_EVENT_RX_COMPLETE) && (timeout_ms > 0)) {
R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
timeout_ms--;
}
if (i2c_event == I2C_MASTER_EVENT_ABORTED || timeout_ms == 0) {
i2c_event = I2C_MASTER_EVENT_ABORTED;
return 0;
}
i2c_event = I2C_MASTER_EVENT_ABORTED;
return 1;
}
/**
* @brief 初始化NSHT30
*/
void NSHT30_Init(void)
{
/* 打开I2C总线 */
R_SCI_I2C_Open(&g_i2c2_ctrl, &g_i2c2_cfg);
/* 等待总线稳定,传感器上电后需要时间准备 */
R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);
/* 发送一次软复位命令 */
uint8_t reset_cmd = {0x30, 0xA2};
R_SCI_I2C_SlaveAddressSet(&g_i2c2_ctrl, NSHT30_I2C_ADDR, I2C_MASTER_ADDR_MODE_7BIT);
R_SCI_I2C_Write(&g_i2c2_ctrl, reset_cmd, 2, false);
R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);
i2c_event = I2C_MASTER_EVENT_ABORTED;
}
/**
* @brief 读取温湿度数据
* @retval 1 成功,0 失败
*/
uint8_t NSHT30_ReadData(void)
{
uint16_t raw_temp, raw_humid;
/* 1. 发送单次测量命令(0x2400) */
if (!NSHT30_SendCmd(NSHT30_CMD_MEASURE)) {
return 0;
}
/* 2. 等待传感器转换完成 */
R_BSP_SoftwareDelay(NSHT30_MEASURE_DELAY_MS, BSP_DELAY_UNITS_MILLISECONDS);
/* 3. 读取6字节数据 */
memset(rx_buf, 0, sizeof(rx_buf));
if (!NSHT30_ReadBytes(rx_buf, 6)) {
return 0;
}
/* 4. 检查数据是否有效 */
if (rx_buf == 0 && rx_buf == 0 && rx_buf == 0 && rx_buf == 0) {
return 0;// 数据无效,可能通信失败
}
/* 5. 解析数据(大端格式:高字节在前) */
raw_temp= ((uint16_t)rx_buf << 8) | rx_buf;
raw_humid = ((uint16_t)rx_buf << 8) | rx_buf;
/* 6. 转换为物理值 */
nsht30_temperature = -45.0f + 175.0f * ((float)raw_temp / 65535.0f);
nsht30_humidity = 100.0f * ((float)raw_humid / 65535.0f);
return 1;
} 另外在LCD显示的线程中,对字符摆放内容及位置进行稍作修改。
new_thread1_entry.c
#include "new_thread1.h"
#include "lcd_init.h"
#include "lcd.h"
#include "pic.h"
typedef struct
{
unsigned char Index;
unsigned char Msk;
}typFNT_GB16;
extern const typFNT_GB16 tfont16[];
typedef struct
{
unsigned char Index;
unsigned char Msk;
}typFNT_GB12;
extern const typFNT_GB12 tfont12[];
void Display_text(void)
{
LCD_ShowIntNum(8,10,2026,4,RED,WHITE,16);
LCD_ShowString(44,10,(uint8_t *)"Renesas",RED,WHITE,16,0);
LCD_ShowChinese(8,30,(uint8_t *)&tfont16,RED,WHITE,16,0); //与
LCD_ShowChinese(24,30,(uint8_t *)&tfont16,RED,WHITE,16,0); //非
LCD_ShowChinese(40,30,(uint8_t *)&tfont16,RED,WHITE,16,0); //网
LCD_ShowChinese(56,30,(uint8_t *)&tfont16,RED,WHITE,16,0); //技
LCD_ShowChinese(72,30,(uint8_t *)&tfont16,RED,WHITE,16,0); //术
LCD_ShowChinese(88,30,(uint8_t *)&tfont16,RED,WHITE,16,0); //论
LCD_ShowChinese(104,30,(uint8_t *)&tfont16,RED,WHITE,16,0); //坛
LCD_ShowString(8,50,(uint8_t *)"RA-Eco-RA6M4 v2.0",BLUE,WHITE,12,0);
LCD_ShowString(60,140,(uint8_t *)"2026-8-9",BLUE,WHITE,16,0);
}
/* New Thread entry function */
/* pvParameters contains TaskHandle_t */
void new_thread1_entry(void * pvParameters)
{
uint16_t cnt = 0;
FSP_PARAMETER_NOT_USED(pvParameters);
LCD_Init();
LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
vTaskDelay(500);
Display_text();
LCD_ShowChinese(8,72,(uint8_t *)&tfont16,BLACK,WHITE,16,0); //当
LCD_ShowChinese(24,72,(uint8_t *)&tfont16,BLACK,WHITE,16,0);//前
LCD_ShowChinese(40,72,(uint8_t *)&tfont16,BLACK,WHITE,16,0);//温
LCD_ShowChinese(56,72,(uint8_t *)&tfont16,BLACK,WHITE,16,0); //度
LCD_ShowChinese(72,72,(uint8_t *)&tfont16,BLACK,WHITE,16,0); //:
LCD_ShowChinese(8,92,(uint8_t *)&tfont16,BLACK,WHITE,16,0); //当
LCD_ShowChinese(24,92,(uint8_t *)&tfont16,BLACK,WHITE,16,0);//前
LCD_ShowChinese(40,92,(uint8_t *)&tfont16,BLACK,WHITE,16,0); //湿
LCD_ShowChinese(56,92,(uint8_t *)&tfont16,BLACK,WHITE,16,0); //度
LCD_ShowChinese(72,92,(uint8_t *)&tfont16,BLACK,WHITE,16,0); //:
/* TODO: add your own code here */
while(1)
{
cnt++;
LCD_ShowIntNum(8,140,cnt,4,RED,WHITE,16);
vTaskDelay(1000);
}
} 工程编译完后,直接使用JLink将程序更新到开发板中,采集的温湿度值显示在LCD屏上,带两位小数点浮点显示,实时采集非常流畅。虽然已经立秋,但南方还是火热的很,室内温度维持在31℃左右,湿度也挺高的。使用手指去触摸NSHT30温湿度传感器表面,采集的温湿度值变化灵敏,挪开手指,数值慢慢回落到室内温湿度值,其原视频展示见哔哩哔哩。
https://www.bilibili.com/video/BV1YWu261EUd/
页:
[1]