|
STM32的USB中断是1ms执行一次,ST官方的代码并不立即将收到的数据发往USB主机,而是定义了一个接收缓冲,接收缓冲的存在就是避免漏接字符,在回调函数中5ms发送一次数据到USB主机,这个时间间隔使得STM32有足够的时间向USB主机传输数据。RS485的情况需另行考虑。注意这是在STM32中实现超时自动添加换行字符,由于Windows并非实时系统,想要在Windows上位机中实现这个功能,那将是几乎是不可能完成的任务。2 j- |! D/ a$ l! N& ^8 P- g! \ / t5 e: [& o" F( ] 在ST官方例程Virtual_COM_Port中增加的函数如下; _ `! A Z2 l' x2 i /*******************************************************************************. @/ [: N: V' ~) T2 ^" W" f; k * Function Name : TIMx_Base_Configration * Description : 定时器基础应用配置 * Input : TIMx,Period,TIM_Prescaler * Output : None." ?# U/ E: h6 S9 O+ L+ S3 l5 Z4 {; \4 e * Return : None.6 F5 h+ x& ]) V/ {/ u1 x7 Q *******************************************************************************/ void TIMx_Base_Configration(TIM_TypeDef* TIMx, uint16_t Period, uint16_t TIM_Prescaler)3 w+ j K5 d& n6 e4 B { // TIM_Prescaler 72 分频则为1M, 计数加1为1us, 7200分频则为10K, 计数加1为100us$ m1 O% h) Y) v1 K TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period = Period - 1; // 定时器计时总数,最大65535 TIM_TimeBaseStructure.TIM_Prescaler = TIM_Prescaler - 1; // 定时器预分频0 F* z2 B- H, n4 @4 O1 y6 Q TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 定时器时钟输入分频3 R: W5 E- s: Q2 r) S7 h TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式3 U7 Z" F1 ?% q% p! W: J1 U TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure); // 初始化定时器$ l. H" E/ `. ~' x+ V; I TIM_ClearFlag(TIMx, TIM_FLAG_Update); // 清除中断标志# Z3 H: z( A: k4 ^/ o TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE); // 使能定时器中断' l# e: T1 n6 k1 D6 e: m N$ } " j1 f7 C; L5 {2 _ TIM_SetCounter(TIMx, 0); // 设置定时器初始值 TIM_Cmd(TIMx, ENABLE); 1 r1 y4 U9 p8 o* f4 w } ; c" R ]' y$ I0 J. ] 6 Z7 t' j- F& Z, o; f* o- B /* Enable TIM2 clocks */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 使能定时器26 ^1 J, ^- f3 a2 _% [# `) Y& P8 z TIMx_Base_Configration(TIM2, 10, 7200); // 设定周期为1ms0 D2 F# J* `# e# K2 a; O 2 ?; ]; f3 i3 e8 j9 v ( z) `. H8 o+ H: P' h% }8 s /*******************************************************************************0 w' ?2 D2 u, S, D4 r) Z * Function Name : EVAL_COM1_IRQHandler6 R/ v3 t) b) R b9 j5 q9 ?8 Q * Description : This function handles EVAL_COM1 global interrupt request. * Input : None; j& L W) K# U* {8 x1 i/ a * Output : None * Return : None9 F1 _9 A% g. @) V# K *******************************************************************************/) P: g4 c G& V" | void EVAL_COM1_IRQHandler(void) { if (USART_GetITStatus(EVAL_COM1, USART_IT_RXNE) != RESET) { /* Send the received data to the PC Host*/+ }. [! N" e% c5 }$ Z* U USART_To_USB_Send_Data(); Y3 [# n- T4 c /* 最后两个字节为0x0d,0x0a, 这是一个符合微软标准的换行字符 如果最后两个字节不为0x0d,0x0a, 超时1毫秒则自动添加0x0d,0x0a- D" c& Q1 G8 [ L# [ */ last_char[0] = last_char[1];4 D% h! s8 T% w8 T# q1 r& p3 m0 ^ last_char[1] = USART_Rx_Buffer[USART_Rx_ptr_in-1];* }; \- A7 a0 s0 `) X! ?; i if((last_char[0] == 0x0d)&&(last_char[1] == 0x0a)){ Flag_CR_CN = 0;' Q3 k) r. l) K0 G) o0 g TIM_Cmd(TIM2, DISABLE); }else{$ H" J4 h, y1 `% J TIM_SetCounter(TIM2, 0);2 Q9 C1 ^1 C4 c5 e TIM_Cmd(TIM2, ENABLE);# y3 D' J: p" O6 t, j Flag_CR_CN = 1;3 ^' o1 Y! Q0 m/ e }: ~* D+ N4 p/ T' C0 N4 C }' ?$ D5 U7 H4 x' F# t* W /* If overrun condition occurs, clear the ORE flag and recover communication */ if (USART_GetFlagStatus(EVAL_COM1, USART_FLAG_ORE) != RESET) z% d' \0 D3 ? { (void)USART_ReceiveData(EVAL_COM1); t0 }0 a; R9 \! R# f& T5 I3 f } } /*******************************************************************************; G Z. W% f& _: K$ f( D# ^. B* U * Function Name : TIM2_IRQHandler & E+ Y8 }, s& C * Description : This function handles TIM2 global interrupt request. * Input : None * Output : None * Return : None *******************************************************************************/0 f7 l* }1 B4 ^3 R: B- m" h1 N % K( m1 U0 e/ a* K9 C- V' r 3 h( c3 a: c) n void TIM2_IRQHandler(void) { TIM_Cmd(TIM2, DISABLE);: ~, I" o ^1 ^" l5 m8 z TIM_ClearITPendingBit(TIM2, TIM_IT_Update); if(Flag_CR_CN){$ b1 w) `( a" C+ ?. N+ h Flag_CR_CN = 0; ! z1 i; Z0 E5 m1 ? USART_Rx_Buffer[USART_Rx_ptr_in] = 0x0d; USART_Rx_ptr_in++; if(USART_Rx_ptr_in == USART_RX_DATA_SIZE)# f) n( K) W$ P4 N. ^# @7 O" O' C {# g x$ M' B/ r# ^1 E USART_Rx_ptr_in = 0;. e9 L8 S) D9 R/ v% y! L }% g# ?$ t+ {3 K' ]$ K+ } USART_Rx_Buffer[USART_Rx_ptr_in] = 0x0a; USART_Rx_ptr_in++; if(USART_Rx_ptr_in == USART_RX_DATA_SIZE); b/ _# s$ d3 a; W9 |; f {+ k4 C1 y% h2 i& v; B- | USART_Rx_ptr_in = 0; } } } ' @5 g* Z' O- r/ }/ W 9 X# R. a5 l; A/ c+ C% C 基于ST官方原版例程Virtual_COM_Port修改,添加智能换行功能- k# G8 A( D$ l' T# v* S 下载地址:
STM32_USB-FS-Device_Lib_V4.0.0(æºè½æ¢è¡).rar
(5.65 MB, 下载次数: 6727)
|
最全USB HID开发资料,悉心整理一个月,亲自测试
【源码】STLINK-V3MINI 高速USB仿真器,成功改刷【高速CMSIS-DAP】
STM32 USB CDC 虚拟多串口
实战经验 | 选择USBX模块生成USB CDC ACM无PD的项目
STM32 USB HID键盘例程
刘氓兔的杂谈【001】-片上USB 高速PHY
【经验分享】在进行 USB CDC 类开发时,无法发送 64整数倍的数据
在线直播|无需编写任何代码即可在STM32上实现USB-C Power Delivery
圈圈发布USB图书第二版有感,以及分享一些我学习USB过程...
USB Audio设计与实现
微信公众号
手机版
可以,上拉D+为全速设备,上拉D-为低速设备,要作为高速设备使用时,才需要使用三极管控制上拉
回复:【MCU实战经验】+ 利用ST官方STM32_USB-FS-Device_Lib_V4.0.0例程实现USB-TO-TTL232的数据包添加智能换行的功能
将64字节的定义改为63字节,可以解决64字节不响应的bug,以上所有例程都有这个bug
可以解决64字节不响应的bug,以上所有例程都有这个bug