本帖最后由 radio2radio 于 2018-7-14 23:51 编辑 * N- F0 ?+ \- M6 r& [
1 Q$ \' n+ K$ }& F, ~3 [4 N$ j
看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。* D0 R" O( K# m+ l% C) u5 d( R4 D9 H. m
简单的要求是,USART1和USART2之间互相转发。7 v& G* `6 E6 u- c2 u# I
发现使用CubeMX平台,建立测试工程没有难度,情况如下:
0 V: C0 E) y, Q- q/ z0 m# S8 O# t3 ~# O$ ?; }1 D6 F3 s
1. 配置管脚,使用BluePill最小板,PC13接有LED:
1 Y& k+ j4 J) |: v% `MCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。8 _& b& d# f+ ^5 J, R
5 u4 N% o7 A) X- V
6 q7 ^! t/ H& W9 x# n2 s2. 配置时钟,重点已经标出:" @; b) V: w4 g! M) v1 U6 o/ m
/ }! b% \, w% Y7 ^" U( B1 K% I/ m
; h' I5 H5 U! a7 _5 C9 }' i
3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:
$ X v* w& d' B. X, P3 _$ H(USART2也要同样配置)- r: g) ]% Z r1 E' }! ~
8 P% ~5 G, n4 f" E N1 Y
, \) R5 e( S) H! a$ G8 \(然后,生成工程代码)
/ R$ h. [% q' y0 F* m5 \
3 |, _5 K& G0 N8 t: J, \1 z( G4. 添加代码, n) q1 G8 D0 ]5 K
4.1 在main的初始化部分,添加接收中断使能:
* s; L8 i, a" ?/ [3 C- __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT
; c9 E1 C8 N5 N2 m - __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码 $ R! K( ^( q, p6 B) V
" ? E0 s \* V$ d. F1 x/ a
4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:7 [ V" Z: q. p, f7 g& J
- /* USER CODE BEGIN 0 */
. z% H/ C' Q6 Y1 w: I - #define UART_BUFFER_SIZE 64 //here must be 2^n
0 g1 s/ E$ K) N9 S" G V - struct bufer_st {/ I1 m) F1 v' X% _* Q) C* J
- unsigned int in; // Next In Index
8 _9 ?; x( Q1 o$ }6 i0 `$ v9 f - unsigned int out; // Next Out Index
/ c' M( B+ w* v" N$ ? - char buffer [UART_BUFFER_SIZE]; // Buffer2 t' r) | `0 N6 M
- };
# O( i# m3 m, f) b - static struct bufer_st uart1buffer = { 0, 0, };) t5 S* i( Z0 Y* o0 N5 Y; S
- static struct bufer_st uart2buffer = { 0, 0, };
* B# h- f3 Y% h7 o - /* USER CODE END 0 */
复制代码
3 o7 m& R! _$ D, s# F0 e# P, k2 n& W% L9 @. G+ n! d, T, f
3 j# s8 w; J! j) R8 d/ F4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下: - /**$ O3 T% E) M- W8 g0 x8 D0 a. R
- * @brief This function handles USART1 global interrupt.
1 D" i2 A e+ w. R: U* }: E - */8 ^2 Y! N" ]! L( t U4 ?3 o* ~
- void USART1_IRQHandler(void)
1 [2 K* P1 p2 U- M& d1 h0 K+ F - {* k* G7 u6 ~# a7 `
- /* USER CODE BEGIN USART1_IRQn 0 */
* P) h2 f& z% a: w9 z - struct bufer_st *p;3 x- C0 Y# E! w ]3 |
- /* USER CODE END USART1_IRQn 0 */
9 t, O1 ^: a+ @9 `2 q6 U+ F. M; Q - HAL_UART_IRQHandler(&huart1);
& h0 w- N. G* U. ~; n5 ` - /* USER CODE BEGIN USART1_IRQn 1 */- k* c. P% h; j. G: H
- p = &uart1buffer; //use UART1 buffer
$ N4 ~& W( f: y' @! I8 o. E* M | -
& z8 o. Q1 N+ }& Y% y - //raed UART18 N4 K0 H# `: x
- if (USART1->SR & UART_IT_RXNE) // read interrupt
9 D# y; b! m8 E! W( p8 g6 G5 N# K - {
O2 M) j* C5 o! v6 o! N - USART1->SR &= ~UART_IT_RXNE; // clear interrupt6 r0 P3 I4 E4 E# M+ s4 b
1 j3 T: s" d H$ @, H" r9 d' {3 z. H+ u- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {
' ~& `; `* o* f/ @* b# c - p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA1 i; f* q( W8 T* F$ D" I! S% L
- p->in++;! S' l1 L) {' N- {- t
- }
8 `7 G# v8 O/ g5 A1 {9 E - }
; B' U, @. i) R3 C - //send to UART2! G: A- P, {9 t2 [7 C
- if (p->in != p->out)
$ A+ E- a' N { - {+ J7 }9 r0 q' R7 M& b! T
- USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out# H* o9 s; Z3 {- [7 F0 |2 D! _
- p->out++;
" r7 y" |7 }: I L - }
0 G( B1 d! Y+ _' F5 D* e" E! N - /* USER CODE END USART1_IRQn 1 */
% x) [ t% q: i' P, w+ Z4 r - }
4 z j3 m; L& X" L
% Q5 x. x1 w7 \' y- f- /**
- J5 b ]- \8 w" X! P# h& s U - * @brief This function handles USART2 global interrupt. \; J# s& u& v" ~# @1 U) p- N
- */7 a# R, v% U( x8 K' e5 O3 d
- void USART2_IRQHandler(void)& a( O) ?$ S) H7 o' D8 |
- {
# E2 {9 h$ A' b& H6 L( O6 ]2 a - /* USER CODE BEGIN USART2_IRQn 0 */
+ {" W9 H+ y1 z; m; | - struct bufer_st *p;. @+ N& o" I2 t/ Y+ P
- /* USER CODE END USART2_IRQn 0 */% U* `7 ^' T5 K K) E, A. |! b- V0 E
- HAL_UART_IRQHandler(&huart2);/ [1 R. h+ L! d' t6 \1 i
- /* USER CODE BEGIN USART2_IRQn 1 */- `' P s4 I; s$ m+ i8 F4 X) V
- p = &uart2buffer; //use UART2 buffer
; A6 s* B7 z' O - + ~: v) S/ M& Z: E$ k' [
- //raed UART2* w8 g7 @9 h& ^5 Z7 w
- if (USART2->SR & UART_IT_RXNE) // read interrupt
3 ~2 L. v% E9 X4 Q/ Q$ l - { 1 @) n1 {/ C# Q, i& m# C' V
- USART2->SR &= ~UART_IT_RXNE; // clear interrupt
' s) y' v. S! G8 c! ~ - 3 E. b' f6 d' Z3 i# `
- if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)9 y" `! N$ G0 Y2 a4 q
- {0 O6 q g$ b$ y$ \4 z! r5 ~
- p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA
, _4 {( Y& B5 |, X - p->in++;' \; s, Y+ ~ R2 S! B
- }
- r' N; m6 s z7 R - }# _* E% d+ h% D# P
- //send to UART1
& Y! E$ T# n; `% C - if (p->in != p->out)
Z# d4 Y2 u# M7 u- [8 T7 E4 E; m - {
$ s, E2 e8 ^. G4 [$ m - USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
$ ^; i0 K d) q! S& f5 ~2 B - p->out++;
/ P! {) @8 @) Z' p - }
( h+ V( r9 q9 q5 U - /* USER CODE END USART2_IRQn 1 */" Q) ^. }4 s/ ~- R! \: T
- }
复制代码 4 [' d0 k4 L! i: [4 Q# J
(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。)
6 J; E$ C1 R: a' W9 W$ w& `5 K. g
$ j, k4 D8 b, ~+ J
大功告成了!! 编译后烧录。
7 O" S+ Q7 l+ c+ n9 Q测试条件,使用两个UART转USB板子(FTDI)和sscom5上位机程序(开两个),发送区都摆放700多个字符,以10ms的间隔连续发送。 测试结果,速度115200bps和1Mbps,双向同时收发100万字符无差错。 2Mbps,单方向100万字符无差错。 (高速测试时,需要修改main.c里面的串口速度BaudRate配置。 我没有测试“自动波特率”的模式是否正常。)
, z0 d' M x% o- a' w' t. W( f最后,完整的工程见附件。 7 u) ?- ~, N2 k5 Q# |( Q* V# R7 P
|
谢谢楼主,解决了我的HAL库不能单字节中断收发的问题!
8 a6 D7 @+ S/ N
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。2 f; u% c8 M; Q# E8 ?7 [
1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,2 X+ M8 V6 q# r' l
2.写入dr寄存器很快,但是发送完成又是另外一会事情
当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
我用国产的,gd32试过 丢失数据严重,不是每个芯片都能这么搞