目录
一、标准库工程
1、USB初始化
由官方进行适配。
void USB_Init(void)
{
pInformation = &Device_Info;
pInformation->ControlState = 2;
pProperty = &Device_Property;
pUser_Standard_Requests = &User_Standard_Requests;
/* Initialize devices one by one */
pProperty->Init();
}
2、USB中断配置
配置了USB外部18中断,使能USB RX和WakeUp中断。
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
/* Configure the EXTI line 18 connected internally to the USB IP */
EXTI_ClearITPendingBit(EXTI_Line18);
// 开启线18上的中断
EXTI_InitStructure.EXTI_Line = EXTI_Line18; // USB resume from suspend mode
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //line 18上事件上升降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* Enable the USB interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; //组2,优先级次之
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* Enable the USB Wake-up interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USBWakeUp_IRQn; //组2,优先级最高
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_Init(&NVIC_InitStructure);
3、中断服务函数与回调接收
以收到\r\n作为结束。
void EP3_OUT_Callback(void)
{
u16 USB_Rx_Cnt;
USB_Rx_Cnt = USB_SIL_Read(EP3_OUT, USB_Rx_Buffer); //得到USB接收到的数据及其长度
USB_To_USART_Send_Data(USB_Rx_Buffer, USB_Rx_Cnt); //处理数据(其实就是保存数据)
SetEPRxValid(ENDP3); //时能端点3的数据接收
}
void USB_To_USART_Send_Data(u8* data_buffer, u8 Nb_bytes)
{
u8 i;
u8 res;
for(i=0;i<Nb_bytes;i++)
{
res=data_buffer[i];
if((USB_USART_RX_STA&0x8000)==0) //接收未完成
{
if(USB_USART_RX_STA&0x4000) //接收到了0x0d
{
if(res!=0x0a)USB_USART_RX_STA=0;//接收错误,重新开始
else USB_USART_RX_STA|=0x8000; //接收完成了
}else //还没收到0X0D
{
if(res==0x0d)USB_USART_RX_STA|=0x4000;
else
{
USB_USART_RX_BUF[USB_USART_RX_STA&0X3FFF]=res;
USB_USART_RX_STA++;
if(USB_USART_RX_STA>(USB_USART_REC_LEN-1))USB_USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
4、USB连接
先将enable置位0,延时一段时间后再置位1。
void USB_Port_Set(u8 enable)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能PORTA时钟
if(enable)_SetCNTR(_GetCNTR()&(~(1<<1)));//退出断电模式
else
{
_SetCNTR(_GetCNTR()|(1<<1)); // 断电模式
GPIOA->CRH&=0XFFF00FFF;
GPIOA->CRH|=0X00033000;
PAout(12)=0;
}
}
5、时钟配置
void Set_USBClock(void)
{
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);//USBclk=PLLclk/1.5=48Mhz
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE); //USB时钟使能
}
6、数据发送
可以看到,通过配置buffer即可实现自动发送,同时循环执行即可实现发送长串字符。
//发送一个字节数据到USB虚拟串口
void USB_USART_SendData(u8 data)
{
uu_txfifo.buffer[uu_txfifo.writeptr]=data;
uu_txfifo.writeptr++;
if(uu_txfifo.writeptr==USB_USART_TXFIFO_SIZE)//超过buf大小了,归零.
{
uu_txfifo.writeptr=0;
}
}
void usb_printf(char* fmt,...)
{
u16 i,j;
va_list ap;
va_start(ap,fmt);
vsprintf((char*)USART_PRINTF_Buffer,fmt,ap);
va_end(ap);
i=strlen((const char*)USART_PRINTF_Buffer);//此次发送数据的长度
for(j=0;j<i;j++)//循环发送数据
{
USB_USART_SendData(USART_PRINTF_Buffer[j]);
}
}
二、HAL库工程
1、USB初始化
由官方进行适配。
void MX_USB_DEVICE_Init(void)
{
/* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */
/* USER CODE END USB_DEVICE_Init_PreTreatment */
/* Init Device Library, add supported class and start the library. */
//1.初始化USBD,初始化设备栈和加载类驱动
if (USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS) != USBD_OK)
{
Error_Handler();
}
//2.注册USB 类
if (USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC) != USBD_OK)
{
Error_Handler();
}
//3.注册CDC接口
if (USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS) != USBD_OK)
{
Error_Handler();
}
//4.启动USBD
if (USBD_Start(&hUsbDeviceFS) != USBD_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USB_DEVICE_Init_PostTreatment */
/* USER CODE END USB_DEVICE_Init_PostTreatment */
}
2、中断服务函数与回调接收
以收到\r\n作为结束。
int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
//CDC_Transmit_FS(Buf,*Len);//串口回环
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
USB_To_USART_Send_Data(Buf, *Len);
return (USBD_OK);
/* USER CODE END 6 */
}
void USB_To_USART_Send_Data(u8* data_buffer, u32 Nb_bytes)
{
u8 i;
u8 res;
for(i=0;i<Nb_bytes;i++)
{
res=data_buffer[i];
if((USB_USART_RX_STA&0x8000)==0) //接收未完成
{
if(USB_USART_RX_STA&0x4000) //接收到了0x0d
{
if(res!=0x0a)USB_USART_RX_STA=0;//接收错误,重新开始
else {
USB_USART_RX_STA|=0x8000; //接收完成了
}
}else //还没收到0X0D
{
if(res==0x0d)USB_USART_RX_STA|=0x4000;
else
{
USB_USART_RX_BUF[USB_USART_RX_STA&0X3FFF]=res;
USB_USART_RX_STA++;
if(USB_USART_RX_STA>(USB_USART_REC_LEN-1))USB_USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
4、USB连接
void USB_Reset()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11 | GPIO_PIN_12, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
delay_us(700);//delay 10 ms
}
5、时钟配置
void Set_USBClock(void)
{
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);//USBclk=PLLclk/1.5=48Mhz
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE); //USB时钟使能
}
6、数据发送
可以看到,通过配置buffer即可实现自动发送,同时循环执行即可实现发送长串字符。
void USB_To_USART_Send_Data(u8* data_buffer, u32 Nb_bytes)
{
u8 i;
u8 res;
for(i=0;i<Nb_bytes;i++)
{
res=data_buffer[i];
if((USB_USART_RX_STA&0x8000)==0) //接收未完成
{
if(USB_USART_RX_STA&0x4000) //接收到了0x0d
{
if(res!=0x0a)USB_USART_RX_STA=0;//接收错误,重新开始
else {
USB_USART_RX_STA|=0x8000; //接收完成了
}
}else //还没收到0X0D
{
if(res==0x0d)USB_USART_RX_STA|=0x4000;
else
{
USB_USART_RX_BUF[USB_USART_RX_STA&0X3FFF]=res;
USB_USART_RX_STA++;
if(USB_USART_RX_STA>(USB_USART_REC_LEN-1))USB_USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
//发送一个字节数据到USB虚拟串口
void USB_USART_SendData(u8 *data)
{
//等待数据发送完毕再发送下一个字节
while((CDC_Transmit_FS(data,sizeof(*data)))==USBD_BUSY);
}
//usb虚拟串口的printf函数p
//确保一次发送数据不超USB_USART_REC_LEN字节
void USB_Printf(char* fmt,...)
{
u16 i,len;
va_list ap;
va_start(ap,fmt);
vsprintf((char*)USART_PRINTF_Buffer,fmt,ap);
va_end(ap);
len=strlen((const char*)USART_PRINTF_Buffer);//此次发送数据的长度
for(i=0;i<len;i++)
{
USB_USART_SendData(&USART_PRINTF_Buffer[i]);
}
//CDC_Transmit_FS(USART_PRINTF_Buffer,len);
}
标签:NVIC,HAL,USB,USART,void,STM32,USBD,串口,GPIO
From: https://blog.csdn.net/qq_39376872/article/details/144498215