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

STM32 配置DMA不定长接收

[复制链接]
STMCU小助手 发布时间:2022-9-3 19:05
导语/ r' F& [  u$ |7 [/ _" [
关键词:STM32 DMA
7 g* C6 k1 Y1 q/ `2 q) ?* N, m本次教程采用的是stm32f401ccu6 + HAL库V1.8.1(F1系列芯片兼容)

5 g1 |$ x" r3 ?$ hCubeMX配置
微信图片_20220903190456.png
微信图片_20220903190454.png
微信图片_20220903190451.png
微信图片_20220903190448.png
最后点击GENERATE CODE生成代码

4 Z$ i7 x. p3 ]6 k2 I/ _
代码编写3 N! e/ O$ w8 R! K" z9 A2 b
测试串口功能(确定无误可跳过)
  1. /* USER CODE BEGIN Header */$ Y* u9 p  ]7 F# `
  2. #include <stdio.h>    //C语言标准输入输出库
    ) V* ?  M/ z2 _
  3. /* USER CODE END Header */
    * N$ t8 g* e  W
  4. ...8 O+ A. g. w# p
  5. /* USER CODE BEGIN 1 */
    5 m, R( I( w' D9 u' |7 z! P& J
  6. int fputc(int ch, FILE *f){
    : b* }) q2 f( [. x% D
  7. uint8_t temp[1] = {ch};
    0 E# L% ^2 @4 @: p5 e- s& f
  8. HAL_UART_Transmit(&huart1, temp, 1, 0xffff); //注意这里的&huart1更改为你使用的串口&huartx2 ?( Y( @3 H" X" H  p
  9. return ch;: O, K1 r6 A0 m6 Z
  10. }
    - d* o  u+ l! S* U' C
  11.   p& V; L% P4 g" H
  12. int fgetc(FILE * f)
    , d4 \! I- H* `! ^
  13. {
    6 a4 Y& E) |4 G! K6 |6 O9 Y/ i
  14.   uint8_t ch = 0;
    8 W, }: x# g! [! F
  15.   HAL_UART_Receive(&huart1,&ch, 1, 0xffff); //同理! C4 y8 S/ ?6 G8 j8 ]* s+ c1 l
  16.   return ch;! p, C' g5 Q% C' j+ _
  17. }% t1 T5 g" r; g4 z' d
复制代码

9 m, h/ z/ O0 U: n
  • 在main.c添加头文件#include <stdio.h>
  • 打开KEIL菜单栏的魔术棒(Options for Target...)
  • 在Target栏下勾选Use MicoLIB
  • 在Debug - Setting - Flash Download栏下勾选Rest and Run(否则需要手动复位单片机)
  • 在main.h中写上测试代码printf("nihao\r\n")
  • 编译下载后,打开串口助手可以看到测试信息,至此串口配置完成。

    : M+ f  r9 d- Z) |" D
微信图片_20220903190444.png
' ]6 h# O9 _3 l$ R/ a
! h/ _; X6 A, }, u, c2 H+ b: q- I, X
微信图片_20220903190441.png

/ d1 H7 ~1 w3 t9 G  dDMA测试及不定长DMA的配置DMA发送测试
  • 在usart.c中添加如下代码:
    * _, u, w0 C: B) F* [' X8 }- g
  1. void DMA_USART_Send(uint8_t *buf, uint8_t len)- J: g9 B1 `1 O6 }7 D
  2. {& ^1 g; Y3 t) U  h7 h! o- o

  3. 8 k+ f) x: h' k  ^9 m8 k. l
  4.     if(HAL_UART_Transmit_DMA(&huart1, buf, len) != HAL_OK)
    : w: b1 G8 q1 |
  5.     {
    * K1 ~. f# C+ e' u8 s" `$ R
  6.         Error_Handler();
    3 e# k9 C5 y7 z/ ?
  7.     }  }4 P$ \! _! _, z% |
  8. }
    $ O& j. c& i4 e3 y* n- X# R
  9. . W$ c4 L: y9 t$ e
  10. void DMA_USART_Read(uint8_t *Data, uint8_t len)
    % p; ^) o  b2 K! [$ }; k  G
  11. {1 v6 v3 Q3 T: b& z! B& D. G
  12.     HAL_UART_Receive_DMA(&huart1, Data, len);
    + a8 j2 H. X, @% }- t8 r5 n; N2 _
  13. }
复制代码
' }+ v( g& ?, r9 Q3 m

, d! V' x; `% B0 ~0 I" h4 _% F; m/ C
  • 在main.c相关位置添加代码

    5 K6 i+ J1 |, b) o8 i' R0 n
  1. DMA_USART_Send((uint8_t*)"Hello\r\n",sizeof("Hello\r\n"));
复制代码
2 ~) e4 j, b3 S. l5 p: J0 @
  • 编译运行后可在串口助手观察到输出。

    * _" f, |. ]8 k0 A

