瑞萨单片机论坛
直播中

jf_07365693

1年用户 379经验值
擅长:嵌入式技术 控制/MCU
私信 关注
[讨论]

【瑞萨RA6E2地奇星开发板试用】串口打印DHT11温湿度数据

dht11

【瑞萨RA6E2地奇星开发板试用】串口打印DHT11温湿度数据

本文介绍了 RA6E2 地奇星开发板驱动 DHT11 传感器实现串口打印环境温湿度数据的项目设计。

项目介绍

RA6E2 地奇星是一款基于100MHz Arm® Cortex®-M33 内核架构的核心板,主控芯片为 R7FA6E2BB3CNE;

项目包括

  • 串口配置:使能 SCI9 异步串口通信功能,实现串口测试;
  • DHT11驱动:添加基于单总线协议的 DHT11 驱动代码,获取环境温湿度数据并串口打印。

硬件连接

包括 JLINK 调试器、DHT11 模块、串口模块。

  • J-Link 调试器
RA6E2 J-Link Note
SWCLK SCL Serial Clock
SWDIO SDA Serial Data
GND GND Ground
3V3 3V3 Power

dht11_hardware_connect.jpg

  • DHT11 模块
RA6E2 DHT11 Note
P407 Data Data line
3V3 VCC Power
GND GND Ground
  • 串口模块 (JLINK CDC)
RA6E2 J-Link Note
TXD (P109) RX Transmit
RXD (P110) TX Receive
GND GND Ground

详见顶部视频。

串口配置

介绍了板载 USB 串口打印字符串的项目设计,以测试 UART 输出功能。

工程创建

  • 打开 e^2^ studio 软件;
  • 依次点击 文件 - 新建 - 瑞萨 C/C++ 项目 - Renesas RA
  • 依次进行工程命名,路径设置,FSP版本,目标开发板选择,Device 选择 R7FA6E2BB3CFM ,工具链选择 GNU ARM Embedded ,调试器选择 J-Link ;
  • 完成工程创建 ;
  • 进入 FSP 配置界面,打开 Pins 标签页,根据原理图或开发板丝印,将 P109 和 P110 引脚分别配置为 TXD9 和 RXD9 串口模式;
  • 新建串口通信堆栈 New Stack - Connectivity - UART (r_sci_uart)
  • 串口属性配置,中断和回调函数 user_uart_callback 设置;
  • 进入 BSP 标签页,配置 RA Common 属性,配置内存空间 0x2000
  • 点击 Generate Project Content 按钮,生成工程代码。

详见:【瑞萨RA6E2】ADC 电压温度计 .

工程代码

在左侧的项目目录中,打开 src/hal_entry.c 文件,添加如下关键代码

#include "hal_data.h"
#include <stdio.h>

fsp_err_t err = FSP_SUCCESS;
volatile bool uart_send_complete_flag = false;
void user_uart_callback (uart_callback_args_t * p_args)
{
    if(p_args->event == UART_EVENT_TX_COMPLETE)
    {
        uart_send_complete_flag = true;
    }
}

/*------------- 串口重定向 -------------*/
#ifdef __GNUC__
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else

#endif

PUTCHAR_PROTOTYPE
{
        err = R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)&ch, 1);
        if(FSP_SUCCESS != err) __BKPT();
        while(uart_send_complete_flag == false){}
        uart_send_complete_flag = false;
        return ch;
}

int _write(int fd,char *pBuffer,int size)
{
    for(int i=0;i<size;i++)
    {
        __io_putchar(*pBuffer++);
    }
    return size;
}

void hal_entry(void)
{
    /* TODO: add your own code here */
    err = R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);
    assert(FSP_SUCCESS == err);
    while(1){
        printf("hello world!\\n");
        R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_02, BSP_IO_LEVEL_HIGH);
        R_BSP_SoftwareDelay (50, BSP_DELAY_UNITS_MILLISECONDS);
        R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_02, BSP_IO_LEVEL_LOW);
        R_BSP_SoftwareDelay (450, BSP_DELAY_UNITS_MILLISECONDS);
    }
}

保存文件,右键项目 - 构建程序;

右键项目 - 调试项目 - 上传固件至开发板。

