yinwuqing 发表于 2026-8-9 22:40:49

【瑞萨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]
查看完整版本: 【瑞萨RA-eco-RA6M4评测】FreeRTOS+NSHT30温湿度采集