在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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

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

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

【GD32F470紫藤派開(kāi)發(fā)板使用手冊(cè)】第十三講 USB_虛擬鍵盤實(shí)驗(yàn)

聚沃科技 ? 2024-05-19 09:59 ? 次閱讀
wKgaomYwSqiAY_PQAAnl063z3JE116.png

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

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

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

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

13.2.1USB通信基礎(chǔ)知識(shí)

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

13.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

13.2.1.2NRZI編碼

USB采用差分信號(hào)傳輸,使用的是如上圖所示的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)過(guò)NRZI編碼后的數(shù)據(jù)序列。

wKgZomZJWxWAQSVxAAIlErHJeKI886.png

13.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)開(kāi)始,之后是同步域(0x00000001),然后是包內(nèi)容,最后以包結(jié)束符(EOP)結(jié)束這個(gè)包。PID為標(biāo)識(shí)域,由四位標(biāo)識(shí)符加4位標(biāo)識(shí)符反碼構(gòu)成,表明包的類型和格式。根據(jù)PID的不同,USB協(xié)議中規(guī)定的包類型有令牌包、數(shù)據(jù)包、握手包和特殊包等。

wKgaomZJWyGAdonqAAB8I0rvGFU350.png

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

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

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

13.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ī)的枚舉以及識(shí)別。USB描述符包括設(shè)備描述符、配置描述符、接口描述符、端點(diǎn)描述符以及字符串描述符等。在GD32 USBD固件庫(kù)中,針對(duì)各種描述符都按照USB協(xié)議定義了相關(guān)結(jié)構(gòu)體,具體說(shuō)明如下。

  • 設(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)體定義如下。

  • 字符串描述符

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

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;

13.2.1.5USB枚舉過(guò)程

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

wKgaomZJW7yAXYOoAAH64GaWpyY119.png

13.2.2GD32 USBD模塊簡(jiǎn)介

GD32F4xx系列MCU提供了一個(gè)USB2.0全速USBFS OTG接口模塊和一個(gè)USB2.0高速USBHS接口模塊,其中,USBHS若需要使用高速接口,需要外接USBHS高速PHY芯片,如果不外借高速PHY,其可以作為USBFS接口,因而GD32F4XX在不接外部高速PHY的情況下,其可以使用兩個(gè)USBFS接口。

USBFS支持USB 2.0協(xié)議所定義的四種傳輸類型(控制、批量、中斷和同步傳輸),本開(kāi)發(fā)板使用的是USBFS接口,以下為大家介紹USBFS接口功能。

USBFS主要特性如下:

n支持USB 2.0全速(12Mb/s)/低速(1.5Mb/s)主機(jī)模式;

n支持USB 2.0全速(12Mb/s) 設(shè)備模式;

n支持遵循HNP(主機(jī)協(xié)商協(xié)議)和SRP(會(huì)話請(qǐng)求協(xié)議)的OTG協(xié)議;

n支持所有的4種傳輸方式:控制傳輸、批量傳輸、中斷傳輸和同步傳輸;

n在主機(jī)模式下,包含USB事務(wù)調(diào)度器,用于有效地處理USB事務(wù)請(qǐng)求;

n包含一個(gè)1.25KB的FIFO RAM;

n在主機(jī)模式下,支持8個(gè)通道;

n在主機(jī)模式下,包含2個(gè)發(fā)送FIFO(周期性發(fā)送FIFO和非周期性發(fā)送FIFO)和1個(gè)接收

FIFO(由所有的通道共享);

n在設(shè)備模式下,包含4個(gè)發(fā)送FIFO(每個(gè)IN端點(diǎn)一個(gè)發(fā)送FIFO)和1個(gè)接收FIFO(由所有

的OUT端點(diǎn)共享);

n在設(shè)備模式下, 支持4個(gè)OUT端點(diǎn)和4個(gè)IN端點(diǎn);

n在設(shè)備模式下,支持遠(yuǎn)程喚醒功能;

n包含一個(gè)支持USB協(xié)議的全速USB PHY;

n在主機(jī)模式下,SOF的時(shí)間間隔可動(dòng)態(tài)調(diào)節(jié);

