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_NUMLED_CAPSLED_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_REPORTSET_REPORT:用于获取和设置HID设备的报告数据。* GET_IDLESET_IDLE:用于获取和设置HID设备的idle状态。* GET_PROTOCOLSET_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 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录