RA4M2开发IOT(5)----读取单双击

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

概述

在上章读取MEMS基础上,我们去识别 单击 与 双击,为后续菜单切换、模式切换等人机交互做铺垫。

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

视频教学

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

RA4M2开发IOT(5)----读取单双击

样品申请

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

硬件准备

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

在这里插入图片描述

参考程序

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

https://gitee.com/CoreMaker/RA4M2_IOT

中断设置

MEMS传感小板原理图如下所示。

在这里插入图片描述

本文使用的转接板原理图如下所示。

在这里插入图片描述
其中MEMS接入RA4M2端口如下所示,INT1接入的是P000。

在这里插入图片描述

在“New Stack”下选择Input > External IRQ (r_icu)。

在这里插入图片描述

模块配置如下所示。
● Name:g_external_irq6,这是该外部中断的名称。
● Channel:选择了6通道。
● Trigger:触发方式设置为Rising(上升沿触发),即信号上升时触发中断。
● Digital Filtering:未启用数字滤波(Not Supported)。
● Digital Filtering Sample Clock:由于数字滤波未启用,因此该项也未支持。
● Callback:指定了回调函数external_irq6_callback。当中断触发时,将调用此函数处理具体逻辑。
● Pin Interrupt Priority:设置为Priority 2,表示该中断的优先级为2。
● IRQ06:映射到引脚P000,即该中断信号通过引脚P000触发。

在这里插入图片描述

配置中断脚。

在这里插入图片描述

实际测试INT管脚触发单击和双击的波形如下所示。
在这里插入图片描述

中断回调函数

● external_irq6_callback函数是外部中断的回调函数,当中断触发时,icu_irq_isr中断服务程序会调用此函数。
● irq_flag变量在每次中断时赋值为1。

bool irq_flag =0;
/* Called from icu_irq_isr */
void external_irq6_callback (external_irq_callback_args_t * p_args)
{
    (void) p_args;
    irq_flag = 1;
}

在这里插入图片描述

使能中断

    // 打开外部中断通道(用于接收 LSM6DSV16X 的中断输出)
    fsp_err_t err = R_ICU_ExternalIrqOpen(&g_external_irq6_ctrl, &g_external_irq6_cfg);
    assert(FSP_SUCCESS == err);

    err = R_ICU_ExternalIrqEnable(&g_external_irq6_ctrl);
    assert(FSP_SUCCESS == err);

在这里插入图片描述

修改变量定义

#define SENSOR_BUS g_i2c2_ctrl

/* Private macro -------------------------------------------------------------*/
#define    BOOT_TIME            10 //ms

/* Private variables ---------------------------------------------------------*/
static uint8_t whoamI;
static uint8_t tx_buffer[1000];

static lsm6dsv16x_interrupt_mode_t irq;
static lsm6dsv16x_tap_detection_t tap;
static lsm6dsv16x_tap_thresholds_t tap_ths;
static lsm6dsv16x_tap_time_windows_t tap_win;

/* Extern variables ----------------------------------------------------------*/
lsm6dsv16x_all_sources_t status;
lsm6dsv16x_pin_int_route_t pin_int;
lsm6dsv16x_reset_t rst;
/* Private functions ---------------------------------------------------------*/
/*
 *   WARNING:
 *   Functions declare in this section are defined at the end of this file
 *   and are strictly related to the hardware platform used.
 *
 */
static int32_t platform_write(void *handle, uint8_t reg, const uint8_t *bufp,
                              uint16_t len);
static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp,
                             uint16_t len);
static void tx_com( uint8_t *tx_buffer, uint16_t len );
static void platform_delay(uint32_t ms);
static void platform_init(void *handle);

static stmdev_ctx_t dev_ctx;
static uint8_t stap_event_catched = 0;
static uint8_t dtap_event_catched = 0;

修改初始化

在主程序中部修改对应的初始化。

    /* =========================
     *  LSM6DSV16X 单/双击检测示例
     * ========================= */
    lsm6dsv16x_reset_t rst;
    stmdev_ctx_t dev_ctx;
    /* Initialize mems driver interface */
    dev_ctx.write_reg = platform_write;
    dev_ctx.read_reg = platform_read;
    dev_ctx.mdelay = platform_delay;
    dev_ctx.handle = &SENSOR_BUS;

    /* Init test platform */
