本帖最后由 radio2radio 于 2018-7-14 23:51 编辑
" m0 Y& z6 G$ `! R/ x1 O1 m9 s3 \) |: A% X
看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。" Z) ]" r3 X- \
简单的要求是,USART1和USART2之间互相转发。
7 E% l# L! ]# h0 U发现使用CubeMX平台,建立测试工程没有难度,情况如下:* U. |- L. f2 a: X6 G
) Q0 K3 k! L7 A1. 配置管脚,使用BluePill最小板,PC13接有LED:. Z; W0 f5 H- Z/ V9 s
MCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。
5 ]! [0 u0 p) R! q
, I3 i; h$ u8 q4 Y7 |2 u4 X3 l3 z; @# [
2. 配置时钟,重点已经标出:; S6 S+ n- J9 U8 H" D
8 F2 e' N; W- \$ U. Q& `' ^
* d& B, e3 j6 S* i u/ }3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:4 Z6 n7 x; K) i% U9 r3 R8 |; x
(USART2也要同样配置)
7 k5 g% x7 a2 N# q& J
* `5 e$ X! K7 [. \. D9 u" ?0 v9 W& T# |. E9 i: j0 T0 l
(然后,生成工程代码)0 r. \9 U* X& `" n1 T/ E
! W; j$ b5 A2 B4. 添加代码
1 r4 E" A0 j- X p4.1 在main的初始化部分,添加接收中断使能:
. i3 ]4 [; i' P8 T, Q1 R- __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT& x$ }2 O( a- t4 e
- __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码 8 |$ @* R# g0 n. h3 P, r6 }( i
" D& h+ a# Z8 t
4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:
5 ]3 z& R8 Y* S+ L- /* USER CODE BEGIN 0 */
3 P& ~% Z, z6 l9 ^* [% F7 J, s0 { - #define UART_BUFFER_SIZE 64 //here must be 2^n% D' }7 Y0 g! [) S$ A2 O
- struct bufer_st {
' i# ~/ w* y, F) Z- Q - unsigned int in; // Next In Index
^: S. k; g1 O' F; _3 v - unsigned int out; // Next Out Index
! N+ @7 a, Y' e D* J" h( s - char buffer [UART_BUFFER_SIZE]; // Buffer
$ y: Q$ O, Q" L6 T5 m - };
0 d; U# x7 ^5 }) H - static struct bufer_st uart1buffer = { 0, 0, };
/ D6 A0 h8 Z O! `0 S5 c - static struct bufer_st uart2buffer = { 0, 0, };0 _( L4 K u) [- S7 Y ]
- /* USER CODE END 0 */
复制代码
- w% y7 f* s/ u, c1 I
3 _5 R9 k( e$ B5 g+ R6 V
9 X( F: x- X1 Z6 h( j# ]( {: I4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下: - /**
; d1 I+ k8 U' p - * @brief This function handles USART1 global interrupt.6 b/ v( Y: }; \3 u
- */- S8 u% R# c% V9 O8 ~
- void USART1_IRQHandler(void)5 h) d+ E, f) g/ P, |2 O
- {3 w h. p, ~1 C& G9 G' u9 w
- /* USER CODE BEGIN USART1_IRQn 0 */
8 `6 ~$ \" C& P6 L. u4 a! U4 w" W5 R - struct bufer_st *p;
1 S- y1 q) G- ~" |3 ^7 d- r - /* USER CODE END USART1_IRQn 0 */: P4 Y6 J. V% P7 R7 r: i) q( g
- HAL_UART_IRQHandler(&huart1);+ m0 R4 z9 `8 W9 k) C
- /* USER CODE BEGIN USART1_IRQn 1 */
! T5 y2 q8 X/ A - p = &uart1buffer; //use UART1 buffer4 {8 m9 o0 h N2 _
-
5 {0 z( [3 G4 B - //raed UART1, W; ]2 o6 Q C# i7 E8 }$ l
- if (USART1->SR & UART_IT_RXNE) // read interrupt5 K: L2 _' j2 }$ X2 ^$ M/ j
- { 4 \1 {' M; L$ [0 \4 a
- USART1->SR &= ~UART_IT_RXNE; // clear interrupt
. k% W2 o% ^6 u7 q - . M8 K" B$ P1 ~4 o
- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {
" Y, y2 K/ T9 c) j2 ~, Y - p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA' h Q8 G a v- S: g8 i3 z
- p->in++;
$ f B2 x2 o4 j: U/ H) k - }
$ y: P% D3 y; a* A N& i! E2 Y - }
+ V ~& k, L; S& _9 H' m( ] - //send to UART2% @$ o- ^) E j! n9 G b) T/ Y
- if (p->in != p->out)
' d9 _5 F' {+ c7 [/ R1 d7 b, A7 e - {! m$ M$ [1 l* [- J8 c
- USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out9 w/ `; h$ D8 x7 _" ^/ |
- p->out++;8 \& E4 l& X8 R4 j3 O" d
- }
0 T2 l2 D" u0 i2 Y5 ]; g, a - /* USER CODE END USART1_IRQn 1 */3 D7 h9 Q; D8 A% |, Q) v9 l, W
- }; L9 K# b) H; w/ n- A" p0 R
- 6 Z: `* C0 b: V
- /**0 S3 I7 A: @ B6 a! l- M4 N
- * @brief This function handles USART2 global interrupt.
7 @- U9 L8 ?8 Q) r1 m; B: L; n - */9 ^6 Q* o% H% j- O! F6 L' w" |
- void USART2_IRQHandler(void)
) ~* l; V7 o, R% h$ F+ j - {
/ @) v9 g' A) s# R- l8 v3 T - /* USER CODE BEGIN USART2_IRQn 0 */
0 d3 a) p( L; e/ x8 h5 J - struct bufer_st *p;0 \6 ~ j, L0 P1 W; B m# T& v% {/ F
- /* USER CODE END USART2_IRQn 0 */
6 c- W8 t3 W3 u0 x - HAL_UART_IRQHandler(&huart2);
: G5 b" X7 V) v2 |4 ~: ^ - /* USER CODE BEGIN USART2_IRQn 1 */
. a9 m( ^- ^% y - p = &uart2buffer; //use UART2 buffer
# u0 C4 w' X; A* v( r) C - * w0 @% U- v7 V9 e: B. H
- //raed UART2- {- Y* x; b9 r. C
- if (USART2->SR & UART_IT_RXNE) // read interrupt
/ d; z* ?+ X& s* S+ S. j( [2 z - { * L7 n1 a$ s. k% e5 _+ k# d( r
- USART2->SR &= ~UART_IT_RXNE; // clear interrupt
+ ]! }- D" I0 n5 u2 K# ]: |: _9 | - " K& _3 w/ M. M8 v k# y
- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)
7 m" A+ w6 `+ z8 x+ _ - {/ X( @1 c! ^0 \
- p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA: i3 W/ U3 V5 g l
- p->in++;
( g- z/ u$ M; f( p! H/ [( E9 R - }
& T6 D) f2 J8 V$ y- t2 @8 \/ z - }
* z9 J( j/ d( @ - //send to UART18 j1 R( M) L7 C( i1 o% L3 h7 V
- if (p->in != p->out)) E) A D5 l& a7 {1 K e1 t" j
- {* H5 e9 ?! c8 E- Y" {$ y Z
- USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out$ P3 R7 s" X( V1 n
- p->out++;
! A# b( i$ }& W1 n0 _& d9 y2 G - }; A$ Z3 ^5 t, R6 o+ a: d9 N
- /* USER CODE END USART2_IRQn 1 */1 w7 k* _0 _, I; j/ P2 X$ l& p- z
- }
复制代码 - `$ s. t9 `5 a8 i" @- `
(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。)
# V1 F+ j2 s" a4 m
, _6 a. ^% {5 L& f2 g) n% c* n大功告成了!! 编译后烧录。
1 }- {& d2 {( G1 i: a: D测试条件,使用两个UART转USB板子(FTDI)和sscom5上位机程序(开两个),发送区都摆放700多个字符,以10ms的间隔连续发送。 测试结果,速度115200bps和1Mbps,双向同时收发100万字符无差错。 2Mbps,单方向100万字符无差错。 (高速测试时,需要修改main.c里面的串口速度BaudRate配置。 我没有测试“自动波特率”的模式是否正常。)
! I( V# o% x, L; p. e, k7 ^6 B# }( y最后,完整的工程见附件。 5 {% ^3 n, v* s2 X; `9 X! x6 w W
|
谢谢楼主,解决了我的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 */
- }
2 Q a% h% U' \1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。
1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,
2.写入dr寄存器很快,但是发送完成又是另外一会事情
: y& h0 L! u4 k' y( X d
当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?& r+ @0 E. i6 ?, L/ U
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
我用国产的,gd32试过 丢失数据严重,不是每个芯片都能这么搞