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

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

[复制链接]
radio2radio 发布时间:2018-7-14 21:15
本帖最后由 radio2radio 于 2018-7-14 23:51 编辑 3 Y: j+ u0 }4 h2 a! R% u

; _$ O" J  k  }1 C4 K' X5 F9 J9 S看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。
" h# g0 Y- n# b. n  }简单的要求是,USART1和USART2之间互相转发。! R# r  I! _) @9 w' _4 e
发现使用CubeMX平台,建立测试工程没有难度,情况如下:
, H8 E+ X. C3 K& K% O, x& D, s# _  ]0 g4 R0 q( {7 ?
1. 配置管脚,使用BluePill最小板,PC13接有LED:
) u' [6 D/ e9 b2 MMCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。3 U" G2 u- i: Z2 ]! q2 I
0.JPG
( k) Q( ?7 S  m, p! d1 o' {
' q- w5 j2 }* }9 q+ a! A( Z. l2. 配置时钟,重点已经标出:) U. U0 Y) f6 x  C4 m% s7 z' W2 R
1.jpg   K6 K8 C6 v2 `4 l

0 B7 W. L, n6 m0 K3 b3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:% O; z. v' R$ d" T
(USART2也要同样配置)$ \/ ~3 _. c( f; d$ n
2.jpg # a5 d9 `4 @& n/ o1 ]: a; i
% a1 x; H0 v. S
(然后,生成工程代码)
5 z- X/ ~! D2 g- p, }5 V/ _5 S  ^! C5 u$ V0 R& H( N
4. 添加代码; L: M7 V2 G5 N( f8 r- R: o* J
4.1 在main的初始化部分,添加接收中断使能:; I& X, @& d; i: e: [6 @7 i. r4 c9 Q
  1. __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT
    ; _/ ^9 B2 v. |
  2. __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码
% ]7 n# q4 f  ]: _4 l
$ F# b# c, x+ d. p  w3 j
4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:5 }2 V" j$ @8 m) X: u
  1. /* USER CODE BEGIN 0 */
    & ?2 [* Y2 I" a+ @; x
  2. #define UART_BUFFER_SIZE    64 //here must be 2^n
    & {, ~9 }( i' m2 ?, y4 G/ m
  3. struct bufer_st {  _' J0 H; ]5 k% n3 u, u8 s
  4.   unsigned int in;                // Next In Index2 f6 ]( H; x, \& _
  5.   unsigned int out;               // Next Out Index
    2 [  n  O  I) [! d( x8 ]
  6.   char buffer [UART_BUFFER_SIZE]; // Buffer$ `1 m8 r/ I4 N1 x
  7. };
    " E; ^# }6 }6 F. }: j! Y& D$ A( W
  8. static struct bufer_st uart1buffer = { 0, 0, };# H' O2 k8 g9 Z; Z& ~
  9. static struct bufer_st uart2buffer = { 0, 0, };
    + n# k9 a' F+ V$ O
  10. /* USER CODE END 0 */
复制代码
) e5 k& l0 I# i2 ^$ U1 @. E
* A9 u7 {/ ^8 E& {: D) O$ C

" R# t% t9 B" [) F$ I0 O  k' M
4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下:
  1. /**5 x6 @1 {6 v: T3 E
  2. * @brief This function handles USART1 global interrupt.
    5 @% [% c, u; J4 u" n0 y) b& M
  3. */$ b; i) t3 u3 |1 O
  4. void USART1_IRQHandler(void)9 ^; S. H+ y" ?5 k) ?( z
  5. {( ?3 G* y: F$ w* F: J( A- Z( }) |3 O
  6.   /* USER CODE BEGIN USART1_IRQn 0 */
    $ ^$ d, g; ?9 }- B" s: ]3 e7 u8 U
  7.   struct bufer_st *p;) Q- f6 H4 e# M
  8.   /* USER CODE END USART1_IRQn 0 */
    ( ]. {! e7 `2 \! W% s8 L! |+ H
  9.   HAL_UART_IRQHandler(&huart1);) w- C/ t% @# [7 c6 f4 z  A' g
  10.   /* USER CODE BEGIN USART1_IRQn 1 */
    3 J( H. ~5 a2 N6 D5 M
  11.   p = &uart1buffer; //use UART1 buffer
    8 i& Y5 R! V2 B
  12.   
    4 ^& A7 P6 E3 ?% w$ m* ~$ l- d9 V3 y5 \
  13.   //raed UART1
    5 Z% S0 ~1 K9 B' {9 ?2 q' V
  14.   if (USART1->SR & UART_IT_RXNE) // read interrupt
    $ X) O3 F* M, c8 C6 G
  15.   {                  " k6 I7 J8 \2 K4 u* `; E
  16.     USART1->SR &= ~UART_IT_RXNE; // clear interrupt4 O3 x2 q6 g/ W1 \  b; e1 `) K1 f# c

  17. 6 x$ g5 o& K2 `( X- B
  18.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {
    ( s! a) ?( n) {/ G4 j
  19.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA
    1 D1 x3 N, j( D( t* L3 F6 r
  20.       p->in++;
    , u4 H. O; W5 f' w" |; L" Y
  21.     }
    ' \3 j% J% ~9 r
  22.   }+ @/ u  d  O0 f" w
  23.   //send to UART2
    7 h1 {4 n+ i# D- ?2 i) ~. y
  24.   if (p->in != p->out)* T" |! O! L7 Q
  25.   {  F" Z" u* s) w: k" B6 W% U/ E
  26.     USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
    - I! a+ {8 g$ a- e! x
  27.     p->out++;
    + }' S2 ^" q6 B& k, Y0 n( M
  28.   }, n, w. c4 L7 `6 m  Z, Q4 u
  29.   /* USER CODE END USART1_IRQn 1 */
    / g% N9 s% ^1 w5 O5 x" ~( o
  30. }6 M+ e  G) v6 t, n  j5 |
  31. 6 m  ]" T6 b8 _7 @/ Q* o# b  P
  32. /**, o' E; G9 a! g7 g: e' i
  33. * @brief This function handles USART2 global interrupt.
    6 }2 T9 Y( l. o0 q3 X, D
  34. */, f% O( `) A7 K: ~! b- V
  35. void USART2_IRQHandler(void)/ m$ o/ ^2 c) v7 O9 y3 M
  36. {: @6 v4 {, G9 {( J8 |# x+ y# U8 B  b# w% h
  37.   /* USER CODE BEGIN USART2_IRQn 0 */' u: }+ k* |/ Z% S7 `4 h, B
  38.   struct bufer_st *p;- w0 I3 f# \$ D; O5 p4 e
  39.   /* USER CODE END USART2_IRQn 0 */  S' z  N( K& G3 U7 V% x% R
  40.   HAL_UART_IRQHandler(&huart2);  S! s( D) m, P5 k2 z- o9 O/ c
  41.   /* USER CODE BEGIN USART2_IRQn 1 */  ~+ k+ O- A* c. V1 Q" h+ w
  42.   p = &uart2buffer; //use UART2 buffer" f" F; c) D+ {0 e5 K
  43.     V1 A' N2 I% z- ^/ E( m& ~
  44.   //raed UART2
    " \" o' _3 U! [; [
  45.   if (USART2->SR & UART_IT_RXNE) // read interrupt- o  E8 |. J+ m  I* T
  46.   {                  : h6 h8 G2 b, W8 y5 ]: m3 t
  47.     USART2->SR &= ~UART_IT_RXNE; // clear interrupt) L  ~6 e% R4 l/ T% g
  48. . I9 D/ R: \( y' m3 N$ Z
  49.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)5 N4 X6 Y% d# H# H1 J5 u9 E; i; v# a
  50.     {! d2 P1 f. ~+ J4 R. W
  51.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA
    9 m0 F8 t. l; M7 e5 |4 I
  52.       p->in++;) G3 G" s; d0 Z2 C' _
  53.     }
    8 D- h! z1 c8 O- X: d
  54.   }9 B5 y+ D& [1 z% p) i
  55.   //send to UART1
    & a/ D3 k' d$ `
  56.   if (p->in != p->out)
    $ o4 R3 F5 L9 H+ t% ]
  57.   {) K9 g2 c& o0 Y
  58.     USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out' _' J1 o) N$ G
  59.     p->out++;( d/ L- T8 o: M: R$ Q& B4 q
  60.   }
    9 z7 o1 w, H( a2 E8 _5 Q: R) p) ^! k
  61.   /* USER CODE END USART2_IRQn 1 */& p! h7 A1 {$ R6 i
  62. }
