0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

【GD32F303紅楓派開發(fā)板使用手冊】第二十七講 USB-虛擬鍵盤實(shí)驗(yàn)

聚沃科技 ? 2024-06-27 09:42 ? 次閱讀
wKgaomZVdiiAfR9BAB3mDFhHnZc972.png

27.1實(shí)驗(yàn)內(nèi)容

通過本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容:

  • USB協(xié)議基本原理
  • GD32F303 USBD的使用
  • 虛擬鍵盤的協(xié)議原理及使用

27.2實(shí)驗(yàn)原理

27.2.1USB通信基礎(chǔ)知識

USB的全稱是Universal Serial Bus,通用串行總線。它的出現(xiàn)主要是為了簡化個(gè)人計(jì)算機(jī)與外圍設(shè)備的連接,增加易用性。USB支持熱插拔,并且是即插即用的,另外,它還具有很強(qiáng)的可擴(kuò)展性,傳輸速度也很快,這些特性使支持USB接口電子設(shè)備更易用、更大眾化。GD32F303系列MCU集成了USB2.0全速設(shè)備USBD模塊,可以滿足作為USB設(shè)備與主機(jī)通信的需求。首先為大家介紹USB通信的一些基礎(chǔ)知識,包括USB協(xié)議、枚舉流程等,建議讀者可以多多閱讀USB協(xié)議,以更深入了解USB,USB官網(wǎng)鏈接如下,可參考:https://www.usb.org/

27.2.1.1USB金字塔型拓?fù)浣Y(jié)構(gòu)

塔頂為USB主控制器和根集線器(Root Hub),下面接USB集線器(Hub),集線器將一個(gè)USB口擴(kuò)展為多個(gè)USB口,USB2.0規(guī)定集線器的層數(shù)最多為6層,理論上一個(gè)USB主控制器最多可接127個(gè)設(shè)備,因?yàn)閰f(xié)議規(guī)定USB設(shè)備具有一個(gè)7 bit的地址(取值范圍為0~127,而地址0是保留給未初始化的設(shè)備使用的)。

wKgZomZJWwyAXF12AAGV9tCTOqI472.png

27.2.1.2NRZI編碼

USB采用差分信號傳輸,使用的是如上圖所示的NRZI編碼方式:數(shù)據(jù)為0時(shí),電平翻轉(zhuǎn);數(shù)據(jù)為1時(shí),電平不翻轉(zhuǎn)。如果出現(xiàn)6個(gè)連續(xù)的數(shù)據(jù)1,則插入一個(gè)數(shù)據(jù)0,強(qiáng)制電平翻轉(zhuǎn),以便時(shí)鐘同步。上面的一條線表示的是原始數(shù)據(jù)序列,下面的一條線表示的是經(jīng)過NRZI編碼后的數(shù)據(jù)序列。

wKgZomZJWxWAQSVxAAIlErHJeKI886.png

27.2.1.3USB數(shù)據(jù)協(xié)議

USB數(shù)據(jù)是由二進(jìn)制數(shù)據(jù)串組成,首先由數(shù)據(jù)串構(gòu)成包(packet),包再構(gòu)成事務(wù)(transaction),事務(wù)最終構(gòu)成傳輸(transfer)。

USB傳輸?shù)淖钚挝粸榘?,一個(gè)包被分成不同的域,根據(jù)不同類型的包,所包含的域是不一樣的,但是不同的包有個(gè)共同的特點(diǎn),就是以包起始(SOP)開始,之后是同步域(0x00000001),然后是包內(nèi)容,最后以包結(jié)束符(EOP)結(jié)束這個(gè)包。PID為標(biāo)識域,由四位標(biāo)識符加4位標(biāo)識符反碼構(gòu)成,表明包的類型和格式。根據(jù)PID的不同,USB協(xié)議中規(guī)定的包類型有令牌包、數(shù)據(jù)包、握手包和特殊包等。

wKgaomZJWyGAdonqAAB8I0rvGFU350.png

USB事務(wù)通常有兩個(gè)或三個(gè)包組成:令牌包、數(shù)據(jù)包和握手包,令牌包用來啟動一個(gè)事務(wù),總是由主機(jī)發(fā)送;數(shù)據(jù)包用來傳輸數(shù)據(jù);握手包由數(shù)據(jù)接收者進(jìn)行發(fā)送,表明數(shù)據(jù)的接收情況。批量、同步和中斷傳輸每次傳輸都是一個(gè)事務(wù),控制傳輸包括三個(gè)階段:建立過程、數(shù)據(jù)過程和狀態(tài)過程。

