你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32基于CubeMX的高速串口收发程序(中断模式)  

[复制链接]
radio2radio 发布时间:2018-7-14 21:15
本帖最后由 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 0.JPG
, I3 i; h$ u8 q4 Y7 |2 u4 X3 l3 z; @# [
2. 配置时钟,重点已经标出:; S6 S+ n- J9 U8 H" D
1.jpg
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 2.jpg
* `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
  1. __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT& x$ }2 O( a- t4 e
  2. __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
  1. /* USER CODE BEGIN 0 */
    3 P& ~% Z, z6 l9 ^* [% F7 J, s0 {
  2. #define UART_BUFFER_SIZE    64 //here must be 2^n% D' }7 Y0 g! [) S$ A2 O
  3. struct bufer_st {
    ' i# ~/ w* y, F) Z- Q
  4.   unsigned int in;                // Next In Index
      ^: S. k; g1 O' F; _3 v
  5.   unsigned int out;               // Next Out Index
    ! N+ @7 a, Y' e  D* J" h( s
  6.   char buffer [UART_BUFFER_SIZE]; // Buffer
    $ y: Q$ O, Q" L6 T5 m
  7. };
    0 d; U# x7 ^5 }) H
  8. static struct bufer_st uart1buffer = { 0, 0, };
    / D6 A0 h8 Z  O! `0 S5 c
  9. static struct bufer_st uart2buffer = { 0, 0, };0 _( L4 K  u) [- S7 Y  ]
  10. /* 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# ]( {: I
4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下:
  1. /**
    ; d1 I+ k8 U' p
  2. * @brief This function handles USART1 global interrupt.6 b/ v( Y: }; \3 u
  3. */- S8 u% R# c% V9 O8 ~
  4. void USART1_IRQHandler(void)5 h) d+ E, f) g/ P, |2 O
  5. {3 w  h. p, ~1 C& G9 G' u9 w
  6.   /* USER CODE BEGIN USART1_IRQn 0 */
    8 `6 ~$ \" C& P6 L. u4 a! U4 w" W5 R
  7.   struct bufer_st *p;
    1 S- y1 q) G- ~" |3 ^7 d- r
  8.   /* USER CODE END USART1_IRQn 0 */: P4 Y6 J. V% P7 R7 r: i) q( g
  9.   HAL_UART_IRQHandler(&huart1);+ m0 R4 z9 `8 W9 k) C
  10.   /* USER CODE BEGIN USART1_IRQn 1 */
    ! T5 y2 q8 X/ A
  11.   p = &uart1buffer; //use UART1 buffer4 {8 m9 o0 h  N2 _
  12.   
    5 {0 z( [3 G4 B
  13.   //raed UART1, W; ]2 o6 Q  C# i7 E8 }$ l
  14.   if (USART1->SR & UART_IT_RXNE) // read interrupt5 K: L2 _' j2 }$ X2 ^$ M/ j
  15.   {                  4 \1 {' M; L$ [0 \4 a
  16.     USART1->SR &= ~UART_IT_RXNE; // clear interrupt
    . k% W2 o% ^6 u7 q
  17. . M8 K" B$ P1 ~4 o
  18.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {
    " Y, y2 K/ T9 c) j2 ~, Y
  19.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA' h  Q8 G  a  v- S: g8 i3 z
  20.       p->in++;
    $ f  B2 x2 o4 j: U/ H) k
  21.     }
    $ y: P% D3 y; a* A  N& i! E2 Y
  22.   }
    + V  ~& k, L; S& _9 H' m( ]
  23.   //send to UART2% @$ o- ^) E  j! n9 G  b) T/ Y
  24.   if (p->in != p->out)
    ' d9 _5 F' {+ c7 [/ R1 d7 b, A7 e
  25.   {! m$ M$ [1 l* [- J8 c
  26.     USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out9 w/ `; h$ D8 x7 _" ^/ |
  27.     p->out++;8 \& E4 l& X8 R4 j3 O" d
  28.   }
    0 T2 l2 D" u0 i2 Y5 ]; g, a
  29.   /* USER CODE END USART1_IRQn 1 */3 D7 h9 Q; D8 A% |, Q) v9 l, W
  30. }; L9 K# b) H; w/ n- A" p0 R
  31. 6 Z: `* C0 b: V
  32. /**0 S3 I7 A: @  B6 a! l- M4 N
  33. * @brief This function handles USART2 global interrupt.
    7 @- U9 L8 ?8 Q) r1 m; B: L; n
  34. */9 ^6 Q* o% H% j- O! F6 L' w" |
  35. void USART2_IRQHandler(void)
    ) ~* l; V7 o, R% h$ F+ j
  36. {
    / @) v9 g' A) s# R- l8 v3 T
  37.   /* USER CODE BEGIN USART2_IRQn 0 */
    0 d3 a) p( L; e/ x8 h5 J
  38.   struct bufer_st *p;0 \6 ~  j, L0 P1 W; B  m# T& v% {/ F
  39.   /* USER CODE END USART2_IRQn 0 */
    6 c- W8 t3 W3 u0 x
  40.   HAL_UART_IRQHandler(&huart2);
    : G5 b" X7 V) v2 |4 ~: ^
  41.   /* USER CODE BEGIN USART2_IRQn 1 */
    . a9 m( ^- ^% y
  42.   p = &uart2buffer; //use UART2 buffer
    # u0 C4 w' X; A* v( r) C
  43.   * w0 @% U- v7 V9 e: B. H
  44.   //raed UART2- {- Y* x; b9 r. C
  45.   if (USART2->SR & UART_IT_RXNE) // read interrupt
    / d; z* ?+ X& s* S+ S. j( [2 z
  46.   {                  * L7 n1 a$ s. k% e5 _+ k# d( r
  47.     USART2->SR &= ~UART_IT_RXNE; // clear interrupt
    + ]! }- D" I0 n5 u2 K# ]: |: _9 |
  48. " K& _3 w/ M. M8 v  k# y
  49.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)
    7 m" A+ w6 `+ z8 x+ _
  50.     {/ X( @1 c! ^0 \
  51.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA: i3 W/ U3 V5 g  l
  52.       p->in++;
    ( g- z/ u$ M; f( p! H/ [( E9 R
  53.     }
    & T6 D) f2 J8 V$ y- t2 @8 \/ z
  54.   }
    * z9 J( j/ d( @
  55.   //send to UART18 j1 R( M) L7 C( i1 o% L3 h7 V
  56.   if (p->in != p->out)) E) A  D5 l& a7 {1 K  e1 t" j
  57.   {* H5 e9 ?! c8 E- Y" {$ y  Z
  58.     USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out$ P3 R7 s" X( V1 n
  59.     p->out++;
    ! A# b( i$ }& W1 n0 _& d9 y2 G
  60.   }; A$ Z3 ^5 t, R6 o+ a: d9 N
  61.   /* USER CODE END USART2_IRQn 1 */1 w7 k* _0 _, I; j/ P2 X$ l& p- z
  62. }
复制代码
- `$ 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

STM32F103-USART-CUBE.rar

下载

599.08 KB, 下载次数: 488

评分

参与人数 1 ST金币 +12 收起 理由
g921002 + 12 很给力!

查看全部评分

收藏 10 评论21 发布时间:2018-7-14 21:15

举报

21个回答
yesterdat 回答时间:2018-8-3 07:39:01
本帖最后由 yesterdat 于 2018-8-3 08:35 编辑 1 }0 e4 v/ E, R' S9 ?# a

; K" B+ n* v6 @3 {, y谢谢楼主,解决了我的HAL库不能单字节中断收发的问题!
2 p) T/ ^  u. K/ s
  • 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 */
  • }

  • 5 V: I; t3 o4 C; P7 t$ t
2 Q  a% h% U' \

) x8 s# y+ i) [1 b0 B1 d
radio2radio 回答时间:2018-8-14 10:23:17
wwwheihei 发表于 2018-8-14 08:30
' e+ m3 V& e, e( V% z1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,
. H. t, B% p4 W4 {3 y; L2.写入dr寄存 ...
' H1 H2 t0 A3 w+ ]1 s
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
9 [  \* n) J) f7 R$ b' Z8 k2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。
4 T& R( t9 K4 k6 K
& Z) L+ l! W' s. U' j5 B1 ^
ssssss 回答时间:2018-8-14 08:30:08
radio2radio 发表于 2018-8-13 19:42
0 ~7 B8 R+ E9 k' I. Y不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
) t% L" B! Y: g/ I0 F/ z ...

- G  ~- I1 [( e1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,
/ `- {1 h$ h: Q  ^1 u1 W2.写入dr寄存器很快,但是发送完成又是另外一会事情
zero99 回答时间:2018-7-16 17:11:27
学习了
yuyuswh 回答时间:2018-7-21 21:45:32
谢谢分享!
annQian 回答时间:2018-7-30 17:00:14
不错
STM1024 回答时间:2018-8-3 08:53:34
看标题以为采用DMA
ssssss 回答时间:2018-8-13 17:22:46
USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out,此处我将USART2修改成USART1,就能实现每个字节接收中断收发- R5 \8 Z8 ~, W. O
: y& h0 L! u4 k' y( X  d
当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?& r+ @0 E. i6 ?, L/ U
radio2radio 回答时间:2018-8-13 19:42:28
wwwheihei 发表于 2018-8-13 17:22
) e7 P0 p$ y+ i% ^0 e" bUSART2->DR = (p->buffer & 0xFF); //send out,此处我将USART2修改成USART1,就能实现每个字节接收中断收 ...
3 m8 i/ n* e' o- p
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
5 ]& I0 s% k$ o, i  K
ssssss 回答时间:2018-8-14 13:41:47
radio2radio 发表于 2018-8-14 10:23
- o( n0 V& z# l3 x1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
- A) Z4 n$ p0 c0 M; {7 ^/ r2. 串口的速度,相对于MCU的运行速度 ...

- y7 g" o$ `5 h% `  |我用国产的,gd32试过 丢失数据严重,不是每个芯片都能这么搞
zmingwang-34437 回答时间:2018-8-15 09:57:14
你这个方案有两个地方可以讨论下,一是转发双方如果速率不同,就需要进行流控制管理;二是如果速率过高,中断会很频繁,这将导致系统中其他程序的实时性变差,最好用DMA
Kevin_G 回答时间:2019-3-25 12:51:50
收藏
lorabbitve 回答时间:2019-9-9 00:15:08
学习了
generalcircuits 回答时间:2019-9-9 10:42:31
学习一下,谢谢
12下一页

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版