RA4M2开发IOT.5--读取单双击
概述
在上章读取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
}