n可將SOF脈沖輸出到PAD;

n可檢測(cè)ID引腳電平和VBUS電壓;

n在主機(jī)模式或者OTG A設(shè)備模式下,需要外部部件為連接的USB設(shè)備提供電源。

USBD模塊框圖如下所示。

wKgZomZJW8qAQM1ZAAFeaVLZSeg329.png

13.2.3USBFS固件庫(kù)說(shuō)明

USBFS 固件庫(kù)使用指南可以參考官網(wǎng)相關(guān)文檔,下載地址如下:https://www.gd32mcu.com/download/down/document_id/372/path_type/2

wKgZomZJW9eASJKTAADFYcxM7qM927.png

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

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

wKgZomZJW-WAEdxUAAGNF-C5ieI167.png

13.4代碼解析

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

本例程主函數(shù)如下所示。

C
int main(void)
{
usb_gpio_config();
usb_rcu_config();
usb_timer_init();

hid_itfop_register (&hid_keyboard, &fop_handler);

usbd_init (&hid_keyboard,
#ifdef USE_USB_FS
USB_CORE_ENUM_FS,
#elif defined(USE_USB_HS)
USB_CORE_ENUM_HS,
#endif
&hid_desc,
&usbd_hid_cb);

usb_intr_config();

/* check if USB device is enumerated successfully */
while (USBD_CONFIGURED != hid_keyboard.dev.cur_status) {
}

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

gpio的配置如下,定義為全速模式,主要配置PA11和PA12引腳。

C
void usb_gpio_config(void)
{
rcu_periph_clock_enable(RCU_SYSCFG);

#ifdef USE_USB_FS

rcu_periph_clock_enable(RCU_GPIOA);

/* USBFS_DM(PA11) and USBFS_DP(PA12) GPIO pin configuration */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11 | GPIO_PIN_12);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_11 | GPIO_PIN_12);

gpio_af_set(GPIOA, GPIO_AF_10, GPIO_PIN_11 | GPIO_PIN_12);

#elif defined(USE_USB_HS)

#ifdef USE_ULPI_PHY
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_GPIOC);
rcu_periph_clock_enable(RCU_GPIOH);
rcu_periph_clock_enable(RCU_GPIOI);

/* ULPI_STP(PC0) GPIO pin configuration */
gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0);
gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_0);

/* ULPI_CK(PA5) GPIO pin configuration */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_5);

/* ULPI_NXT(PH4) GPIO pin configuration */
gpio_mode_set(GPIOH, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_4);
gpio_output_options_set(GPIOH, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_4);

/* ULPI_DIR(PI11) GPIO pin configuration */
gpio_mode_set(GPIOI, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_11);
gpio_output_options_set(GPIOI, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_11);

/* ULPI_D1(PB0), ULPI_D2(PB1), ULPI_D3(PB10), ULPI_D4(PB11) \
ULPI_D5(PB12), ULPI_D6(PB13) and ULPI_D7(PB5) GPIO pin configuration */
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, \
GPIO_PIN_5 | GPIO_PIN_13 | GPIO_PIN_12 |\
GPIO_PIN_11 | GPIO_PIN_10 | GPIO_PIN_1 | GPIO_PIN_0);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, \
GPIO_PIN_5 | GPIO_PIN_13 | GPIO_PIN_12 |\
GPIO_PIN_11 | GPIO_PIN_10 | GPIO_PIN_1 | GPIO_PIN_0);

/* ULPI_D0(PA3) GPIO pin configuration */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_3);

gpio_af_set(GPIOC, GPIO_AF_10, GPIO_PIN_0);
gpio_af_set(GPIOH, GPIO_AF_10, GPIO_PIN_4);
gpio_af_set(GPIOI, GPIO_AF_10, GPIO_PIN_11);
gpio_af_set(GPIOA, GPIO_AF_10, GPIO_PIN_5 | GPIO_PIN_3);
gpio_af_set(GPIOB, GPIO_AF_10, GPIO_PIN_5 | GPIO_PIN_13 | GPIO_PIN_12 |\
GPIO_PIN_11 | GPIO_PIN_10 | GPIO_PIN_1 | GPIO_PIN_0);
#elif defined(USE_EMBEDDED_PHY)
rcu_periph_clock_enable(RCU_GPIOB);

