活动Funpack3-3 基于X-NUCLEO-IKS4A1的环境传感器扩展板开发
该项目使用了板卡上的触摸按键,实现了点按和左右滑动,实现传感器选择和切换的设计,它的主要功能为:能够选择加速度传感器,开启X轴数据发送,然后关闭加速度显示,选择温度。
标签
嵌入式系统
Funpack活动
显示
开发板
pildio
更新2024-07-08
哈尔滨远东理工学院
45

一.项目需求

• 使用板卡上的触摸按键,实现点按和左右滑动,实现传感器选择和切换,并将数据发送到上位机,功能选择的可视化也在上位机完成如:能够选择加速度传感器,开启X轴数据发送,然后关闭加速度显示,选择温度

二. 实现过程

主函数 main

int flag;
char* TouchState = "IDLE";
int i = 0;
while (1)
{
/* Check touch sensor state */
flag = TouchResult();
switch(flag) {
case LEFT_PRESSED:
TouchState = "LEFT_PRESSED";
break;
case RIGHT_PRESSED:
TouchState = "RIGHT_PRESSED";
break;
case SLIDING_LEFT:
TouchState = "SLIDING_LEFT";
break;
case SLIDING_RIGHT:
TouchState = "SLIDING_RIGHT";
break;
default:
TouchState = "IDLE";
}

/* Delay for 250ms */
HAL_Delay(250);

/* Every 1 second, process MEMS data */
if (i++ == 4) {
MX_MEMS_Process();
i = 0;
}

/* Print touch state */
printf("%s-touch\r\n", TouchState);

初始化阶段

  • HAL_Init() 初始化HAL库。
  • SystemClock_Config() 配置系统时钟。
  • MX_GPIO_Init()MX_TIM6_Init()MX_MEMS_Init() 分别初始化GPIO、定时器和MEMS传感器。
  • 主循环
  • 触摸传感器检测:通过 TouchResult() 函数获取触摸传感器的状态(LEFT_PRESSED、RIGHT_PRESSED、SLIDING_LEFT、SLIDING_RIGHT 或 IDLE),并将状态存储在 TouchState 变量中。
  • 延时:使用 HAL_Delay(250) 函数实现250毫秒的延迟。
  • MEMS数据处理:每隔1秒钟(通过 if (i++ == 4) 实现),调用 MX_MEMS_Process() 函数处理MEMS传感器的数据。这将触发 MX_IKS4A1_DataLogTerminal_Process() 函数来获取和处理传感器数据,并将结果打印输出。
  • 打印触摸状态:使用 printf("%s-touch\r\n", TouchState) 将当前触摸状态打印输出到串口。


------------------------------------------------------------------------------------------------------------------------------------

重点函数介绍

1. MX_MEMS_Init(void)

  • 功能:初始化MEMS(Micro Electro-Mechanical Systems)传感器和外设。
  • 操作
    • 调用 MX_IKS4A1_DataLogTerminal_Init() 初始化数据日志终端。
    • 分别调用各个传感器的初始化函数:加速度传感器(LSM6DSV16X, LSM6DSO16IS, LIS2DUXS12)、陀螺仪传感器(LSM6DSO16IS, LSM6DSV16X)、磁力计传感器(MAG)、压力传感器(PRESS)、温度传感器(TEMP)、湿度传感器(HUM)。
    • 设置加速度传感器的输出数据率(ODR)和满量程(Full Scale)

------------------------------------------------------------------------------------------------------------------------------------

2. MX_MEMS_Process(void)

功能:处理MEMS传感器数据。

操作:调用 MX_IKS4A1_DataLogTerminal_Process() 处理数据日志终端

------------------------------------------------------------------------------------------------------------------------------------

3. MX_IKS4A1_DataLogTerminal_Process(void)

  • 功能:处理数据日志终端的过程。
  • 操作
    • 检测并处理按钮中断(用于重置数据日志终端)。
    • dataOut 缓冲区输出分隔线。
    • 循环处理所有的运动和环境传感器实例:
      • 如果传感器具备加速度、陀螺仪、磁力计功能,则调用相应的处理函数:Accelero_Sensor_Handler()Gyro_Sensor_Handler()Magneto_Sensor_Handler()
      • 如果传感器具备湿度、温度、压力功能,则调用相应的处理函数:Hum_Sensor_Handler()Temp_Sensor_Handler()Press_Sensor_Handler()

------------------------------------------------------------------------------------------------------------------------------------

4. 传感器数据处理函数:Accelero_Sensor_Handler、Gyro_Sensor_Handler、Magneto_Sensor_Handler、Hum_Sensor_Handler、Temp_Sensor_Handler、Press_Sensor_Handler

  • 功能:输出整个传感器采集到的数据

具体分析如下

1) Accelero_Sensor_Handler

