这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【DIY手势翻页笔】手势翻页笔-成果贴:通过手势实现翻页功能

共9条 1/1 1 跳转至

【DIY手势翻页笔】手势翻页笔-成果贴:通过手势实现翻页功能

菜鸟
2024-07-06 14:47:03     打赏

大家好,在上一期的帖子中我们已经成功通过threadx线程把数据通过串口打印出来了

这一期主要两个事情

    1.成功驱动IIC手势识别模块

    2.实现usb(hid keyboard)功能


注意:这里给大家一个建议,很重要

          代码不要一次性全部完成再调试,写一点就运行看看板子功能是否正常。

          本人调试USB时就全部写完了,后面发现板子运行异常,最后是改一些就运行观察现象

          最后才把USB调试通过


话不多说,进入正题

我们先来调试IIC手势传感器

先来看一下IIC接口的简介

I²C只使用两条双向漏极开路(Open Drain)线,其中一条线为传输数据的串行资料线(SDA, Serial DAta line),另一条线是启动或停止传输以及发送时钟序列的串行主频(SCL, Serial CLock line)线,这两条线上都有上拉电阻[2]。I²C允许相当大的工作电压范围,但典型的电压准位为+3.3V或+5v。

I²C的参考设计使用一个7比特长度的地址空间但保留了16个地址,所以在一组总线最多可和112个节点通信[a]。常见的I²C总线依传输速率的不同而有不同的模式:标准模式(100 kbit/s)、低速模式(10 kbit/s),但时钟频率可被允许下降至零,这代表可以暂停通信。而新一代的I²C总线可以和更多的节点(支持10比特长度的地址空间)以更快的速率通信:快速模式(400 kbit/s)、快速+模式(1 Mbit/s)高速模式(3.4 Mbit/s)超高速模式(5 Mbit/s)。

I²C被应用在构造简单且可以牺牲传输速度来降低制造成本的外设上。一些常见的应用如下:

  • 为了保存用户的设置而访问NVRAM芯片。

  • 访问低速的数字模拟转换器(DAC)和模拟数字转换器(ADC)。

  • 改变监控器的对比度、色调及色彩平衡设置(VESA显示数据频道)。

  • 控制小型液晶或OLED屏幕。

  • 改变音量大小。

  • 获取硬件监控及诊断资料,例如中央处理器的温度及风扇转速。

  • 读取实时时钟(Real-time clock)。

  • 在系统设备中用来开启或关闭电源供应。

    下面是手势传感器的相关信息

    cd86a68e0a4b1923261619bb893cee6.png




硬件接线见下图

6030721d439f90e3a207e333b6ddbf5.jpg

166c7964916216d67eb749679d468ae.jpg

配置硬件IIC

1025a65a3fa7e34fce1d3543e5cfe8b.png

相关驱动函数添加

a2b8c8700b58106551f5e9c9a311872.png

8263c41261f01e265ca78f2035efd0d.png

驱动函数来自坛友共享代码,在这里感谢坛友

d016ccedb4d5e9dc825711df33645c4.png接下来

我们先添加printf函数方便调试信息打印。

https://shequ.stmicroelectronics.cn/thread-639670-1-1.html

相关printf教程可以参考上面的链接

在main.c中添加代码

/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

/* USER CODE BEGIN 0 */
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart3 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END 0 */

这样就能在工程其他地方愉快使用printf函数了,话说这里我搞了一小时。

论坛上坛友的教程只针对keil有效,这个例子基本对大部分IDE是通用的。

本人使用的cubemxIDE.


下面在app_threadx.c中添加手势传感器测试代码

/* USER CODE BEGIN Includes */
#include "main.h"
#include "i2c.h"
#include "icache.h"
#include "memorymap.h"
#include "usart.h"
#include "gpio.h"

#include "stdio.h"
#include <string.h>
#include "stdlib.h"
#include "Gesture.h"
#include "paj7620.h"
/* USER CODE END Includes */

/* USER CODE BEGIN 1 */
void my_thread_enytry(ULONG initial_input)
{
	printf("PAJ7620U2 Gesture Sensor Test Program ...\r\n");
	PAJ7620_Init();
	printf("PAJ7620U2 Gesture Sensor OK \r\n");
	while(1){
		HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
		printf("my thread test\r\n");
		GetCurrentGesture();
		tx_thread_sleep(50);
	}
}
/* USER CODE END 1 */

这里是打印信息

[14:37:31.262]收←◆PAJ7620U2 Gesture Sensor Test Program ...

[14:37:31.857]收←◆PAJ7620U2 Gesture Sensor Test Program ...

[14:37:33.218]收←◆PAJ7620U2 OK
PAJ7620U2 Gesture Sensor OK 
EEPW user:rasngsun 

[14:37:38.716]收←◆Right

[14:37:40.715]收←◆Left

[14:37:42.216]收←◆Up

[14:37:43.716]收←◆Down

[14:37:46.216]收←◆Clockwise

[14:37:46.716]收←◆Down

[14:37:48.716]收←◆Down

[14:37:51.216]收←◆Forward