3 |1 R8 a+ O5 c! T; q/ E, C/ e
# G9 Z; D; p8 V2 u7 w; P7 i4 }9 q
5 S+ k; Y$ c" T/ G
DMA不定长接收
  • 在usart.c中添加全局定义uint8_t rx_buffer[100] = {0};其中“100”可修改,其值为最大的单次接收字符个数。
    (定义可放在别的文件,使用时包含该文件或者使用extern关键字)

    ; y% @: [4 j% G2 [* H; Y, d& x
  • 在usart.c中打开串口的空闲中断(IDLE中断)、找到串口初始化函数
    void MX_USARTx_UART_Init(void),其中,X为使用的串口号
    0 V. b! b1 X3 b5 ~' B
相关代码如下:
  1. /* USER CODE BEGIN USART1_Init 2 */: Y# ?8 _) g% }) E  a5 _$ O
  2.     __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能IDLE中断
    3 F9 n0 p) d( c# i( Y) O3 [
  3.     HAL_UART_Receive_DMA(&huart1,rx_buffer,100); //100对应了前面定义的数组大小
    " M' c5 J3 v5 |9 _
  4.   /* USER CODE END USART1_Init 2 */
复制代码

' ^& d0 h. l% r- p7 }, V
注意:此处HAL库较低版本没有用户自定义代码的区域,可自行更新HAL库版本或将代码添加到别处(否则cubemx更新代码时会丢失)
* w/ s6 I- y5 f( G/ ~/ ~2 e
  • 在stm32f*xx_it.c开头中添加extern uint8_t rx_buffer[];引用(其中*为使用的芯片系列,f1,f4云云)。并把前面修改的usart.h包含进来。

    , D0 M- Z% d4 ^) }
  1. // in stm32f*xx_it.c" O/ [  F, Z- a* Z9 c4 K

  2. 6 [: {# P2 h. ^: {( n
  3. /* USER CODE BEGIN Header */
    ( P% }& n; N* K- w& U6 y

  4. & b  X9 h- y3 ^1 d* L! ]+ i8 J7 Z
  5.     #include "usart.h"
    * Y1 E5 j- W6 S3 ~! p3 [& V1 T
  6.     #include <stdio.h>* u7 U; b9 e: e3 Q3 Q/ P

  7. ( V$ j0 N  I" \5 `. Z
  8. /* USER CODE END Header */
复制代码

+ [3 c  O8 U! K3 u: K
' t+ {% V- x  Y8 b* ^/ T
  • 找到函数void USARTx_IRQHandler(void)在函数
    HAL_UART_IRQHandler(&huartx);添加不定长接收逻辑代码(此处以回显功能为例):

    $ N3 h1 P9 X# T( p0 _9 |+ c0 f
  1. uint16_t tmp = 0;1 A4 n- ?4 h* p+ f3 Z3 e4 K
  2.     uint16_t Rx_Len = 0;
    . D# b' F( p& v) z  s, O2 I
  3.    
    % W# w* x9 Y; q+ ]
  4.     if(__HAL_UART_GET_FLAG(uartHandle, UART_FLAG_IDLE) != RESET)    //是否进入空闲中断
    ) U( b9 C" R& r2 ^! u  X  L
  5.     {
    . U" }# Y2 G( X6 `1 }
  6.         __HAL_UART_CLEAR_IDLEFLAG(uartHandle); //清除空闲中断标志位
    2 i' @+ e8 F: B3 r# W9 L
  7.         HAL_UART_DMAStop(uartHandle);       //此时信息已保存至rx_buffer,暂时停止DMA接收   
    9 k/ Z2 K( w; a$ t4 Z8 I7 g( o

  8. $ m, ?& \' q/ b5 c- D% j6 A
  9.             //... 在此添加解码程序或其他自定义代码,此处以接收信息后回显代码为例
    , U4 O3 h% B" [: N
  10.             tmp = __HAL_DMA_GET_COUNTER(hudma); //读取计数器后自动清除空闲中断,也可以直接读寄存器      
    / H; s! ~. L& Q/ _
  11.             Rx_Len = BUFFER_SIZE - tmp;
    $ g. x1 h8 T" [. q- ~  T
  12.             DMA_USART_Send(rx_buffer, Rx_Len);
    9 }- l  N8 `( P$ T' Y% a
  13.             Rx_Len = 0;, ^. H9 S. ?# Q% y
  14.             //
    , l8 V9 }' u* G: e* n) d. u9 _
  15.         HAL_UART_Receive_DMA(uartHandle,rx_buffer,BUFFER_SIZE);     //重新打开DMA接收
复制代码
4 z' j. G/ `0 l8 N  @; t/ V
  u( G: g( e  G6 V) B
  • 此时连接单片机,给单片机发送字符串,可以看到单片机回传相同的信息。

    1 ?& S, G1 t, q4 ^# @  @8 ^
/ s- }# Q7 M2 `9 y% [
微信图片_20220903190421.png

, N" o1 a6 g7 ]
转载自:hardware

& c  g& ?% E# Z2 \9 _
微信图片_20220903190430.png
微信图片_20220903190427.png
赞 收藏 评论0 发布时间:2022-9-3 19:05

举报

0个回答

所属标签

相似技术帖

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