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

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

[复制链接]
radio2radio 发布时间:2018-7-14 21:15
本帖最后由 radio2radio 于 2018-7-14 23:51 编辑 ( k* n  Y# W# g4 {$ T6 Y5 t
6 f) B* H5 c7 s. e2 b2 H
看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。
+ g9 S9 E, L! J. I+ X1 P0 g简单的要求是,USART1和USART2之间互相转发7 {/ \/ l3 @& z& X& A3 f) U
发现使用CubeMX平台,建立测试工程没有难度,情况如下:
( d- w; U' y% I  N& g/ A8 d, ?$ |4 r) Q& O1 b
1. 配置管脚,使用BluePill最小板,PC13接有LED:
6 w3 C, s7 p7 R  P$ n1 fMCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。1 S& }" J" \. U5 m2 B9 j, Z! g
0.JPG
9 F: J$ q' N0 F  P
3 M' T  c* O- s4 l$ A  ]6 q6 K2. 配置时钟,重点已经标出:" `7 g6 o& r- p- {& x# [
1.jpg
. a* }4 V/ G  I) s/ i5 G- g  {& J8 @" p4 d/ M
3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:1 C7 ?7 J4 O! g. R7 c! d7 s
(USART2也要同样配置)
' m2 y: u( I  A  i 2.jpg ' o% |2 i2 j% {$ ^! F: a

- b& R4 O4 k+ G(然后,生成工程代码)
1 d4 o5 Z! b+ |( F* r6 b/ L5 U4 q
6 ]& H9 P5 f* I; U9 h4 J4. 添加代码" Q- d8 g: p1 B) x  Z
4.1 在main的初始化部分,添加接收中断使能:' R' q, Y6 ]! K
  1. __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT/ G6 N/ y7 u' }8 W9 m; V
  2. __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码
5 j' }" T( Q6 S( k4 D6 T7 }2 Z/ V
  S1 R) A' m* r1 l9 ^3 P3 Q
