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

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

[复制链接]
radio2radio 发布时间:2018-7-14 21:15
本帖最后由 radio2radio 于 2018-7-14 23:51 编辑 9 X: h% Y* g+ f) j; e  d# U
) l# s, o9 K. O: I; q7 k
看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。
# |/ t+ L7 K; F简单的要求是,USART1和USART2之间互相转发
1 r; s' x; t# P$ G! m9 O5 f: ?* q发现使用CubeMX平台,建立测试工程没有难度,情况如下:
* G/ Z3 S/ s) m4 p
7 O0 ]5 \& n0 h6 p/ X. q0 g1. 配置管脚,使用BluePill最小板,PC13接有LED:
& }) R! b6 }0 p! i1 r( a8 AMCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。
  W# Z/ @3 _( J: y 0.JPG
  n2 A! w9 {  X1 k" ]$ g5 |/ A! P1 _# W9 {& L
2. 配置时钟,重点已经标出:
% c' Q" w# f) J3 L, c* E 1.jpg , u; T( \) I* W; g( l/ a

1 e6 \0 w! `4 V3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:
4 s' F2 |. t& `% r7 f" e0 g(USART2也要同样配置)
7 [" C9 t4 a# @3 O 2.jpg 6 J9 b7 p' v: u% h* S. ]

5 K8 K: R3 X2 t(然后,生成工程代码)
" u' n* T7 |* l& Y4 _
8 F2 I9 ?" @1 L7 P- r4. 添加代码
2 R2 Y6 o, H4 |, }" j3 i7 L4.1 在main的初始化部分,添加接收中断使能:; n) x$ B  E$ v' y
  1. __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT/ C! E8 a+ ~$ ^" [$ l
  2. __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码
2 O( _  @6 a$ T+ D. f
; h5 _% j" p& y; m. m9 b" X) s
4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:
- V' p9 H0 r  S5 d2 B  x2 F3 s
  1. /* USER CODE BEGIN 0 */
    % P- t; u& W/ n. ?) ?9 @# R* R
  2. #define UART_BUFFER_SIZE    64 //here must be 2^n
    9 C2 I% C0 N+ X9 e9 h3 f
  3. struct bufer_st {9 O+ M! Y4 H/ n; I6 r7 K# V9 w3 l/ x
  4.   unsigned int in;                // Next In Index
    + @3 j4 z6 g% \) f& A: t
  5.   unsigned int out;               // Next Out Index) V. h; y; [* r/ O  k7 r
  6.   char buffer [UART_BUFFER_SIZE]; // Buffer+ ]- T6 _* ^4 j9 T
  7. };
    % f% L! V: R2 ~* q
  8. static struct bufer_st uart1buffer = { 0, 0, };
    / s" F5 ^3 I3 _' o9 M8 F: o
  9. static struct bufer_st uart2buffer = { 0, 0, };
    " \5 [% r" z! p4 {
  10. /* USER CODE END 0 */
复制代码

; k2 N4 f  F1 r+ P: ]" A& n6 W7 c- W( W
) K2 [2 w0 M: h6 g0 o  ?# Q
4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下:
  1. /**. I) c# V$ [) P& ~% M4 W' e$ _
  2. * @brief This function handles USART1 global interrupt.9 S1 k6 h: Z3 {( W8 K
  3. */, u' F% W6 [) k$ o
  4. void USART1_IRQHandler(void)
    4 N. ]* v. t- b: ~. q
  5. {" r  O6 i, @2 n! f: O4 r
  6.   /* USER CODE BEGIN USART1_IRQn 0 */
    6 a: |( q4 s" T6 `3 n/ a* t
  7.   struct bufer_st *p;
    - L, E/ `5 f1 Z; W
  8.   /* USER CODE END USART1_IRQn 0 */7 u' m5 W: b8 ]; `; r
  9.   HAL_UART_IRQHandler(&huart1);
    2 c2 M# ^2 ~# h5 Z
  10.   /* USER CODE BEGIN USART1_IRQn 1 */
    0 }5 D$ t2 f/ O% Q* Z7 w
  11.   p = &uart1buffer; //use UART1 buffer
    , p' {! P' w- S
  12.   & I1 k# j3 [; f0 a+ P  `) L  T
  13.   //raed UART1
    2 P1 `5 z/ D- x8 V9 i( m) s
  14.   if (USART1->SR & UART_IT_RXNE) // read interrupt
    ( b0 r2 W5 L+ v! r
  15.   {                  ) ]& s5 T  m* m. S$ _8 H/ u
  16.     USART1->SR &= ~UART_IT_RXNE; // clear interrupt
    " Q( n% U' @: `7 ^! I# ~

  17. & ^" a# Z' U4 C# y$ [- l# B
  18.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {6 C; ^- J. H3 G% T- u3 p$ p/ i4 {
  19.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA
    7 F6 C% L( p" s8 L4 B, t. o6 W
  20.       p->in++;* J5 T+ [$ X$ J
  21.     }5 X5 j$ B) {4 B. N7 m. J9 E
  22.   }
    2 U9 r! y3 o# K' L% ~
  23.   //send to UART27 ~5 z  W$ q  M* P, O
  24.   if (p->in != p->out)/ ^* Q1 a- J: N9 g& X1 g. @* N" L
  25.   {/ t6 k. P) p% H5 |( L; P' u# ~
  26.     USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
    , I" F. r* m0 U) P1 \+ ?
  27.     p->out++;0 B8 _' Z6 |, p: ~, a  T* V4 [6 n, J
  28.   }  H: \- K' c/ V) a' j
  29.   /* USER CODE END USART1_IRQn 1 */: f$ V: q  d% P: M
  30. }
    8 J  C5 w& ~1 s- b$ [' v' d8 @# X
  31. ; e& H! P4 S. a) p
  32. /**1 \+ |' W6 T) y
  33. * @brief This function handles USART2 global interrupt.7 w  b1 P5 J: K- E& J
  34. */
    4 I* l( R5 D2 E. x& Q, P8 D- E5 K9 o
  35. void USART2_IRQHandler(void)/ W0 Y: j. z6 J. f8 {3 K& g
  36. {9 o" T) l' N. r6 i+ w' ?
  37.   /* USER CODE BEGIN USART2_IRQn 0 *// y) {# L) N$ y: [- F3 {, n
  38.   struct bufer_st *p;* |. I  k  Z; D9 [) d/ [
  39.   /* USER CODE END USART2_IRQn 0 */# r: f3 u" O: [, U' F4 n
  40.   HAL_UART_IRQHandler(&huart2);
    0 ^/ I- ~3 b& x* ?  i6 ~$ e
  41.   /* USER CODE BEGIN USART2_IRQn 1 */6 e0 s: @* V+ }' x2 a% {7 S$ _
  42.   p = &uart2buffer; //use UART2 buffer
    8 P' k# H* D- k
  43.   # Y; W( N& W5 l( H5 Q4 U# d' V  H
  44.   //raed UART2
    $ g* z! g( v9 n  V+ O7 z5 ~
  45.   if (USART2->SR & UART_IT_RXNE) // read interrupt! c( b# z' w4 ^0 n/ @4 P% c0 c
  46.   {                  * i. f6 Y1 c) v2 h( x1 s, G+ f
  47.     USART2->SR &= ~UART_IT_RXNE; // clear interrupt
    1 l8 R1 U% ]4 v- {4 a

  48. 2 @- E, T5 C4 _3 W, Z4 h
  49.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)( G  Q# a, x  N8 j1 V; n
  50.     {
    & |- x# I7 C# H5 k' I
  51.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA
    ) \1 ^, S5 e0 v( @8 @
  52.       p->in++;
    7 E( S) z9 ~" D& |0 d
  53.     }' T7 \4 R/ P; D8 v( C& D" O1 z! {
  54.   }
    % G7 u! I( [$ w; \
  55.   //send to UART1
    : R8 {) }0 _( P1 v
  56.   if (p->in != p->out)
    $ o, M7 i6 ^6 U* v2 ]% z
  57.   {$ T4 D( K5 h; r; B$ R7 a
  58.     USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out( V. l0 P. M1 {( c
  59.     p->out++;
    " N# M3 V5 v  y2 Z) t8 e1 D
  60.   }6 m8 b* ]$ Q2 o7 R+ _  R
  61.   /* USER CODE END USART2_IRQn 1 */
    2 C6 K# N/ U9 @! H
  62. }
复制代码
) q3 R) z! x9 X( }
(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。)
8 g' d& K' j6 c" ^

6 B( a2 l) i' H8 o5 b0 _5 E5 w4 K
大功告成了!! 编译后烧录。
3 u8 A5 R: i1 s' U# \
测试条件,使用两个UART转USB板子(FTDI)和sscom5上位机程序(开两个),发送区都摆放700多个字符,以10ms的间隔连续发送。
测试结果,速度115200bps和1Mbps,双向同时收发100万字符无差错2Mbps,单方向100万字符无差错。
(高速测试时,需要修改main.c里面的串口速度BaudRate配置。 我没有测试“自动波特率”的模式是否正常。)

1 }/ U: D7 f: ~, x
最后,完整的工程见附件。
2 ~4 U# f- K- S0 R

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 编辑 0 W5 e" y. ~- g  T/ X* Y: a: E

2 _+ W0 D3 W7 ]7 D! V! g谢谢楼主,解决了我的HAL库不能单字节中断收发的问题!( d4 C% ^" k# v+ i0 \2 p
  • 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 */
  • }

  • " H3 A3 c4 Z4 J
, u1 |  v3 T( [
+ {/ ?7 ]$ I9 n2 n& B! x- S
radio2radio 回答时间:2018-8-14 10:23:17
wwwheihei 发表于 2018-8-14 08:30
, i0 U5 S5 h1 b1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,4 R  ~; _2 D  A! ?- D
2.写入dr寄存 ...
+ x8 n6 l: C/ w7 T
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
* }2 B) y+ k# {1 `" u2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。
: j3 L- J; M8 z9 ?/ R, k" [- u% m" \, a7 S+ X. {+ z' w% n5 H
ssssss 回答时间:2018-8-14 08:30:08
radio2radio 发表于 2018-8-13 19:42
+ o7 |! b( j0 ]+ Q1 t: h, ~不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。# m8 n4 P" ?2 B- q
...

1 a) q' o6 H- k: O) P: q1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,' h/ B, A2 B$ X; |. N* d* L
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,就能实现每个字节接收中断收发6 ?0 ^6 R* F- z2 T
, |" m- Z: L8 i* |% ?
当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?
/ m" ^7 E! ?% I1 R- E& e
radio2radio 回答时间:2018-8-13 19:42:28
wwwheihei 发表于 2018-8-13 17:22
2 c/ V; k; t+ B8 f6 FUSART2->DR = (p->buffer & 0xFF); //send out,此处我将USART2修改成USART1,就能实现每个字节接收中断收 ...
. r6 o( ?! A* \/ U2 D2 n3 e
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
/ O7 N- k" Y; W- f& p" e5 I% [
ssssss 回答时间:2018-8-14 13:41:47
radio2radio 发表于 2018-8-14 10:234 [; k" c5 C/ X8 U
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
% V" V" n2 ~* D0 J2. 串口的速度,相对于MCU的运行速度 ...
' J' T' O# e' m; {; _6 Z
我用国产的,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 手机版