若报错,可右键项目进入属性界面,选择 C/C++ 构建 - 设置 - GNU Arm Cross C Linker - Miscellaneous,勾选 printf 、scanf 以及syscalls 选项。

测试效果

  • JLINK CDC UART 接收端连接开发板串口发送端 P109;
  • 运行串口调试助手,配置端口号、波特率等参数;
  • 打开串口,即可接收芯片发送的字符串;

uart_test.jpg

  • 每接收到一次消息,板载 LED 闪烁一次。

DHT11 驱动

在串口通信的基础上,使用单总线协议,驱动 DHT11 温湿度传感器,获取环境温湿度数据,并串口打印。

代码

dht11.h

新建 .../src/dht11.h 头文件,并添加如下代码

#ifndef DHT11_H_
#define DHT11_H_

#include "hal_data.h"
#include <stdio.h>

#ifndef delay_ms
#define delay_ms(x)   R_BSP_SoftwareDelay(x, BSP_DELAY_UNITS_MILLISECONDS)
#endif
#ifndef delay_1ms
#define delay_1ms(x)  R_BSP_SoftwareDelay(x, BSP_DELAY_UNITS_MILLISECONDS)
#endif
#ifndef delay_us
#define delay_us(x)   R_BSP_SoftwareDelay(x, BSP_DELAY_UNITS_MICROSECONDS)
#endif
#ifndef delay_1us
#define delay_1us(x)  R_BSP_SoftwareDelay(x, BSP_DELAY_UNITS_MICROSECONDS)
#endif

#ifndef u8
#define u8  uint8_t
#endif
#ifndef u16
#define u16 uint16_t
#endif
#ifndef u32
#define u32 uint32_t
#endif

#define DHT11_DAT_GPIO_PIN       BSP_IO_PORT_04_PIN_07  // DHT11数据引脚

// 设置DHT11输出高或低电平
#define DATA_GPIO_OUT(x)    R_IOPORT_PinWrite(&g_ioport_ctrl, DHT11_DAT_GPIO_PIN, x)

// 获取DHT11数据引脚高低电平状态
static inline bsp_io_level_t DATA_GPIO_IN(void)
{
    bsp_io_level_t p_pin_value;
    fsp_err_t err = R_IOPORT_PinRead(&g_ioport_ctrl, DHT11_DAT_GPIO_PIN, &p_pin_value);
    if(err != FSP_SUCCESS)
    {
        printf("DATA_GPIO_IN Failed!!\\r\\n");
    }
    return p_pin_value;
}

void DHT11_Init(void);
uint8_t DHT11_Read_Data(float *temperature, float *humidity);

#endif /* DHT11_H_ */

dht11.c

新建 .../src/dht11.c 源文件,并添加如下代码

#include "dht11.h"

#define DHT11_DEBUG     0       // 调试信息 1:开启 0:关闭
#define DHT11_TIMEOUT   1000    // 超时阈值

/******************************************************************
 * 函 数 名 称:DHT11_Init
 * 函 数 说 明:配置DHT11的初始化
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
******************************************************************/
void DHT11_Init(void)
{
    //调用 R_IOPORT_Open 函数来初始化 IOPORT 模块
    R_IOPORT_Open (&g_ioport_ctrl, g_ioport.p_cfg);

    /* 设置DHT11数据引脚输出高电平 */
    DATA_GPIO_OUT(1);

    delay_1ms(100); // 等待DHT11稳定
}



/******************************************************************
 * 函 数 名 称:DHT11_GPIO_Mode_OUT
 * 函 数 说 明:配置DHT11的数据引脚为输出模式
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
******************************************************************/
static void DHT11_GPIO_Mode_OUT(void)
{
    // 在运行过程中配置DHT11数据引脚为输出模式
    // 这里使用R_IOPORT_PinCfg函数配置引脚
    fsp_err_t err = R_IOPORT_PinCfg(&g_ioport_ctrl, DHT11_DAT_GPIO_PIN,
            ((uint32_t) IOPORT_CFG_DRIVE_HIGH
        | (uint32_t) IOPORT_CFG_PORT_DIRECTION_OUTPUT
        | (uint32_t) IOPORT_CFG_PORT_OUTPUT_HIGH));
    if(err != FSP_SUCCESS)
    {
        printf("DHT11_GPIO_Mode_OUT Failed!!\\r\\n");
    }
}

