瑞芯微Rockchip开发者社区
直播中

王磊

7年用户 1517经验值
私信 关注
[经验]

如何在RK2206开发板上实现一种智能手势的设计呢

硬件资源

EEPROM 24C02的设备地址为:0x1010001* ; 手势传感器 PAJ7620U2 的设备地址为:0x0111001*

硬件接口说明

引脚名称开发者可在硬件资源图中查看,也可在人体感应模块背面查看。

引脚名称 功能描述
LED_UP 向上,LED灯控制线,低电平有效
LED_DOWN 向下,LED灯控制线,低电平有效
LED_LEFT 向左,LED灯控制线,低电平有效
LED_RIGHT 向右,LED灯控制线,低电平有效
INT_N 中断信号,低电平有效
I2C_SCL I2C时钟信号线
I2C-SDA I2C数据信号线
LED_CW 顺时针,LED灯控制线,低电平有效
LED_CCW 逆时针,LED灯控制线,低电平有效
LED_WAVE 摆动,LED灯控制线,低电平有效
GND 电源地引脚
3V3 3.3V电源输入引脚
GND 电源地引脚
5V 5V电源输入引脚

硬件设计

模块整体硬件电路如上图所示,电路中包含了E53接口连接器,EEPROM存储器、手势识别传感器电路,灯光指示电路。电路比较简单,本文不再过多说明。

硬件连接

小凌派开发板与模块均带有防呆设计,故很容易区分安装方向,直接将模块插入到开发板的E53母座接口上即可,

程序设计

API分析

GPIO接口

GPIO接口文档

I2C接口

I2C接口文档

LiteOS任务管理

LiteOS任务管理接口文档

主要代码分析

初始化代码分析

初始化GPIO

本模块使用以下引脚作为LED灯。具体如下所示:

引脚 功能
GPIO0_PB1 LED_UP
GPIO0_PB0 LED_DOWN
GPIO0_PA2 LED_LEFT
GPIO0_PC4 LED_RIGHT
GPIO0_PB4 LED_FORWARD
GPIO0_PB7 LED_BACKWARD
GPIO0_PB6 LED_CW
GPIO0_PB5 LED_CCW
GPIO0_PB2 LED_WAVE

初始化引脚为GPIO。首先通过 LzGpioInit()初始化GPIO引脚,其次通过 LzGpioSetDir()设置GPIO为输出模式,最后通过 LzGpioSetVal()设置输出高电平/低电平。

/***************************************************************
* 函数名称: gesture_sensor_led_init
* 说    明: 初始化LED的GPIO引脚
* 参    数: 无
* 返 回 值: 无
***************************************************************/
static void gesture_sensor_led_init()
{
    PinctrlSet(GPIO_LED_UP, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP);
    LzGpioInit(GPIO_LED_UP);
    LzGpioSetDir(GPIO_LED_UP, LZGPIO_DIR_OUT);
    gesture_sensor_led_up(0);

    PinctrlSet(GPIO_LED_DOWN, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP);
    LzGpioInit(GPIO_LED_DOWN);
    LzGpioSetDir(GPIO_LED_DOWN, LZGPIO_DIR_OUT);
    gesture_sensor_led_down(0);

    PinctrlSet(GPIO_LED_LEFT, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP);
    LzGpioInit(GPIO_LED_LEFT);
    LzGpioSetDir(GPIO_LED_LEFT, LZGPIO_DIR_OUT);
    gesture_sensor_led_left(0);

    PinctrlSet(GPIO_LED_RIGHT, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP);
    LzGpioInit(GPIO_LED_RIGHT);
    LzGpioSetDir(GPIO_LED_RIGHT, LZGPIO_DIR_OUT);
    gesture_sensor_led_right(0);

    PinctrlSet(GPIO_LED_FORWARD, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP);
    LzGpioInit(GPIO_LED_FORWARD);
    LzGpioSetDir(GPIO_LED_FORWARD, LZGPIO_DIR_OUT);
    gesture_sensor_led_forward(0);

    PinctrlSet(GPIO_LED_BACKWARD, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP);
    LzGpioInit(GPIO_LED_BACKWARD);
    LzGpioSetDir(GPIO_LED_BACKWARD, LZGPIO_DIR_OUT);
    gesture_sensor_led_backward(0);

    PinctrlSet(GPIO_LED_CW, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP);
    LzGpioInit(GPIO_LED_CW);
    LzGpioSetDir(GPIO_LED_CW, LZGPIO_DIR_OUT);
    gesture_sensor_led_cw(0);

    PinctrlSet(GPIO_LED_CCW, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP);
    LzGpioInit(GPIO_LED_CCW);
    LzGpioSetDir(GPIO_LED_CCW, LZGPIO_DIR_OUT);
    gesture_sensor_led_ccw(0);

    PinctrlSet(GPIO_LED_WAVE, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP);
    LzGpioInit(GPIO_LED_WAVE);
    LzGpioSetDir(GPIO_LED_WAVE, LZGPIO_DIR_OUT);
    gesture_sensor_led_wave(0);
}