/* USBHS_DM(PB14) and USBHS_DP(PB15) GPIO pin configuration */
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14 | GPIO_PIN_15);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_14 | GPIO_PIN_15);
gpio_af_set(GPIOB, GPIO_AF_12, GPIO_PIN_14 | GPIO_PIN_15);
#endif /* USE_ULPI_PHY */

#endif /* USE_USBFS */
}

rcu的配置如下,主要用于配置USB時(shí)鐘,USB需要一個(gè)穩(wěn)定的48M時(shí)鐘。

C
void usb_rcu_config(void)
{
#ifdef USE_USB_FS
rcu_pll48m_clock_config(RCU_PLL48MSRC_PLLQ);
rcu_ck48m_clock_config(RCU_CK48MSRC_PLL48M);

rcu_periph_clock_enable(RCU_USBFS);
#elif defined(USE_USB_HS)
#ifdef USE_EMBEDDED_PHY
rcu_pll48m_clock_config(RCU_PLL48MSRC_PLLQ);
rcu_ck48m_clock_config(RCU_CK48MSRC_PLL48M);
#elif defined(USE_ULPI_PHY)
rcu_periph_clock_enable(RCU_USBHSULPI);
#endif /* USE_EMBEDDED_PHY */

rcu_periph_clock_enable(RCU_USBHS);
#endif /* USB_USBFS */
}

Usb timer的配置如下,主要用于延遲。

C
void usb_timer_init (void)
{
/* configure the priority group to 2 bits */
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);

/* enable the TIMER2 global interrupt */
nvic_irq_enable((uint8_t)TIMER2_IRQn, 1U, 0U);

rcu_periph_clock_enable(RCU_TIMER2);
}

注冊(cè)HID接口操作函數(shù)如下所示。在該代碼清單中,注冊(cè)了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->dev.user_data = (void *)hid_fop;

return USBD_OK;
}

return USBD_FAIL;
}

USBD內(nèi)核初始化函數(shù)如下所示。在該代碼清單中,首先配置設(shè)備類callback函數(shù),之后創(chuàng)建字符串,配置USB以及初始化USB內(nèi)核,斷開(kāi)USB連接,初始化USB設(shè)備模式,之后設(shè)置USB連接,將USB連接狀態(tài)配置為DEFAULT默認(rèn)狀態(tài),啟動(dòng)狀態(tài)機(jī)。

C
void usbd_init (usb_core_driver *udev, usb_core_enum core, usb_desc *desc, usb_class_core *class_core)
{
udev->dev.desc = desc;

/* class callbacks */
udev->dev.class_core = class_core;

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

/* configure USB capabilities */
(void)usb_basic_init (&udev->bp, &udev->regs, core);

usb_globalint_disable(&udev->regs);

/* initializes the USB core*/
(void)usb_core_init (udev->bp, &udev->regs);

/* set device disconnect */
usbd_disconnect (udev);

#ifndef USE_OTG_MODE
usb_curmode_set(&udev->regs, DEVICE_MODE);
#endif /* USE_OTG_MODE */

/* initializes device mode */
(void)usb_devcore_init (udev);

usb_globalint_enable(&udev->regs);

/* set device connect */
usbd_connect (udev);

udev->dev.cur_status = (uint8_t)USBD_DEFAULT;
}

配置USB中斷函數(shù)如下。

C
void usb_intr_config(void)
{
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);

#ifdef USE_USB_FS
nvic_irq_enable((uint8_t)USBFS_IRQn, 3U, 0U);

#if USBFS_LOW_POWER
/* enable the power module clock */
rcu_periph_clock_enable(RCU_PMU);

