STC单片机USB HID设备驱动程序详解
STC单片机USB HID设备驱动程序详解
本文介绍一个使用C语言编写的STC单片机USB HID设备驱动程序。该程序实现了USB设备的类请求处理、报告读取和设置、idle状态读取和设置等功能,并通过示例演示了如何控制LED灯和读取按键状态。
代码分析
1. 头文件和全局变量c#include 'stc.h'#include 'usb.h'#include 'usb_req_class.h'
BYTE bHidIdle;BYTE bKeyCode = 0;BYTE bKeyDebounce = 0;BOOL fKeyOK;
sbit LED_NUM = P2^7;sbit LED_CAPS = P2^6;sbit LED_SCROLL = P2^5;
- 程序包含了三个头文件:'stc.h'、'usb.h'和'usb_req_class.h',分别用于STC单片机定义、USB协议栈以及类请求处理。* 定义了全局变量: *
bHidIdle:记录HID设备的idle状态。 *bKeyCode:记录按键码。 *bKeyDebounce:用于按键防抖处理,记录防抖计数。 *fKeyOK:标记是否有按键按下。* 定义了三个LED灯的控制位:LED_NUM、LED_CAPS和LED_SCROLL,分别对应键盘上的Num Lock、Caps Lock和Scroll Lock指示灯。
2. usb_req_class()函数
该函数用于处理USB类请求,根据Setup包中的请求类型进行相应的处理。cvoid usb_req_class(){ switch (Setup.bRequest) { case GET_REPORT: usb_get_report(); break; case SET_REPORT: usb_set_report(); break; case GET_IDLE: usb_get_idle(); break; case SET_IDLE: usb_set_idle(); break; case GET_PROTOCOL: usb_get_protocol(); break; case SET_PROTOCOL: usb_set_protocol(); break; default: usb_setup_stall(); return; }}
GET_REPORT和SET_REPORT:用于获取和设置HID设备的报告数据。*GET_IDLE和SET_IDLE:用于获取和设置HID设备的idle状态。*GET_PROTOCOL和SET_PROTOCOL:用于获取和设置HID设备的协议。* 如果收到的请求类型不支持,则调用usb_setup_stall()函数返回stall信号。
3. usb_get_report()和usb_set_report()函数
这两个函数分别用于读取和设置HID设备的报告数据,通过Ep0State.pData指针指向数据缓冲区,Ep0State.wSize指定数据长度。cvoid usb_get_report(){ // ... Ep0State.pData = UsbBuffer; Ep0State.wSize = Setup.wLength; usb_setup_in();}
void usb_set_report(){ // ... Ep0State.pData = UsbBuffer; Ep0State.wSize = Setup.wLength; usb_setup_out();}
usb_setup_in()和usb_setup_out()函数分别用于准备数据的输入和输出。
4. usb_get_idle()和usb_set_idle()函数
这两个函数分别用于读取和设置HID设备的idle状态,即设备在没有数据传输时进入低功耗模式的时间间隔。cvoid usb_get_idle(){ // ... Ep0State.pData = &bHidIdle; Ep0State.wSize = 1; usb_setup_in();}
void usb_set_idle(){ // ... bHidIdle = Setup.wValueH; usb_setup_status();}
usb_setup_status()函数用于发送状态阶段数据包,表示设置成功。
5. usb_class_out()函数
该函数用于处理从主机发送到设备的类请求数据,本例中用于控制LED灯的状态。cvoid usb_class_out(){ BYTE led; if (usb_bulk_intr_out(UsbBuffer, 1) == 1) { led = UsbBuffer[0]; LED_NUM = !(led & 0x01); //获取 NUM 指示灯状态 LED_CAPS = !(led & 0x02); //获取 CAPS 指示灯状态 LED_SCROLL = !(led & 0x04); //获取 SCROLL 指示灯状态 }}
usb_bulk_intr_out()函数用于接收主机发送的数据。* 根据接收到的数据控制三个LED灯的状态。
6. usb_class_in()函数
该函数用于处理从设备发送到主机的类请求数据,本例中用于发送按键数据。cvoid usb_class_in(){ BYTE key[8]; BYTE i; if (DeviceState != DEVSTATE_CONFIGURED) //如果USB配置没有完成,就直接退出 return;
if (!UsbInBusy && fKeyOK) //判断USB是否空闲,以及是否有按键按下 { fKeyOK = 0;
key[0] = 0; //清除发送缓冲区 key[1] = 0; key[2] = 0; key[3] = 0; key[4] = 0; key[5] = 0; key[6] = 0; key[7] = 0;
switch (bKeyCode) { case 0x0e: key[1] =0xe0; break; //0x1e -> 'CTRL' case 0x0d: key[2] = 0x06; break; //0x1f -> 'C' case 0x0b: key[3] = 0x19; break; //0x20 -> 'V' case 0x07: key[4] = 0x1B; break; //0x21 -> 'x' } EUSB = 0; UsbInBusy = 1; usb_write_reg(INDEX, 1); for (i=0; i<8; i++) { usb_write_reg(FIFO1, key[i]); //发送按键码 } usb_write_reg(INCSR1, INIPRDY); EUSB = 1; }}
- 检查USB连接状态和按键标志位。* 根据按键码填充按键数据。* 通过USB接口发送按键数据。
7. scan_key()函数
该函数用于扫描按键状态,并进行防抖处理。cvoid scan_key(){ BYTE key; key = 0; P3 |= 0x3c; nop(); nop(); key = (P3 & 0x3c) >> 2; //获取P3.2~P3.5按键状态 if (key != bKeyCode) { bKeyCode = key; bKeyDebounce = 20; //设置防抖时间 20 * 1ms = 20ms } else { if (bKeyDebounce) { bKeyDebounce--; if (bKeyDebounce == 0) { fKeyOK = 1; //检测到按键状态发送变化 } } } }
- 读取P3端口的按键状态。* 如果按键状态发生变化,则更新按键码并设置防抖计数器。* 如果按键状态稳定,则清除防抖计数器,并将按键标志位置位。
总结
本文详细介绍了STC单片机USB HID设备驱动程序的各个功能模块,包括类请求处理、报告读写、idle状态管理、按键扫描以及LED控制等。通过学习本程序,读者可以了解USB HID设备的基本工作原理,并能够根据自身需求进行修改和扩展。
原文地址: https://www.cveoy.top/t/topic/NVN 著作权归作者所有。请勿转载和采集!