4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:
3 S% H3 N# E2 ?0 T8 e
  1. /* USER CODE BEGIN 0 */
    8 E) m* _- a' y5 A& N. q- J" W
  2. #define UART_BUFFER_SIZE    64 //here must be 2^n
    ( U- }! M2 m/ p9 P4 i9 }
  3. struct bufer_st {
    + B; I, Q% N5 d( b. z6 S) N1 R
  4.   unsigned int in;                // Next In Index
    " |- }0 [0 v  i% h1 I# R: `
  5.   unsigned int out;               // Next Out Index
    6 \( r* d4 u4 M7 Z: B9 G
  6.   char buffer [UART_BUFFER_SIZE]; // Buffer
    : Y+ ]7 n3 P2 x0 f+ i$ c
  7. };* n: r. n" e1 \: k$ c9 F! A
  8. static struct bufer_st uart1buffer = { 0, 0, };
    . e3 r( q! J5 u
  9. static struct bufer_st uart2buffer = { 0, 0, };! k* W/ D8 m5 Y
  10. /* USER CODE END 0 */
复制代码

' W/ k3 y7 X. k* {$ g9 c, A  I& k/ U/ x0 ~
; Z; a! D! \0 J: `/ t
4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下:
  1. /**$ q2 n% J0 K) n$ J" i% A; j
  2. * @brief This function handles USART1 global interrupt.
    $ j! S3 ]5 B4 G
  3. */& m  B* b: Q( A0 s, a$ o" g+ C. v. X
  4. void USART1_IRQHandler(void)5 L$ u) |: `3 V
  5. {8 t6 L0 L9 \/ K7 c7 N
  6.   /* USER CODE BEGIN USART1_IRQn 0 */
    4 s" s5 ^% S0 u& R
  7.   struct bufer_st *p;9 r, @( g. ]; J- t, X
  8.   /* USER CODE END USART1_IRQn 0 */  K1 v8 s4 }( ^( L
  9.   HAL_UART_IRQHandler(&huart1);
    % X; i* S3 I5 X% {5 v
  10.   /* USER CODE BEGIN USART1_IRQn 1 */3 S' t$ Q& B, [, C  A/ o  R* A
  11.   p = &uart1buffer; //use UART1 buffer
    4 ?2 m% G$ h1 o1 H# H  @( s! j
  12.   
    2 ^# d  q" Z) v& F, p6 I, N/ L% W
  13.   //raed UART1
    $ M9 B8 J) F( Q/ z8 z7 I' o
  14.   if (USART1->SR & UART_IT_RXNE) // read interrupt3 W  j; O6 |. o1 W' v$ ~2 X0 v9 d; z
  15.   {                  , H* f& ?) f; t
  16.     USART1->SR &= ~UART_IT_RXNE; // clear interrupt/ o' o) `4 t9 Y' V

  17. / c1 B' \3 m4 B- I  t( c
  18.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {, q+ J! n& \4 p: p$ \
  19.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA
    ( j, Y, S' B4 X0 Y) B
  20.       p->in++;
    5 T3 ]1 h7 j) T. h6 o/ f
  21.     }9 b( K/ b$ Z8 C' O' _
  22.   }
    9 [" `$ c/ F' B/ `% y' }
  23.   //send to UART2
    ( K- h# H+ M# c" C; d1 q' s
  24.   if (p->in != p->out)
      A! ]& }( R/ F
  25.   {
    ) w$ z! t# }; L) X
  26.     USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out! a+ v7 ?/ I% ?! M0 U
  27.     p->out++;
      r+ x& d) B# t
  28.   }& q: w! \- a! {: A, u' G0 z
  29.   /* USER CODE END USART1_IRQn 1 */7 k' O5 y4 C( a* m9 |8 J/ Z
  30. }
    4 E7 t4 L4 R- s
  31.   B4 h! \- a. U) i& ^
  32. /**
    ( g' H$ n9 V* T9 f# i$ D+ X: O
  33. * @brief This function handles USART2 global interrupt.) [8 ?# H7 B0 M2 e. x( @- \" `$ ?
  34. */4 |' Y# q: y9 z1 }( B
  35. void USART2_IRQHandler(void)
    : R  m, w. ?( i( A4 {( l! \1 a4 D
  36. {, J2 O2 W( s8 o3 A4 K
  37.   /* USER CODE BEGIN USART2_IRQn 0 */" z! g7 K. m" L0 [
  38.   struct bufer_st *p;8 q6 a* P8 Z% m  E3 b
  39.   /* USER CODE END USART2_IRQn 0 */5 S2 j/ i3 S- x; `
  40.   HAL_UART_IRQHandler(&huart2);" |( b8 W& j, A( Y5 c% e
  41.   /* USER CODE BEGIN USART2_IRQn 1 */( `0 h, X0 ]) u6 z, R4 X( ^
  42.   p = &uart2buffer; //use UART2 buffer6 r" G8 m/ s) Z% U0 W
  43.   ( K: _. U9 s# E
  44.   //raed UART2- c; o% c3 {2 x7 n! W; s
  45.   if (USART2->SR & UART_IT_RXNE) // read interrupt) t( ?. q" u$ p# y, v$ N
  46.   {                  
    4 r1 F' q* m: ~; V$ k# V4 r
  47.     USART2->SR &= ~UART_IT_RXNE; // clear interrupt/ F+ C* @. a2 x8 @

  48. 4 e# c& {4 j: i5 V, V
  49.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)
    % e4 \2 x( O& r8 P5 F1 l' g2 }
  50.     {
    ; y  {9 |- i( H8 w, @
  51.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA
    : Z7 U- \/ H3 h1 N. j
  52.       p->in++;
    9 i! q, W) {! N7 H: A) Y" D" I
  53.     }; W. J- Y2 v  y/ c) s
  54.   }
    + L# d  J5 `8 U9 g6 [" D5 l
  55.   //send to UART1. o+ r5 _5 _9 u; C/ }: X* D
  56.   if (p->in != p->out)) P# \9 c3 T/ n
  57.   {
    2 ^! p$ z' ?' j* v0 Z; y  j& Z4 o
  58.     USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
    5 {1 }" j0 Z# u
  59.     p->out++;$ R! e3 ?/ C( b# H3 k2 w+ I
  60.   }" G7 W( S2 {8 s
  61.   /* USER CODE END USART2_IRQn 1 */
    / G9 r9 W) k0 v  l& o/ D+ |
  62. }
复制代码

. n0 O  o+ m! c9 u; [  f1 b9 X(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。), F, L  C3 ?1 Y- Y

8 d# ]- c' y. z, M0 P& h% k
大功告成了!! 编译后烧录。

" }. j& ]! W2 T, [! k2 f2 O
测试条件,使用两个UART转USB板子(FTDI)和sscom5上位机程序(开两个),发送区都摆放700多个字符,以10ms的间隔连续发送。
测试结果,速度115200bps和1Mbps,双向同时收发100万字符无差错2Mbps,单方向100万字符无差错。
(高速测试时,需要修改main.c里面的串口速度BaudRate配置。 我没有测试“自动波特率”的模式是否正常。)

* ]6 z6 V! E( |# T
最后,完整的工程见附件。

  q0 F% B4 [7 X! M' j

STM32F103-USART-CUBE.rar

下载

599.08 KB, 下载次数: 499

评分

参与人数 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 编辑 3 T! K! g4 P3 r! Y

4 A2 Z4 C! t; H谢谢楼主,解决了我的HAL库不能单字节中断收发的问题!
1 B! ]" }( e: R, ?
  • 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 */
  • }

  • % T" w& u9 C; C
" I8 t+ G9 Q; F# k; L

8 Z" m* B/ ]: Q. a, z3 T0 t
radio2radio 回答时间:2018-8-14 10:23:17
wwwheihei 发表于 2018-8-14 08:30
5 s. j9 n9 \1 L; t) h' _  d" \1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,
2 R7 R9 {; R" g* m  c3 p  w7 E2.写入dr寄存 ...
, I; }! i7 W- G8 J* r, u5 _" y
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
  K+ v  H, {+ E9 [2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。: K5 z" z+ |# `8 ]/ ?

* `$ C0 q, f. y& b
ssssss 回答时间:2018-8-14 08:30:08
radio2radio 发表于 2018-8-13 19:42
2 ~* y* b- _" f2 ^( L不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。8 H, i+ f* K5 E& [9 L
...
6 ?' q5 U& i& Z5 n+ ]  W
1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,) U$ B* @2 ^+ D9 O
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,就能实现每个字节接收中断收发
+ K" [4 H+ @, N0 |$ ]7 B4 B8 G. z
2 f# r+ O0 M3 P" v3 M当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?! Q2 l6 a1 |+ t# T* G0 i8 i; ^
radio2radio 回答时间:2018-8-13 19:42:28
wwwheihei 发表于 2018-8-13 17:22
3 a2 p% Q+ {" T5 K8 m: yUSART2->DR = (p->buffer & 0xFF); //send out,此处我将USART2修改成USART1,就能实现每个字节接收中断收 ...

* P$ u* Z7 N! b! \不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。( H; l+ T0 _/ l
ssssss 回答时间:2018-8-14 13:41:47
radio2radio 发表于 2018-8-14 10:23$ G; @5 f, U0 ~- `- ~
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。8 m0 j: W: u5 j" a4 Q: b: B4 I
2. 串口的速度,相对于MCU的运行速度 ...

$ f8 J- U* e+ `我用国产的,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管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版