1# 小凌派-RK2206开发板E53模块开发——智能手势 2 3本示例将演示如何在小凌派-RK2206开发板上实现智能手势的应用案例。 4 5 6 7## 硬件资源 8 9硬件资源图如下所示: 10 11 12EEPROM 24C02的设备地址为:0x1010001* ; 13手势传感器 PAJ7620U2 的设备地址为:0x0111001* 14 15## 硬件接口说明 16 17引脚名称开发者可在硬件资源图中查看,也可在人体感应模块背面查看。 18 19| 引脚名称 | 功能描述 | 20| :-------- | :------------------------------ | 21| LED_UP | 向上,LED灯控制线,低电平有效 | 22| LED_DOWN | 向下,LED灯控制线,低电平有效 | 23| LED_LEFT | 向左,LED灯控制线,低电平有效 | 24| LED_RIGHT | 向右,LED灯控制线,低电平有效 | 25| INT_N | 中断信号,低电平有效 | 26| I2C_SCL | I2C时钟信号线 | 27| I2C-SDA | I2C数据信号线 | 28| LED_CW | 顺时针,LED灯控制线,低电平有效 | 29| LED_CCW | 逆时针,LED灯控制线,低电平有效 | 30| LED_WAVE | 摆动,LED灯控制线,低电平有效 | 31| GND | 电源地引脚 | 32| 3V3 | 3.3V电源输入引脚 | 33| GND | 电源地引脚 | 34| 5V | 5V电源输入引脚 | 35 36## 硬件设计 37 38硬件电路如下图所示: 39 40 41模块整体硬件电路如上图所示,电路中包含了E53接口连接器,EEPROM存储器、手势识别传感器电路,灯光指示电路。电路比较简单,本文不再过多说明。 42 43### 硬件连接 44 45小凌派开发板与模块均带有防呆设计,故很容易区分安装方向,直接将模块插入到开发板的E53母座接口上即可,安装图如下所示: 46 47 48## 程序设计 49 50### API分析 51 52#### GPIO接口 53 54[GPIO接口文档](/device/rockchip/hardware/docs/GPIO.md) 55 56#### I2C接口 57 58[I2C接口文档](/device/rockchip/hardware/docs/I2C.md) 59 60#### LiteOS任务管理 61 62[LiteOS任务管理接口文档](/vendor/lockzhiner/lingpi/samples/a1_kernel_task/task.md) 63 64### 主要代码分析 65 66#### 初始化代码分析 67 68**初始化GPIO** 69 70本模块使用以下引脚作为LED灯。具体如下所示: 71 72| 引脚 | 功能 | 73| :-------- | :----------- | 74| GPIO0_PB1 | LED_UP | 75| GPIO0_PB0 | LED_DOWN | 76| GPIO0_PA2 | LED_LEFT | 77| GPIO0_PC4 | LED_RIGHT | 78| GPIO0_PB4 | LED_FORWARD | 79| GPIO0_PB7 | LED_BACKWARD | 80| GPIO0_PB6 | LED_CW | 81| GPIO0_PB5 | LED_CCW | 82| GPIO0_PB2 | LED_WAVE | 83 84初始化引脚为GPIO。首先通过 `LzGpioInit()`初始化GPIO引脚,其次通过 `LzGpioSetDir()`设置GPIO为输出模式,最后通过 `LzGpioSetVal()`设置输出高电平/低电平。 85 86```c 87/*************************************************************** 88* 函数名称: gesture_sensor_led_init 89* 说 明: 初始化LED的GPIO引脚 90* 参 数: 无 91* 返 回 值: 无 92***************************************************************/ 93static void gesture_sensor_led_init() 94{ 95 PinctrlSet(GPIO_LED_UP, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP); 96 LzGpioInit(GPIO_LED_UP); 97 LzGpioSetDir(GPIO_LED_UP, LZGPIO_DIR_OUT); 98 gesture_sensor_led_up(0); 99 100 PinctrlSet(GPIO_LED_DOWN, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP); 101 LzGpioInit(GPIO_LED_DOWN); 102 LzGpioSetDir(GPIO_LED_DOWN, LZGPIO_DIR_OUT); 103 gesture_sensor_led_down(0); 104 105 PinctrlSet(GPIO_LED_LEFT, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP); 106 LzGpioInit(GPIO_LED_LEFT); 107 LzGpioSetDir(GPIO_LED_LEFT, LZGPIO_DIR_OUT); 108 gesture_sensor_led_left(0); 109 110 PinctrlSet(GPIO_LED_RIGHT, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP); 111 LzGpioInit(GPIO_LED_RIGHT); 112 LzGpioSetDir(GPIO_LED_RIGHT, LZGPIO_DIR_OUT); 113 gesture_sensor_led_right(0); 114 115 PinctrlSet(GPIO_LED_FORWARD, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP); 116 LzGpioInit(GPIO_LED_FORWARD); 117 LzGpioSetDir(GPIO_LED_FORWARD, LZGPIO_DIR_OUT); 118 gesture_sensor_led_forward(0); 119 120 PinctrlSet(GPIO_LED_BACKWARD, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP); 121 LzGpioInit(GPIO_LED_BACKWARD); 122 LzGpioSetDir(GPIO_LED_BACKWARD, LZGPIO_DIR_OUT); 123 gesture_sensor_led_backward(0); 124 125 PinctrlSet(GPIO_LED_CW, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP); 126 LzGpioInit(GPIO_LED_CW); 127 LzGpioSetDir(GPIO_LED_CW, LZGPIO_DIR_OUT); 128 gesture_sensor_led_cw(0); 129 130 PinctrlSet(GPIO_LED_CCW, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP); 131 LzGpioInit(GPIO_LED_CCW); 132 LzGpioSetDir(GPIO_LED_CCW, LZGPIO_DIR_OUT); 133 gesture_sensor_led_ccw(0); 134 135 PinctrlSet(GPIO_LED_WAVE, MUX_FUNC0, PULL_KEEP, DRIVE_KEEP); 136 LzGpioInit(GPIO_LED_WAVE); 137 LzGpioSetDir(GPIO_LED_WAVE, LZGPIO_DIR_OUT); 138 gesture_sensor_led_wave(0); 139} 140``` 141 142**初始化i2c** 143 144初始化GPIO0_PA1和GPIO0_PA0为I2C0。首先通过 `I2cIoInit()`初始化i2c通道,最后通过 `LzI2cInit()`设置i2c配置。具体代码如下所示: 145 146```c 147/*************************************************************** 148* 函数名称: paj7620u2_i2c_init 149* 说 明: 初始化与PAJ7620U2通信的i2c 150* 参 数: 无 151* 返 回 值: 无 152***************************************************************/ 153static void paj7620u2_i2c_init() 154{ 155 if (I2cIoInit(m_i2cBus) != LZ_HARDWARE_SUCCESS) 156 { 157 printf("%s, %d: I2cIoInit failed!\n", __FILE__, __LINE__); 158 return; 159 } 160 if (LzI2cInit(E53_I2C_BUS, m_i2c_freq) != LZ_HARDWARE_SUCCESS) 161 { 162 printf("%s, %d: I2cIoInit failed!\n", __FILE__, __LINE__); 163 return; 164 } 165 166 PinctrlSet(GPIO0_PA1, MUX_FUNC3, PULL_KEEP, DRIVE_KEEP); 167 PinctrlSet(GPIO0_PA0, MUX_FUNC3, PULL_KEEP, DRIVE_KEEP); 168} 169``` 170 171**配置PAJ7620U2** 172 173通过i2c通信协议,配置PAJ7620U2。具体代码如下所示: 174 175```c 176/*************************************************************** 177* 函数名称: paj7620u2_init_config 178* 说 明: 配置PAJ7620U2为手势感应模式 179* 参 数: 无 180* 返 回 值: 无 181***************************************************************/ 182static void paj7620u2_init_config() 183{ 184 uint8_t ret = 0; 185 uint32_t size; 186 187 ret = paj7620u2_wake_up(); 188 if (ret != 0) 189 { 190 printf("%s, %s, %d: paj7620u2_wake_up failed(%d)\n", __FILE__, __func__, __LINE__, ret); 191 } 192 193 /* 初始化PAJ7620U2 */ 194 size = sizeof(m_Paj7620u2_InitRegisterConfig) / (sizeof(uint8_t) * 2); 195 for (uint32_t i = 0; i < size; i++) 196 { 197 paj7620u2_write_data(m_Paj7620u2_InitRegisterConfig[i][0], m_Paj7620u2_InitRegisterConfig[i][1]); 198 } 199 200 /* 设置为手势识别模式 */ 201 size = sizeof(m_Paj7620u2_SetGestureModeConfig) / (sizeof(uint8_t) * 2); 202 for (uint32_t i = 0; i < size; i++) 203 { 204 paj7620u2_write_data(m_Paj7620u2_SetGestureModeConfig[i][0], m_Paj7620u2_SetGestureModeConfig[i][1]); 205 } 206 207 paj7620u2_select_bank(BANK0); 208} 209``` 210 211**创建轮询任务** 212 213通过 `LOS_TaskCreate()`创建任务,每隔100msec轮询PAJ7620U2的手势寄存器。具体代码如下所示: 214 215```c 216/*************************************************************** 217* 函数名称: paj7620u2_poll_task_init 218* 说 明: 初始化轮询PAJ7620U2手势的任务 219* 参 数: 无 220* 返 回 值: 无 221***************************************************************/ 222static void paj7620u2_poll_task_init() 223{ 224 TSK_INIT_PARAM_S task; 225 uint8_t int_flag1, int_flag2; 226 UINT32 ret; 227 228 /* 初始化先进先出缓冲区 */ 229 m_fifo_intflags.offset_read = 0; 230 m_fifo_intflags.offset_write = 0; 231 232 /* 锁任务调度 */ 233 LOS_TaskLock(); 234 235 /* 创建中断之后的i2c读取中断标记寄存器的任务 */ 236 (VOID)memset_s(&task, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S)); 237 task.pfnTaskEntry = (TSK_ENTRY_FUNC)paj7620u2_poll_task; 238 task.pcName = "InterruptSemTask"; 239 task.uwStackSize = TASK_STACK_SIZE; 240 task.usTaskPrio = 10; 241 ret = LOS_TaskCreate(&m_pollTaskId, &task); 242 if (ret != LOS_OK) 243 { 244 printf("%s, %d: LOS_TaskCreate failed(%d)\n", __func__, __LINE__, ret); 245 /* 解锁任务调度 */ 246 LOS_TaskUnlock(); 247 return; 248 } 249 250 /* 解锁任务调度 */ 251 LOS_TaskUnlock(); 252 253 /* 先清空PAJ7620U2的中断标记寄存器 */ 254 paj7620u2_select_bank(BANK0); 255 paj7620u2_read_data(PAJ_REG_GET_INT_FLAG1, &int_flag1); 256 paj7620u2_read_data(PAJ_REG_GET_INT_FLAG2, &int_flag2); 257} 258``` 259 260#### 查询手势感应代码分析 261 262首先,通过 `LOS_TaskCreate()`创建任务,每隔100msec轮询PAJ7620U2的手势寄存器。如果寄存器有数据,则存储到FIFO队列中。具体代码如下所示: 263 264```c 265/*************************************************************** 266* 函数名称: paj7620u2_poll_task 267* 说 明: 轮询任务,每隔100msec访问PAJ7620U2的手势中断寄存器, 268* 如果有手势数据,则填写到m_fifo_intflags队列中。 269* 参 数: 无 270* 返 回 值: 无 271***************************************************************/ 272static VOID paj7620u2_poll_task(VOID *args) 273{ 274 uint8_t int_flag1 = 0; 275 uint8_t int_flag2 = 0; 276 uint16_t value = 0; 277 278 while (1) 279 { 280 /* 读取Paj7620U2的手势中断寄存器 */ 281 paj7620u2_select_bank(BANK0); 282 paj7620u2_read_data(PAJ_REG_GET_INT_FLAG1, &int_flag1); 283 paj7620u2_read_data(PAJ_REG_GET_INT_FLAG2, &int_flag2); 284 285 value = 0; 286 if (int_flag1 != 0) 287 { 288 value |= (uint16_t)(int_flag1); 289 } 290 if (int_flag2 != 0) 291 { 292 value |= (uint16_t)(int_flag2 << 8); 293 } 294 295 if (value != 0) 296 FifoPut(&m_fifo_intflags, value); 297 298 LOS_Msleep(100); 299 } 300} 301``` 302 303上层软件通过调用 `E53_GestureSensor_GetGestureState()`获知FIFO队列中的最新手势信息。具体代码如下: 304 305```c 306/*************************************************************** 307 * 函数名称: gesture_sensor_get_gesture_state 308 * 说 明: 获取手势感应模块手势 309 * 参 数: 310 * @flag:获取当前手势 311 * 返 回 值: 1为成功,0为失败 312 ***************************************************************/ 313unsigned int gesture_sensor_get_gesture_state(unsigned short *flag) 314{ 315 *flag = 0; 316 317 if (FifoGet(&m_fifo_intflags, flag) != 0) 318 { 319 return 1; 320 } 321 else 322 { 323 return 0; 324 } 325} 326``` 327 328## 5. 编译调试 329 330### 5.1 修改 BUILD.gn 文件 331 332修改 `vendor/lockzhiner/lingpi/sample` 路径下 BUILD.gn 文件,指定 `e53_gs_example` 参与编译。 333 334```r 335"e53_gesture_sensor", 336``` 337 338在主目录下输入编译命令。 339 340```shell 341hb build -f 342``` 343 344### 5.2 运行结果 345 346示例代码编译烧录代码后,按下开发板的RESET按键,通过串口助手查看日志,并请使用带有LCD屏幕显示如下: 347 348```c 349========== E53 Gesture Sensor Example ========== 350Get Gesture Statu: 0x1 351 Down 352========== E53 Gesture Sensor Example ========== 353Get Gesture Statu: 0x5 354 Down 355 Left 356``` 357