RA4M2开发IOT(9)----动态显示MEMS数据

发布于:2025-06-24 ⋅ 阅读:(16) ⋅ 点赞:(0)

概述

本工程在瑞萨 RA4M2 单片机上,利用 0.96ʺ 128×64 OLED 实时展示多源信息,并把 涂鸦状态和LSM6DSV16X 六轴 IMU 的运动数据(单/双击、温度、三轴加速度)以“无闪烁”方式动态刷到屏幕。

最近在瑞萨RA的课程,需要样片的可以加qun申请:925643491。

在这里插入图片描述

视频教学

https://www.bilibili.com/video/BV1aENbzhEYN

RA4M2开发IOT(9)----动态显示MEMS数据

样品申请

https://www.wjx.top/vm/rCrkUrz.aspx

硬件准备

首先需要准备一个开发板,这里我准备的是自己绘制的开发板,需要的可以进行申请。
主控为R7FA4M2AD3CFL#AA0

在这里插入图片描述
同时添加RA4M2_IOT扩展版。

在这里插入图片描述

参考程序

https://github.com/CoreMaker-lab/RA4M2_IOT

https://gitee.com/CoreMaker/RA4M2_IOT

定义变量

● g_oled_clear:只在切换页面或进入特定模式时置 1,触发一次 OLED_Clear(),
之后页面内容靠覆写更新,避免闪屏。
● g_tuya_num:你用它做 100-次计数(在 1 ms 定时循环里 +1),到 100 (~100 ms) 再刷新页面一次,减少 I²C 带宽。

/* ==================  OLED Page Control  ================== */
static uint8_t g_oled_clear = 1;   // 1=需要清屏;0=正常增量刷新
static uint8_t g_oled_page  = 0;   // 当前页索引:0-Tuya 1-MEMS 2-Baro
static uint8_t g_tuya_num   = 0;   // 100ms 级计数器,用来节流页面刷新
AC
/* —— Tuya(涂鸦)配网状态 —— */
static uint8_t  g_tuya_ap_mode      = 0;  // 1=处于 AP 快配;0=普通
static uint32_t g_tuya_ap_mode_num  = 0;  // AP 模式剩余倒计时 (ms)

在这里插入图片描述

轻触切屏

在button_wifi_ap长按配网添加轻触切屏

/*******************************************************************************************************************
 * @brief 长按按键 3 s 进入配网模式 (发送 0x05 命令)
 *******************************************************************************************************************/
static void button_wifi_ap(void)
{
    //  wifi_ap_num
    bsp_io_level_t p_port_value_pin_111;
    R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_01_PIN_11, &p_port_value_pin_111);
    if(p_port_value_pin_111)/* 松开 */
        wifi_ap_num=0;
    else//长按3s复位wifi
    {
        if(wifi_ap_num<3000)
            wifi_ap_num++;
        else if(wifi_ap_num==3000)
        {
            g_oled_clear=1;// 切屏前清屏
            g_oled_page=0;// 0-Tuya 1-MEMS 2-Baro

            g_tuya_ap_mode_num=60*1*1000;//1分钟AP配网
            wifi_ap_num++;
            printf("[BTN] wifi_ap_mode\r\n");
            fsp_err_t err = R_SCI_UART_Write(&g_uart0_ctrl, g_tuya_wifi_cfg, 8);
            if(FSP_SUCCESS != err) __BKPT();
            while(uart_wifi_TX_flag == false){}
            uart_wifi_TX_flag = false;
        }

        if(wifi_ap_num==100)//轻触切换OLED显示
        {
            g_oled_clear=1;// 下一帧先清屏
            if(g_oled_page<2)// 0-Tuya 1-MEMS 2-Baro
                g_oled_page++;
            else
                g_oled_page=0;

        }
    }
}

在这里插入图片描述

静态标签

在检测到 g_oled_page 变化时——由 button_wifi_ap() 轻触切换或上电初始化——一次性绘制对应页面的静态标签(页标题、固定字段名)。
只要 g_oled_clear == 1 就清屏并绘骨架;随后动态数值由各 OLED_DrawPage_* 覆写,不闪烁。