/******************************************************************
 * 函 数 名 称:DHT11_GPIO_Mode_IN
 * 函 数 说 明:配置DHT11的数据引脚为输入模式
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
******************************************************************/
static void DHT11_GPIO_Mode_IN(void)
{
    // 在运行过程中配置DHT11数据引脚为输入模式
    // 这里使用R_IOPORT_PinCfg函数配置引脚
    fsp_err_t err = R_IOPORT_PinCfg(&g_ioport_ctrl, DHT11_DAT_GPIO_PIN,
                    (uint32_t) IOPORT_CFG_PORT_DIRECTION_INPUT);
    if(err != FSP_SUCCESS)
    {
        printf("DHT11_GPIO_Mode_IN Failed!!\\r\\n");
    }
}


/******************************************************************
 * 函 数 名 称:DHT11_Start
 * 函 数 说 明:开始DHT11测量
 * 函 数 形 参:无
 * 函 数 返 回:无
 * 作       者:LC
 * 备       注:无
******************************************************************/
void DHT11_Start(void)
{
    DHT11_GPIO_Mode_OUT(); // 输出模式
    DATA_GPIO_OUT(1);
    DATA_GPIO_OUT(0);
    delay_ms(25);        // 保持18+ms低电平
    DATA_GPIO_OUT(1);
    delay_us(25);        // 主机释放总线

    DHT11_GPIO_Mode_IN(); // 切换输入模式
}

/******************************************************************
 * 函 数 名 称:DHT11_CheckResponse
 * 函 数 说 明:检查DHT11从机的相应是否正确
 * 函 数 形 参:无
 * 函 数 返 回:1:正确 0:错误
 * 作       者:LC
 * 备       注:无
******************************************************************/
uint8_t DHT11_CheckResponse(void)
{
    uint32_t timeout = 0;

    // 等待从机响应发送电平响应(低电平)(80µs)
    timeout = DHT11_TIMEOUT;
    while(DATA_GPIO_IN() && timeout--)
    {
        if(timeout == 0)
        {
            printf("DHT11_CheckResponse Failed[1]!!\\r\\n");
            return 0; // 失败
        }
    }

    // 等待从机响应发送电平响应(高电平)(80µs)
    timeout = DHT11_TIMEOUT;
    while((!DATA_GPIO_IN()) && timeout--)
    {
        if(timeout == 0)
        {
            printf("DHT11_CheckResponse Failed[2]!!\\r\\n");
            return 0; // 失败
        }
    }

    // 进入前导低电平
    timeout = DHT11_TIMEOUT;
    while(DATA_GPIO_IN() && timeout--)
    {
        if(timeout == 0)
        {
            printf("DHT11_CheckResponse Failed[3]!!\\r\\n");
            return 0; // 失败
        }
    }

    return 1;
}


