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

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

[复制链接]
radio2radio 发布时间:2018-7-14 21:15
本帖最后由 radio2radio 于 2018-7-14 23:51 编辑 * N- F0 ?+ \- M6 r& [
1 Q$ \' n+ K$ }& F, ~3 [4 N$ j
看到大家经常写一些关于串口的问题,我也尝试开一个使用串口的工程。* D0 R" O( K# m+ l% C) u5 d( R4 D9 H. m
简单的要求是,USART1和USART2之间互相转发7 v& G* `6 E6 u- c2 u# I
发现使用CubeMX平台,建立测试工程没有难度,情况如下:
0 V: C0 E) y, Q- q/ z0 m# S8 O# t3 ~# O$ ?; }1 D6 F3 s
1. 配置管脚,使用BluePill最小板,PC13接有LED:
1 Y& k+ j4 J) |: v% `MCU是STM32F103C8T6,这个不重要. 不要忘记配置SWD调试接口。8 _& b& d# f+ ^5 J, R
0.JPG 5 u4 N% o7 A) X- V

6 q7 ^! t/ H& W9 x# n2 s2. 配置时钟,重点已经标出:" @; b) V: w4 g! M) v1 U6 o/ m
1.jpg / }! b% \, w% Y7 ^" U( B1 K% I/ m
; h' I5 H5 U! a7 _5 C9 }' i
3. 配置中断选项,由于不使用DMA,可以不理DMA的选项:
$ X  v* w& d' B. X, P3 _$ H(USART2也要同样配置)- r: g) ]% Z  r1 E' }! ~
2.jpg
8 P% ~5 G, n4 f" E  N1 Y
, \) R5 e( S) H! a$ G8 \(然后,生成工程代码)
/ R$ h. [% q' y0 F* m5 \
3 |, _5 K& G0 N8 t: J, \1 z( G4. 添加代码, n) q1 G8 D0 ]5 K
4.1 在main的初始化部分,添加接收中断使能:
* s; L8 i, a" ?/ [3 C
  1. __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE); //enable Rx INT
    ; c9 E1 C8 N5 N2 m
  2. __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); //enable Rx INT
