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

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

[复制链接]
radio2radio 发布时间:2018-7-14 21:15
本帖最后由 radio2radio 于 2018-7-14 23:51 编辑
% o" F/ W% [3 Q/ @+ U$ a! E
: R* p7 k2 e. m3 N8 F; Q0 B- r0 j5 c看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。
% H+ S( t1 |% I) ]3 V4 d简单的要求是,USART1和USART2之间互相转发
- ~8 E5 S6 `$ }$ E4 P发现使用CubeMX平台,建立测试工程没有难度,情况如下:
* @: k9 }/ f% ~$ `$ I7 [! M& Q. m0 f) S/ @6 p
1. 配置管脚,使用BluePill最小板,PC13接有LED:
4 s- c- M& d: P& D/ ], s# QMCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。
' {3 a' Z1 {0 O 0.JPG 1 R: T; I& @+ f1 \* A2 S+ t; M9 ]
6 `  @5 p: B  V! H
2. 配置时钟,重点已经标出:7 T( T: O* L' @0 h3 _
1.jpg / `! v" N3 w1 K# r( h% O; ]) u) Y

9 w5 Z4 y5 t. K' w3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:* i3 f# T* p* }, _& M
(USART2也要同样配置)
4 P: I+ [) R% i" _, A. g 2.jpg
1 Q: V6 n  p. x4 C* e
9 m! s4 A) I5 J(然后,生成工程代码)4 o7 k7 I4 R# R5 M% y
9 `  T( o: O- x& @* V
4. 添加代码
1 M1 n0 r+ p- j: Y- w. @% K4.1 在main的初始化部分,添加接收中断使能:8 q! L7 |6 C/ {6 G7 z4 h
  1. __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT0 V; T$ O! k) t$ F' r) H7 F4 t
  2. __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码

, X! M3 k5 ~. a: q# f8 N
) t3 z+ u# ^3 H8 {8 \0 n; i( Q3 Q& L
4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:3 p" U8 P  C" M( ~9 ?0 k0 K
  1. /* USER CODE BEGIN 0 */6 ?6 R& H+ A7 p3 J2 ~- W
  2. #define UART_BUFFER_SIZE    64 //here must be 2^n, h3 c1 s9 P( Q' O5 i% r
  3. struct bufer_st {& y  e( e* e; t, b! |' f
  4.   unsigned int in;                // Next In Index
    ' ]+ F$ W. \) k7 O3 o6 j3 W
  5.   unsigned int out;               // Next Out Index
    ' j( e' `$ u) ]) d
  6.   char buffer [UART_BUFFER_SIZE]; // Buffer
    3 s3 D/ ]3 U% j+ |( P+ ?: _/ z
  7. };
    : |4 q2 I7 P; ?+ I3 Y
  8. static struct bufer_st uart1buffer = { 0, 0, };5 a5 r( O1 a" X8 N  w' `! l7 z
  9. static struct bufer_st uart2buffer = { 0, 0, };1 R* O. x) L6 Z; L2 i8 S' b
  10. /* USER CODE END 0 */
复制代码