复制代码

% t9 }4 `  i2 J- ]+ k4 ~) I(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。)
# S7 F& z: q" P, Q. ~9 L. F

0 z  o9 L+ z- p6 l+ b4 J
大功告成了!! 编译后烧录。

1 o& j  k4 M0 d* W3 P
测试条件,使用两个UART转USB板子(FTDI)和sscom5上位机程序(开两个),发送区都摆放700多个字符,以10ms的间隔连续发送。
测试结果,速度115200bps和1Mbps,双向同时收发100万字符无差错。 2Mbps,单方向100万字符无差错。
(高速测试时,需要修改main.c里面的串口速度BaudRate配置。 我没有测试“自动波特率”的模式是否正常。)
+ v# a$ ?. V0 J# d& |- P" y
最后,完整的工程见附件。
1 p# t' }# _* \1 V  I  f

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 编辑 $ k: ^7 W, m/ u! j9 Q
/ }6 P: C, H% {) h
谢谢楼主,解决了我的HAL库不能单字节中断收发的问题!
) z8 ~! F& f+ i# `! i# o8 P5 u' 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 */
  • }
  • 7 I) |' P5 {: ^
. W+ p5 G1 I$ c0 B

, a5 c2 Q: P5 G2 `  w
radio2radio 回答时间:2018-8-14 10:23:17
wwwheihei 发表于 2018-8-14 08:30
  Y8 E' Q! I+ x/ E$ G1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,( u* n" ^. q( S: O
2.写入dr寄存 ...

# G- d  D: H0 r, B: U. Y) h! P1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
6 G6 E8 }4 ~' t1 H. v2 h# v# W2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。0 h6 p! T) p6 b( ?4 U7 e- a& F: U5 C
: f2 Z# X9 ]2 R, d3 q
ssssss 回答时间:2018-8-14 08:30:08
radio2radio 发表于 2018-8-13 19:42
2 A, {) `% |  ]/ g0 ?5 A# `- f* u不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
! _8 \  q4 E7 @( w+ O. ` ...

, T! u0 A( H4 B! _  N1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,
/ k& ]( ~2 f0 A9 t- |/ s. m2.写入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,就能实现每个字节接收中断收发
" F" [9 B% m4 g8 g( W3 V2 y/ H# @) K" B5 S4 F: h
当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?
# b+ W+ ~2 h2 J$ i1 p' F& N9 K) `
radio2radio 回答时间:2018-8-13 19:42:28
wwwheihei 发表于 2018-8-13 17:220 w  [9 X) K0 Z) M$ [1 n  T, a
USART2->DR = (p->buffer & 0xFF); //send out,此处我将USART2修改成USART1,就能实现每个字节接收中断收 ...
# S$ A2 Z" a3 Q8 @6 R
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。. h: c5 r  M9 ^; p( e1 ?9 A; U' O
ssssss 回答时间:2018-8-14 13:41:47
radio2radio 发表于 2018-8-14 10:23$ p2 d1 N) p% K' L
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。# w+ r+ z0 A% y( y# ]+ H0 k
2. 串口的速度,相对于MCU的运行速度 ...

2 L) o# C8 X$ u* T' a# t+ B& Q% 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管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版