//    platform_init(dev_ctx.handle);
    /* ---------- 2. 传感器上电后延时 ---------- */
    platform_delay(BOOT_TIME);

    /* ---------- 3. 读取并校验芯片 ID ---------- */
    lsm6dsv16x_device_id_get(&dev_ctx, &whoamI);
    printf("LSM6DSV16X_ID=0x%x,whoamI=0x%x\n",LSM6DSV16X_ID,whoamI);
    if (whoamI != LSM6DSV16X_ID)
      while (1);

    /* ---------- 4. 恢复默认寄存器配置 ---------- */
    lsm6dsv16x_reset_set(&dev_ctx, LSM6DSV16X_RESTORE_CTRL_REGS);
    do {
      lsm6dsv16x_reset_get(&dev_ctx, &rst);
    } while (rst != LSM6DSV16X_READY);

    /* ---------- 5. 使能 Block Data Update ---------- */
    lsm6dsv16x_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);

    /* ========== 6. Tap / Double-Tap 中断配置 ========== */
    /* 6-1 路由单击 & 双击事件到 INT1 引脚 */
    pin_int.double_tap = PROPERTY_ENABLE;// 使能“双击”事件
    pin_int.single_tap = PROPERTY_ENABLE;// 使能“单击”事件
    lsm6dsv16x_pin_int1_route_set(&dev_ctx, &pin_int);
    // 若想用 INT2,可调用 lsm6dsv16x_pin_int2_route_set(&dev_ctx, &pin_int);
    //lsm6dsv16x_pin_int2_route_set(&dev_ctx, &pin_int);

    /* 6-2 打开功能中断总开关 & 选择脉冲模式 */
    irq.enable = 1;// FUNCTIONS_ENABLE.INTERRUPTS_ENABLE = 1
    irq.lir = 0;// TAP_CFG0.LIR = 0 → 脉冲输出
    lsm6dsv16x_interrupt_enable_set(&dev_ctx, irq);

    /* 6-3 选择参与 Tap 检测的轴(此处仅启用 Z 轴) */
    tap.tap_z_en = 1;
    lsm6dsv16x_tap_detection_set(&dev_ctx, tap);

    /* 6-4 设置 Z 轴阈值(3 LSB ≈ 186 mg @ ±8 g) */
    tap_ths.z = 3;
    lsm6dsv16x_tap_thresholds_set(&dev_ctx, tap_ths);

    /* 6-5 设置时间窗:SHOCK / QUIET / DUR
     *   - SHOCK = 3  → 约 58 ms   (峰值持续窗口)
     *   - QUIET = 3  → 约 29 ms   (第一次敲击后的静默期)
     *   - tap_gap= 7 → 约 500 ms  (双击最大间隔)
     *   公式基于 ODR = 480 Hz
     */
    tap_win.tap_gap = 7;
    tap_win.shock = 3;
    tap_win.quiet = 3;
    lsm6dsv16x_tap_time_windows_set(&dev_ctx, tap_win);

    /* 6-6 同时启用单击 + 双击识别 */
    lsm6dsv16x_tap_mode_set(&dev_ctx, LSM6DSV16X_BOTH_SINGLE_DOUBLE);

    /* ========== 7. 加速度计工作参数 ========== */
    /* 7-1 采样率:480 Hz(官方建议 ≥400 Hz 以保证 Tap 检测精度)*/
    lsm6dsv16x_xl_data_rate_set(&dev_ctx, LSM6DSV16X_ODR_AT_480Hz);
    /* 7-2 量程:±8 g(每 LSB ≈ 62 mg,兼顾灵敏度与范围)*/
    lsm6dsv16x_xl_full_scale_set(&dev_ctx, LSM6DSV16X_8g);

在这里插入图片描述

启用单/双击中断输出

把“单击 / 双击”事件从 TAP_SRC 路由到 INT1 脚,后面只需读寄存器即可清除中断状态。寄存器位定义见 MD1_CFG 。

    pin_int.double_tap = PROPERTY_ENABLE;
    pin_int.single_tap = PROPERTY_ENABLE;
    lsm6dsv16x_pin_int1_route_set(&dev_ctx, &pin_int);
    //lsm6dsv16x_pin_int2_route_set(&dev_ctx, &pin_int);

只要内部 “Tap 检测单元” 判定出单击/双击,就会让 MD1_CFG 对应位 =1 , INT1 引脚的输出逻辑,形成中断脉冲(或锁存电平,取决于 LIR 设置)。

在这里插入图片描述

在这里插入图片描述

启用功能中断并配置脉冲模式

打开 LSM6DSV16X 的“功能中断”总开关(irq.enable = 1),选择将中断以 脉冲模式 输出而非锁存(irq.lir = 0),把这两个设置写入芯片寄存器,使单/双击等事件真的能在 INT 引脚上产生脉冲。

    irq.enable = 1;
    irq.lir = 0;
    lsm6dsv16x_interrupt_enable_set(&dev_ctx, irq);

在这里插入图片描述
只有把 INTERRUPTS_ENABLE = 1,基本功能中断(Tap、6D/4D、Free-fall、Wake-up、Inactivity)才会被内部逻辑送往 MD1_CFG / MD2_CFG,再到 INT1/INT2。
若忘记这一步,即使 MD1_CFG 已经启用单击/双击,INT 引脚也不会有任何跳变。

