STM32 USB学习整理3
usbd_cdc_vcp.c
这个文件主要和 VCP 驱动有直接关系!很多部分都是空的内容,其中包含了一些参数的设置,需要注意的是 波特率的大小与USB速度没有关系,波特率的设置会影响串口速度;
//USB虚拟串口相关配置参数
LINE_CODING linecoding =
{
115200, //波特率 USBSlavede 速度与波特率没有关系,爱咋咋地
0x00, //停止位,默认1位
0x00, //校验位,默认无
0x08 //数据位,默认8位
};
u8 USART_PRINTF_Buffer[USB_USART_REC_LEN]; //usb_printf发送缓冲区(200字节)
//用类似串口1接收数据的方法,来处理USB虚拟串口接收到的数据.
u8 USB_USART_RX_BUF[USB_USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN(200)个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USB_USART_RX_STA=0; //接收状态标记
extern uint8_t APP_Rx_Buffer []; //虚拟串口发送缓冲区(发给电脑)
extern uint32_t APP_Rx_ptr_in;
//虚拟串口配置函数(供USB内核调用)
CDC_IF_Prop_TypeDef VCP_fops =
{
VCP_Init,
VCP_DeInit,
VCP_Ctrl,
VCP_DataTx,
VCP_DataRx
};
//初始化VCP
//返回值:USBD_OK
uint16_t VCP_Init(void)
{
return USBD_OK;
}
//复位VCP
//返回值:USBD_OK
uint16_t VCP_DeInit(void)
{
return USBD_OK;
}
//控制VCP的设置
//buf:命令数据缓冲区/参数保存缓冲区
//len:数据长度
//返回值:USBD_OK
uint16_t VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len)
{
switch (Cmd)
{
case SEND_ENCAPSULATED_COMMAND:
break;
case GET_ENCAPSULATED_RESPONSE:
break;
case SET_COMM_FEATURE:
break;
case GET_COMM_FEATURE:
break;
case CLEAR_COMM_FEATURE:
break;
case SET_LINE_CODING:/*当我们在PC端上的串口工具中修改串口通信的属性时就会触发CDC_SET_LINE_CODING请求*/
linecoding.bitrate = (uint32_t)(Buf[0] | (Buf[1] << 8) | (Buf[2] << 16) | (Buf[3] << 24));
linecoding.format = Buf[4];
linecoding.paritytype = Buf[5];
linecoding.datatype = Buf[6];
//打印配置参数
printf("linecoding.format:%d\r\n",linecoding.format);
printf("linecoding.paritytype:%d\r\n",linecoding.paritytype);
printf("linecoding.datatype:%d\r\n",linecoding.datatype);
printf("linecoding.bitrate:%d\r\n",linecoding.bitrate);
break;
case GET_LINE_CODING:
Buf[0] = (uint8_t)(linecoding.bitrate);
Buf[1] = (uint8_t)(linecoding.bitrate >> 8);
Buf[2] = (uint8_t)(linecoding.bitrate >> 16);
Buf[3] = (uint8_t)(linecoding.bitrate >> 24);
Buf[4] = linecoding.format;
Buf[5] = linecoding.paritytype;
Buf[6] = linecoding.datatype;
break;
case SET_CONTROL_LINE_STATE:
break;
case SEND_BREAK:
break;
default:
break;
}
return USBD_OK;
}
VCP_DataTx ();发送一个字节给虚拟串口(发给电脑),实际上是把一个8位数据发送到 u8的缓存区里面了,这个缓存区默认大小2048,从0开始写,写到2048个数之后,下一次重新写入到第1个位置,如此往复。
//返回值:USBD_OK
uint16_t VCP_DataTx (uint8_t data)
{
APP_Rx_Buffer[APP_Rx_ptr_in]=data; //写入发送buf
APP_Rx_ptr_in++; //写位置加1
if(APP_Rx_ptr_in==APP_RX_DATA_SIZE) //超过buf大小了,归零.
{
APP_Rx_ptr_in = 0;
}
return USBD_OK;
}
VCP_DataRx ();处理从USB虚拟串口接收到的数据(电脑发来的数据),与串口一的接收程序差不多。
//返回值:USBD_OK
uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len)
{
u8 i;
u8 res;
for(i=0;i<Len;i++)
{
res=Buf[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;//接收数据错误,重新开始接收
}
}
}
}
return USBD_OK;
}
usb_printf();这个函数是最通用的发送函数,作用相当于 printf();但是实际上还是内部调用VCP_DataTx()。
//usb虚拟串口,printf 函数
//确保一次发送数据不超USB_USART_REC_LEN字节
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++)//循环发送数据
{
VCP_DataTx(USART_PRINTF_Buffer[j]); //200
}
}
usb_bsp.c
USB_OTG_BSP_Init();函数是底层IO口的初始化函数,STM32F429使用的是MicroUSB,此USB有5根线,VCC,D-,D+,NC,GND,PA11和PA12硬件上连接到D+.D-上。本例程的两个延时函数采用SYSTEM文件夹的delay.c里面的delay_us函数实现
,官方例程采用的是定时器2来实现的。此外,这里面还有中断优先级设置和中断使能。
//USB OTG 底层IO初始化
//pdev:USB OTG内核结构体指针
void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev)
{
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟
__HAL_RCC_USB_OTG_FS_CLK_ENABLE(); //使能OTG FS时钟
//配置PA11 12 PA11 PA12 硬件上连接D+ D-
GPIO_InitStruct.Pin=GPIO_PIN_11|GPIO_PIN_12; //PA11 12
GPIO_InitStruct.Mode=GPIO_MODE_AF_PP; //复用
GPIO_InitStruct.Pull=GPIO_NOPULL; //无上下拉
GPIO_InitStruct.Speed=GPIO_SPEED_HIGH; //高速
GPIO_InitStruct.Alternate=GPIO_AF10_OTG_FS; //复用为OTG FS
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); //初始化
PCF8574_WriteBit(USB_PWR_IO,1); //开启USB HOST电源供电 我觉得就是主机供电
}
//USB OTG 中断设置,开启USB FS中断
//pdev:USB OTG内核结构体指针
void USB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE *pdev)
{
HAL_NVIC_SetPriority(OTG_FS_IRQn,0,3); //抢占优先级0,子优先级3
HAL_NVIC_EnableIRQ(OTG_FS_IRQn); //使能OTG USB FS中断
}
//USB OTG 中断设置,开启USB FS中断0(本例程未用到)
//pdev:USB OTG内核结构体指针
void USB_OTG_BSP_DisableInterrupt(void)
{
}
//USB OTG 端口供电设置(本例程未用到)
//pdev:USB OTG内核结构体指针
//state:0,断电;1,上电
void USB_OTG_BSP_DriveVBUS(USB_OTG_CORE_HANDLE *pdev, uint8_t state)
{
}
//USB_OTG 端口供电IO配置(本例程未用到)
//pdev:USB OTG内核结构体指针
void USB_OTG_BSP_ConfigVBUS(USB_OTG_CORE_HANDLE *pdev)
{
}
//USB_OTG us级延时函数
//usec:要延时的us数.
void USB_OTG_BSP_uDelay (const uint32_t usec)
{
delay_us(usec);
}
//USB_OTG ms级延时函数
//msec:要延时的ms数.
void USB_OTG_BSP_mDelay (const uint32_t msec)
{
delay_ms(msec);
}