針對不同的數(shù)據(jù)傳輸場景,USB分為四種數(shù)據(jù)傳輸模式,這四種傳輸模式分別由不同的包(packet)組成,并且有不同的數(shù)據(jù)處理策略。每種數(shù)據(jù)傳輸模式的流程示意圖以及應(yīng)用場景如下:

  • 控制傳輸一般用于命令和狀態(tài)的傳輸,分為控制讀、控制寫和無數(shù)據(jù)控制傳輸。在設(shè)備枚舉的過程中,采用控制傳輸方式進(jìn)行數(shù)據(jù)傳輸。
wKgaomZJWyyADNPjAACEVK-mK84554.png
  • 批量傳輸分為批量讀和批量寫,用于數(shù)據(jù)量大、對實(shí)時(shí)性要求不高的場合,如U盤。
wKgaomZJWzqAZO8uAAFUBWvFHOc025.png
  • 中斷傳輸用于數(shù)據(jù)量小的場合,保證查詢頻率,如鼠標(biāo)、鍵盤。
wKgZomZJW0eAXrKzAACbdpLmWDg195.png
  • 同步傳輸用于數(shù)據(jù)量大、同時(shí)對實(shí)時(shí)性要求較高的場合,如音視頻。不保證數(shù)據(jù)完整性,沒有ACK/NAK應(yīng)答包,不進(jìn)行數(shù)據(jù)重傳。
wKgZomZJW0eAXrKzAACbdpLmWDg195.png

27.2.1.4USB描述符

wKgZomZJW12AEgDpAAG50oNk3Wg291.png
  • 一個(gè)USB設(shè)備通常有一個(gè)或多個(gè)配置,但在同一時(shí)刻只能有一個(gè)配置;
  • 一個(gè)配置通常有一個(gè)或多個(gè)接口;
  • 一個(gè)接口通常有一個(gè)或多個(gè)端點(diǎn);

在USB通信中,USB設(shè)備需要配置多個(gè)USB描述符用以枚舉階段將描述符返回給主機(jī),用以主機(jī)的枚舉以及識別。USB描述符包括設(shè)備描述符、配置描述符、接口描述符、端點(diǎn)描述符以及字符串描述符等。在GD32 USBD固件庫中,針對各種描述符都按照USB協(xié)議定義了相關(guān)結(jié)構(gòu)體,具體說明如下。

  • 設(shè)備描述符

每個(gè)設(shè)備必須有一個(gè)設(shè)備描述符,設(shè)備描述符提供了關(guān)于設(shè)備的配置、設(shè)備所歸屬的類、設(shè)備所遵循的協(xié)議代碼、VID、PID等信息,其相關(guān)結(jié)構(gòu)體定義如下。

C
typedef struct _usb_desc_dev {
usb_desc_header header; /*!< descriptor header, including type and size */
uint16_t bcdUSB; /*!< BCD of the supported USB specification */
uint8_t bDeviceClass; /*!< USB device class */
uint8_t bDeviceSubClass; /*!< USB device subclass */
uint8_t bDeviceProtocol; /*!< USB device protocol */
uint8_t bMaxPacketSize0; /*!< size of the control (address 0) endpoint's bank in bytes */
uint16_t idVendor; /*!< vendor ID for the USB product */
uint16_t idProduct; /*!< unique product ID for the USB product */
uint16_t bcdDevice; /*!< product release (version) number */
uint8_t iManufacturer; /*!< string index for the manufacturer's name */
uint8_t iProduct; /*!< string index for the product name/details */
uint8_t iSerialNumber; /*!< string index for the product's globally unique hexadecimal serial number */
uint8_t bNumberConfigurations; /*!< total number of configurations supported by the device */
} usb_desc_dev;
  • 配置描述符

每個(gè)USB設(shè)備都至少具有一個(gè)配置描述符,在設(shè)備描述符中規(guī)定了該設(shè)備有多少種配置,每種配置都有一個(gè)描述符,其相關(guān)結(jié)構(gòu)體定義如下。

C
typedef struct _usb_desc_config {
usb_desc_header header; /*!< descriptor header, including type and size */
uint16_t wTotalLength; /*!< size of the configuration descriptor header, and all sub descriptors inside the configuration */
uint8_t bNumInterfaces; /*!< total number of interfaces in the configuration */
uint8_t bConfigurationValue; /*!< configuration index of the current configuration */
uint8_t iConfiguration; /*!< index of a string descriptor describing the configuration */
uint8_t bmAttributes; /*!< configuration attributes */
uint8_t bMaxPower; /*!< maximum power consumption of the device while in the current configuration */
} usb_desc_config;
  • 接口描述符