/* USB wakeup EXTI line configuration */
exti_interrupt_flag_clear(EXTI_18);
exti_init(EXTI_18, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_enable(EXTI_18);

nvic_irq_enable((uint8_t)USBFS_WKUP_IRQn, 0U, 0U);
#endif /* USBFS_LOW_POWER */
#elif defined(USE_USB_HS)
nvic_irq_enable((uint8_t)USBHS_IRQn, 3U, 0U);

#if USBHS_LOW_POWER
/* enable the power module clock */
rcu_periph_clock_enable(RCU_PMU);

/* USB wakeup EXTI line configuration */
exti_interrupt_flag_clear(EXTI_20);
exti_init(EXTI_20, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_enable(EXTI_20);

nvic_irq_enable((uint8_t)USBHS_WKUP_IRQn, 0U, 0U);
#endif /* USBHS_LOW_POWER */
#endif /* USE_USB_FS */

#ifdef USB_HS_DEDICATED_EP1_ENABLED
nvic_irq_enable(USBHS_EP1_Out_IRQn, 1, 0);
nvic_irq_enable(USBHS_EP1_In_IRQn, 1, 0);
#endif /* USB_HS_DEDICATED_EP1_ENABLED */
}

內(nèi)部上拉電阻被上拉后,主機(jī)將會(huì)對(duì)設(shè)備進(jìn)行枚舉,設(shè)備端采用while (USBD_CONFIGURED != hid_keyboard.dev.cur_status) 語(yǔ)句進(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ù)中,首先判斷上次傳輸是否完成,完成之后通過(guò)掃描按鍵的方式查看按鍵是否被按下,若按鍵被按下,則通過(guò)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->dev.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;
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)告的長(zhǎng)度。在該函數(shù)中,如果設(shè)備已經(jīng)被枚舉成功,則首先將prev_transfer_complete標(biāo)志位設(shè)置為0,表明接下來(lái)將進(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, uint32_t len)
{
standard_hid_handler *hid = (standard_hid_handler *)udev->dev.class_data[USBD_HID_INTERFACE];

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

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

if (0U != 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;
}

return USBD_OK;
}

在該例程中通過(guò)hid->prev_transfer_complete數(shù)據(jù)流程標(biāo)志位進(jìn)行數(shù)據(jù)發(fā)送控制,讀者可使用該標(biāo)志位用于對(duì)數(shù)據(jù)發(fā)送的控制,當(dāng)該標(biāo)志位為0的時(shí)候,表明數(shù)據(jù)已被填送到USB緩沖區(qū),但還沒(méi)有發(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ù)。

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