[14:37:51.716]收←◆Backward

[14:37:53.216]收←◆Forward

[14:37:53.716]收←◆Backward

至此我们就可以调试USB Hid keyboard了

这里说一下主要步骤

第一步初始化USB外设,配置USB描述信息,启动USB外设

第二步就是需要创建一个USB线程去周期性读取IIC手势传感器信息通过键盘发送出去


老师视频里很多细节没有讲清楚,有可能是想让我等学院多动脑思考,好在没有辜负老师的一片苦心。

USB部分的功能其实在写这篇文章的前天就调试通过了,这里主要是巩固加强一下。

话不多说,首先配置打开USB外设,配置device模式,开启中断

d3db84f1f45f7de80c55531f5385d5d.png

接下来配置usbx组件

ea524700a2ce225237996078865ab54.png

编辑app_usb_device.c,添加如下代码

/* USER CODE BEGIN Includes */
c
/* USER CODE END Includes */

/* USER CODE BEGIN PV */
static TX_THREAD ux_hid_thread;
extern PCD_HandleTypeDef hpcd_USB_DRD_FS;
/* USER CODE END PV */

/* USER CODE BEGIN PFP */
VOID USBX_APP_Device_Init(VOID);
/* USER CODE END PFP */

/* USER CODE BEGIN 1 */
VOID USBX_APP_Device_Init(VOID)
{
    /* 初始化外设,必不可少 */
    MX_USB_PCD_Init();

    /* 外设配置 */
    HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x00, PCD_SNG_BUF, 0X18);
    HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, 0x80, PCD_SNG_BUF, 0X58);
    HAL_PCDEx_PMAConfig(&hpcd_USB_DRD_FS, USBD_HID_KEYBOARD_EPIN_ADDR, PCD_SNG_BUF, 0X98);
    ux_dcd_stm32_initialize((ULONG)USB_DRD_FS, (ULONG)&hpcd_USB_DRD_FS);

    /* 打开外设 */
    HAL_PCD_Start(&hpcd_USB_DRD_FS);
}
/* USER CODE END 1 */

接下来修改static VOID app_ux_device_thread_entry(ULONG thread_input)线程函数

在线程中初始化USB外设

/**
  * @brief  Function implementing app_ux_device_thread_entry.
  * @param  thread_input: User thread input parameter.
  * @retval none
  */
static VOID app_ux_device_thread_entry(ULONG thread_input)
{
/* USER CODE BEGIN app_ux_device_thread_entry */
TX_PARAMETER_NOT_USED(thread_input);
USBX_APP_Device_Init();
/* USER CODE END app_ux_device_thread_entry */
}

编译运行,观察效果

效果如何呢,不太理想,并没有识别到,需要调整USBX组件配置

UX_SLAVE_REQUEST_DATA_MAX_LENGTH = 64  /* 这个值太大会占用栈空间,默认最小值就行 */

UXDevice memory pool size = 8192 /* 扩大内存池空间 */

USBX Device System Stack Size = 4 * 1024 /* 扩大栈空间 */

调整参数后,重新编译运行

893666989f236181592959f93573bea.png

设备管理器应该能正常识别键盘了


下一步就是添加键值生成相关函数代码

修改ux_device_keyboard.c


/* USER CODE BEGIN Includes */
#include "main.h"
/* USER CODE END Includes */

/* USER CODE BEGIN PV */
UX_SLAVE_CLASS_HID *hid_keyboard;
/* USER CODE END PV */