接口描述符用以描述接口信息,接口描述符不能單獨(dú)返回,必須附著在配置描述符后一并返回,其相關(guān)結(jié)構(gòu)體定義如下。

C
typedef struct _usb_desc_itf {
usb_desc_header header; /*!< descriptor header, including type and size */
uint8_t bInterfaceNumber; /*!< index of the interface in the current configuration */
uint8_t bAlternateSetting; /*!< alternate setting for the interface number */
uint8_t bNumEndpoints; /*!< total number of endpoints in the interface */
uint8_t bInterfaceClass; /*!< interface class ID */
uint8_t bInterfaceSubClass; /*!< interface subclass ID */
uint8_t bInterfaceProtocol; /*!< interface protocol ID */
uint8_t iInterface; /*!< index of the string descriptor describing the interface */
} usb_desc_itf;
  • 端點(diǎn)描述符

端點(diǎn)描述符用以描述端點(diǎn)信息,端點(diǎn)描述符不能單獨(dú)返回,必須附著在配置描述符后一并返回,其相關(guān)結(jié)構(gòu)體定義如下。

C
typedef struct _usb_desc_ep {
usb_desc_header header; /*!< descriptor header, including type and size */
uint8_t bEndpointAddress; /*!< logical address of the endpoint */
uint8_t bmAttributes; /*!< endpoint attribute */
uint16_t wMaxPacketSize; /*!< size of the endpoint bank, in bytes */
uint8_t bInterval; /*!< polling interval in milliseconds for the endpoint if it is an INTERRUPT or ISOCHRONOUS type */
} usb_desc_ep;
  • 字符串描述符

字符串描述符可含有指向描述制造商、產(chǎn)品、序列號、配置和接口的字符串的索引。類和制造商專屬描述符可含有指向額外字符串描述符的索引。對字符串描述符的支持是可選的,有些類可能會需要它們。

C
typedef struct _usb_desc_str {
usb_desc_header header; /*!< descriptor header, including type and size. */
uint16_t unicode_string[64]; /*!< unicode string data */
} usb_desc_str;

27.2.1.5USB枚舉過程

USB枚舉實(shí)際上是host檢測到device插入后,通過發(fā)送各種標(biāo)準(zhǔn)請求,請device返回各種USB描述符的過程。USB枚舉的示意圖如下:

wKgaomZJW7yAXYOoAAH64GaWpyY119.png

27.2.2GD32 USBD模塊簡介

GD32F303系列MCU提供了一個(gè)USB2.0全速USBD接口模塊,它內(nèi)部包含了一個(gè)USB物理層而不需要額外的外部物理層芯片。USBD支持USB 2.0協(xié)議所定義的四種傳輸類型(控制、批量、中斷和同步傳輸)。

主要特性如下:

? USB 2.0全速設(shè)備控制器;
?最多支持8個(gè)可配置的端點(diǎn);
?支持雙緩沖的批量傳輸端點(diǎn)/同步傳輸端點(diǎn);
?支持USB 2.0鏈接電源管理;
?每個(gè)端點(diǎn)都支持控制,批量,同步或中斷傳輸(端點(diǎn)0除外,端點(diǎn)0只支持控制傳輸) ;
?支持USB掛起/恢復(fù)操作;
?與CAN共享512字節(jié)的專用SRAM用于數(shù)據(jù)緩沖;
?集成的USB物理層。

USBD模塊框圖如下所示。

wKgaomZ8wnKAbBqzAAFbCLXh4Mc211.png

27.2.3USBD固件庫說明

USBD固件庫框圖如下所示。用戶應(yīng)用程序(User application)調(diào)用GD32全速USB設(shè)備固件庫中的接口實(shí)現(xiàn)USB設(shè)備與主機(jī)之間的通信,架構(gòu)的最底層為GD32 MCU開發(fā)板的硬件。其中,GD32全速USB設(shè)備固件庫(GD32F30x_usbd_Library)分為兩層,頂層為應(yīng)用接口層,用戶可以修改,包含main.c和USB相關(guān)設(shè)備類驅(qū)動;底層為USBD設(shè)備驅(qū)動層,不建議用戶修改,該驅(qū)動層包含實(shí)現(xiàn)USB通信相關(guān)協(xié)議以及USBD底層模塊操作。