將本例程燒錄到紫藤派開(kāi)發(fā)板中,通過(guò)Type C數(shù)據(jù)線連接開(kāi)發(fā)板和PC,之后分別按下WKUP和USER按鍵,將會(huì)向PC發(fā)送A、B鍵值。

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

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

    關(guān)注

    6043

    文章

    44621

    瀏覽量

    638560
  • usb
    usb
    +關(guān)注

    關(guān)注

    60

    文章

    7980

    瀏覽量

    266095
  • 開(kāi)發(fā)板
    +關(guān)注

    關(guān)注

    25

    文章

    5121

    瀏覽量

    98195
  • 虛擬鍵盤
    +關(guān)注

    關(guān)注

    0

    文章

    11

    瀏覽量

    7875
  • GD32
    +關(guān)注

    關(guān)注

    7

    文章

    413

    瀏覽量

    24470
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    GD32F470紫藤開(kāi)發(fā)板使用手冊(cè)】第九講 USART-printf打印實(shí)驗(yàn)

    通過(guò)本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容: 串口簡(jiǎn)介 GD32F470串口工作原理 使用printf打印信息
    的頭像 發(fā)表于 05-13 10:14 ?1866次閱讀
    【<b class='flag-5'>GD32F470</b><b class='flag-5'>紫藤</b><b class='flag-5'>派</b><b class='flag-5'>開(kāi)發(fā)板</b><b class='flag-5'>使用手冊(cè)</b>】第九講  USART-printf打印<b class='flag-5'>實(shí)驗(yàn)</b>

    GD32F470紫藤開(kāi)發(fā)板使用手冊(cè)第十一講 SPI-SPI NOR FLASH讀寫實(shí)驗(yàn)

    通過(guò)本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容: ?SPI簡(jiǎn)介 ?GD32F470 SPI簡(jiǎn)介 ?SPI NOR FLASH——GD25Q32ESIGR簡(jiǎn)介 ?使用GD32F470 SPI接口實(shí)現(xiàn)對(duì)
    的頭像 發(fā)表于 05-17 09:57 ?1940次閱讀
    【<b class='flag-5'>GD32F470</b><b class='flag-5'>紫藤</b><b class='flag-5'>派</b><b class='flag-5'>開(kāi)發(fā)板</b><b class='flag-5'>使用手冊(cè)</b>】<b class='flag-5'>第十</b>一講 SPI-SPI NOR FLASH讀寫<b class='flag-5'>實(shí)驗(yàn)</b>

    GD32H757Z海棠開(kāi)發(fā)板使用手冊(cè)第十三講 SDIO-SD卡讀寫實(shí)驗(yàn)

    通過(guò)本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容: ?USB協(xié)議基本原理 ?GD32H7xx USBHS的使用 ?虛擬鍵盤的協(xié)議原理及使用
    的頭像 發(fā)表于 06-06 11:26 ?2139次閱讀
    【<b class='flag-5'>GD</b>32H757Z海棠<b class='flag-5'>派</b><b class='flag-5'>開(kāi)發(fā)板</b><b class='flag-5'>使用手冊(cè)</b>】<b class='flag-5'>第十三講</b> SDIO-SD卡讀寫<b class='flag-5'>實(shí)驗(yàn)</b>

    迅為iMX6ULL開(kāi)發(fā)板使用手冊(cè)資料下載

    的知識(shí)點(diǎn),它都有!《嵌入式Linux開(kāi)發(fā)指南》+《開(kāi)發(fā)板使用手冊(cè)》+《裸機(jī)使用手冊(cè)》鏈接:https://pan.baidu.com/s/1Xat4C-cDa2Gi1UwNckNRTw
    發(fā)表于 12-02 14:13

    第十三講 施密特觸發(fā)器

    第十三講 施密特觸發(fā)器 內(nèi)容提要5.1 概述5.2 施密特觸發(fā)器一、工作原理1.特點(diǎn):2.電壓傳輸特性3.回差4.邏
    發(fā)表于 03-30 16:19 ?5515次閱讀
    <b class='flag-5'>第十三講</b> 施密特觸發(fā)器

    YL-51開(kāi)發(fā)板使用手冊(cè)

    YL-51開(kāi)發(fā)板使用手冊(cè),YL-51開(kāi)發(fā)板使用手冊(cè)YL-51開(kāi)發(fā)板使用手冊(cè)YL-51
    發(fā)表于 05-10 16:31 ?21次下載

    開(kāi)發(fā)板燒寫測(cè)試使用手冊(cè)

    開(kāi)發(fā)板燒寫測(cè)試使用手冊(cè),有需要的下來(lái)看看
    發(fā)表于 06-03 14:30 ?0次下載

    51開(kāi)發(fā)板使用手冊(cè)

    51開(kāi)發(fā)板使用手冊(cè),感興趣的小伙伴們可以瞧一瞧。
    發(fā)表于 11-23 15:45 ?11次下載

    KC705開(kāi)發(fā)板英文使用手冊(cè)

    KC705開(kāi)發(fā)板英文使用手冊(cè)
    發(fā)表于 11-01 10:19 ?5次下載

    iTOP-3399開(kāi)發(fā)板使用手冊(cè)大更新

    iTOP-3399開(kāi)發(fā)板使用手冊(cè)大更新
    的頭像 發(fā)表于 12-10 15:46 ?1421次閱讀
    iTOP-3399<b class='flag-5'>開(kāi)發(fā)板</b><b class='flag-5'>使用手冊(cè)</b>大更新

    APT32F102 開(kāi)發(fā)板使用手冊(cè)

    電子發(fā)燒友網(wǎng)站提供《APT32F102 開(kāi)發(fā)板使用手冊(cè).pdf》資料免費(fèi)下載
    發(fā)表于 04-16 09:07 ?0次下載

    GD32F470紫藤開(kāi)發(fā)板使用手冊(cè)】第二講 GPIO-按鍵查詢實(shí)驗(yàn)

    通過(guò)本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容: GPIO輸入功能原理; 按鍵查詢輸入檢測(cè)原理;
    的頭像 發(fā)表于 04-30 11:39 ?836次閱讀
    【<b class='flag-5'>GD32F470</b><b class='flag-5'>紫藤</b><b class='flag-5'>派</b><b class='flag-5'>開(kāi)發(fā)板</b><b class='flag-5'>使用手冊(cè)</b>】第二講 GPIO-按鍵查詢<b class='flag-5'>實(shí)驗(yàn)</b>

    GD32F470紫藤開(kāi)發(fā)板使用手冊(cè)】第五講 PMU-低功耗實(shí)驗(yàn)

    通過(guò)本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容: PMU原理; 低功耗的進(jìn)入以及退出操作
    的頭像 發(fā)表于 05-07 09:29 ?800次閱讀
    【<b class='flag-5'>GD32F470</b><b class='flag-5'>紫藤</b><b class='flag-5'>派</b><b class='flag-5'>開(kāi)發(fā)板</b><b class='flag-5'>使用手冊(cè)</b>】第五講  PMU-低功耗<b class='flag-5'>實(shí)驗(yàn)</b>

    GD32F470紫藤開(kāi)發(fā)板使用手冊(cè)】第八講 ADC-規(guī)則組多通道采樣實(shí)驗(yàn)

    通過(guò)本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容: ?ADC的簡(jiǎn)介 ?GD32F470 ADC工作原理 ?DMA原理 ?規(guī)則組多通道循環(huán)采樣
    的頭像 發(fā)表于 05-12 10:00 ?895次閱讀
    【<b class='flag-5'>GD32F470</b><b class='flag-5'>紫藤</b><b class='flag-5'>派</b><b class='flag-5'>開(kāi)發(fā)板</b><b class='flag-5'>使用手冊(cè)</b>】第八講 ADC-規(guī)則組多通道采樣<b class='flag-5'>實(shí)驗(yàn)</b>

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

    通過(guò)本實(shí)驗(yàn)主要學(xué)習(xí)以下內(nèi)容: ?SPI通信協(xié)議,參考19.2.1東方紅開(kāi)發(fā)板使用手冊(cè) ?GD32F303 SPI操作方式,參考19.2.2東方紅開(kāi)
    的頭像 發(fā)表于 06-20 09:50 ?1074次閱讀
    【<b class='flag-5'>GD32F</b>303紅楓<b class='flag-5'>派</b><b class='flag-5'>開(kāi)發(fā)板</b><b class='flag-5'>使用手冊(cè)</b>】第二十講 SPI-SPI NAND FLASH讀寫<b class='flag-5'>實(shí)驗(yàn)</b>
    主站蜘蛛池模板: 色多多在线免费观看 | 天堂8资源在线官网资源 | 色多多最新地址福利地址 | 一色桃子juy774在线播放 | 午夜视频免费观看 | 色之综合网 | 国产黄色a三级三级三级 | 日韩黄色免费 | 163黄页网又粗又长又舒服 | 色在线视频观看 | 日本欧洲亚洲一区在线观看 | 国产精品一区二区三区四区五区 | 亚洲成色www久久网站 | aa黄色片 | 欧美不卡一区 | 99久久久精品免费观看国产 | 欧美午夜一区 | 天天做天天爱夜夜想毛片 | 国产亚洲欧美成人久久片 | 亚洲精品aaa揭晓 | 一色屋成人免费精品网 | 美国一级毛片不卡无毒 | 久久亚洲精选 | xxxxxxxxx18免费视频 | 亚洲人在线 | 91成人免费观看 | 九九天天影视 | 伊人亚洲综合网成人 | 天天操天天艹 | 亚洲激情视频网 | 四虎永久免费网站 | 欧美洲视频在线观看 | vr亚洲成年网址在线观看 | 爽爽爽爽爽爽a成人免费视频 | 天天草天天草 | 狠狠色狠狠色综合婷婷tag | 美女视频很黄很a免费国产 美女视频很黄很暴黄是免费的 | 77788色淫视频免费观看 | 午夜一级免费视频 | 无遮挡很爽很污很黄很色的网站 | 夜夜夜网|