/* USER CODE BEGIN 0 */
uint8_t keyboard[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

static void GetKeyboardData(UX_SLAVE_CLASS_HID_EVENT *hid_event)
{
    keyboard[2] = 0x04;
    hid_event->ux_device_class_hid_event_length = 8;
    for (size_t i = 0; i < 8; i++)
    {
        hid_event->ux_device_class_hid_event_buffer[i] = keyboard[i];
    }
}

static void ClearKeyboardData(UX_SLAVE_CLASS_HID_EVENT *hid_event)
{
    hid_event->ux_device_class_hid_event_length = 8;
    for (size_t i = 0; i < 8; i++)
    {
        hid_event->ux_device_class_hid_event_buffer[i] = 0;
    }
}
/* USER CODE END 0 */

以上是添加的,还有两处需要修改

VOID USBD_HID_Keyboard_Activate(VOID *hid_instance)
{
  /* USER CODE BEGIN USBD_HID_Keyboard_Activate */
//   UX_PARAMETER_NOT_USED(hid_instance);
    hid_keyboard = (UX_SLAVE_CLASS_HID *)hid_instance;
  /* USER CODE END USBD_HID_Keyboard_Activate */

  return;
}

VOID USBD_HID_Keyboard_Deactivate(VOID *hid_instance)
{
  /* USER CODE BEGIN USBD_HID_Keyboard_Deactivate */
  UX_PARAMETER_NOT_USED(hid_instance);
  hid_keyboard = UX_NULL;
  /* USER CODE END USBD_HID_Keyboard_Deactivate */

  return;
}

这两个代码是USB插拔的时候执行的相关功能代码。

接下来修改ux_device_keyboard.h添加外部声明

/* USER CODE BEGIN ET */
extern UX_SLAVE_CLASS_HID *hid_keyboard;
extern static void GetKeyboardData(UX_SLAVE_CLASS_HID_EVENT *hid_event);
extern static void ClearKeyboardData(UX_SLAVE_CLASS_HID_EVENT *hid_event);
/* USER CODE END ET */


接下来我们需要调整IIC外设初始化函数的位置

修改app_threadx.c文件my_thread_enytry函数

把手势识别相关代码屏蔽

void my_thread_enytry(ULONG initial_input)
{
//	printf("PAJ7620U2 Gesture Sensor Test Program ...\r\n");
////	PAJ7620_Init();
//	printf("PAJ7620U2 Gesture Sensor OK \r\n");
//	printf("EEPW user:rasngsun \r\n");
	while(1){
		HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
//		GetCurrentGesture();
		tx_thread_sleep(50);
	}
}

手势识别模块读取将在app_usbx_device.c文件中完成

接下来编辑app_usbx_device.c文件

/* USER CODE BEGIN Includes */
#include "main.h"
#include "i2c.h"
#include "icache.h"
#include "memorymap.h"
#include "usart.h"
#include "gpio.h"

#include "stdio.h"
#include <string.h>
#include "stdlib.h"
#include "Gesture.h"
#include "paj7620.h"
/* USER CODE END Includes */

static VOID app_ux_device_thread_entry(ULONG thread_input)
{
/* USER CODE BEGIN app_ux_device_thread_entry */
TX_PARAMETER_NOT_USED(thread_input);
USBX_APP_Device_Init();

UX_SLAVE_DEVICE *device;
UX_SLAVE_CLASS_HID_EVENT hid_event;
device = &_ux_system_slave->ux_system_slave_device;
ux_utility_memory_set(&hid_event, 0, sizeof(UX_SLAVE_CLASS_HID_EVENT));
PAJ7620_Init();
printf("app_ux_device_thread EEPW user:rasngsun \r\n");
while (1)
{
		/* Check if the device state already configured */  
		if ((device->ux_slave_device_state == UX_DEVICE_CONFIGURED) && (hid_keyboard != UX_NULL))
		{
			/* sleep for 10ms */  
			tx_thread_sleep(MS_TO_TICK(100));
			hid_event.ux_device_class_hid_event_length = 8;
			hid_event.ux_device_class_hid_event_buffer[0] = 0;
			hid_event.ux_device_class_hid_event_buffer[1] = 0;

			int Gesture_Data = GetCurrentGesture();
			/* 默认键值 */
			UCHAR keyValue = 0;
			switch (Gesture_Data)
			{
				case PAJ_UP:			//Keyboard PageUp
					keyValue = 0x4B;
					break;
				case PAJ_DOWN:		//Keyboard PageDown
					keyValue = 0x4E;
					break;
				case PAJ_LEFT:		//Keyboard LeftArrow
					keyValue = 0x50;
					break;
				case PAJ_RIGHT:		//Keyboard RightArrow
					keyValue = 0x4F;
					break;
				case PAJ_FORWARD:	//Keyboard Home
					keyValue = 0x4A;
					break;
				case PAJ_BACKWARD://Keyboard End
					keyValue = 0x4A;
					break;
				case PAJ_CLOCKWISE:
					break;
				case PAJ_COUNT_CLOCKWISE:
					break;
				case PAJ_WAVE:
					break;
				default:
					break;
			}

			/* 按键赋值 */
			hid_event.ux_device_class_hid_event_buffer[2] = keyValue;
			/* 按键事件发送*/
			ux_device_class_hid_event_set(hid_keyboard, &hid_event);
		}
		else  
		{
			/* sleep for 10ms */  
			tx_thread_sleep(MS_TO_TICK(10));
		}
}
/* USER CODE END app_ux_device_thread_entry */
}

我这里的代码直接在它现有的线程里面运行的,和老师讲的不太一样

没有单独创建usb_hid_keyboard_thread,这里还请留意。

条条大路通罗马,没必要执着。

能调试通过就可以。


下面来看效果:

我是通过网页在线keyboard event log工具查看的键盘事件

e0a5ea8ab3a26ac2ef654904f91ac09.png

至此工作完成。

知其然当知其所以然。

b站链接

https://www.bilibili.com/video/BV16rageqEQT/



高工
2024-07-06 14:55:07     打赏
2楼

谢谢分享


高工
2024-07-06 15:07:57     打赏
3楼

谢谢分享


专家
2024-07-06 15:12:33     打赏
4楼

谢谢分享


高工
2024-07-06 22:48:54     打赏
5楼

谢谢分享


专家
2024-07-07 07:02:50     打赏
6楼

看一下


专家
2024-07-07 10:50:27     打赏
7楼

不错啊


专家
2024-07-07 18:02:40     打赏
8楼

看一下


高工
2024-07-08 08:40:30     打赏
9楼

看一下


共9条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]