功能: 处理加速度传感器的数据。

2)Gyro_Sensor_Handler

功能: 处理陀螺仪传感器的数据。

3) Magneto_Sensor_Handler

功能: 处理磁力计传感器的数据。

4) Hum_Sensor_Handler

功能: 处理湿度传感器的数据。

5.)Temp_Sensor_Handler

功能: 处理温度传感器的数据。

6) Press_Sensor_Handler

功能: 处理压力传感器的数据。

这些传感器处理函数的核心工作流程是相似的:

  • 通过 IKS4A1_MOTION_SENSOR_GetAxes 获取加速度数据,并打印。
  • 如果 verbose 模式打开,还会获取和打印传感器ID、输出数据速率和满量程范围。

------------------------------------------------------------------------------------------------------------------------------------

5. 按压检测 int TouchResult(void)

TouchResult 函数用于返回最终的触摸状态,包含防误触发和长按的处理逻辑:

  • 如果当前状态与上上次状态相同,则返回 IDLE
  • 如果在空闲状态后立刻检测到按下状态,则返回 IDLE
  • 如果滑动状态连续两次相同,则返回 IDLE
  • 否则,返回当前的触摸状态。


中断回调函数HAL_TIM_PeriodElapsedCallback

  • 初始状态 IDLE
    • 如果当前触摸值的绝对值超过 PRESS_THRESHOLD,则判断为按下状态,设置 touchStateLEFT_PRESSEDRIGHT_PRESSED
  • 按下状态 LEFT_PRESSEDRIGHT_PRESSED
    • 如果当前触摸值的绝对值小于或等于 RELEASE_THRESHOLD,则恢复为 IDLE 状态。
    • 如果当前触摸值变化超过 SLIDE_START_THRESHOLD,则判断为滑动状态,设置 touchStateSLIDING_RIGHTSLIDING_LEFT
  • 滑动状态 SLIDING_LEFTSLIDING_RIGHT
    • 如果当前触摸值的绝对值小于或等于 RELEASE_THRESHOLD,则恢复为 IDLE 状态。


程序框图如下


image.png

这里提供一些memes里面的定义


Accelerometer  g值加速度  测量底面物理量
Gyroscope    陀螺仪   测量转动物理量
Magnetometer  磁力计
Pressure 大气压
Temperature 温度
Quaternion & rotation四元数和旋转
Gravity g值
Linear Acceleration 线性加速度
Heading Angle 航迹角

4ab20db65743ee6ab64ee896dd170e8.png

图2-1mems中进行数据可视化读取

三.qt图形化界面的设置

由于qt图形化并不在本次活动要求范围内 所以本文不提供代码讲解 仅提供ui截图以供参考


我使用的是Qt_5_11_1_MinGW连接串口设置波特率为115200

image.png

图3-1选择串口

image.png

图3-2选择波特率

image.png

图3-3选择数据位


设置好后点击open启动串口 可以通过调整右下角控制条来控制数据传输快慢

image.png

图3-3启动传输


按下板子右侧按键启动数据传输 滑动右左侧可以切换传感器

image.pngimage.png

图3-4启动传输 图3-5滑动按键

点击传感器选项下拉栏也可以实现传感器的更换

image.png

图3-6手动切换传感器



长按左键关闭传感器

image.png

图3-7传输已经关闭



部分关键逻辑代码