/******************************************************************
 * 函 数 名 称:DHT11_ReadBit
 * 函 数 说 明:读取一位数据位
 * 函 数 形 参:无
 * 函 数 返 回:0 或 1
 * 作       者:LC
 * 备       注:无
******************************************************************/
uint8_t DHT11_ReadBit(void)
{
    uint8_t bit = 0;
    uint8_t timeCount = 0;
    uint32_t timeout;

    // 等待前导低电平过去
    // 等待信号线由低变高
    timeout = DHT11_TIMEOUT;
    while((!DATA_GPIO_IN()) && timeout--)
    {
        if(timeout == 0)
        {
            printf("DHT11_ReadBit Failed[1]!!\\r\\n");
            return 0;
        }
    }

    // 判断是0还是1?
    timeout = DHT11_TIMEOUT;
    while(DATA_GPIO_IN() && timeout--)
    {
        timeCount++;
        delay_us(1); // 等待1us
        if(timeout == 0)
        {
            printf("DHT11_ReadBit Failed[2]!!\\r\\n");
            return 0; // 失败
        }
    }

    // 只要大于30us的高电平即可判断为数据1
    if(timeCount >= 30)
        bit = 1; // 数据1
    else
        bit = 0; // 数据0

    return bit;

}
/******************************************************************
 * 函 数 名 称:DHT11_Read_Data
 * 函 数 说 明:根据时序读取温湿度数据
 * 函 数 形 参:
 * 函 数 返 回:0=数据校验失败  其他=错误
 * 作       者:LC
 * 备       注:无
******************************************************************/
uint8_t DHT11_Read_Data(float *temperature, float *humidity)
{
    int i;
    uint8_t data[5] = {0};
    uint64_t val = 0;

    // 开始起始信号
    DHT11_Start();

    // 检查响应是否合规
    if(0 == DHT11_CheckResponse())
    {
        printf("DHT11_CheckResponse Failed!!\\r\\n");
        return 0;
    }

    // 数据读取核心(40-bit)
    for(i = 0; i < 40; i++)
    {
        val <<= 1;
        val |= DHT11_ReadBit();
    }

    // 校验与数据提取
    data[0] = (val >> 32) & 0xFF; // 湿度整数
    data[1] = (val >> 24) & 0xFF; // 湿度小数
    data[2] = (val >> 16) & 0xFF; // 温度整数
    data[3] = (val >> 8)  & 0xFF; // 温度小数
    data[4] = val & 0xFF;         // 校验和

#if DHT11_DEBUG
    printf("data[0] = %d\\r\\n",data[0]);
    printf("data[1] = %d\\r\\n",data[1]);
    printf("data[2] = %d\\r\\n",data[2]);
    printf("data[3] = %d\\r\\n",data[3]);
    printf("data[4] = %d\\r\\n",data[4]);
#endif

    // 校验计算:前4字节和 = 第5字节
    if ((data[4] != (data[0] + data[1] + data[2] + data[3])) ||
        (data[4] == 0)) {
        printf("CheckSum Failed!!!\\r\\n");
        return 0; // 校验失败
    }

    // 保存温湿度
    *humidity    = data[0] + (data[1] * 0.1f);  // 湿度(%)
    *temperature = data[2] + (data[3] * 0.1f);  // 温度(℃)

#if DHT11_DEBUG
    printf("T: %d\\r\\n",(int)*temperature);
    printf("H: %d\\r\\n",(int)*humidity);
#endif

    return 1;
}

hal_entry.c

修改 .../src/hal_entry.c 主程序,代码如下

void hal_entry(void)
{
    /* TODO: add your own code here */
    err = R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);
    assert(FSP_SUCCESS == err);
    /* initialize DHT11 */
        DHT11_Init();

        /* 空读两次 */
        DHT11_Read_Data(NULL, NULL);
        delay_1ms(1000); // 等待DHT11稳定
        DHT11_Read_Data(NULL, NULL);
        delay_1ms(1000); // 等待DHT11稳定

        printf("\\r\\n= = = = = = = = DHT11 Demo Start = = = = = = = = =\\r\\n");

        while(1){
            float temperature = 0.0;
            float humidity = 0.0;

            if(DHT11_Read_Data(&temperature, &humidity))
            {
                printf("Temperature = %.2f, Humidity = %.2f\\r\\n", temperature, humidity);
            }
            else
            {
                printf("\\r\\nRead Error!!\\r\\n");
            }
            //printf("hello world!\\n");
            R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_02, BSP_IO_LEVEL_HIGH);
            R_BSP_SoftwareDelay (50, BSP_DELAY_UNITS_MILLISECONDS);
            R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_02, BSP_IO_LEVEL_LOW);
            R_BSP_SoftwareDelay (950, BSP_DELAY_UNITS_MILLISECONDS);
        }
}

保存代码,编译工程并调试。

效果

  • JLINK CDC UART 接收端连接开发板串口发送端 P109;
  • 运行串口调试助手,配置端口号、波特率等参数;
  • 打开串口,即可接收温湿度数据;

dht11_print.jpg

  • 每接收到一组数据,板载 LED 闪烁一次。

详见底部视频。

总结

本文介绍了瑞萨 RA6E2 地奇星开发板驱动 DHT11 传感器实现串口打印环境温湿度数据的项目设计,包括串口调试和配置、DHT11 驱动和串口输出等,为相关产品的快速开发和应用设计提供了参考。

dht11_print

更多回帖

发帖
×
20
完善资料,
赚取积分