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

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

[复制链接]
donatello1996 发布时间:2019-1-7 09:38
    串口不定长接收在项目中经常用到,像MODBUS串口服务器中就会经常传来一大帧数据,数据的长度不定,通常人们的做法是采用环形队列接收的方式,以特定的结束标志位如0x0d 0x0a等用以判断一帧数据的结束,但实际上STM32这种高级的ARM单片机是带有空闲中断和DMA的,不需要用环形队列这种纯软件的做法实现不定长接收,直接用空闲中断+DMA就可以实现了,非常简单,小白也能一看就懂。7 E# z( S4 j# C
    首先是要初始化串口不定长接收,比如打开空闲中断,打开DMA,这里我选的是板上的USB转TTL串口即串口3,对应的接收DMA为DMA1流1:
  q: d3 A7 f) k 12.jpg 13.jpg * X- [: d) L: i, d
代码如下:" [9 c* F2 R& I4 H

" O3 p" n: ?3 N+ }8 |* Z3 |

& ^3 _; {& Q9 Q2 Cvoid UART3_Init(int baud)
* T+ h- x6 S3 \# i2 X" w{
6 `* b1 {& s9 K( Q, v        __HAL_RCC_GPIOB_CLK_ENABLE();
: L1 L& ~: _3 J0 H2 g6 m, u! u% f        __HAL_RCC_USART3_CLK_ENABLE();1 X  S) C' d/ n& R4 ^
        __HAL_RCC_DMA1_CLK_ENABLE();& X9 i; ?  q+ _. j- ~+ U
        * O& K& o. V/ n5 q; ?
        GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
. `; A: m9 h& U, z  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
. B5 P1 {( n4 d$ {% q; t  GPIO_InitStruct.Pull = GPIO_PULLUP;
4 N$ c* h9 q6 C$ {& Z- `$ w  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;6 {5 m: B7 c( ?0 m
  GPIO_InitStruct.Alternate = GPIO_AF7_USART3;5 e3 z. ~' a1 }3 h8 w1 ^% g
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);. D( p$ A' g& j  y$ w# {# S
       
4 Z* e' ]: X7 F. N  huart3.Instance = USART3;
! K, Q6 ]# Y$ [8 w' K  huart3.Init.BaudRate = baud;# |5 L1 o% t  L+ P$ D" ]
  huart3.Init.WordLength = UART_WORDLENGTH_8B;- ?7 A0 Z6 A9 m& R2 \% E3 t
  huart3.Init.StopBits = UART_STOPBITS_1;# O% y# C. S/ C) d
  huart3.Init.Parity = UART_PARITY_NONE;
; H+ ?! s4 L! O$ }  huart3.Init.Mode = UART_MODE_TX_RX;
, C! J$ q. |; \  huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
6 d" w: {1 W8 A% f  huart3.Init.OverSampling = UART_OVERSAMPLING_16;9 D& f' m0 i6 f" ^6 V
  HAL_UART_Init(&huart3);* m. e  R3 y, L5 U
        __HAL_UART_ENABLE_IT(&huart3,UART_IT_IDLE);! G! ^, r% h- @
        HAL_NVIC_SetPriority(USART3_IRQn,0,0);6 D, l5 P# b( e
  HAL_NVIC_EnableIRQ(USART3_IRQn);- s  L3 M8 b8 [8 {# B; D
       
7 V$ Z1 u6 E% ^8 j/ I3 A        hdma_usart3_rx.Instance = DMA1_Stream1;
  r1 x5 C& @' T& G  hdma_usart3_rx.Init.Channel = DMA_CHANNEL_4;8 b4 y! R, ?* p. ^, _6 [! X
  hdma_usart3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;, u% a5 y  }8 [$ p& o# J/ U
  hdma_usart3_rx.Init.PeriphInc = DMA_PINC_DISABLE;: f* z+ J" Y$ D4 T* m; a- E' f; ~
  hdma_usart3_rx.Init.MemInc = DMA_MINC_ENABLE;
* G6 ?, v& W/ E  hdma_usart3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;3 K% n% Z7 l# p  V0 d0 `& ^1 E
  hdma_usart3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;) e$ i) F0 R9 y* |
  hdma_usart3_rx.Init.Mode = DMA_NORMAL;0 {( ~1 T$ _2 G$ `7 A
  hdma_usart3_rx.Init.Priority = DMA_PRIORITY_LOW;- H6 [% l  N) J* u5 @5 c
  hdma_usart3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;6 ?$ u: M) }2 H
  HAL_DMA_Init(&hdma_usart3_rx);/ X) R3 {0 c6 v$ Q1 F, w1 Y+ h
       
) B6 L8 i3 b$ s9 Y& z  __HAL_LINKDMA(&huart3,hdmarx,hdma_usart3_rx);4 [- y: w" D. I$ z: M* i2 m5 |
}
# X9 a" X) U2 T/ `2 |# ^& w$ f8 @+ V& T

" e7 h$ o+ T5 D1 T: K2 @/ L) nvoid USART3_IRQHandler()# ^0 I2 s7 `! y3 f# _% A
{* T' x) z' ^! a3 a8 {
        int temp;8 M5 M" A* l! h) |" m
        if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE))
4 a) t/ w+ ], P3 f9 a        {( M! _8 ^/ Q: C6 z0 d
                __HAL_UART_CLEAR_IDLEFLAG(&huart3);8 h& P& e5 l- D! H0 h. Q
                HAL_UART_DMAStop(&huart3);
2 ]& z$ L  B1 `' D. ^                temp=__HAL_DMA_GET_COUNTER(&hdma_usart3_rx);+ ^( O' s8 M3 |: |4 o$ g
                rx_len_uart3=BUFFERSIZE-temp; ) t; d" L1 k: V0 r# @# X! A/ N
                rx_flag_uart3=1;# h! z; u; K4 O! r+ D" C- A8 N2 o
        }+ ^3 d2 p% d1 i0 ?
}# l. i( o* P$ Y! W' c6 P. W+ t! P
在主循环中加入以下语句以让单片机轮询串口不定长接收的标志位,并在液晶彩屏上显示出来:
" t3 o- \3 P/ }5 Tvoid UART_DMA_Get()" X$ |. C2 o0 r7 V1 C
{
8 G" m9 k: Q! P1 M: `        int i;
1 ^; R/ ]; _+ m7 m" }2 Y3 r$ v/ R( I        if(rx_flag_uart1==1)1 m0 s- V0 o0 [( U# P
        {7 _: M: Y1 X  R2 w5 r
                printf("rx_len=%d\n\n",rx_len_uart1);/ j! t# x. @6 O% X" Z. o
                printf("%s\n\n",rx_buf_uart1); 7 J; Q; Z2 X0 {9 d& K
                rx_len_uart1=0;
5 o3 j9 C* A; n7 m- r2 h+ e                rx_flag_uart1=0;/ d" c! ]9 r# q
        }7 H/ m; C( N2 \1 m( l
        if(rx_flag_uart3==1)5 O) ?+ r2 E& b0 H6 q/ C7 {
        {
  I: t4 W) r8 o0 {2 U# m                printf("rx_len=%d\n\n",rx_len_uart3);
6 n% V" Q2 v2 ]                for(i=0;i<rx_len_uart3;i++)
& D' L  V; a/ h! a                {. j* F3 {9 E" n
                        if(rx_buf_uart3=='\r'||rx_buf_uart3=='\n')
5 i# x/ r) p% q# g. {. V                                rx_buf_uart3=0;
* K7 O5 F* _; X5 c- d1 u
2 _" Q  K' s2 ]$ ^# ?/ J+ ?

  z) p3 ]: y" J+ }                }* x9 w! Q) a6 T9 N, q" l/ W& L2 G; \
                printf("%s\n\n",rx_buf_uart3);& i9 @0 p( x; C
                SPILCD_DrawString(0,128,"                              ",BLACK,CYAN,ZF32_NORMAL);3 e' F: a4 n8 L. C
                SPILCD_DrawString(0,128,rx_buf_uart3,BLACK,CYAN,ZF32_NORMAL);2 H# D, X0 D3 R6 P8 r1 b. H, f) o

; Y" K! f# O+ m- n1 K, Z4 M
' T3 U, b+ E- s" P% i0 K
                rx_len_uart3=0;
8 S( C$ E  q( x0 n3 I% V+ u" k/ c                rx_flag_uart3=0;* W; Q/ V1 p: X
        }5 `+ J: e7 h* F' H
        HAL_UART_Receive_DMA(&huart1,(uint8_t*)rx_buf_uart1,BUFFERSIZE);) M  g' |. l! H
        HAL_UART_Receive_DMA(&huart3,(uint8_t*)rx_buf_uart3,BUFFERSIZE);7 y+ S( d- Y! j" z, G7 g1 D
}
6 b6 a& Q' P3 |; A7 Y; D% O+ H
7 a% M4 [, A0 M: n- g( _

/ Y* m, t) ~9 k+ z- O7 ^) q: b& E看看效果,可以看到,上位机串口程序那边发什么,显示屏就显示什么:9 q* g6 [1 F- O, M/ B9 ]2 {4 v
14.jpg 15.jpg
/ D, O6 z; c7 ~$ r IMG_20190106_183604.jpg IMG_20190106_183620.jpg IMG_20190106_183643.jpg ( E$ v% s* `- ]9 \
上传工程文件:' f" s  Z* l$ u
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
空闲中断是个思路,
1 w/ t! s3 k6 K不过可靠性可能需要认真考虑。
9 L7 P# e- A: O  N* ]9 S串口属于硬件层,数据链路层协议还是需要考虑的。* ?+ E4 j8 V; e* B
david69chen 回答时间:2019-2-24 15:36:53
好东西,感谢分享!
q790198803 回答时间:2020-10-31 23:19:16

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