目录
- 项目介绍
- 硬件介绍
- 项目设计
- 开发环境及工程参考
- 总体流程图
- 硬件基本配置
- 光照传感器读取
- 定时器
- 检测逻辑
- 功能展示
- 项目总结
👉 【Funpack3-2】基于EV54Y39A PIC-IOT WA的手指数量检测功能开发
👉 Github: EmbeddedCamerata/PIC-IOT_finger_recognition
项目介绍
基于 Microchip 的 EV54Y39A PIC-IOT WA 开发板,通过板卡上集成的光照传感器,将板卡平放后,每秒对挥动的手指数量进行检测。在较强光源下,可准确识别挥动的手指数量。
👉 MPLAB X IDE
硬件介绍
PIC-IoT WA硬件概述:
- 控制器包含两个主要组件:PIC微控制器(PIC24FJ128GA705)和Wi-Fi模块(WINC1510)。PIC24F是一款低功耗的16位微控制器,时钟频率为32MHz,具有集成的12位ADC。Wi-Fi模块采用Microchip的ATWINC1510,是低功耗认证的IoT网络控制器。
- 板载ATECC608的密码协处理器。用于生成私钥和公钥,私钥用于加密发送的每条消息,而公钥可与服务提供商(如Google IoT cloud或AWS)共享。
- 板载传感器包括TEMT6000X01光传感器和MCP9808温度传感器。光传感器连接到PIC控制器的10位ADC,温度传感器通过I2C接口测量-20℃至100℃之间的温度,典型精度为0.25℃。
- PIC IoT WA开发板可通过微型USB端口或4.2V锂电池供电,同时具有板上编程仿真器和调试器(PKOB)支持一路串口和一个IO的逻辑分析功能。
项目设计
开发环境及工程参考
本项目使用 Microchip 官方的 MPLAB X IDE 开发。项目所用到的工具链、库或 packs 如下:
- 编译器:xc16 v1.50,这个版本的编译器确保编译通过
- Packs: PIC24F-GA-GB_DFP 1.9.336、PKOB nano 1.13.715
- MCC Content Libraries:
1. MCC core 5.7.1
2. PIC24 / dsPIC33 MCUs 1.171.4
3. Board Support Library 1.12.0
总体流程图
进行系统初始化以后,先启动周期为1s的定时器,该定时器自动重载,在其回调函数中打印识别的手指数目 count
,之后清零并进入 IDLE 态。工程主体为一个 while(1)
循环的 FSM,用一个全局变量记录系统状态:
- 每次都会先读取光照传感器的数据,并根据此次与上次读数的差值,进入其他的状态
- 在 IDLE 态中,当差值小于一个负阈值时,进入 NEGA 态,此时识别到光照降低,这说明有手指遮挡。其余情况没有手指遮挡,状态不转移。当定时器触发时,打印出此时的识别数目并将
count
清零,系统重新进入 IDLE 态。 - 在 NEGA 态中,当差值大于一个正阈值时,进入 POS 态,此时识别到光照增加,这说明手指移开了,
count++
。在 NEGA 态中,若保持光照读数相对稳定,这说明该手指还未完全经过传感器,状态不转移。当定时器触发时,打印出此时的识别数目并将count
清零,系统重新进入 IDLE 态。 - 在 POS 态中,只有当差值又一次小于负阈值时,进入 NEGA 态,此时识别到光照降低,这说明又有手指遮挡。若保持光照读数相对稳定或增加,这说明并没有新的手指遮挡。当定时器触发时,打印出此时的识别数目并将
count
清零,系统重新进入 IDLE 态。
由于测量周期是1s,即便测量状态没有变化,定时器回调也会将状态、变量全部重置。在 FSM 中,只需要处理有效的测量的统计逻辑即可。
硬件基本配置
根据手册可知,板载光照传感器与ADC AN8(RB12)相连。检测的周期设计为1秒,如此,需要一个定时器 TMR1。其次,还需要串口以供调试与结果显示。在MCC中,IO口设置如下图所示:
RB10/11供调试使用。串口设置为9600 8N1,RC8 UITX 需要勾选“Start High”,勾选“Redirect printf to UART”。
光照传感器读取
需要修改一下默认的 ADC1 配置。根据下方提示,修改“Conversion Clock”为2即可。
根据生成的ADC示例,可以修改实现光照传感器数据的读取。
uint16_t get_light_sensor(void)
{
int i;
uint16_t conversion;
ADC1_Enable();
ADC1_ChannelSelect(LIGHT_SENSOR);
ADC1_SoftwareTriggerEnable();
//Provide Delay
for(i = 0; i < 1000; i++){}
ADC1_SoftwareTriggerDisable();
while(!ADC1_IsConversionComplete(LIGHT_SENSOR));
conversion = ADC1_ConversionResultGet(LIGHT_SENSOR);
ADC1_Disable();
return conversion;
}
定时器
如下图所示配置,设置 TMR1 为1s周期定时器。
在定时器的回调函数 periodic_handler
中,打印 count
手指数目,而后清零并将状态设置为 APP_STATE_IDLE
。在主循环之前创建定时器,定时器超时设置为 0xF423
,在主循环内需要调用 timeout_callNextCallback()
以检查回调。
static uint32_t periodic_handler(void)
{
printf("Finger count: %d\n", count);
appState = APP_STATE_IDLE;
count = 0;
return 0xF423;
}
int main(void)
{
// initialize the device
SYSTEM_Initialize();
timerStruct_t periodic_timer = {periodic_handler, NULL};
timeout_create(&periodic_timer, 0xF423);
while (1)
{
timeout_callNextCallback();
main_app();
}
return 1;
}
检测逻辑
当手指遮挡时,光照减小,前后两次读数的差值为负数,反之为正数。因此,设置一个合适的阈值 LIGHT_TRIGGER_THRES
,用于判断是否发生了这两种变化,同时也可以过滤掉读数不稳定的影响。该值需要根据实际环境进行调整。
#define LIGHT_TRIGGER_THRES (50)
系统分为三个状态,用全局变量 appState
记录。同时,需要几个参数记录传感器的数值以及手指数目。
typedef enum {
APP_STATE_IDLE,
APP_STATE_DETECTED_NEGA,
APP_STATE_DETECTED_POS
} appStates_e;
static appStates_e appState = APP_STATE_IDLE;
static uint16_t light1 = 0;
static uint16_t light2 = 0;
static float light_prev1 = 0.;
static int count = 0;
反复读取光照传感器数据,读取最近的两次数据取平均值作为此次测量的结果,并与上次读数作差。根据该差值进行状态跳转:
- 处于
APP_STATE_IDLE
时,当差值delta
小于负阈值LIGHT_TRIGGER_THRES
时,进入APP_STATE_DETECTED_NEGA
,此时检测到有手指遮挡,光照降低。其余情况下,均不会有手指遮挡,状态不转移。 - 处于
APP_STATE_DETECTED_NEGA
时,当delta
大于正阈值LIGHT_TRIGGER_THRES
时,进入APP_STATE_DETECTED_POS
,此时说明手指移开了,计数+1。其余情况下,手指还未完全经过传感器,因此差值不够大(可以过滤毛刺情况)或者为负,状态均不转移。 - 处于
APP_STATE_DETECTED_POS
时,当delta
又一次小于负阈值LIGHT_TRIGGER_THRES
时,进入APP_STATE_DETECTED_NEGA
,此时又有手指遮挡。其余情况下,说明光照无较大变化或者光照变强,这说明没有手指遮挡或手指逐渐远离,状态均不跳转。 - 测量周期为1s,定时器超时后,将打印出计数结果
count
并清零,同时状态转移至APP_STATE_IDLE
,进行下一次测量。
void main_app(void)
{
float delta;
float light;
light1 = get_light_sensor();
light2 = get_light_sensor();
light = (light1 + light2) / 2;
delta = light - light_prev1;
light_prev1 = light;
switch(appState) {
case APP_STATE_IDLE:
{
if (delta < -LIGHT_TRIGGER_THRES) {
appState = APP_STATE_DETECTED_NEGA;
}
break;
}
case APP_STATE_DETECTED_NEGA:
{
if (delta > LIGHT_TRIGGER_THRES) {
count++;
appState = APP_STATE_DETECTED_POS;
}
break;
}
case APP_STATE_DETECTED_POS:
{
if (delta < -LIGHT_TRIGGER_THRES) {
appState = APP_STATE_DETECTED_NEGA;
}
break;
}
}
}
功能展示
下载程序后将板卡平放,注意需要保证环境光照较强,需要根据实际情况调整阈值 LIGHT_TRIGGER_THRES
。本测试在室内,并用手机手电筒照射光照传感器的环境下进行。测试需要挥动手指,结果输出有延迟,测试效果参见视频更直观。
👉 详细展示参见:B站:基于EV54Y39A PIC-IOT WA的手指数量检测功能开发
项目总结
本次项目通过光照传感器、定时器与状态机,可在一定场景下准确识别挥动的手指数量,可以根据实际场景调整参数,以达到最佳效果。MPLAB IDE 一言难尽,打开 MCC 没个半天是不可能的,这个板卡的有些配置还有坑,例如,编译器需要选择 v1.50 而不能是最新版的。