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

【屋脊雀F407开发板】串口空闲中断+DMA实现不定长接收&处理

[复制链接]
donatello1996 发布时间:2019-1-7 09:38
    串口不定长接收在项目中经常用到,像MODBUS串口服务器中就会经常传来一大帧数据,数据的长度不定,通常人们的做法是采用环形队列接收的方式,以特定的结束标志位如0x0d 0x0a等用以判断一帧数据的结束,但实际上STM32这种高级的ARM单片机是带有空闲中断和DMA的,不需要用环形队列这种纯软件的做法实现不定长接收,直接用空闲中断+DMA就可以实现了,非常简单,小白也能一看就懂。4 Y4 t* _7 q+ O5 A& ~
    首先是要初始化串口不定长接收,比如打开空闲中断,打开DMA,这里我选的是板上的USB转TTL串口即串口3,对应的接收DMA为DMA1流1:# f2 R- r1 V4 b0 }3 J
12.jpg 13.jpg 0 _4 Z) ~+ R7 x. r4 g
代码如下:5 |" Q1 ?' C9 i

$ }( T. Q. Z2 M, X* w) R' p& N
, [' E3 P" D! D2 M8 ~) }8 L: [2 T
void UART3_Init(int baud)) i! u9 @/ A- E! U! p
{
+ F) \; X5 L  P$ T2 k. W        __HAL_RCC_GPIOB_CLK_ENABLE();
% n7 _: y& x5 B0 k7 S6 R        __HAL_RCC_USART3_CLK_ENABLE();
  Q4 P4 u5 ^3 s9 F0 y        __HAL_RCC_DMA1_CLK_ENABLE();
  i7 r# ^6 g9 {" w, C* \3 E* c5 o        * Z& s8 T  L; c: ?: u$ f3 ]4 N2 Z
        GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;8 y6 n9 e* O2 t# [8 o
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
! w7 x# r6 ~- A8 t5 J  GPIO_InitStruct.Pull = GPIO_PULLUP;. [) i, C# I6 A8 V# h
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;" k* Q' Y( P  P+ ~' l. L5 I
  GPIO_InitStruct.Alternate = GPIO_AF7_USART3;1 ]* o* F, j' ]; d6 E9 u
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);2 S3 [) x' ?& b$ B
        & X+ v- N6 ~$ x+ Y
  huart3.Instance = USART3;* C3 J1 E1 S3 N
  huart3.Init.BaudRate = baud;+ N- H9 N1 l) \% h% I7 f8 ~( c+ O
  huart3.Init.WordLength = UART_WORDLENGTH_8B;
0 ~6 q4 |8 T3 Z  huart3.Init.StopBits = UART_STOPBITS_1;- S! e5 J6 \# D; W
  huart3.Init.Parity = UART_PARITY_NONE;
' r+ P" ~% I8 v& l  huart3.Init.Mode = UART_MODE_TX_RX;$ m5 k- p( N- B
  huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
+ d, B9 ?4 p7 q! d' i( p1 i; P  huart3.Init.OverSampling = UART_OVERSAMPLING_16;
, G+ i5 x' _8 @8 t: C  HAL_UART_Init(&huart3);
+ X/ a1 x) g4 \/ Q5 P1 y* F) @        __HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);) K9 W2 {. W/ |' v! _
        HAL_NVIC_SetPriority(USART3_IRQn,0,0);+ E6 X& M3 f2 T$ }9 f  p# L, z
  HAL_NVIC_EnableIRQ(USART3_IRQn);/ u" C: o9 s2 w
       
$ c, U8 [2 E8 P6 x        hdma_usart3_rx.Instance = DMA1_Stream1;
, J2 l$ t; r$ r- o  hdma_usart3_rx.Init.Channel = DMA_CHANNEL_4;
* P0 c' f1 t: C7 @# f) O6 Y1 i  hdma_usart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
# B% e* _6 I2 O# b; o; N  hdma_usart3_rx.Init.PeriphInc = DMA_PINC_DISABLE;; `" r. M/ Y7 n3 i2 G& H
  hdma_usart3_rx.Init.MemInc = DMA_MINC_ENABLE;
# _# T# }/ {2 q! a  hdma_usart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;  [& Y: l8 Q+ x0 s. h8 O$ w2 t
  hdma_usart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
' B# ~% X& u9 L, ?# }9 S" k  hdma_usart3_rx.Init.Mode = DMA_NORMAL;
9 b9 p/ ~, O; O) O- `% a  hdma_usart3_rx.Init.Priority = DMA_PRIORITY_LOW;' ~0 q/ I4 p" b0 b, n! c' ?8 e
  hdma_usart3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;' j* C& ^( j! ^4 G9 C; U+ X
  HAL_DMA_Init(&hdma_usart3_rx);2 |, C# D: c4 w* R/ m
        - C1 E% |' Y  h3 O% Y/ q$ e( _7 J
  __HAL_LINKDMA(&huart3,hdmarx,hdma_usart3_rx);
6 M& M: j$ J& J7 O4 r7 S}
) f6 C0 A; P7 l+ z# h) a! l/ s( E
& j1 B  s: f& U/ R* G2 U7 U
void USART3_IRQHandler()
, e3 u0 h& c' ~! K{
. z) \# M0 o5 f6 B% I- C% C, P6 U, X        int temp;
/ A0 i/ d' D* [; R2 D1 C# U5 n) I        if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE))
0 G2 n6 F5 ]1 {7 w        {
/ x# \& G0 `/ k/ R: ]& [                __HAL_UART_CLEAR_IDLEFLAG(&huart3);6 L9 G2 J$ k1 F- Q& f8 U) {  R
                HAL_UART_DMAStop(&huart3);/ W8 ?8 J4 T8 A
                temp=__HAL_DMA_GET_COUNTER(&hdma_usart3_rx);
; g* S$ r7 q7 q9 h8 U                rx_len_uart3=BUFFERSIZE-temp; 2 a: I1 A' C8 W* C& A& Z8 B
                rx_flag_uart3=1;& P; A5 _; J) N/ f! [5 x1 Y
        }