* n( ^- C0 a& D+ Q
: @1 L: J* |; S5 k  k/ h1 g" j4 z7 D' V9 f0 H6 r% x- M+ F7 ?
4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下:
  1. /**4 g# ?% q9 w  q% I) e
  2. * @brief This function handles USART1 global interrupt.1 t, Z# x. W# p( R1 p1 d
  3. */" f- S: r2 ?  Q
  4. void USART1_IRQHandler(void)
    + v: s$ X2 x) I8 ^( E" Y* ?
  5. {
    9 |1 i% x& _% w+ ]( B
  6.   /* USER CODE BEGIN USART1_IRQn 0 */
      T, z( f9 D* f1 i2 D
  7.   struct bufer_st *p;
    ; }! Y, R8 y/ a
  8.   /* USER CODE END USART1_IRQn 0 */: J8 t6 ?. Z1 z+ f% l- ?. W' C
  9.   HAL_UART_IRQHandler(&huart1);/ A/ s# P  V* E
  10.   /* USER CODE BEGIN USART1_IRQn 1 */
    ! p( d8 e1 y9 k& M
  11.   p = &uart1buffer; //use UART1 buffer
      u5 k! c0 x1 j2 ^$ i) k) V
  12.   
    . y/ O6 g9 d1 ~8 d  D% P: `! ~$ G
  13.   //raed UART1$ A/ P, ?7 S) Y% ?1 z/ [7 A$ T
  14.   if (USART1->SR & UART_IT_RXNE) // read interrupt
    % g5 t8 W+ D' B* Q$ U
  15.   {                  
    ( a& n6 y1 \/ N* t+ ]+ y! ^
  16.     USART1->SR &= ~UART_IT_RXNE; // clear interrupt
    1 Y2 M; Z2 u5 q) w3 |

  17. : S! H# B' F* \5 ^8 @0 u
  18.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {
    % t; t+ {) p* z  o
  19.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA
    ! K8 Y/ P7 o3 h
  20.       p->in++;
    4 a& F6 J! t2 l8 C
  21.     }
    / f; b% x0 \2 J, L% n
  22.   }  F( ]8 d  r4 i) l( W
  23.   //send to UART2
    ; n0 f2 x# |2 b1 S2 {" q% g
  24.   if (p->in != p->out)
    ( f0 R! V$ y4 \: e6 h
  25.   {/ g0 _* Y+ H$ Y( N/ n9 U/ X
  26.     USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out9 g4 H+ B& U/ V9 k" A. d, z
  27.     p->out++;
    , y! N; n$ s& N
  28.   }
    + \: _9 o' l0 p  |/ T% r! I
  29.   /* USER CODE END USART1_IRQn 1 */
    " I" a7 u, l2 o/ z
  30. }# o& h0 y6 s. [$ Z
  31. ) O  M: v# D. Y
  32. /**
    . Z0 X  B4 P$ w( a( x
  33. * @brief This function handles USART2 global interrupt.7 t7 A- C/ q! v6 b2 r0 {
  34. */2 L7 q$ Q- T) ]
  35. void USART2_IRQHandler(void)
    2 j4 G! p0 U' C0 ?  F4 `" P, j; `2 {
  36. {
    - q$ \8 u, ~/ H) I3 i( V
  37.   /* USER CODE BEGIN USART2_IRQn 0 */" N! L, {* T2 D, k! w
  38.   struct bufer_st *p;
    % f! u; Q. J5 S9 e
  39.   /* USER CODE END USART2_IRQn 0 */. P; a4 K1 ^* ^! G: A5 d9 X2 Z
  40.   HAL_UART_IRQHandler(&huart2);
    / S) h# S% ?  l' n$ o! |8 [9 y5 r) o
  41.   /* USER CODE BEGIN USART2_IRQn 1 */
    " P, H$ c! c* C, |
  42.   p = &uart2buffer; //use UART2 buffer5 M, a! L) C5 K1 ?, [% [
  43.   
    ' L% A7 p% U4 p1 h: _2 C; C
  44.   //raed UART2
      R  z# Y  f8 L: d8 g
  45.   if (USART2->SR & UART_IT_RXNE) // read interrupt2 N" j. |! ^+ x4 \! d
  46.   {                  
    ! \( a* Y* ?4 J
  47.     USART2->SR &= ~UART_IT_RXNE; // clear interrupt2 L1 K- N, F! \4 {) G
  48. - b& ?$ J( q6 U7 S8 T1 [0 v! J
  49.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)
    " V3 P* A# x8 o( x% s/ S4 h
  50.     {9 J* T$ r/ A, ^# J, W* \1 v3 x
  51.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA
      U" {+ w0 H, Y% Z5 e) c6 z
  52.       p->in++;
    % ^9 X. Y/ q- Z" e8 ]
  53.     }
    ! O( l8 a8 _  e0 b# d4 b
  54.   }
    0 S8 n. H( N; I  V% v5 {+ f
  55.   //send to UART14 m$ _6 `) k' u: U% I
  56.   if (p->in != p->out): b) ?0 [6 @* J/ v
  57.   {
    . L! ?/ a( F. ?% P& |
  58.     USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out6 l5 D- i' U! ^: d  m; V
  59.     p->out++;$ \; _+ R, T4 g' u# L
  60.   }$ H$ v6 `% \: Y' P
  61.   /* USER CODE END USART2_IRQn 1 */
    # x' o6 v7 K. ?( C: Y+ n
  62. }
复制代码
; e9 L% O% w+ o% N) S
(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。)9 T8 v. `( H) I4 }6 y) v$ U* [
: M+ t5 x+ X% U" s9 [
大功告成了!! 编译后烧录。

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

7 W1 b6 J  u" ]' t
最后,完整的工程见附件。

. D1 R' ~6 _, J

STM32F103-USART-CUBE.rar

下载

599.08 KB, 下载次数: 487

评分

参与人数 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 编辑
) |+ M0 ]1 i$ Y6 z& N; E# w# n# w5 X- _9 k3 L+ O$ v8 v
谢谢楼主,解决了我的HAL库不能单字节中断收发的问题!' s1 Y$ ~+ g& j# t0 h
  • 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 */
  • }

  •   G, k; ?" [5 F" T; S+ U) t
' w$ I  W; K* D9 i8 o. ]

: X6 ^: u( C) Q) r
radio2radio 回答时间:2018-8-14 10:23:17
wwwheihei 发表于 2018-8-14 08:30
, I4 v2 E% v) [6 ]1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,
% x( O8 y; J1 y/ G6 X2 k2.写入dr寄存 ...

6 s; D8 A7 j  f/ S# a( u0 n! Y1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
3 @$ m! K* q  f1 V2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。2 B/ ?; ]6 K& O% r( O+ g# w

6 ^% Q: m4 H4 v: j
ssssss 回答时间:2018-8-14 08:30:08
radio2radio 发表于 2018-8-13 19:42
. R) l4 Z% \* \3 J  @不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
  w9 [' }8 X( Z. t. X- S ...

) a% Y- W! W5 [% ^1 t0 n5 h1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,4 s; Z& n  m- a$ |/ V6 V4 t# d
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,就能实现每个字节接收中断收发; E5 @3 W% q. A: \6 E
' W, S7 Z$ z0 [. a/ H' ]
当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?
  N9 u( p7 C# y: P* d# u: |
radio2radio 回答时间:2018-8-13 19:42:28
wwwheihei 发表于 2018-8-13 17:22
+ P$ c6 j+ |, ~USART2->DR = (p->buffer & 0xFF); //send out,此处我将USART2修改成USART1,就能实现每个字节接收中断收 ...
# J6 O6 ^1 B0 A$ x) `
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
  D9 p  H7 a# T# }2 f, l7 G
ssssss 回答时间:2018-8-14 13:41:47
radio2radio 发表于 2018-8-14 10:23
9 E& a6 n/ |/ a& ?& C4 ]# e1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。  C3 T5 }3 l2 b2 {  T& d' }  y
2. 串口的速度,相对于MCU的运行速度 ...

4 t  E2 m+ W- _8 Y$ Z$ W我用国产的,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 手机版