基于EV54Y39A PIC-IOT WA的手指数量检测功能开发(MPLAB+ADC)

发布于:2024-06-03 ⋅ 阅读:(111) ⋅ 点赞:(0)

👉 【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的逻辑分析功能。

PIC-IOT WA

项目设计

开发环境及工程参考

本项目使用 Microchip 官方的 MPLAB X IDE 开发。项目所用到的工具链、库或 packs 如下:

  1. 编译器:xc16 v1.50,这个版本的编译器确保编译通过
  2. Packs: PIC24F-GA-GB_DFP 1.9.336、PKOB nano 1.13.715
  3. 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,之后清零并进入 STATE_IDLE。工程主体为一个 while(1) 循环的 FSM,用一个全局变量记录系统状态:

  • 每次都会先读取光照传感器的数据,并根据此次与上次读数的差值,进入其他的状态
  • 在 STATE_IDLE 中,当差值小于一个负阈值时,进入 STATE_NEGA,此时识别到光照降低,这说明有手指遮挡。其余情况没有手指遮挡,状态不转移。当定时器触发时,打印出此时的识别数目并将 count 清零,系统重新进入 STATE_IDLE。
  • 在 STATE_NEGA,当差值大于一个正阈值时,进入 STATE_POS,此时识别到光照增加,这说明手指移开了,count++。在 STATE_NEGA,若保持光照读数相对稳定,这说明该手指还未完全经过传感器,状态不转移。当定时器触发时,打印出此时的识别数目并将 count 清零,系统重新进入 STATE_IDLE。
  • 在 STATE_POS 中,只有当差值又一次小于负阈值时,进入 STATE_NEGA,此时识别到光照降低,这说明又有手指遮挡。若保持光照读数相对稳定或增加,这说明并没有新的手指遮挡。当定时器触发时,打印出此时的识别数目并将 count 清零,系统重新进入 STATE_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即可。

ADC1配置修改
根据生成的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周期定时器。

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;

反复读取光照传感器数据,读取最近的两次数据取平均值作为此次测量的结果,并与上次读数作差。根据该差值进行状态跳转:

  1. 处于 APP_STATE_IDLE 时,当差值 delta 小于负阈值 LIGHT_TRIGGER_THRES 时,进入 APP_STATE_DETECTED_NEGA,此时检测到有手指遮挡,光照降低。其余情况下,均不会有手指遮挡,状态不转移。
  2. 处于 APP_STATE_DETECTED_NEGA 时,当 delta 大于正阈值 LIGHT_TRIGGER_THRES 时,进入 APP_STATE_DETECTED_POS,此时说明手指移开了,计数+1。其余情况下,手指还未完全经过传感器,因此差值不够大(可以过滤毛刺情况)或者为负,状态均不转移。
  3. 处于 APP_STATE_DETECTED_POS 时,当 delta 又一次小于负阈值 LIGHT_TRIGGER_THRES 时,进入 APP_STATE_DETECTED_NEGA,此时又有手指遮挡。其余情况下,说明光照无较大变化或者光照变强,这说明没有手指遮挡或手指逐渐远离,状态均不跳转。
  4. 测量周期为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 而不能是最新版的。


网站公告

今日签到

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