static void OLED_switch(void)
{
    if (g_oled_clear)                     // ← 仅当需切屏时进入
    {
        g_oled_clear = 0;                 // 标记已完成清屏
        OLED_Clear();                     // ① 清显存并刷新,黑场一次

        switch (g_oled_page)              // ② 根据当前页写“标签”
        {
            /* ---------- Page-0 : Tuya 模组 ---------- */
            case 0:
                OLED_ShowString(0,  0, (u8 *)"TUYA",       16,1);
                OLED_ShowString(0, 16, (u8 *)"WIFI MODE:", 16,1);
                OLED_ShowString(0, 32, (u8 *)"AP MODE:",   16,1);
                break;

            /* ---------- Page-1 : LSM6DSV16X ---------- */
            case 1:
                OLED_ShowString(0,  0, (u8 *)"MEMS_LSM6DSV16X", 12,1);
                OLED_ShowString(0, 12, (u8 *)"TAP:",   12,1);
                OLED_ShowString(60,12, (u8 *)"TEMP:",  12,1);
                OLED_ShowString(0, 24, (u8 *)"X(mg):", 12,1);
                OLED_ShowString(0, 36, (u8 *)"Y(mg):", 12,1);
                OLED_ShowString(0, 48, (u8 *)"Z(mg):", 12,1);
                break;

            /* ---------- Page-2 : LPS22DF 气压计 ------- */
            case 2:
                OLED_ShowString(0,  0, (u8 *)"MEMS_LPS22DF", 12,1);
                break;
        }
        OLED_Refresh();                   // ③ 推送骨架到屏幕
    }
}

在这里插入图片描述

涂鸦界面

在 Page-0 下周期性(每 100×1 ms ≈ 100 ms)刷新两行动态信息:
● AP MODE 行:显示 AP 或 normal
● WIFI MODE 行:显示 g_tuya_mode_flag(0~4)。
同时根据 g_tuya_mode_flag 控制 60 s AP 配网倒计时,使文字在倒计时结束后回到 normal。

/* ------------ Page-0 : TUYA 模组信息 -------------------------------- */

static void OLED_DrawPage_TUYA(void)
{
    /* ① 管理倒计时 ── 在线时清零;否则每 1 ms 递减 */
    if (g_tuya_mode_flag == 4)                // 4 = 已连云
        g_tuya_ap_mode_num = 0;
    else if (g_tuya_ap_mode_num > 0)
        g_tuya_ap_mode_num--;

    /* ② 100 ms 节流:g_tuya_num 递增至 100 再刷新一次 */
    if (++g_tuya_num >= 100)
    {
        g_tuya_num = 0;

        /* --- 行1: AP/normal --- */
        if (g_tuya_ap_mode_num > 0)           // 倒计时仍在 → AP
            OLED_ShowString(80,16,(u8 *)"AP    ",16,1);
        else                                  // 否则 normal
            OLED_ShowString(80,16,(u8 *)"normal",16,1);

        /* --- 行2: Wi-Fi work-mode 数字标志 --- */
        OLED_ShowNum(80, 32, g_tuya_mode_flag, 1, 16,1);

        OLED_Refresh();                       // 推送局部变更
    }
}

在这里插入图片描述

LSM6DSV16X界面

在 Page-1 下每 100 ms 刷新:

  1. 单/双击状态文本 (up_down)
  2. 片内温度 (temperature_degC)
  3. X/Y/Z 三轴加速度(mg,带符号,小数点后两位)