wKgaomZ8woyAaJ2EAAG4MhOkvhQ070.png

USBD_Drivers設(shè)備驅(qū)動層(Firmware\GD32F30x_usbd_library\usbd)包含兩個(gè)文件夾,分別為Include和Source,其中,Include為底層頭文件,Source為底層源文件。

wKgaomZ8wpeAJ9tuAAA6iP8RPTI757.png

其中,usbd_lld_core.h/c文件中的庫函數(shù)說明如下所示。

wKgZomZ8wqKAepARAAFfoy9s5nQ263.png

usbd_lld_int.h/.c文件中的庫函數(shù)說明如下所示。

wKgaomZ8wq6AeCZJAABXo8wU760943.png

USBD_Device設(shè)備驅(qū)動層(Firmware\GD32F30x_usbd_library\device)包含兩個(gè)文件夾,分別為Include和Source,其中,Include為底層頭文件,Source為底層源文件。

wKgZomZ8wrqASq86AABRpf5vw68059.png

其中,usbd_core.h/.c文件中的庫函數(shù)說明如下所示。

wKgZomZ8wvGAN-dgAABTmIPI5aA557.png

usbd_enum.h/.c文件中的庫函數(shù)說明如下所示。

wKgaomZ8wvaAI6iyAAFtq4sz3Vc285.png

usbd_pwr.h/.c文件中的庫函數(shù)說明如下所示。

wKgaomZ8wwKAXm77AAAooMMPhFY828.png

usbd_transc.h/.c文件中的庫函數(shù)說明如下所示。

wKgZomZ8wwuALMMpAACzxZJpV2s097.png

27.3硬件設(shè)計(jì)

GD32F303紅楓派開發(fā)板的USB通信接口選擇的是目前較為通用的Type C接口,讀者手中的用于手機(jī)充電的Type C通信線即可使用。

USB的DP和DM線上使用22歐姆串阻,DP線通過1.5K電阻上拉到USBFS_CTL控制引腳,該引腳使用的是PD3引腳。

wKgaomZ8wymAQvBMAAG-5PxXOdw157.png

27.4代碼解析

本例程主要實(shí)現(xiàn)通過按鍵向PC發(fā)送鍵值的現(xiàn)象,實(shí)現(xiàn)模擬鍵盤的效果。

本例程主函數(shù)如下所示,首先配置延遲初始化,歷程中使用到了ms延遲,之后配置rcu、gpio、usbd、NVIC等相關(guān)外設(shè),具體說明將在后續(xù)介紹。

C
int main(void)
{
delay_init();
/* system clocks configuration */
rcu_config();

/* GPIO configuration */
gpio_config();

hid_itfop_register (&usb_hid, &fop_handler);

/* USB device configuration */
usbd_init(&usb_hid, &hid_desc, &hid_class);

/* NVIC configuration */
nvic_config();

usbd_connect(&usb_hid);

while(USBD_CONFIGURED != usb_hid.cur_status){
}

while (1) {
fop_handler.hid_itf_data_process(&usb_hid);
}
}

rcu的配置如下,主要用于配置USB時(shí)鐘,USB需要一個(gè)穩(wěn)定的48M時(shí)鐘,一般可通過系統(tǒng)時(shí)鐘分頻獲取,由于有固定的分頻系數(shù),所以系統(tǒng)時(shí)鐘一般選擇48M、72M、96M或120M,歷程中做了自動分頻適配。另外如果使用IRC48Mhz時(shí)鐘作為USB時(shí)鐘,系統(tǒng)時(shí)鐘大于24MHz即可。

C
void rcu_config(void)
{
uint32_t system_clock = rcu_clock_freq_get(CK_SYS);

/* enable USB pull-up pin clock */
rcu_periph_clock_enable(RCU_AHBPeriph_GPIO_PULLUP);

if (48000000U == system_clock) {
rcu_usb_clock_config(RCU_CKUSB_CKPLL_DIV1);
} else if (72000000U == system_clock) {
rcu_usb_clock_config(RCU_CKUSB_CKPLL_DIV1_5);
} else if (96000000U == system_clock) {
rcu_usb_clock_config(RCU_CKUSB_CKPLL_DIV2);
} else if (120000000U == system_clock) {
rcu_usb_clock_config(RCU_CKUSB_CKPLL_DIV2_5);
} else {
/* reserved */
}

/* enable USB APB1 clock */
rcu_periph_clock_enable(RCU_USBD);
}