5 T! H  A0 |5 t}
" q' q; W# I6 W9 [在主循环中加入以下语句以让单片机轮询串口不定长接收的标志位,并在液晶彩屏上显示出来:
% x1 {$ ^* `" N2 {! Wvoid UART_DMA_Get()5 |0 d) c6 E4 ~' {6 _
{6 w1 N; X! x9 Z$ s
        int i;
0 s" Y' B0 N3 L5 L( H        if(rx_flag_uart1==1)
9 V$ e/ a6 |/ A* D! m( w$ z; i1 f        {
6 D8 |* D+ z% t1 X* c" P                printf("rx_len=%d\n\n",rx_len_uart1);
8 b4 M# Q2 I. W- G9 v6 n                printf("%s\n\n",rx_buf_uart1);
) g" t* J: }! v" z; K                rx_len_uart1=0;$ n/ s. _$ }& K3 x3 \' p, K
                rx_flag_uart1=0;  a; c, G8 o4 i  z& w9 E9 r
        }& U) E4 x* e  f) a
        if(rx_flag_uart3==1)) a. I! t% R$ o( @) U* l/ ~6 V
        {
) q( f/ Q1 B0 ]# J                printf("rx_len=%d\n\n",rx_len_uart3);
3 c& a1 k* o: W                for(i=0;i<rx_len_uart3;i++)* q9 \+ ]+ z3 g" r3 g, X
                {; E7 U& Q& g' N) }
                        if(rx_buf_uart3=='\r'||rx_buf_uart3=='\n')
3 M' n& b% {! u3 Z                                rx_buf_uart3=0;7 F9 K- y' G* ^% p. D  S
% J- g( \& W' ?, z' S2 C! K

# g+ k1 D) q7 {4 C: J9 T                }
! Q' d& L7 M: J                printf("%s\n\n",rx_buf_uart3);5 a: p5 o! \# o+ T* P, M
                SPILCD_DrawString(0,128,"                              ",BLACK,CYAN,ZF32_NORMAL);' j1 M+ h3 b- N( q2 m- g/ S" B0 Z
                SPILCD_DrawString(0,128,rx_buf_uart3,BLACK,CYAN,ZF32_NORMAL);
( s( E5 Q3 k8 v8 X% W$ m/ H7 o5 M( _7 d% G

3 M8 C5 e" ]+ f$ M) B/ F% p  S                rx_len_uart3=0;/ x. S# L% q' x1 U$ D
                rx_flag_uart3=0;. j7 g7 V. n% w) b3 Q
        }3 }4 q9 o6 `) A
        HAL_UART_Receive_DMA(&huart1,(uint8_t*)rx_buf_uart1,BUFFERSIZE);8 {. n* Z5 _3 C
        HAL_UART_Receive_DMA(&huart3,(uint8_t*)rx_buf_uart3,BUFFERSIZE);0 S- B) ?9 w: u: }$ S# N# |
}4 \( ]" D* q9 p0 i2 [

4 a& c! b) K* x
9 R$ X# o1 b- G4 n
看看效果,可以看到,上位机串口程序那边发什么,显示屏就显示什么:
: p) W' X; U  f 14.jpg 15.jpg
8 R: U" K# c% l' V* H IMG_20190106_183604.jpg IMG_20190106_183620.jpg IMG_20190106_183643.jpg
( b0 n- p# K. p9 r" U% F  H* f上传工程文件:
0 O0 j5 l& F8 D+ r9 \ STM32F407ZGT6.zip (551.38 KB, 下载次数: 31)
收藏 2 评论6 发布时间:2019-1-7 09:38

举报

6个回答
Kevin_G 回答时间:2019-1-7 10:04:17
好文章!
STMCU-管管 回答时间:2019-1-7 10:39:15
支持支持
杨满意 回答时间:2019-1-7 13:07:33
有些外设模块不能用,会存在断帧问题
wujique 回答时间:2019-1-9 14:50:33
空闲中断是个思路,9 ^/ ?  p8 c/ u8 `! y1 L
不过可靠性可能需要认真考虑。& `. v" j. r' U( m7 W( U% X4 _" c1 v
串口属于硬件层,数据链路层协议还是需要考虑的。
% h" \- k( W1 g' g
david69chen 回答时间:2019-2-24 15:36:53
好东西,感谢分享!
q790198803 回答时间:2020-10-31 23:19:16

( ~, K) b- r( U) ^: w好东西,感谢分享!

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版