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

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

[复制链接]
radio2radio 发布时间:2018-7-14 21:15
本帖最后由 radio2radio 于 2018-7-14 23:51 编辑 " H/ S% W% S! J$ A  D

! C- Z! g: s2 j5 D7 @/ u看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。" |3 @( z  ]7 y+ m; W
简单的要求是,USART1和USART2之间互相转发。# d6 d" V  e3 d0 l6 {1 ?
发现使用CubeMX平台,建立测试工程没有难度,情况如下:  w3 z* V+ G# I+ S

4 E) z* H5 i7 d- k' K4 `: E- `' J1. 配置管脚,使用BluePill最小板,PC13接有LED:
& {/ Q$ q( F+ z: Z7 a; V- uMCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。2 U! K4 v8 P- d  h
0.JPG
) c' P: J6 U3 `- S2 g8 q) Z
! m7 u. q( R$ ?) H5 a* ]2. 配置时钟,重点已经标出:+ K# `9 z0 R9 v+ \# a
1.jpg
0 v! l* d. H  w1 E
* a  ~( v6 O1 @2 D: M3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:" t8 L. W4 n, n
(USART2也要同样配置)+ W; L# o; k, q, w8 s# ^' @
2.jpg
+ u7 ^! W: k* M4 M# c
7 {1 F* Y: _! C' }" L, u$ @( ~8 s: u(然后,生成工程代码)
! Z4 N& [  ]$ c0 v, \; R
0 K) _; W2 C, x' X# v3 s+ x5 I4. 添加代码
8 u" v% b( N" u; I4.1 在main的初始化部分,添加接收中断使能:2 {+ l7 y& h! H/ K  X- ^0 |
  1. __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT
    + l$ l7 H8 O' z8 |. ?- o
  2. __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码
( J% ~7 m% W2 C

2 G7 I1 X. I6 j; Q9 E% @1 }" h& Y
4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:3 O0 F; R8 n: Z
  1. /* USER CODE BEGIN 0 */! k1 \- g0 e6 Y( r9 \
  2. #define UART_BUFFER_SIZE    64 //here must be 2^n
    2 {) ?4 Z7 ?' ^8 i$ t! s+ j
  3. struct bufer_st {
    ) S9 e! M; U' `* H  V  M: L
  4.   unsigned int in;                // Next In Index5 A! B9 \, G7 z( M. _* j6 O! }2 v" x
  5.   unsigned int out;               // Next Out Index3 B9 I7 S8 ]. _) N% |0 L% _
  6.   char buffer [UART_BUFFER_SIZE]; // Buffer
    4 b0 Z) e+ f1 M- f& k; q
  7. };
    . d5 C9 G8 G: q1 P
  8. static struct bufer_st uart1buffer = { 0, 0, };
    . v+ o2 v9 X- o8 y
  9. static struct bufer_st uart2buffer = { 0, 0, };' b; B( S/ Q& a8 p4 L3 W
  10. /* USER CODE END 0 */
复制代码

2 n% V" B, i3 y1 {- U- K1 Z0 W" I3 s4 G

, F' Z! \7 D$ k
4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下:
  1. /**
    % E- O( q4 L/ u( j
  2. * @brief This function handles USART1 global interrupt." s# J. I5 H6 h9 d; K& N8 v* N
  3. *// L" D' M  `/ w$ ]4 I
  4. void USART1_IRQHandler(void)
    - y  L" i+ g3 S# w
  5. {7 y& O% C3 n3 @; t* u1 u
  6.   /* USER CODE BEGIN USART1_IRQn 0 */
    & B! \) q4 z* Y+ L" P
  7.   struct bufer_st *p;
    + ]5 j% V3 I) w& z( t$ W
  8.   /* USER CODE END USART1_IRQn 0 */; p1 F6 M% Q* A+ p  V/ J
  9.   HAL_UART_IRQHandler(&huart1);
    ! U% G% `, F$ D: D* `" c2 U
  10.   /* USER CODE BEGIN USART1_IRQn 1 */
      o7 Y" T6 |& c& r/ [- |2 N
  11.   p = &uart1buffer; //use UART1 buffer
    ) i! B& {& ]) q& P
  12.   3 Q# H' c9 O4 ~4 R. @. D# J5 w
  13.   //raed UART14 j3 C# k4 K8 U& ]2 Z' u
  14.   if (USART1->SR & UART_IT_RXNE) // read interrupt
    0 l. k' ^) s- U) ~% G. {  j# f! K
  15.   {                  
    , p& J. |8 Q6 F2 [$ n7 y* D8 Y
  16.     USART1->SR &= ~UART_IT_RXNE; // clear interrupt0 I! p( D7 q' A2 e9 r) B, t& ]

  17. 9 U; S  ]$ f: A& M" d" D8 Y
  18.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {
    : W/ d8 e4 I% ]. o
  19.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA
    7 i: u1 P% Q. B7 R9 R
  20.       p->in++;
    & @; O. l+ f1 `+ @
  21.     }
    & T/ n  H2 Z$ ^! W3 v7 n
  22.   }
    8 W3 p, Y/ Y' z6 y5 D
  23.   //send to UART24 s* j8 a; N) ^! D
  24.   if (p->in != p->out)% v. ^. Q8 J* u" f! x
  25.   {* J: P7 @  `) e7 f
  26.     USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out/ F) i9 j6 C: L/ n$ N
  27.     p->out++;
    / P; d2 _7 j: w
  28.   }
    5 z. Y* X) j5 G" u$ t; \/ U+ o
  29.   /* USER CODE END USART1_IRQn 1 */- V, A: M+ g9 E
  30. }3 @) M+ d" Q9 C
  31. + [& C& \2 p# d5 Y: Z
  32. /**1 l. z0 {, X: J5 }* p  @
  33. * @brief This function handles USART2 global interrupt.1 |7 X9 ^9 Z& {' \1 {6 ?
  34. */+ e3 j; X, |7 }$ ^5 s/ t, f4 H! l
  35. void USART2_IRQHandler(void)/ C  R! S7 G. F; O
  36. {
    9 u0 l  [& Q, x, Q5 \
  37.   /* USER CODE BEGIN USART2_IRQn 0 */) G9 U) o5 i; w6 d
  38.   struct bufer_st *p;4 O% d  V' s; G8 t0 S+ r$ L
  39.   /* USER CODE END USART2_IRQn 0 */
    9 ~7 v* Z  ~% f1 h0 ~
  40.   HAL_UART_IRQHandler(&huart2);
    6 b- R) f$ C: N/ x/ T6 B- t
  41.   /* USER CODE BEGIN USART2_IRQn 1 */; U( U- l" k, h- w. D/ R) v5 Q
  42.   p = &uart2buffer; //use UART2 buffer, b+ d. ~; `* n
  43.   - {6 U0 k, R# ]
  44.   //raed UART2
    & Q- j" d/ G9 T! K
  45.   if (USART2->SR & UART_IT_RXNE) // read interrupt
    ( `! i* m$ Q4 U6 ?5 K8 ^7 i
  46.   {                  
    ' U( p- ]+ i( z
  47.     USART2->SR &= ~UART_IT_RXNE; // clear interrupt) D+ F  q+ b' O* _2 E1 _

  48. % h, {6 R- Q1 \3 i5 j
  49.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)& \0 h  b6 E+ V4 Q. b" a( Q: W6 J9 _
  50.     {8 i) G5 _5 v# Y! _
  51.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA
    3 q9 \7 v' F) o8 k6 H8 U
  52.       p->in++;& e4 t% r* k7 U$ E
  53.     }# u: `/ K1 ~0 s7 y- n
  54.   }
    5 \+ Q7 A" h% ^+ S. {. T
  55.   //send to UART1
    " T# f+ m& v+ s2 q
  56.   if (p->in != p->out)
    9 y, q! `; x8 [
  57.   {
    , N5 A; T# ~& N( y0 J; o) I
  58.     USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
    + w/ T+ G3 F+ E$ h: P# r) W: J
  59.     p->out++;5 @0 G, ~- J: {+ ~
  60.   }
    ( W2 Q# i  K8 S7 s9 B# V
  61.   /* USER CODE END USART2_IRQn 1 */8 I9 ]  j" E* M* Z! m; C/ c
  62. }
复制代码
  w2 k9 |+ P. Q1 I2 I+ W
(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。)
* j; A; J% ^0 X9 {. P* c1 o! M5 A# R

0 c+ A7 V- p! U! x: Q6 F
大功告成了!! 编译后烧录。
9 q  k* t# T8 o8 f0 O
测试条件,使用两个UART转USB板子(FTDI)和sscom5上位机程序(开两个),发送区都摆放700多个字符,以10ms的间隔连续发送。
测试结果,速度115200bps和1Mbps,双向同时收发100万字符无差错。 2Mbps,单方向100万字符无差错。
(高速测试时,需要修改main.c里面的串口速度BaudRate配置。 我没有测试“自动波特率”的模式是否正常。)

  @7 u# L+ ^, ^4 j! h
最后,完整的工程见附件。
) q" x8 A$ u, L2 f7 j7 {  C! [

STM32F103-USART-CUBE.rar

下载

599.08 KB, 下载次数: 511

评分

参与人数 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 编辑 : R- @; h& l; o5 j2 c

& Z8 k, H: h2 d. s) o谢谢楼主,解决了我的HAL库不能单字节中断收发的问题!
0 l% h2 h; H# \! B! Q
  • 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 */
  • }

  • , \0 H. d' V" T/ \$ z
5 u. H: d. {8 u& D  d
$ R. k3 |2 L) J$ C$ z
radio2radio 回答时间:2018-8-14 10:23:17
wwwheihei 发表于 2018-8-14 08:30
1 ^! @% R$ a" q* K8 X1 u1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,
' [* n) J+ Y4 m1 M7 ~5 L2.写入dr寄存 ...
5 d$ O) N: K; t7 \
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。! U4 F- i4 S8 A! X5 W+ G
2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。5 i$ H- S: [! s: u4 k( y
( O" [( B% }& F. j
ssssss 回答时间:2018-8-14 08:30:08
radio2radio 发表于 2018-8-13 19:42) w" X6 o8 j2 u! d" H, q
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
  g5 a9 h% L* v7 z ...

; p; ^" P" ^* ~6 M5 a1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,9 S4 C4 U7 Y( H3 k7 Q5 a
2.写入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,就能实现每个字节接收中断收发  X7 ]. E3 z8 `+ W5 n

7 L) d( i4 D7 P3 T7 `8 i1 S当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?
1 n9 r4 ^! l, j/ H" I
radio2radio 回答时间:2018-8-13 19:42:28
wwwheihei 发表于 2018-8-13 17:222 W7 A: }8 |4 h% G
USART2->DR = (p->buffer & 0xFF); //send out,此处我将USART2修改成USART1,就能实现每个字节接收中断收 ...
4 J1 i8 A( A- @$ ?, R1 b8 V
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
1 G" F+ O$ o. G" s+ |% Y6 c
ssssss 回答时间:2018-8-14 13:41:47
radio2radio 发表于 2018-8-14 10:23# V& R. u5 U; `$ Q3 Q2 {0 i
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
+ V9 K5 b" o/ ^% v. d  S+ }2. 串口的速度,相对于MCU的运行速度 ...
6 E" h0 y9 l/ z- @% J
我用国产的,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管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版