/* ------------ Page-1 : MEMS_LSM6DSV16X -------------------------- */
static void OLED_DrawPage_MEMS(void)
{
    if(g_tuya_num<100)
    g_tuya_num++;
    else
    {
        g_tuya_num=0;
        /* ---------- 1. TAP 状态 ---------- */
        if(up_down==0)
            OLED_ShowString(24, 12, "Normal", 12, 1);//在坐标 (24,12)
        else if(up_down==1)
            OLED_ShowString(24, 12, "Single", 12, 1);//在坐标 (24,12)
        else if(up_down==2)
            OLED_ShowString(24, 12, "Double", 12, 1);//在坐标 (24,12)
        /* ---------- 2. 读取并显示片内温度 ---------- */
        int16_t data_raw_temperature;
        double_t temperature_degC;
        /* Read temperature data */
        memset(&data_raw_temperature, 0x00, sizeof(int16_t));// 清空原始数据缓存
        // 读取 LSM6DSV16X 的原始温度数据
        lsm6dsv16x_temperature_raw_get(&dev_ctx, &data_raw_temperature);
        // 将原始 LSB 数据转换为摄氏温度
        temperature_degC = lsm6dsv16x_from_lsb_to_celsius(
                                 data_raw_temperature);
        OLED_ShowNum  (90, 12,(uint32_t)temperature_degC, 3, 12, 1);// 整数位
        OLED_ShowChar (110, 12, '.',12, 1);
        uint32_t t100 = (uint32_t)(temperature_degC * 100);
        OLED_ShowNum  (116, 12,(uint32_t)t100%100, 2, 12, 1);// 整数位

        /* ---------- 3. 读取并显示 X/Y/Z 加速度 ---------- */
        int16_t data_raw_acceleration[3];
        double_t acceleration_mg[3];
        lsm6dsv16x_acceleration_raw_get(&dev_ctx, data_raw_acceleration);
        acceleration_mg[0] =
                lsm6dsv16x_from_fs8_to_mg(data_raw_acceleration[0]);
        acceleration_mg[1] =
                lsm6dsv16x_from_fs8_to_mg(data_raw_acceleration[1]);
        acceleration_mg[2] =
                lsm6dsv16x_from_fs8_to_mg(data_raw_acceleration[2]);

        if(acceleration_mg[0]<0)
            OLED_ShowChar (36, 24, '-',12, 1);
        else
            OLED_ShowChar (36, 24, '+',12, 1);
        OLED_ShowNum (42, 24,(uint32_t)fabs(acceleration_mg[0]),5,12, 1);
        OLED_ShowChar (72, 24, '.',12, 1);
        t100=(uint32_t)(fabs(acceleration_mg[0])*100);
        OLED_ShowNum (78, 24,(uint32_t)t100%100,2,12, 1);

        if(acceleration_mg[1]<0)
            OLED_ShowChar (36, 36, '-',12, 1);
        else
            OLED_ShowChar (36, 36, '+',12, 1);
        OLED_ShowNum (42, 36,(uint32_t)fabs(acceleration_mg[1]),5,12, 1);
        OLED_ShowChar (72, 36, '.',12, 1);
        t100=(uint32_t)(fabs(acceleration_mg[1])*100);
        OLED_ShowNum (78, 36,(uint32_t)t100%100,2,12, 1);

        if(acceleration_mg[2]<0)
            OLED_ShowChar (36, 48, '-',12, 1);
        else
            OLED_ShowChar (36, 48, '+',12, 1);
        OLED_ShowNum (42, 48,(uint32_t)fabs(acceleration_mg[2]),5,12, 1);
        OLED_ShowChar (72, 48, '.',12, 1);
        t100=(uint32_t)(fabs(acceleration_mg[2])*100);
        OLED_ShowNum (78, 48,(uint32_t)t100%100,2,12, 1);
        OLED_Refresh();
//        printf("Acceleration [mg]:%4.2f\t%4.2f\t%4.2f\r\n",
//                acceleration_mg[0], acceleration_mg[1], acceleration_mg[2]);

    }
}

在这里插入图片描述

主程序

hal_entry() 的主循环中,负责把 MCU 采集到的实时传感器/通信状态 动态绘制到 0.96ʺ OLED——并确保在不同功能页之间平滑切换、无闪烁。

        //切屏完成后不再清屏,保持增量刷新,避免闪烁
        OLED_switch();
        if(g_oled_page==0) /* Page-0 : Tuya 状态页 */
            OLED_DrawPage_TUYA();// 显示 Wi-Fi / AP 配网信息
        else if(g_oled_page==1)/* Page-1 : LSM6DSV16X 状态页 */
            OLED_DrawPage_MEMS();// 显示单/双击、温度、XYZ 加速度

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到