if (message.contains("MAG_X[0]")) {
// 用逗号分隔字符串
QStringList elements = message.split(", ");
LIS2MDL_data[0] = elements[0].section(": ", 1, 1).toInt(); // 获取X值
LIS2MDL_data[1] = elements[1].section(": ", 1, 1).toInt(); // 获取Y值
LIS2MDL_data[2] = elements[2].section(": ", 1, 1).toInt(); // 获取Z值

SensorData[0] = message;
} else if (message.contains("ACC_X[1]")) {
// 用逗号分隔字符串
QStringList elements = message.split(", ");
LSM6DSO16IS_data[0] = elements[0].section(": ", 1, 1).toInt(); // 获取X值
LSM6DSO16IS_data[1] = elements[1].section(": ", 1, 1).toInt(); // 获取Y值
LSM6DSO16IS_data[2] = elements[2].section(": ", 1, 1).toInt(); // 获取Z值

SensorData[1] = message;
} else if (message.contains("GYR_X[1]")) {
// 用逗号分隔字符串
QStringList elements = message.split(", ");
LSM6DSO16IS_data[3] = elements[0].section(": ", 1, 1).toInt(); // 获取X值
LSM6DSO16IS_data[4] = elements[1].section(": ", 1, 1).toInt(); // 获取Y值
LSM6DSO16IS_data[5] = elements[2].section(": ", 1, 1).toInt(); // 获取Z值

SensorData[2] = message;
} else if (message.contains("ACC_X[2]")) {
// 用逗号分隔字符串
QStringList elements = message.split(", ");
LIS2DUXS12_data[0] = elements[0].section(": ", 1, 1).toInt(); // 获取X值
LIS2DUXS12_data[1] = elements[1].section(": ", 1, 1).toInt(); // 获取Y值
LIS2DUXS12_data[2] = elements[2].section(": ", 1, 1).toInt(); // 获取Z值

SensorData[3] = message;
} else if (message.contains("ACC_X[3]")) {
// 用逗号分隔字符串
QStringList elements = message.split(", ");
LSM6DSV16X_data[0] = elements[0].section(": ", 1, 1).toInt(); // 获取X值
LSM6DSV16X_data[1] = elements[1].section(": ", 1, 1).toInt(); // 获取Y值
LSM6DSV16X_data[2] = elements[2].section(": ", 1, 1).toInt(); // 获取Z值

SensorData[4] = message;
} else if (message.contains("GYR_X[3]")) {
// 用逗号分隔字符串
QStringList elements = message.split(", ");
LSM6DSV16X_data[3] = elements[0].section(": ", 1, 1).toInt(); // 获取X值
LSM6DSV16X_data[4] = elements[1].section(": ", 1, 1).toInt(); // 获取Y值
LSM6DSV16X_data[5] = elements[2].section(": ", 1, 1).toInt(); // 获取Z值

SensorData[5] = message;
} else if (message.contains("Temp[0]")) {
QString tempValue = message.section(": ", 1, 1).section(" degC", 0, 0);
STTS22H_data = tempValue.toDouble();

SensorData[6] = message;
} else if (message.contains("Press[1]")) {
QString pressValue = message.section(": ", 1, 1).section(" hPa", 0, 0);
LPS22DF_data = pressValue.toDouble();

SensorData[7] = message;
} else if (message.contains("Hum[2]")) {
QString humValue = message.section(": ", 1, 1).section(" %", 0, 0);
SHT40AD1B_data[0] = humValue.toDouble();

SensorData[8] = message;
} else if (message.contains("Temp[2]")) {
QString tempValue = message.section(": ", 1, 1).section(" degC", 0, 0);
SHT40AD1B_data[1] = tempValue.toDouble();

SensorData[9] = message;

四.对本活动的心得体会

1. 对定时器配置和初始化的理解加深

通过详细分析定时器TIM6的配置和初始化过程,我对定时器的工作机制有了更深入的了解。尤其是在了解如何通过设置预分频器和周期来控制定时器的时钟频率和中断触发频率方面,这为我今后处理类似任务打下了坚实的基础。

2. 触摸传感器数据处理的逻辑清晰

在分析触摸传感器的按压和滑动检测逻辑时,我认识到传感器数据处理的复杂性。代码中的逻辑不仅需要准确地检测触摸事件,还要考虑防止误触发和长按的情况。这使我认识到在嵌入式系统中如何有效地处理传感器数据以确保系统的稳定性和可靠性。

通过这次活动,我不仅提高了技术水平,还增强了对嵌入式系统开发的理解和信心。这次经历将对我未来的学习和工作产生深远的影响。我将继续努力,不断提升自己的技术能力,为未来的开发工作做好充分的准备。

附件下载
build-project-Desktop_Qt_5_11_1_MinGW_32bit-Debug.zip
project.zip
G0B1_ALL.zip
团队介绍
团队成员
pildio
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号