本帖最后由 radio2radio 于 2018-7-14 23:51 编辑 9 X: h% Y* g+ f) j; e d# U
) l# s, o9 K. O: I; q7 k
看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。
# |/ t+ L7 K; F简单的要求是,USART1和USART2之间互相转发。
1 r; s' x; t# P$ G! m9 O5 f: ?* q发现使用CubeMX平台,建立测试工程没有难度,情况如下:
* G/ Z3 S/ s) m4 p
7 O0 ]5 \& n0 h6 p/ X. q0 g1. 配置管脚,使用BluePill最小板,PC13接有LED:
& }) R! b6 }0 p! i1 r( a8 AMCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。
W# Z/ @3 _( J: y
n2 A! w9 { X1 k" ]$ g5 |/ A! P1 _# W9 {& L
2. 配置时钟,重点已经标出:
% c' Q" w# f) J3 L, c* E
, u; T( \) I* W; g( l/ a
1 e6 \0 w! `4 V3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:
4 s' F2 |. t& `% r7 f" e0 g(USART2也要同样配置)
7 [" C9 t4 a# @3 O
6 J9 b7 p' v: u% h* S. ]
5 K8 K: R3 X2 t(然后,生成工程代码)
" u' n* T7 |* l& Y4 _
8 F2 I9 ?" @1 L7 P- r4. 添加代码
2 R2 Y6 o, H4 |, }" j3 i7 L4.1 在main的初始化部分,添加接收中断使能:; n) x$ B E$ v' y
- __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT/ C! E8 a+ ~$ ^" [$ l
- __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码 2 O( _ @6 a$ T+ D. f
; h5 _% j" p& y; m. m9 b" X) s
4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:
- V' p9 H0 r S5 d2 B x2 F3 s- /* USER CODE BEGIN 0 */
% P- t; u& W/ n. ?) ?9 @# R* R - #define UART_BUFFER_SIZE 64 //here must be 2^n
9 C2 I% C0 N+ X9 e9 h3 f - struct bufer_st {9 O+ M! Y4 H/ n; I6 r7 K# V9 w3 l/ x
- unsigned int in; // Next In Index
+ @3 j4 z6 g% \) f& A: t - unsigned int out; // Next Out Index) V. h; y; [* r/ O k7 r
- char buffer [UART_BUFFER_SIZE]; // Buffer+ ]- T6 _* ^4 j9 T
- };
% f% L! V: R2 ~* q - static struct bufer_st uart1buffer = { 0, 0, };
/ s" F5 ^3 I3 _' o9 M8 F: o - static struct bufer_st uart2buffer = { 0, 0, };
" \5 [% r" z! p4 { - /* USER CODE END 0 */
复制代码
; k2 N4 f F1 r+ P: ]" A& n6 W7 c- W( W
) K2 [2 w0 M: h6 g0 o ?# Q
4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下: - /**. I) c# V$ [) P& ~% M4 W' e$ _
- * @brief This function handles USART1 global interrupt.9 S1 k6 h: Z3 {( W8 K
- */, u' F% W6 [) k$ o
- void USART1_IRQHandler(void)
4 N. ]* v. t- b: ~. q - {" r O6 i, @2 n! f: O4 r
- /* USER CODE BEGIN USART1_IRQn 0 */
6 a: |( q4 s" T6 `3 n/ a* t - struct bufer_st *p;
- L, E/ `5 f1 Z; W - /* USER CODE END USART1_IRQn 0 */7 u' m5 W: b8 ]; `; r
- HAL_UART_IRQHandler(&huart1);
2 c2 M# ^2 ~# h5 Z - /* USER CODE BEGIN USART1_IRQn 1 */
0 }5 D$ t2 f/ O% Q* Z7 w - p = &uart1buffer; //use UART1 buffer
, p' {! P' w- S - & I1 k# j3 [; f0 a+ P `) L T
- //raed UART1
2 P1 `5 z/ D- x8 V9 i( m) s - if (USART1->SR & UART_IT_RXNE) // read interrupt
( b0 r2 W5 L+ v! r - { ) ]& s5 T m* m. S$ _8 H/ u
- USART1->SR &= ~UART_IT_RXNE; // clear interrupt
" Q( n% U' @: `7 ^! I# ~
& ^" a# Z' U4 C# y$ [- l# B- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {6 C; ^- J. H3 G% T- u3 p$ p/ i4 {
- p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA
7 F6 C% L( p" s8 L4 B, t. o6 W - p->in++;* J5 T+ [$ X$ J
- }5 X5 j$ B) {4 B. N7 m. J9 E
- }
2 U9 r! y3 o# K' L% ~ - //send to UART27 ~5 z W$ q M* P, O
- if (p->in != p->out)/ ^* Q1 a- J: N9 g& X1 g. @* N" L
- {/ t6 k. P) p% H5 |( L; P' u# ~
- USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
, I" F. r* m0 U) P1 \+ ? - p->out++;0 B8 _' Z6 |, p: ~, a T* V4 [6 n, J
- } H: \- K' c/ V) a' j
- /* USER CODE END USART1_IRQn 1 */: f$ V: q d% P: M
- }
8 J C5 w& ~1 s- b$ [' v' d8 @# X - ; e& H! P4 S. a) p
- /**1 \+ |' W6 T) y
- * @brief This function handles USART2 global interrupt.7 w b1 P5 J: K- E& J
- */
4 I* l( R5 D2 E. x& Q, P8 D- E5 K9 o - void USART2_IRQHandler(void)/ W0 Y: j. z6 J. f8 {3 K& g
- {9 o" T) l' N. r6 i+ w' ?
- /* USER CODE BEGIN USART2_IRQn 0 *// y) {# L) N$ y: [- F3 {, n
- struct bufer_st *p;* |. I k Z; D9 [) d/ [
- /* USER CODE END USART2_IRQn 0 */# r: f3 u" O: [, U' F4 n
- HAL_UART_IRQHandler(&huart2);
0 ^/ I- ~3 b& x* ? i6 ~$ e - /* USER CODE BEGIN USART2_IRQn 1 */6 e0 s: @* V+ }' x2 a% {7 S$ _
- p = &uart2buffer; //use UART2 buffer
8 P' k# H* D- k - # Y; W( N& W5 l( H5 Q4 U# d' V H
- //raed UART2
$ g* z! g( v9 n V+ O7 z5 ~ - if (USART2->SR & UART_IT_RXNE) // read interrupt! c( b# z' w4 ^0 n/ @4 P% c0 c
- { * i. f6 Y1 c) v2 h( x1 s, G+ f
- USART2->SR &= ~UART_IT_RXNE; // clear interrupt
1 l8 R1 U% ]4 v- {4 a
2 @- E, T5 C4 _3 W, Z4 h- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)( G Q# a, x N8 j1 V; n
- {
& |- x# I7 C# H5 k' I - p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA
) \1 ^, S5 e0 v( @8 @ - p->in++;
7 E( S) z9 ~" D& |0 d - }' T7 \4 R/ P; D8 v( C& D" O1 z! {
- }
% G7 u! I( [$ w; \ - //send to UART1
: R8 {) }0 _( P1 v - if (p->in != p->out)
$ o, M7 i6 ^6 U* v2 ]% z - {$ T4 D( K5 h; r; B$ R7 a
- USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out( V. l0 P. M1 {( c
- p->out++;
" N# M3 V5 v y2 Z) t8 e1 D - }6 m8 b* ]$ Q2 o7 R+ _ R
- /* USER CODE END USART2_IRQn 1 */
2 C6 K# N/ U9 @! H - }
复制代码 ) q3 R) z! x9 X( }
(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。)
8 g' d& K' j6 c" ^
6 B( a2 l) i' H8 o5 b0 _5 E5 w4 K大功告成了!! 编译后烧录。 3 u8 A5 R: i1 s' U# \
测试条件,使用两个UART转USB板子(FTDI)和sscom5上位机程序(开两个),发送区都摆放700多个字符,以10ms的间隔连续发送。 测试结果,速度115200bps和1Mbps,双向同时收发100万字符无差错。 2Mbps,单方向100万字符无差错。 (高速测试时,需要修改main.c里面的串口速度BaudRate配置。 我没有测试“自动波特率”的模式是否正常。)
1 }/ U: D7 f: ~, x最后,完整的工程见附件。 2 ~4 U# f- K- S0 R
|
谢谢楼主,解决了我的HAL库不能单字节中断收发的问题!( d4 C% ^" k# v+ i0 \2 p
- 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 */
- }
, u1 | v3 T( [+ {/ ?7 ]$ I9 n2 n& B! x- S
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。
" \, a7 S+ X. {+ z' w% n5 H
1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,' h/ B, A2 B$ X; |. N* d* L
2.写入dr寄存器很快,但是发送完成又是另外一会事情
, |" m- Z: L8 i* |% ?
当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
我用国产的,gd32试过 丢失数据严重,不是每个芯片都能这么搞