gpio配置主要用于配置DP線的上拉電阻,dp線上拉主要用于控制USB設(shè)備接入主機(jī)的時(shí)機(jī)。本例程中使用PD3的引腳。

若讀者的硬件使用其他的引腳作為dp線的上拉控制,修改上拉引腳的宏定義配置即可。

C
void gpio_config(void)
{
/* configure usb pull-up pin */
gpio_init(USB_PULLUP, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, USB_PULLUP_PIN);

/* USB wakeup EXTI line configuration */
exti_interrupt_flag_clear(EXTI_18);
exti_init(EXTI_18, EXTI_INTERRUPT, EXTI_TRIG_RISING);
}
#define USB_PULLUP GPIOD
#define USB_PULLUP_PIN GPIO_PIN_3
#define RCU_AHBPeriph_GPIO_PULLUP RCU_GPIOD

注冊HID接口操作函數(shù)如下所示。在該代碼清單中,注冊了HID接口操作的配置以及數(shù)據(jù)處理函數(shù)句柄,用于后續(xù)函數(shù)調(diào)用。

C
uint8_t hid_itfop_register (usb_dev *udev, hid_fop_handler *hid_fop)
{
if (NULL != hid_fop) {
udev->user_data = (void *)hid_fop;

return USBD_OK;
}

return USBD_FAIL;
}

USBD內(nèi)核初始化函數(shù)如下所示。在該代碼清單中,首先配置USB內(nèi)核基本屬性參數(shù),然后初始化USBD描述符、設(shè)備類內(nèi)核以及設(shè)備類處理函數(shù)指針,之后初始化端點(diǎn)事務(wù)函數(shù)數(shù)組,配置電源管理以及USB掛起狀態(tài)使能,最后調(diào)用設(shè)備類內(nèi)核初始化函數(shù)完成USBD內(nèi)核初始化。

C
void usbd_init (usb_dev *udev, usb_desc *desc, usb_class *usbc)
{
/* configure USBD core basic attributes */
usbd_core.basic.max_ep_count = 8U;
usbd_core.basic.twin_buf = 1U;
usbd_core.basic.ram_size = 512U;

usbd_core.dev = udev;

udev->desc = desc;
udev->class_core = usbc;
udev->drv_handler = &usbd_drv_handler;

udev->ep_transc[0][TRANSC_SETUP] = _usb_setup_transc;
udev->ep_transc[0][TRANSC_OUT] = _usb_out0_transc;
udev->ep_transc[0][TRANSC_IN] = _usb_in0_transc;

/* configure power management */
udev->pm.power_mode = (udev->desc->config_desc[7] & 0x40U) >> 5;

/* enable USB suspend */
udev->pm.suspend_enabled = 1U;

/* USB low level initialization */
udev->drv_handler->init();

/* create serial string */
serial_string_get((uint16_t *)udev->desc->strings[STR_IDX_SERIAL]);
}

NVIC配置函數(shù)如下所示。在該代碼清單中首先對NVIC分組進(jìn)行配置,其中1位用于搶占優(yōu)先級,3位用于次優(yōu)先級。之后使能USBD低優(yōu)先級中斷和喚醒中斷。

C
void nvic_config(void)
{
/* 2 bits for preemption priority, 2 bits for subpriority */
nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);

/* enable the USB low priority interrupt */
nvic_irq_enable((uint8_t)USBD_LP_CAN0_RX0_IRQn, 1U, 0U);

/* enable the USB Wake-up interrupt */
nvic_irq_enable((uint8_t)USBD_WKUP_IRQn, 0U, 0U);
}

然后調(diào)用usbd_connect(&usb_hid);函數(shù)將上拉引腳電平進(jìn)行上拉,并將USB設(shè)備狀態(tài)udev->cur_status設(shè)置為連接狀態(tài)USBD_CONNECTED。

C
__STATIC_INLINE void usbd_connect (usb_dev *udev)
{
udev->drv_handler->dp_pullup(SET);

udev->cur_status = (uint8_t)USBD_CONNECTED;
}

上拉電阻被上拉后,主機(jī)將會對設(shè)備進(jìn)行枚舉,設(shè)備端采用while(USBD_CONFIGURED != usb_hid.cur_status)語句進(jìn)行等待。當(dāng)USB設(shè)備狀態(tài)變?yōu)閁SBD_CONFIGURED狀態(tài)時(shí),表明設(shè)備枚舉完成。

