本帖最后由 radio2radio 于 2018-7-14 23:51 编辑
z: T! U! j8 X/ D* c/ d
+ P8 ~; T8 R2 N: U$ [+ p7 ?8 }; H% f4 U) Q看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。" X+ {" f3 Q+ v& j
简单的要求是,USART1和USART2之间互相转发。
- \& K8 J1 X9 `+ R. C5 p N& ~发现使用CubeMX平台,建立测试工程没有难度,情况如下:
1 H6 e, ~) H, n! R
; v- T0 |: [7 S8 z6 g1. 配置管脚,使用BluePill最小板,PC13接有LED:
( R# y+ P* I% d7 Q# g* v+ yMCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。6 O9 y; p% s/ P0 j3 f6 v5 `' m
& [$ ~4 F' ? Y* X( i2 A* [% c
4 K. ^( q7 w H2 {! C$ _2. 配置时钟,重点已经标出:+ `4 A+ r- q0 j* G
5 j% G. s- }$ w- h, H' s, A/ N" C( ^) V! u
3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:
" d8 K3 J9 {' y; I* V8 \9 _8 x: Q(USART2也要同样配置)
- m- |0 r! [9 o& |; F
3 n+ ~& M3 |7 `. ~2 V! |0 b |. y) [1 d
(然后,生成工程代码)8 x8 `1 A1 j! U8 Q( {. G
$ L7 ~: E6 U3 v& b# m4. 添加代码3 Q- ^( [! Q, y9 ~7 j/ H" }
4.1 在main的初始化部分,添加接收中断使能:
# e) v7 L4 l- T- __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT
5 d/ {+ ^7 {7 e b- _# x9 p# \ - __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码
- O* ^; R1 r; N, I5 V
' I6 o8 H; J# H5 B
4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:+ d2 P/ I- o/ t/ P- Z1 l N2 ^
- /* USER CODE BEGIN 0 */
; d ~7 F* i/ p- S- @ - #define UART_BUFFER_SIZE 64 //here must be 2^n5 a ^3 }% X9 G4 |5 ^% c S7 ~& c
- struct bufer_st {/ p/ T( a7 f7 o0 m6 X" R
- unsigned int in; // Next In Index3 C+ J, G2 t; M) v: t+ T% V$ q% j
- unsigned int out; // Next Out Index
# ?( K K0 C6 h$ n! e: n - char buffer [UART_BUFFER_SIZE]; // Buffer1 |/ \( T- e A
- };4 E9 P# R" Z# m, U8 ^, ~( v
- static struct bufer_st uart1buffer = { 0, 0, };
+ R; v. N) o# O5 c, \, s - static struct bufer_st uart2buffer = { 0, 0, };
6 j2 G4 |7 R! f. I' Q8 O: Z$ v - /* USER CODE END 0 */
复制代码
9 c. q- Y" o; A- E) X% P3 K1 [6 e8 _" }- `! ~. @3 U8 D2 |
+ r# P3 p9 |( x$ ]
4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下: - /**
! }5 u" X) A, L! t' L& B& o5 s - * @brief This function handles USART1 global interrupt.
; [+ K4 c z: X" O - */
' a2 M: _, e) z# p" d# W K - void USART1_IRQHandler(void)
/ \8 e. ^& I$ @2 Z, l - {7 ?0 _+ l: S8 w- e$ C! E
- /* USER CODE BEGIN USART1_IRQn 0 */
3 {; t! r4 I5 w - struct bufer_st *p;6 c7 q- \! I. n% o
- /* USER CODE END USART1_IRQn 0 */
9 O% R ~% t ] d) ?1 F& G' A4 E! Y, x1 } - HAL_UART_IRQHandler(&huart1);
* B$ ~5 X, e' c7 ?: _! b) g, M - /* USER CODE BEGIN USART1_IRQn 1 */5 F" d, S5 o7 f& v$ o, {# c; k
- p = &uart1buffer; //use UART1 buffer
0 o' W( W4 V3 [* i2 H4 S: \# A -
5 |/ j: T8 k) |3 b - //raed UART1% v$ l$ n, c3 J# }' `" H
- if (USART1->SR & UART_IT_RXNE) // read interrupt5 w7 J: u& D3 C) e
- { 7 x6 R7 L- s) X9 l, v4 V
- USART1->SR &= ~UART_IT_RXNE; // clear interrupt
_! C6 @, F6 X+ m* u - # r! E# x' T* V$ s0 S! G
- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {' i* E- z7 [: e: C+ B% k7 L- z+ Q' @
- p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA
E. d. F7 w8 I" ]. o+ [ - p->in++;
- b: v3 _$ L, T2 r/ X - }
' p, l; O: j7 e$ Q - }
2 ~# J2 P4 I% R5 l) V - //send to UART2
- a5 j7 U- c$ b- U - if (p->in != p->out)
/ l, `: r2 G; a& ]8 E! @5 o - {
0 u' N/ Q3 a4 K2 i/ I" l; d - USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
0 `+ `3 U- P6 o - p->out++;! r+ O5 f3 [5 e. a7 j
- }
! A. w ?/ a. r; `( G - /* USER CODE END USART1_IRQn 1 */; H C w) P! `4 c# l. q, G
- }8 @- F; N* ~9 [! Q+ D, @
- * _3 N9 P% G& d2 }- V/ h3 ]
- /**) o L9 V) _) A
- * @brief This function handles USART2 global interrupt.' M: w$ h# s; g1 [* T
- */
0 ^/ C; H+ F1 p+ i - void USART2_IRQHandler(void)
" G4 G7 I" E( { - {: R0 Z/ L4 \$ E$ w
- /* USER CODE BEGIN USART2_IRQn 0 */
+ o" D5 n9 ^$ @# ~5 o; k4 ` - struct bufer_st *p;! c4 i5 M f+ E$ u
- /* USER CODE END USART2_IRQn 0 */7 e/ r/ o( t6 u0 S) A& J! G
- HAL_UART_IRQHandler(&huart2);
E/ w: h$ q, |! f( s" v - /* USER CODE BEGIN USART2_IRQn 1 */
5 q1 E' W8 W, l* `4 B8 S - p = &uart2buffer; //use UART2 buffer# } p! L! g' W* D1 c4 N. F
- ' p. L4 C7 x: \3 o
- //raed UART2! [9 N4 O: T8 ~+ y
- if (USART2->SR & UART_IT_RXNE) // read interrupt% M, G& [ C: }" u( b( y9 t0 ?
- {
. @5 \! C; m% d; ^% d4 L3 `# v( E4 ] - USART2->SR &= ~UART_IT_RXNE; // clear interrupt
* f: v2 {# P3 ?! O( {' b4 H - % _$ h. i& ^' T
- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)# C; {) b# m+ n: o6 C9 C' l3 m
- {
: V4 n( W4 a, y( ~ - p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA9 D W- T4 \& v& c/ y
- p->in++;
; Q" {) N. h0 Q: N8 J" s- D - }1 P5 e M) S% G+ a8 o- ]! I
- }; Q% u" j& Y2 r9 ^* p
- //send to UART1
7 ?9 u, e5 \3 u. x1 N0 E$ d - if (p->in != p->out)6 t$ k4 v9 _9 T0 Y
- {
# s% G1 T6 l: L - USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out4 A I0 ~4 p! ?+ _
- p->out++;7 E0 G2 D" V' J' L U
- }* N3 d5 m6 Y* Y$ {, q
- /* USER CODE END USART2_IRQn 1 */. }: K/ b Q7 L* x% x% j
- }
复制代码
5 L _4 U" ~' k- t! L2 _- j, L7 x3 M(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。)8 o9 _; }* x/ f: Y
' K6 E/ G, y0 w2 h* k大功告成了!! 编译后烧录。
5 x# l; A0 _9 \( e. X* _测试条件,使用两个UART转USB板子(FTDI)和sscom5上位机程序(开两个),发送区都摆放700多个字符,以10ms的间隔连续发送。 测试结果,速度115200bps和1Mbps,双向同时收发100万字符无差错。 2Mbps,单方向100万字符无差错。 (高速测试时,需要修改main.c里面的串口速度BaudRate配置。 我没有测试“自动波特率”的模式是否正常。) - \8 W/ L& q- [4 {' @
最后,完整的工程见附件。
7 I9 G3 P, q2 T4 b; v |
: [' x H T8 z2 m" o
谢谢楼主,解决了我的HAL库不能单字节中断收发的问题!
6 _( a R! D0 P/ }! s& p7 n
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。; z' M8 O( r( e
2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。; {. w; C8 P% N, d# q
1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,
2.写入dr寄存器很快,但是发送完成又是另外一会事情
当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?# ~/ c5 F& [. R3 }- C
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
我用国产的,gd32试过 丢失数据严重,不是每个芯片都能这么搞