初始化i2c

初始化GPIO0_PA1和GPIO0_PA0为I2C0。首先通过 I2cIoInit()初始化i2c通道,最后通过 LzI2cInit()设置i2c配置。具体代码如下所示:

/***************************************************************
* 函数名称: paj7620u2_i2c_init
* 说    明: 初始化与PAJ7620U2通信的i2c
* 参    数: 无
* 返 回 值: 无
***************************************************************/
static void paj7620u2_i2c_init()
{
    if (I2cIoInit(m_i2cBus) != LZ_HARDWARE_SUCCESS)
    {
        printf("%s, %d: I2cIoInit failed!
", __FILE__, __LINE__);
        return;
    }
    if (LzI2cInit(E53_I2C_BUS, m_i2c_freq) != LZ_HARDWARE_SUCCESS)
    {
        printf("%s, %d: I2cIoInit failed!
", __FILE__, __LINE__);
        return;
    }

    PinctrlSet(GPIO0_PA1, MUX_FUNC3, PULL_KEEP, DRIVE_KEEP);
    PinctrlSet(GPIO0_PA0, MUX_FUNC3, PULL_KEEP, DRIVE_KEEP);
}

配置PAJ7620U2

通过i2c通信协议,配置PAJ7620U2。具体代码如下所示:

/***************************************************************
* 函数名称: paj7620u2_init_config
* 说    明: 配置PAJ7620U2为手势感应模式
* 参    数: 无
* 返 回 值: 无
***************************************************************/
static void paj7620u2_init_config()
{
    uint8_t ret = 0;
    uint32_t size;
  
    ret = paj7620u2_wake_up();
    if (ret != 0)
    {
        printf("%s, %s, %d: paj7620u2_wake_up failed(%d)
", __FILE__, __func__, __LINE__, ret);
    }

    /* 初始化PAJ7620U2 */
    size = sizeof(m_Paj7620u2_InitRegisterConfig) / (sizeof(uint8_t) * 2);
    for (uint32_t i = 0; i < size; i++) 
    {
        paj7620u2_write_data(m_Paj7620u2_InitRegisterConfig[i][0], m_Paj7620u2_InitRegisterConfig[i][1]);
    }

    /* 设置为手势识别模式 */
    size = sizeof(m_Paj7620u2_SetGestureModeConfig) / (sizeof(uint8_t) * 2);
    for (uint32_t i = 0; i < size; i++)
    {
        paj7620u2_write_data(m_Paj7620u2_SetGestureModeConfig[i][0], m_Paj7620u2_SetGestureModeConfig[i][1]);
    }

    paj7620u2_select_bank(BANK0);
}

创建轮询任务

通过 LOS_TaskCreate()创建任务,每隔100msec轮询PAJ7620U2的手势寄存器。具体代码如下所示:

/***************************************************************
* 函数名称: paj7620u2_poll_task_init
* 说    明: 初始化轮询PAJ7620U2手势的任务
* 参    数: 无
* 返 回 值: 无
***************************************************************/
static void paj7620u2_poll_task_init()
{
    TSK_INIT_PARAM_S task;
    uint8_t int_flag1, int_flag2;
    UINT32 ret;
  
    /* 初始化先进先出缓冲区 */
    m_fifo_intflags.offset_read = 0;
    m_fifo_intflags.offset_write = 0;

    /* 锁任务调度 */
    LOS_TaskLock();

    /* 创建中断之后的i2c读取中断标记寄存器的任务 */
    (VOID)memset_s(&task, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));
    task.pfnTaskEntry   = (TSK_ENTRY_FUNC)paj7620u2_poll_task;
    task.pcName         = "InterruptSemTask";
    task.uwStackSize    = 0x400;
    task.usTaskPrio     = 10;
    ret = LOS_TaskCreate(&m_pollTaskId, &task);
    if (ret != LOS_OK)
    {
        printf("%s, %d: LOS_TaskCreate failed(%d)
", __func__, __LINE__, ret);
        /* 解锁任务调度 */
        LOS_TaskUnlock();
        return;
    }

    /* 解锁任务调度 */
    LOS_TaskUnlock();

    /* 先清空PAJ7620U2的中断标记寄存器 */
    paj7620u2_select_bank(BANK0);
    paj7620u2_read_data(PAJ_REG_GET_INT_FLAG1, &int_flag1);
    paj7620u2_read_data(PAJ_REG_GET_INT_FLAG2, &int_flag2);
}

查询手势感应代码分析

首先,通过 LOS_TaskCreate()创建任务,每隔100msec轮询PAJ7620U2的手势寄存器。如果寄存器有数据,则存储到FIFO队列中。具体代码如下所示:

/***************************************************************
* 函数名称: paj7620u2_poll_task
* 说    明: 轮询任务,每隔100msec访问PAJ7620U2的手势中断寄存器,
*       如果有手势数据,则填写到m_fifo_intflags队列中。
* 参    数: 无
* 返 回 值: 无
***************************************************************/
static VOID paj7620u2_poll_task(VOID *args)
{
    uint8_t int_flag1 = 0;
    uint8_t int_flag2 = 0;
    uint16_t value = 0;
  
    while (1)
    {
        /* 读取Paj7620U2的手势中断寄存器 */
        paj7620u2_select_bank(BANK0);
        paj7620u2_read_data(PAJ_REG_GET_INT_FLAG1, &int_flag1);
        paj7620u2_read_data(PAJ_REG_GET_INT_FLAG2, &int_flag2);

        value = 0;
        if (int_flag1 != 0)
        {
            value |= (uint16_t)(int_flag1);
        }
        if (int_flag2 != 0)
        {
            value |= (uint16_t)(int_flag2 << 8);
        }

        if (value != 0)
            FifoPut(&m_fifo_intflags, value);

        LOS_Msleep(100);
    }
}

上层软件通过调用 E53_GestureSensor_GetGestureState()获知FIFO队列中的最新手势信息。具体代码如下:

/***************************************************************
 * 函数名称: gesture_sensor_get_gesture_state
 * 说    明: 获取手势感应模块手势
 * 参    数: 
 *      @flag:获取当前手势
 * 返 回 值: 1为成功,0为失败
 ***************************************************************/
unsigned int gesture_sensor_get_gesture_state(unsigned short *flag)
{
    *flag = 0;

    if (FifoGet(&m_fifo_intflags, flag) != 0)
    {
        return 1;
    }
    else 
    {
        return 0;
    }
}

5 编译调试

5.1 修改 BUILD.gn 文件

修改 vendor/lockzhiner/lingpi/sample 路径下 BUILD.gn 文件,指定 e53_gs_example 参与编译。

"e53_gesture_sensor",

在主目录下输入编译命令。

hb build -f

5.2 运行结果

示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,并请使用带有LCD屏幕显示如下:

========== E53 Gesture Sensor Example ==========
Get Gesture Statu: 0x1
   Down
========== E53 Gesture Sensor Example ==========
Get Gesture Statu: 0x5
   Down
   Left

原作者:王小彬 Gitee

更多回帖

发帖
×
20
完善资料,
赚取积分