本帖最后由 radio2radio 于 2018-7-14 23:51 编辑 ( k* n Y# W# g4 {$ T6 Y5 t
6 f) B* H5 c7 s. e2 b2 H
看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。
+ g9 S9 E, L! J. I+ X1 P0 g简单的要求是,USART1和USART2之间互相转发。7 {/ \/ l3 @& z& X& A3 f) U
发现使用CubeMX平台,建立测试工程没有难度,情况如下:
( d- w; U' y% I N& g/ A8 d, ?$ |4 r) Q& O1 b
1. 配置管脚,使用BluePill最小板,PC13接有LED:
6 w3 C, s7 p7 R P$ n1 fMCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。1 S& }" J" \. U5 m2 B9 j, Z! g
9 F: J$ q' N0 F P
3 M' T c* O- s4 l$ A ]6 q6 K2. 配置时钟,重点已经标出:" `7 g6 o& r- p- {& x# [
. a* }4 V/ G I) s/ i5 G- g {& J8 @" p4 d/ M
3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:1 C7 ?7 J4 O! g. R7 c! d7 s
(USART2也要同样配置)
' m2 y: u( I A i
' o% |2 i2 j% {$ ^! F: a
- b& R4 O4 k+ G(然后,生成工程代码)
1 d4 o5 Z! b+ |( F* r6 b/ L5 U4 q
6 ]& H9 P5 f* I; U9 h4 J4. 添加代码" Q- d8 g: p1 B) x Z
4.1 在main的初始化部分,添加接收中断使能:' R' q, Y6 ]! K
- __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT/ G6 N/ y7 u' }8 W9 m; V
- __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码 5 j' }" T( Q6 S( k4 D6 T7 }2 Z/ V
S1 R) A' m* r1 l9 ^3 P3 Q
4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:
3 S% H3 N# E2 ?0 T8 e- /* USER CODE BEGIN 0 */
8 E) m* _- a' y5 A& N. q- J" W - #define UART_BUFFER_SIZE 64 //here must be 2^n
( U- }! M2 m/ p9 P4 i9 } - struct bufer_st {
+ B; I, Q% N5 d( b. z6 S) N1 R - unsigned int in; // Next In Index
" |- }0 [0 v i% h1 I# R: ` - unsigned int out; // Next Out Index
6 \( r* d4 u4 M7 Z: B9 G - char buffer [UART_BUFFER_SIZE]; // Buffer
: Y+ ]7 n3 P2 x0 f+ i$ c - };* n: r. n" e1 \: k$ c9 F! A
- static struct bufer_st uart1buffer = { 0, 0, };
. e3 r( q! J5 u - static struct bufer_st uart2buffer = { 0, 0, };! k* W/ D8 m5 Y
- /* USER CODE END 0 */
复制代码
' W/ k3 y7 X. k* {$ g9 c, A I& k/ U/ x0 ~
; Z; a! D! \0 J: `/ t
4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下: - /**$ q2 n% J0 K) n$ J" i% A; j
- * @brief This function handles USART1 global interrupt.
$ j! S3 ]5 B4 G - */& m B* b: Q( A0 s, a$ o" g+ C. v. X
- void USART1_IRQHandler(void)5 L$ u) |: `3 V
- {8 t6 L0 L9 \/ K7 c7 N
- /* USER CODE BEGIN USART1_IRQn 0 */
4 s" s5 ^% S0 u& R - struct bufer_st *p;9 r, @( g. ]; J- t, X
- /* USER CODE END USART1_IRQn 0 */ K1 v8 s4 }( ^( L
- HAL_UART_IRQHandler(&huart1);
% X; i* S3 I5 X% {5 v - /* USER CODE BEGIN USART1_IRQn 1 */3 S' t$ Q& B, [, C A/ o R* A
- p = &uart1buffer; //use UART1 buffer
4 ?2 m% G$ h1 o1 H# H @( s! j -
2 ^# d q" Z) v& F, p6 I, N/ L% W - //raed UART1
$ M9 B8 J) F( Q/ z8 z7 I' o - if (USART1->SR & UART_IT_RXNE) // read interrupt3 W j; O6 |. o1 W' v$ ~2 X0 v9 d; z
- { , H* f& ?) f; t
- USART1->SR &= ~UART_IT_RXNE; // clear interrupt/ o' o) `4 t9 Y' V
/ c1 B' \3 m4 B- I t( c- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {, q+ J! n& \4 p: p$ \
- p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA
( j, Y, S' B4 X0 Y) B - p->in++;
5 T3 ]1 h7 j) T. h6 o/ f - }9 b( K/ b$ Z8 C' O' _
- }
9 [" `$ c/ F' B/ `% y' } - //send to UART2
( K- h# H+ M# c" C; d1 q' s - if (p->in != p->out)
A! ]& }( R/ F - {
) w$ z! t# }; L) X - USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out! a+ v7 ?/ I% ?! M0 U
- p->out++;
r+ x& d) B# t - }& q: w! \- a! {: A, u' G0 z
- /* USER CODE END USART1_IRQn 1 */7 k' O5 y4 C( a* m9 |8 J/ Z
- }
4 E7 t4 L4 R- s - B4 h! \- a. U) i& ^
- /**
( g' H$ n9 V* T9 f# i$ D+ X: O - * @brief This function handles USART2 global interrupt.) [8 ?# H7 B0 M2 e. x( @- \" `$ ?
- */4 |' Y# q: y9 z1 }( B
- void USART2_IRQHandler(void)
: R m, w. ?( i( A4 {( l! \1 a4 D - {, J2 O2 W( s8 o3 A4 K
- /* USER CODE BEGIN USART2_IRQn 0 */" z! g7 K. m" L0 [
- struct bufer_st *p;8 q6 a* P8 Z% m E3 b
- /* USER CODE END USART2_IRQn 0 */5 S2 j/ i3 S- x; `
- HAL_UART_IRQHandler(&huart2);" |( b8 W& j, A( Y5 c% e
- /* USER CODE BEGIN USART2_IRQn 1 */( `0 h, X0 ]) u6 z, R4 X( ^
- p = &uart2buffer; //use UART2 buffer6 r" G8 m/ s) Z% U0 W
- ( K: _. U9 s# E
- //raed UART2- c; o% c3 {2 x7 n! W; s
- if (USART2->SR & UART_IT_RXNE) // read interrupt) t( ?. q" u$ p# y, v$ N
- {
4 r1 F' q* m: ~; V$ k# V4 r - USART2->SR &= ~UART_IT_RXNE; // clear interrupt/ F+ C* @. a2 x8 @
4 e# c& {4 j: i5 V, V- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)
% e4 \2 x( O& r8 P5 F1 l' g2 } - {
; y {9 |- i( H8 w, @ - p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA
: Z7 U- \/ H3 h1 N. j - p->in++;
9 i! q, W) {! N7 H: A) Y" D" I - }; W. J- Y2 v y/ c) s
- }
+ L# d J5 `8 U9 g6 [" D5 l - //send to UART1. o+ r5 _5 _9 u; C/ }: X* D
- if (p->in != p->out)) P# \9 c3 T/ n
- {
2 ^! p$ z' ?' j* v0 Z; y j& Z4 o - USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
5 {1 }" j0 Z# u - p->out++;$ R! e3 ?/ C( b# H3 k2 w+ I
- }" G7 W( S2 {8 s
- /* USER CODE END USART2_IRQn 1 */
/ G9 r9 W) k0 v l& o/ D+ | - }
复制代码
. n0 O o+ m! c9 u; [ f1 b9 X(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。), F, L C3 ?1 Y- Y
8 d# ]- c' y. z, M0 P& h% k大功告成了!! 编译后烧录。
" }. j& ]! W2 T, [! k2 f2 O测试条件,使用两个UART转USB板子(FTDI)和sscom5上位机程序(开两个),发送区都摆放700多个字符,以10ms的间隔连续发送。 测试结果,速度115200bps和1Mbps,双向同时收发100万字符无差错。 2Mbps,单方向100万字符无差错。 (高速测试时,需要修改main.c里面的串口速度BaudRate配置。 我没有测试“自动波特率”的模式是否正常。)
* ]6 z6 V! E( |# T最后,完整的工程见附件。
q0 F% B4 [7 X! M' j |
谢谢楼主,解决了我的HAL库不能单字节中断收发的问题!
- void USART1_IRQHandler(void)
- {
- /* USER CODE BEGIN USART1_IRQn 0 */
- struct bufer_st *p;
- /* USER CODE END USART1_IRQn 0 */
- HAL_UART_IRQHandler(&huart1);
- /* USER CODE BEGIN USART1_IRQn 1 */
- p = &uart1buffer; //use UART1 buffer
- //raed UART1
- if (USART1->SR & UART_IT_RXNE) // read interrupt
- {
- USART1->SR &= ~UART_IT_RXNE; // clear interrupt
- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {
- p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA
- p->in++;
- }
- }
- //send to UART2
- if (p->in != p->out)
- {
- USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out,此处我将USART2修改成USART1,就能实现每个字节接收中断收发
- p->out++;
- }
- /* USER CODE END USART1_IRQn 1 */
- }
" I8 t+ G9 Q; F# k; L1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。: K5 z" z+ |# `8 ]/ ?
1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,) U$ B* @2 ^+ D9 O
2.写入dr寄存器很快,但是发送完成又是另外一会事情
当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?! Q2 l6 a1 |+ t# T* G0 i8 i; ^
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。( H; l+ T0 _/ l
我用国产的,gd32试过 丢失数据严重,不是每个芯片都能这么搞