枚舉完成之后,程序?qū)⑦M(jìn)入主循環(huán)中,在主循環(huán)中,循環(huán)調(diào)用HID USB模擬鍵盤數(shù)據(jù)處理函數(shù),在該函數(shù)中,首先判斷上次傳輸是否完成,完成之后通過掃描按鍵的方式查看按鍵是否被按下,若按鍵被按下,則通過hid_report_send()函數(shù)發(fā)送鍵盤報(bào)告數(shù)據(jù)。

C
static void hid_key_data_send(usb_dev *udev)
{
standard_hid_handler *hid = (standard_hid_handler *)udev->class_data[USBD_HID_INTERFACE];

if (hid->prev_transfer_complete) {
switch (key_state()) {
case CHAR_A:
hid->data[2] = 0x04U;
break;
case CHAR_B:
hid->data[2] = 0x05U;
break;
case CHAR_C:
hid->data[2] = 0x06U;
break;
default:
break;
}

if (0U != hid->data[2]) {
hid_report_send(udev, hid->data, HID_IN_PACKET);
}
}
}

報(bào)文發(fā)送函數(shù)定義如下,該函數(shù)包含三個(gè)參數(shù),udev為初始化后的設(shè)備操作結(jié)構(gòu)體;report為發(fā)送報(bào)告緩沖區(qū)地址;len為發(fā)送報(bào)告的長度。在該函數(shù)中,如果設(shè)備已經(jīng)被枚舉成功,則首先將prev_transfer_complete標(biāo)志位設(shè)置為0,表明接下來將進(jìn)行發(fā)送數(shù)據(jù),數(shù)據(jù)并未發(fā)送完成,之后,調(diào)用usbd_ep_send()將需要發(fā)送的報(bào)告拷貝到USB外設(shè)緩沖區(qū)中并設(shè)置端點(diǎn)為有效狀態(tài),等待主機(jī)發(fā)送IN令牌包,USB設(shè)備將外設(shè)緩沖區(qū)中的數(shù)據(jù)發(fā)送給主機(jī)。

C
uint8_t hid_report_send (usb_dev *udev, uint8_t *report, uint16_t len)
{
standard_hid_handler *hid = (standard_hid_handler *)udev->class_data[USBD_HID_INTERFACE];

/* check if USB is configured */
hid->prev_transfer_complete = 0U;

usbd_ep_send(udev, HID_IN_EP, report, len);

return USBD_OK;
}

當(dāng)數(shù)據(jù)發(fā)送完成,USB設(shè)備將調(diào)用hid_data_in_handler()函數(shù)進(jìn)行數(shù)據(jù)處理。該函數(shù)程序如下所示。在該函數(shù)中,首先判斷hid->data[2]的數(shù)據(jù)是否為0x00,如果不為0x00表明上次發(fā)送的為按鍵按下的鍵值,還需發(fā)送按鍵松開的鍵值,如果為0x00表明上次按鍵按下和松開的鍵值均已發(fā)送完成,之后將prev_transfer_complete設(shè)置為1,表明上一次的按鍵數(shù)據(jù)傳輸完成,可進(jìn)行下次按鍵數(shù)據(jù)傳輸。

C
static void hid_data_in_handler (usb_dev *udev, uint8_t ep_num)
{
standard_hid_handler *hid = (standard_hid_handler *)udev->class_data[USBD_HID_INTERFACE];

if (hid->data[2]) {
hid->data[2] = 0x00U;

usbd_ep_send(udev, HID_IN_EP, hid->data, HID_IN_PACKET);
} else {
hid->prev_transfer_complete = 1U;
}
}

在該例程中通過hid->prev_transfer_complete數(shù)據(jù)流程標(biāo)志位進(jìn)行數(shù)據(jù)發(fā)送控制,讀者可使用該標(biāo)志位用于對數(shù)據(jù)發(fā)送的控制,當(dāng)該標(biāo)志位為0的時(shí)候,表明數(shù)據(jù)已被填送到USB緩沖區(qū),但還沒有發(fā)送給主機(jī),此時(shí)MCU不能繼續(xù)調(diào)用發(fā)送函數(shù)向緩沖區(qū)中填數(shù)據(jù),否則可能導(dǎo)致數(shù)據(jù)覆蓋丟失,正確做法是等待該標(biāo)志位置位,表明上一包數(shù)據(jù)已被主機(jī)讀取,然后再繼續(xù)發(fā)送后續(xù)數(shù)據(jù)。