复制代码
$ R! K( ^( q, p6 B) V

" ?  E0 s  \* V$ d. F1 x/ a
4.2 打开stm32f1xx_it.c,在前面添加接收缓存结构体:7 [  V" Z: q. p, f7 g& J
  1. /* USER CODE BEGIN 0 */
    . z% H/ C' Q6 Y1 w: I
  2. #define UART_BUFFER_SIZE    64 //here must be 2^n
    0 g1 s/ E$ K) N9 S" G  V
  3. struct bufer_st {/ I1 m) F1 v' X% _* Q) C* J
  4.   unsigned int in;                // Next In Index
    8 _9 ?; x( Q1 o$ }6 i0 `$ v9 f
  5.   unsigned int out;               // Next Out Index
    / c' M( B+ w* v" N$ ?
  6.   char buffer [UART_BUFFER_SIZE]; // Buffer2 t' r) |  `0 N6 M
  7. };
    # O( i# m3 m, f) b
  8. static struct bufer_st uart1buffer = { 0, 0, };) t5 S* i( Z0 Y* o0 N5 Y; S
  9. static struct bufer_st uart2buffer = { 0, 0, };
    * B# h- f3 Y% h7 o
  10. /* USER CODE END 0 */
复制代码

3 o7 m& R! _$ D, s# F0 e# P, k2 n& W% L9 @. G+ n! d, T, f

3 j# s8 w; J! j) R8 d/ F
4.3 在stm32f1xx_it.c的底下,修改USART1和USART2的中断服务程序如下:
  1. /**$ O3 T% E) M- W8 g0 x8 D0 a. R
  2. * @brief This function handles USART1 global interrupt.
    1 D" i2 A  e+ w. R: U* }: E
  3. */8 ^2 Y! N" ]! L( t  U4 ?3 o* ~
  4. void USART1_IRQHandler(void)
    1 [2 K* P1 p2 U- M& d1 h0 K+ F
  5. {* k* G7 u6 ~# a7 `
  6.   /* USER CODE BEGIN USART1_IRQn 0 */
    * P) h2 f& z% a: w9 z
  7.   struct bufer_st *p;3 x- C0 Y# E! w  ]3 |
  8.   /* USER CODE END USART1_IRQn 0 */
    9 t, O1 ^: a+ @9 `2 q6 U+ F. M; Q
  9.   HAL_UART_IRQHandler(&huart1);
    & h0 w- N. G* U. ~; n5 `
  10.   /* USER CODE BEGIN USART1_IRQn 1 */- k* c. P% h; j. G: H
  11.   p = &uart1buffer; //use UART1 buffer
    $ N4 ~& W( f: y' @! I8 o. E* M  |
  12.   
    & z8 o. Q1 N+ }& Y% y
  13.   //raed UART18 N4 K0 H# `: x
  14.   if (USART1->SR & UART_IT_RXNE) // read interrupt
    9 D# y; b! m8 E! W( p8 g6 G5 N# K
  15.   {                  
      O2 M) j* C5 o! v6 o! N
  16.     USART1->SR &= ~UART_IT_RXNE; // clear interrupt6 r0 P3 I4 E4 E# M+ s4 b

  17. 1 j3 T: s" d  H$ @, H" r9 d' {3 z. H+ u
  18.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0) {
    ' ~& `; `* o* f/ @* b# c
  19.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART1->DR & 0xFF); //read DATA1 i; f* q( W8 T* F$ D" I! S% L
  20.       p->in++;! S' l1 L) {' N- {- t
  21.     }
    8 `7 G# v8 O/ g5 A1 {9 E
  22.   }
    ; B' U, @. i) R3 C
  23.   //send to UART2! G: A- P, {9 t2 [7 C
  24.   if (p->in != p->out)
    $ A+ E- a' N  {
  25.   {+ J7 }9 r0 q' R7 M& b! T
  26.     USART2->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out# H* o9 s; Z3 {- [7 F0 |2 D! _
  27.     p->out++;
    " r7 y" |7 }: I  L
  28.   }
    0 G( B1 d! Y+ _' F5 D* e" E! N
  29.   /* USER CODE END USART1_IRQn 1 */
    % x) [  t% q: i' P, w+ Z4 r
  30. }
    4 z  j3 m; L& X" L

  31. % Q5 x. x1 w7 \' y- f
  32. /**
    - J5 b  ]- \8 w" X! P# h& s  U
  33. * @brief This function handles USART2 global interrupt.  \; J# s& u& v" ~# @1 U) p- N
  34. */7 a# R, v% U( x8 K' e5 O3 d
  35. void USART2_IRQHandler(void)& a( O) ?$ S) H7 o' D8 |
  36. {
    # E2 {9 h$ A' b& H6 L( O6 ]2 a
  37.   /* USER CODE BEGIN USART2_IRQn 0 */
    + {" W9 H+ y1 z; m; |
  38.   struct bufer_st *p;. @+ N& o" I2 t/ Y+ P
  39.   /* USER CODE END USART2_IRQn 0 */% U* `7 ^' T5 K  K) E, A. |! b- V0 E
  40.   HAL_UART_IRQHandler(&huart2);/ [1 R. h+ L! d' t6 \1 i
  41.   /* USER CODE BEGIN USART2_IRQn 1 */- `' P  s4 I; s$ m+ i8 F4 X) V
  42.   p = &uart2buffer; //use UART2 buffer
    ; A6 s* B7 z' O
  43.   + ~: v) S/ M& Z: E$ k' [
  44.   //raed UART2* w8 g7 @9 h& ^5 Z7 w
  45.   if (USART2->SR & UART_IT_RXNE) // read interrupt
    3 ~2 L. v% E9 X4 Q/ Q$ l
  46.   {                  1 @) n1 {/ C# Q, i& m# C' V
  47.     USART2->SR &= ~UART_IT_RXNE; // clear interrupt
    ' s) y' v. S! G8 c! ~
  48. 3 E. b' f6 d' Z3 i# `
  49.     if (((p->in - p->out) & ~(UART_BUFFER_SIZE-1)) == 0)9 y" `! N$ G0 Y2 a4 q
  50.     {0 O6 q  g$ b$ y$ \4 z! r5 ~
  51.       p->buffer[p->in & (UART_BUFFER_SIZE-1)] = (USART2->DR & 0xFF); //read DATA
    , _4 {( Y& B5 |, X
  52.       p->in++;' \; s, Y+ ~  R2 S! B
  53.     }
    - r' N; m6 s  z7 R
  54.   }# _* E% d+ h% D# P
  55.   //send to UART1
    & Y! E$ T# n; `% C
  56.   if (p->in != p->out)
      Z# d4 Y2 u# M7 u- [8 T7 E4 E; m
  57.   {
    $ s, E2 e8 ^. G4 [$ m
  58.     USART1->DR = (p->buffer[p->out & (UART_BUFFER_SIZE-1)] & 0xFF); //send out
    $ ^; i0 K  d) q! S& f5 ~2 B
  59.     p->out++;
    / P! {) @8 @) Z' p
  60.   }
    ( h+ V( r9 q9 q5 U
  61.   /* USER CODE END USART2_IRQn 1 */" Q) ^. }4 s/ ~- R! \: T
  62. }
复制代码
4 [' d0 k4 L! i: [4 Q# J
(看得出,中断里面是收到一个字符发送一个字符。 发送是直接发送,不处理发送中断。)
6 J; E$ C1 R: a' W9 W$ w& `5 K. g
$ j, k4 D8 b, ~+ J
大功告成了!! 编译后烧录。

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

, z0 d' M  x% o- a' w' t. W( f
最后,完整的工程见附件。
7 u) ?- ~, N2 k5 Q# |( Q* V# R7 P

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 编辑
2 ^( c; V- p- ^1 O- g. ?. A
* v6 g! M! Q% |. l4 d/ ]( R谢谢楼主,解决了我的HAL库不能单字节中断收发的问题!
- u1 U# s$ c, V7 x* v/ }8 v- {. L
  • 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 */
  • }

  • + J& b0 u* M! b: n

- A( A) G4 y# W7 j8 a6 D7 @+ S/ N
radio2radio 回答时间:2018-8-14 10:23:17
wwwheihei 发表于 2018-8-14 08:30
* E  E0 x5 s+ j' K- f. ~1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,, c! {# f- q# k. d: y& p- b# ]
2.写入dr寄存 ...

4 l6 ~4 O& q# X) K4 K: z1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
: L8 @: Q7 y; k' u' x- _2. 串口的速度,相对于MCU的运行速度是慢太多,由于收发的速度相同,近似于“同步状态”,接收和发送是受硬件控制同时进行的,收到一个字节,触发中断进行处理,处理中断这个时候,上一个字节刚好发送完成。所以不会重叠的。2 f; u% c8 M; Q# E8 ?7 [

# q$ t; Y$ W# J$ j
ssssss 回答时间:2018-8-14 08:30:08
radio2radio 发表于 2018-8-13 19:42
8 q5 x: B: @4 C6 d/ y不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。) S3 @3 p; y5 d
...

7 ^! q- a1 l* [, k1.那你搞的那个数组有啥用啊,看似环形数组,那还不如直接收到一个数据然后直接给dr寄存器,2 X+ M8 V6 q# r' 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,就能实现每个字节接收中断收发
) |# O3 V, J. n; B
1 v! J6 ~6 t4 Y) J* U' F当你把数据送到dr寄存器后,你没判断发送完成寄存器啊?会不会覆盖数据呢?
# Z! d; m6 I* U  s3 V- {) A* o9 N# x# ~8 a
radio2radio 回答时间:2018-8-13 19:42:28
wwwheihei 发表于 2018-8-13 17:222 _. [3 R9 w  f
USART2->DR = (p->buffer & 0xFF); //send out,此处我将USART2修改成USART1,就能实现每个字节接收中断收 ...
+ c/ W; W1 }9 H2 @7 j  T) b
不会,因为收到1个字节之后发送一个字节,写入DR是瞬间完成,收发速度相同,不会有重叠的。
7 b) ]- }+ D2 q, A' {3 R
ssssss 回答时间:2018-8-14 13:41:47
radio2radio 发表于 2018-8-14 10:23+ ?6 Q" A: d& H5 m" z
1. 同意您的说法,数组并不重要。反正是收到一个字节发送一个字节。
5 T# L2 Y) {# s: v$ w- ]1 {2. 串口的速度,相对于MCU的运行速度 ...

: L5 i" S! b; Y- i我用国产的,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 手机版