大家好,在上一期的帖子中我们已经成功通过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)。
在系统设备中用来开启或关闭电源供应。
下面是手势传感器的相关信息

硬件接线见下图


配置硬件IIC

相关驱动函数添加


驱动函数来自坛友共享代码,在这里感谢坛友
接下来
我们先添加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模式,开启中断

接下来配置usbx组件

编辑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 /* 扩大栈空间 */
调整参数后,重新编译运行

设备管理器应该能正常识别键盘了
下一步就是添加键值生成相关函数代码
修改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工具查看的键盘事件

至此工作完成。
知其然当知其所以然。
b站链接
https://www.bilibili.com/video/BV16rageqEQT/
我要赚赏金