27.5實(shí)驗(yàn)結(jié)果

將本例程燒錄到紅楓派開發(fā)板中,通過Type C數(shù)據(jù)線連接開發(fā)板和PC,之后按下ROCKER_KEY、K1、K2按鍵,將會向PC發(fā)送A、B、C鍵值。

wKgaomZ8wzyAfmMqAAA0SJAUT7k527.png

教程GD32 MCU方案商聚沃科技原創(chuàng)發(fā)布,了解更多GD32 MCU教程,關(guān)注聚沃科技官網(wǎng)

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 單片機(jī)
    +關(guān)注

    關(guān)注

    6037

    文章

    44558

    瀏覽量

    635217
  • 嵌入式
    +關(guān)注

    關(guān)注

    5082

    文章

    19123

    瀏覽量

    305147
  • 彩燈
    +關(guān)注

    關(guān)注

    4

    文章

    65

    瀏覽量

    33724
  • 開發(fā)板
    +關(guān)注

    關(guān)注

    25

    文章

    5050

    瀏覽量

    97456
  • Timer
    +關(guān)注

    關(guān)注

    1

    文章

    64

    瀏覽量

    12786
收藏 人收藏

    評論

    相關(guān)推薦

    GD32F303紅楓開發(fā)板使用手冊第二十USB-虛擬串口實(shí)驗(yàn)

    USB的CDC類是USB通信設(shè)備類 (Communication Device Class)的簡稱。CDC類是USB組織定義的一類專門給各種通信設(shè)備使用的USB子類。該設(shè)備類采用批量傳
    的頭像 發(fā)表于 07-03 10:48 ?1314次閱讀
    【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】<b class='flag-5'>第二十</b><b class='flag-5'>講</b>八 <b class='flag-5'>USB-</b><b class='flag-5'>虛擬</b>串口<b class='flag-5'>實(shí)驗(yàn)</b>

    GD32F303】星空介紹

    一、開發(fā)板介紹星空GD開發(fā)板是由旗點(diǎn)科技推出的一款GD32開發(fā)板,板載
    發(fā)表于 09-11 17:55

    【星空GD32F303開發(fā)板試用體驗(yàn)】開發(fā)記錄匯總

    本帖最后由 申小林一號 于 2021-10-15 14:47 編輯 開貼日期:2021年10月11日該貼主要是用于記錄星空開發(fā)板使用記錄以及學(xué)習(xí)GD32F303芯片的一個(gè)過程,將所有的
    發(fā)表于 10-11 16:09

    【星空GD32F303開發(fā)板試用體驗(yàn)】開箱+環(huán)境搭建

    本帖最后由 lustao 于 2021-10-19 09:29 編輯 感謝 發(fā)燒友學(xué)院以及廣州旗點(diǎn)智能科技有限公司為我和孩子提供此產(chǎn)品星空GD32F303開發(fā)板。收到了星空
    發(fā)表于 10-18 14:15

    【星空GD32F303開發(fā)板試用體驗(yàn)】開箱+環(huán)境搭建

    https://bbs.elecfans.com/jishu_2179209_1_1.html感謝 發(fā)燒友學(xué)院以及廣州旗點(diǎn)智能科技有限公司為我和孩子提供此產(chǎn)品星空gd32F303開發(fā)板。收到了星空
    發(fā)表于 11-02 15:36

    【星空GD32F303開發(fā)板試用體驗(yàn)】+板卡概覽

    本帖最后由 cooldog123pp 于 2021-11-6 21:07 編輯 星空GD開發(fā)板是由旗點(diǎn)科技推出的一款GD32開發(fā)板
    發(fā)表于 11-06 21:05

    星空GD32F303開發(fā)板的相關(guān)資料下載

    一、開發(fā)板介紹星空GD開發(fā)板是由旗點(diǎn)科技推出的一款GD32開發(fā)板,板載
    發(fā)表于 12-10 08:27

    第二十七 同步時(shí)序邏輯電路的設(shè)計(jì)

    第二十七 同步時(shí)序邏輯電路的設(shè)計(jì) 7.5 同步時(shí)序邏輯電路的設(shè)計(jì)用SSI觸發(fā)器16進(jìn)制以內(nèi)7.5.1 同步時(shí)序邏輯電路的設(shè)計(jì)方法
    發(fā)表于 03-30 16:31 ?3971次閱讀
    <b class='flag-5'>第二十七</b><b class='flag-5'>講</b> 同步時(shí)序邏輯電路的設(shè)計(jì)

    STM32CUBEMX開發(fā)GD32F303(14)----IIC之配置OLED

    本章STM32CUBEMX配置STM32F103,并且在GD32F303中進(jìn)行開發(fā),同時(shí)通過開發(fā)板內(nèi)進(jìn)行驗(yàn)證。
    的頭像 發(fā)表于 07-26 13:52 ?2037次閱讀
    STM32CUBEMX<b class='flag-5'>開發(fā)</b><b class='flag-5'>GD32F303</b>(14)----IIC之配置OLED

    GD32F303固件庫開發(fā)

    的可以加群申請:615061293 。 GD32F303固件庫開發(fā)(1)----前期準(zhǔn)備與燒錄 使用GDLINK、jlink、串口下載程序到GD芯片。 [https://blog.csdn.net
    的頭像 發(fā)表于 07-27 09:27 ?1177次閱讀
    <b class='flag-5'>GD32F303</b>固件庫<b class='flag-5'>開發(fā)</b>

    GD32F303紅楓開發(fā)板使用手冊第二 GPIO-流水燈實(shí)驗(yàn)

    GD32F303系列MCU最多可支持?112?個(gè)通用I/O?引腳(GPIO),分別為?PA0 ~ PA15,?PB0 ~ PB15,?PC0 ~ PC15,PD0 ~ PD15,?PE0
    的頭像 發(fā)表于 05-29 10:02 ?1660次閱讀
    【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】<b class='flag-5'>第二</b><b class='flag-5'>講</b> GPIO-流水燈<b class='flag-5'>實(shí)驗(yàn)</b>

    GD32F303紅楓開發(fā)板使用手冊】第三 GPIO-按鍵查詢檢測實(shí)驗(yàn)

    GD32F303系列MCU GPIO輸入配置結(jié)構(gòu)如下圖所示,輸入可配置上下拉電阻,通過施密特觸發(fā)器后可通過備用功能輸入或者通過輸入狀態(tài)寄存器進(jìn)行讀取。
    的頭像 發(fā)表于 05-30 10:02 ?881次閱讀
    【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】第三<b class='flag-5'>講</b> GPIO-按鍵查詢檢測<b class='flag-5'>實(shí)驗(yàn)</b>

    GD32F303紅楓開發(fā)板使用手冊】第五 FMC-片內(nèi)Flash擦寫讀實(shí)驗(yàn)

    MC即Flash控制器,其提供了片上Flash操作所需要的所有功能,在GD32F303系列MCU中,F(xiàn)lash前256K字節(jié)空間內(nèi),?CPU執(zhí)行指令零等待,具有相同主頻下最快的代碼執(zhí)行效率。FMC也
    的頭像 發(fā)表于 06-02 10:05 ?786次閱讀
    【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】第五<b class='flag-5'>講</b> FMC-片內(nèi)Flash擦寫讀<b class='flag-5'>實(shí)驗(yàn)</b>

    GD32F303紅楓開發(fā)板使用手冊】第十六 USART-DMA串口收發(fā)實(shí)驗(yàn)

    在前面ADC章節(jié)中,我們介紹了DMA的工作原理,這里就不多做介紹。從GD32F303用戶手冊中可以查到,各串口的TX和RX分別對應(yīng)DMA的不同通道,比如USART0的TX對應(yīng)DMA0的通道3,而RX對應(yīng)DMA0的通道4。
    的頭像 發(fā)表于 06-15 09:54 ?1086次閱讀
    【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】第十六<b class='flag-5'>講</b> USART-DMA串口收發(fā)<b class='flag-5'>實(shí)驗(yàn)</b>

    GD32F303紅楓開發(fā)板使用手冊第二十 SPI-SPI NAND FLASH讀寫實(shí)驗(yàn)

    通過本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容: ?SPI通信協(xié)議,參考19.2.1東方紅開發(fā)板使用手冊 ?GD32F303 SPI操作方式,參考19.2.2東方紅
    的頭像 發(fā)表于 06-20 09:50 ?903次閱讀
    【<b class='flag-5'>GD32F303</b><b class='flag-5'>紅楓</b><b class='flag-5'>派</b><b class='flag-5'>開發(fā)板</b><b class='flag-5'>使用手冊</b>】<b class='flag-5'>第二十</b><b class='flag-5'>講</b> SPI-SPI NAND FLASH讀寫<b class='flag-5'>實(shí)驗(yàn)</b>