时钟配置
本键盘用的主控芯片为STM32F103C8T6,12Mhz和32.768Khz的外部无源晶振。
系统主频72Mhz,USB时钟频率48Mhz。
USB接口配置
添加USB驱动代码。
USB_DEVICE配置为 Communication Device Class(虚拟串口)。
串口收发测试
串口发送
此时在“usbd_cdc_ic.c”文件的“static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)”函数中的“CDC_SET_LINE_CODING”和“CDC_GET_LINE_CODING”配置为空白,填写以下内容。
/**
* @brief Manage the CDC class requests
* @param cmd: Command code
* @param pbuf: Buffer containing command data (request parameters)
* @param length: Number of data to be sent (in bytes)
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
{
/* USER CODE BEGIN 5 */
switch(cmd)
{
case CDC_SEND_ENCAPSULATED_COMMAND:
break;
case CDC_GET_ENCAPSULATED_RESPONSE:
break;
case CDC_SET_COMM_FEATURE:
break;
case CDC_GET_COMM_FEATURE:
break;
case CDC_CLEAR_COMM_FEATURE:
break;
/*******************************************************************************/
/* Line Coding Structure */
/*-----------------------------------------------------------------------------*/
/* Offset | Field | Size | Value | Description */
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
/* 4 | bCharFormat | 1 | Number | Stop bits */
/* 0 - 1 Stop bit */
/* 1 - 1.5 Stop bits */
/* 2 - 2 Stop bits */
/* 5 | bParityType | 1 | Number | Parity */
/* 0 - None */
/* 1 - Odd */
/* 2 - Even */
/* 3 - Mark */
/* 4 - Space */
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
/*******************************************************************************/
case CDC_SET_LINE_CODING:
USBD_CDC_LineCoding.bitrate = (uint32_t)(pbuf[0] | pbuf[1]<<8 | pbuf[2]<<16 | pbuf[3]<<24);
USBD_CDC_LineCoding.format = pbuf[4];
USBD_CDC_LineCoding.paritytype = pbuf[5];
USBD_CDC_LineCoding.datatype = pbuf[6];
break;
case CDC_GET_LINE_CODING:
pbuf[0] = USBD_CDC_LineCoding.bitrate & 0x000000ff;
pbuf[1] = USBD_CDC_LineCoding.bitrate & 0x0000ff00;
pbuf[2] = USBD_CDC_LineCoding.bitrate & 0x00ff0000;
pbuf[3] = USBD_CDC_LineCoding.bitrate & 0xff000000;
pbuf[4] = USBD_CDC_LineCoding.format;
pbuf[5] = USBD_CDC_LineCoding.paritytype;
pbuf[6] = USBD_CDC_LineCoding.datatype;
break;
case CDC_SET_CONTROL_LINE_STATE:
break;
case CDC_SEND_BREAK:
break;
default:
break;
}
return (USBD_OK);
/* USER CODE END 5 */
}
USBD_CDC_LineCoding变量类型为USBD_CDC_LineCodingTypeDef ,USBD_CDC_LineCodingTypeDef 的结构体类型定义在文件“usbd_cdc.h”中。
经过以上配置后,生成的keil工程中可以直接进行虚拟串口数据发送。
CDC_Transmit_FS((uint8_t *)"hello world\r\n",13);
HAL_Delay(100);
在电脑上的串口助手上,修改任意波特率都可以正常接收数据。
串口接收
void MX_USB_DEVICE_Init(void)函数在USB接收中断中调用static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)函数的USBD_Interface_fops_FS接收数据,可以在该函数中进行接收数据的转存。
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
usb_uart_rx_flag = 1;
memset(usb_uart_rx_buf,0x00,64);
memcpy(usb_uart_rx_buf,Buf,*Len);
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
}
USB串口回声示例
while (1)
{
if(usb_uart_rx_flag == 1)
{
usb_uart_rx_flag = 0;
CDC_Transmit_FS(usb_uart_rx_buf,strlen(usb_uart_rx_buf));
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
USB重新枚举
以上程序,每次下载之后,需要重新插拔USB才能让电脑重新识别枚举单片机USB设备,将IO口PA12拉低一段时间可以实现重新枚举功能。
void usb_re_ennum()
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_RESET);
HAL_Delay(500);
HAL_GPIO_DeInit(GPIOA,GPIO_PIN_12);
return;
}