本帖最后由 radio2radio 于 2018-7-14 23:51 编辑 3 Y: j+ u0 }4 h2 a! R% u
; _$ O" J k }1 C4 K' X5 F9 J9 S看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。
" h# g0 Y- n# b. n }简单的要求是,USART1和USART2之间互相转发。! R# r I! _) @9 w' _4 e
发现使用CubeMX平台,建立测试工程没有难度,情况如下:
, H8 E+ X. C3 K& K% O, x& D, s# _ ]0 g4 R0 q( {7 ?
1. 配置管脚,使用BluePill最小板,PC13接有LED:
) u' [6 D/ e9 b2 MMCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。3 U" G2 u- i: Z2 ]! q2 I
( k) Q( ?7 S m, p! d1 o' {
' q- w5 j2 }* }9 q+ a! A( Z. l2. 配置时钟,重点已经标出:) U. U0 Y) f6 x C4 m% s7 z' W2 R
K6 K8 C6 v2 `4 l
0 B7 W. L, n6 m0 K3 b3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:% O; z. v' R$ d" T
(USART2也要同样配置)$ \/ ~3 _. c( f; d$ n
# a5 d9 `4 @& n/ o1 ]: a; i
% a1 x; H0 v. S
(然后,生成工程代码)
5 z- X/ ~! D2 g- p, }5 V/ _5 S ^! C5 u$ V0 R& H( N
4. 添加代码; L: M7 V2 G5 N( f8 r- R: o* J
4.1 在main的初始化部分,添加接收中断使能:; I& X, @& d; i: e: [6 @7 i. r4 c9 Q
- __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT
; _/ ^9 B2 v. | - __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码 % ]7 n# q4 f ]: _4 l
$ F# b# c, x+ d. p w3 j
4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:5 }2 V" j$ @8 m) X: u
- /* USER CODE BEGIN 0 */
& ?2 [* Y2 I" a+ @; x - #define UART_BUFFER_SIZE 64 //here must be 2^n
& {, ~9 }( i' m2 ?, y4 G/ m - struct bufer_st { _' J0 H; ]5 k% n3 u, u8 s
- unsigned int in; // Next In Index2 f6 ]( H; x, \& _
- unsigned int out; // Next Out Index
2 [ n O I) [! d( x8 ] - char buffer [UART_BUFFER_SIZE]; // Buffer$ `1 m8 r/ I4 N1 x
- };
" E; ^# }6 }6 F. }: j! Y& D$ A( W - static struct bufer_st uart1buffer = { 0, 0, };# H' O2 k8 g9 Z; Z& ~
- static struct bufer_st uart2buffer = { 0, 0, };
+ n# k9 a' F+ V$ O - /* USER CODE END 0 */
复制代码 ) e5 k& l0 I# i2 ^$ U1 @. E
* A9 u7 {/ ^8 E& {: D) O$ C
" R# t% t9 B" [) F$ I0 O k' M4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下: - /**5 x6 @1 {6 v: T3 E
- * @brief This function handles USART1 global interrupt.
5 @% [% c, u; J4 u" n0 y) b& M - */$ b; i) t3 u3 |1 O
- void USART1_IRQHandler(void)9 ^; S. H+ y" ?5 k) ?( z
- {( ?3 G* y: F$ w* F: J( A- Z( }) |3 O
- /* USER CODE BEGIN USART1_IRQn 0 */
$ ^$ d, g; ?9 }- B" s: ]3 e7 u8 U - struct bufer_st *p;) Q- f6 H4 e# M
- /* USER CODE END USART1_IRQn 0 */
( ]. {! e7 `2 \! W% s8 L! |+ H - HAL_UART_IRQHandler(&huart1);) w- C/ t% @# [7 c6 f4 z A' g
- /* USER CODE BEGIN USART1_IRQn 1 */
3 J( H. ~5 a2 N6 D5 M - p = &uart1buffer; //use UART1 buffer
8 i& Y5 R! V2 B -
4 ^& A7 P6 E3 ?% w$ m* ~$ l- d9 V3 y5 \ - //raed UART1
5 Z% S0 ~1 K9 B' {9 ?2 q' V - if (USART1->SR & UART_IT_RXNE) // read interrupt
$ X) O3 F* M, c8 C6 G - { " k6 I7 J8 \2 K4 u* `; E
- USART1->SR &= ~UART_IT_RXNE; // clear interrupt4 O3 x2 q6 g/ W1 \ b; e1 `) K1 f# c
6 x$ g5 o& K2 `( X- B- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {
( s! a) ?( n) {/ G4 j - p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA
1 D1 x3 N, j( D( t* L3 F6 r - p->in++;
, u4 H. O; W5 f' w" |; L" Y - }
' \3 j% J% ~9 r - }+ @/ u d O0 f" w
- //send to UART2
7 h1 {4 n+ i# D- ?2 i) ~. y - if (p->in != p->out)* T" |! O! L7 Q
- { F" Z" u* s) w: k" B6 W% U/ E
- USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
- I! a+ {8 g$ a- e! x - p->out++;
+ }' S2 ^" q6 B& k, Y0 n( M - }, n, w. c4 L7 `6 m Z, Q4 u
- /* USER CODE END USART1_IRQn 1 */
/ g% N9 s% ^1 w5 O5 x" ~( o - }6 M+ e G) v6 t, n j5 |
- 6 m ]" T6 b8 _7 @/ Q* o# b P
- /**, o' E; G9 a! g7 g: e' i
- * @brief This function handles USART2 global interrupt.
6 }2 T9 Y( l. o0 q3 X, D - */, f% O( `) A7 K: ~! b- V
- void USART2_IRQHandler(void)/ m$ o/ ^2 c) v7 O9 y3 M
- {: @6 v4 {, G9 {( J8 |# x+ y# U8 B b# w% h
- /* USER CODE BEGIN USART2_IRQn 0 */' u: }+ k* |/ Z% S7 `4 h, B
- struct bufer_st *p;- w0 I3 f# \$ D; O5 p4 e
- /* USER CODE END USART2_IRQn 0 */ S' z N( K& G3 U7 V% x% R
- HAL_UART_IRQHandler(&huart2); S! s( D) m, P5 k2 z- o9 O/ c
- /* USER CODE BEGIN USART2_IRQn 1 */ ~+ k+ O- A* c. V1 Q" h+ w
- p = &uart2buffer; //use UART2 buffer" f" F; c) D+ {0 e5 K
- V1 A' N2 I% z- ^/ E( m& ~
- //raed UART2
" \" o' _3 U! [; [ - if (USART2->SR & UART_IT_RXNE) // read interrupt- o E8 |. J+ m I* T
- { : h6 h8 G2 b, W8 y5 ]: m3 t
- USART2->SR &= ~UART_IT_RXNE; // clear interrupt) L ~6 e% R4 l/ T% g
- . I9 D/ R: \( y' m3 N$ Z
- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)5 N4 X6 Y% d# H# H1 J5 u9 E; i; v# a
- {! d2 P1 f. ~+ J4 R. W
- p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA
9 m0 F8 t. l; M7 e5 |4 I - p->in++;) G3 G" s; d0 Z2 C' _
- }
8 D- h! z1 c8 O- X: d - }9 B5 y+ D& [1 z% p) i
- //send to UART1
& a/ D3 k' d$ ` - if (p->in != p->out)
$ o4 R3 F5 L9 H+ t% ] - {) K9 g2 c& o0 Y
- USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out' _' J1 o) N$ G
- p->out++;( d/ L- T8 o: M: R$ Q& B4 q
- }
9 z7 o1 w, H( a2 E8 _5 Q: R) p) ^! k - /* USER CODE END USART2_IRQn 1 */& p! h7 A1 {$ R6 i
- }
复制代码
% t9 }4 ` i2 J- ]+ k4 ~) I(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。)
# S7 F& z: q" P, Q. ~9 L. F
0 z o9 L+ z- p6 l+ b4 J大功告成了!! 编译后烧录。
1 o& j k4 M0 d* W3 P测试条件,使用两个UART转USB板子(FTDI)和sscom5上位机程序(开两个),发送区都摆放700多个字符,以10ms的间隔连续发送。 测试结果,速度115200bps和1Mbps,双向同时收发100万字符无差错。 2Mbps,单方向100万字符无差错。 (高速测试时,需要修改main.c里面的串口速度BaudRate配置。 我没有测试“自动波特率”的模式是否正常。) + v# a$ ?. V0 J# d& |- P" y
最后,完整的工程见附件。 1 p# t' }# _* \1 V I f
|
/ }6 P: C, H% {) h
谢谢楼主,解决了我的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 */
- }
- 7 I) |' P5 {: ^
. W+ p5 G1 I$ c0 B1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。0 h6 p! T) p6 b( ?4 U7 e- a& F: U5 C
: f2 Z# X9 ]2 R, d3 q
1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,
2.写入dr寄存器很快,但是发送完成又是另外一会事情
2 y/ H# @) K" B5 S4 F: h
当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。. h: c5 r M9 ^; p( e1 ?9 A; U' O
我用国产的,gd32试过 丢失数据严重,不是每个芯片都能这么搞