在这里插入图片描述

脉冲 / 锁存 选择

  • 0 (默认):脉冲模式 → INT1/INT2 只输出 ≈ 65 µs 的方波,高电平自动复位。
  • 1:锁存模式 → INT 引脚保持高电平,直到 MCU 读取对应寄存器才清零。
    使用脉冲模式时,最好在外部中断回调里立即读取寄存器,防止高频事件错过下一次脉冲。

在这里插入图片描述

启用 Z 轴点击检测

让 Z 轴参与单击 / 双击检测:
● tap.tap_z_en = 1 把 Z-轴使能标志置 1;
● lsm6dsv16x_tap_detection_set() 把该标志写入寄存器 TAP_CFG0.TAP_Z_EN,从而告诉芯片“检测点击时也监视 Z 方向加速度”。

    tap.tap_z_en = 1;
    lsm6dsv16x_tap_detection_set(&dev_ctx, tap);

在这里插入图片描述
在这里插入图片描述

配置 Z 轴点击阈值

● tap_ths.z = 3; → 把 Z 轴点击阈值 设为 3 LSB。
● lsm6dsv16x_tap_thresholds_set() → 将该值写进寄存器 TAP_THS_6D.TAP_THS_Z[4:0]。
在 ±8 g 量程下 1 LSB≈62 mg,所以阈值≈3 × 62 mg≈186 mg:
阈值越大,点击判定越“硬”,越不易被小抖动触发。

    tap_ths.z = 3;
    lsm6dsv16x_tap_thresholds_set(&dev_ctx, tap_ths);

在这里插入图片描述
在这里插入图片描述

配置单/双击时间窗参数

● tap_win.shock = 3; → 设置 SHOCK 窗口:一次敲击的“冲击”信号最长持续时间。
● tap_win.quiet = 3; → 设置 QUIET 窗口:第一次敲击后必须保持的静默期,不允许再次超阈。
● tap_win.tap_gap = 7; → 设置 DUR 窗口:双击时两次敲击之间允许的最大间隔。
● lsm6dsv16x_tap_time_windows_set() → 把以上 3 个值写入 TAP_DUR 寄存器,完成单击/双击的时序参数配置。

    tap_win.tap_gap = 7;
    tap_win.shock = 3;
    tap_win.quiet = 3;
    lsm6dsv16x_tap_time_windows_set(&dev_ctx, tap_win);

在这里插入图片描述
在这里插入图片描述

启用单/双击识别模式

调用 lsm6dsv16x_tap_mode_set(&dev_ctx, LSM6DSV16X_BOTH_SINGLE_DOUBLE);
→ 把 WAKE_UP_THS 寄存器中的 SINGLE_DOUBLE_TAP 位置 1,芯片即可同时识别“单击”和“双击”事件。

    /* 6-6 同时启用单击 + 双击识别 */
    lsm6dsv16x_tap_mode_set(&dev_ctx, LSM6DSV16X_BOTH_SINGLE_DOUBLE);

在这里插入图片描述
在这里插入图片描述

量程设置

● 480 Hz ODR:把加速度计采样频率设为 480 Hz,为 Tap/Double-Tap 算法提供足够时间分辨率。
● ±8 g 量程:将全量程设为 ±8 g,扩大可测动态范围,同时让 1 LSB ≈ 62 mg,便于过滤轻微抖动。

    /* Set Output Data Rate.*/
    lsm6dsv16x_xl_data_rate_set(&dev_ctx, LSM6DSV16X_ODR_AT_480Hz);
    /* Set full scale */
    lsm6dsv16x_xl_full_scale_set(&dev_ctx, LSM6DSV16X_8g);

主程序

    while (1)
    {
        if (irq_flag)  // 如果中断标志被置位(表示有新的 Tap 事件)
        {
            /* 读取所有中断源状态并清除中断 */
            lsm6dsv16x_all_sources_get(&dev_ctx, &status);
            irq_flag = 0;  // 清除中断标志,防止重复处理同一次中断

            if (status.single_tap) {        // 判断是否捕获到“单击”事件
                stap_event_catched = 1;      // 标记单击事件已捕获
            }
            if (status.double_tap) {        // 判断是否捕获到“双击”事件
                dtap_event_catched = 1;      // 标记双击事件已捕获
            }
        }

        if (stap_event_catched) {          // 如果有单击事件需要处理
            stap_event_catched = 0;        // 清除单击事件标志
            printf("Single TAP\r\n");     // 打印“Single TAP”提示
        }
        if (dtap_event_catched) {          // 如果有双击事件需要处理
            dtap_event_catched = 0;        // 清除双击事件标志
            printf("Double TAP\r\n");     // 打印“Double TAP”提示
        }

        R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);  // 延时 10 ms,避免频繁轮询占用 CPU
    }

在这里插入图片描述


网站公告

今日签到

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