一.项目需求
• 使用板卡上的触摸按键,实现点按和左右滑动,实现传感器选择和切换,并将数据发送到上位机,功能选择的可视化也在上位机完成如:能够选择加速度传感器,开启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
,则判断为按下状态,设置touchState
为LEFT_PRESSED
或RIGHT_PRESSED
。
- 如果当前触摸值的绝对值超过
- 按下状态
LEFT_PRESSED
或RIGHT_PRESSED
: - 如果当前触摸值的绝对值小于或等于
RELEASE_THRESHOLD
,则恢复为IDLE
状态。 - 如果当前触摸值变化超过
SLIDE_START_THRESHOLD
,则判断为滑动状态,设置touchState
为SLIDING_RIGHT
或SLIDING_LEFT
。
- 如果当前触摸值的绝对值小于或等于
- 滑动状态
SLIDING_LEFT
或SLIDING_RIGHT
: - 如果当前触摸值的绝对值小于或等于
RELEASE_THRESHOLD
,则恢复为IDLE
状态。
- 如果当前触摸值的绝对值小于或等于
程序框图如下
这里提供一些memes里面的定义
Accelerometer g值加速度 测量底面物理量
Gyroscope 陀螺仪 测量转动物理量
Magnetometer 磁力计
Pressure 大气压
Temperature 温度
Quaternion & rotation四元数和旋转
Gravity g值
Linear Acceleration 线性加速度
Heading Angle 航迹角
图2-1mems中进行数据可视化读取
三.qt图形化界面的设置
由于qt图形化并不在本次活动要求范围内 所以本文不提供代码讲解 仅提供ui截图以供参考
我使用的是Qt_5_11_1_MinGW连接串口设置波特率为115200
图3-1选择串口
图3-2选择波特率
图3-3选择数据位
设置好后点击open启动串口 可以通过调整右下角控制条来控制数据传输快慢
图3-3启动传输
按下板子右侧按键启动数据传输 滑动右左侧可以切换传感器
图3-4启动传输 图3-5滑动按键
点击传感器选项下拉栏也可以实现传感器的更换
图3-6手动切换传感器
长按左键关闭传感器
图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. 触摸传感器数据处理的逻辑清晰
在分析触摸传感器的按压和滑动检测逻辑时,我认识到传感器数据处理的复杂性。代码中的逻辑不仅需要准确地检测触摸事件,还要考虑防止误触发和长按的情况。这使我认识到在嵌入式系统中如何有效地处理传感器数据以确保系统的稳定性和可靠性。
通过这次活动,我不仅提高了技术水平,还增强了对嵌入式系统开发的理解和信心。这次经历将对我未来的学习和工作产生深远的影响。我将继续努力,不断提升自己的技术能力,为未来的开发工作做好充分的准备。