STM32—cubeMX+DMA+USART 接收任意长度的数据

发布者:oplkjjj最新更新时间:2019-02-12 来源: eefocus关键字:STM32  cubeMX  DMA  USART  任意长度 手机看文章 扫描二维码
随时随地手机看文章

前言  


  之前的一篇文章中我为了可以实现USART接收任意长度的数据,对HAL的库进行了修改,可以实现接收以0x0a结尾的任意长度数据,即认为接收到0x0a时接收结束,见链接:HAL USART接收任意长度。 


  然而,上述这种方法并不合适,原则上HAL库一般不去修改,不便于其他人移植程序,降低了程序中库的适用性,这是很不好的习惯,所以这种方法并不可取。 


  后查资料得知STM32中还可以利用DMA的方式实现串口的任意长度数据的接收,故开始学习DMA+串口接收任意长度的数据这种方式。


cubeMX软件配置过程


首先,第一步都是进行时钟树的配置,配置好系统的时钟,不同的芯片配置不同的时钟频率,如图。 


这里写图片描述


接着,配置USART1,选择异步asynchronous,软件自动配置了PA9和PA10管脚。 


这里写图片描述


然后,继续添加USART1的发送和接收DMA,其余默认即可。 


这里写图片描述


接着,勾选上USART1的中断使能。 


这里写图片描述


最后,生成MDK-ARM V5版本环境的程序。 


这里写图片描述


UASRT串口程序修改

//添加变量,为什么用关键字volatile见链接:[链接](http://blog.csdn.net/u014470361/article/details/78830147)

volatile uint8_t rx_len=0;

volatile uint8_t recv_end_flag=0;

uint8_t rx_buffer[200];

static void MX_USART1_UART_Init(void)

{


  huart1.Instance = USART1;

  huart1.Init.BaudRate = 115200;

  huart1.Init.WordLength = UART_WORDLENGTH_8B;

  huart1.Init.StopBits = UART_STOPBITS_1;

  huart1.Init.Parity = UART_PARITY_NONE;

  huart1.Init.Mode = UART_MODE_TX_RX;

  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;

  huart1.Init.OverSampling = UART_OVERSAMPLING_16;

  if (HAL_UART_Init(&huart1) != HAL_OK)

  {

    _Error_Handler(__FILE__, __LINE__);

  }

  //上面的usart配置代码为cubemx自动生成的,在下方添加使能idle中断和打开串口DMA接收语句

    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);//使能idle中断

    HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);//打开DMA接收,数据存入rx_buffer数组中。 

}



接下来修改串口中断函数。


void USART1_IRQHandler(void)

{

    uint32_t tmp_flag = 0;

    uint32_t temp;

    tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位

    if((tmp_flag != RESET))//idle标志被置位

    { 

        __HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位

        temp = huart1.Instance->SR;  //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能

        temp = huart1.Instance->DR; //读取数据寄存器中的数据

        HAL_UART_DMAStop(&huart1); //

        temp  = hdma_usart1_rx.Instance->NDTR;// 获取DMA中未传输的数据个数,NDTR寄存器分析见下面

        rx_len =  BUFFER_SIZE - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数

        recv_end_flag = 1;  // 接受完成标志位置1    

     }

  HAL_UART_IRQHandler(&huart1);


}



DMA通道结构体中定义了NDTR寄存器,那为什么是未传输的数据数呢,STM32的中文手册给出了该寄存器的具体说明。


typedef struct

{

  __IO uint32_t CR;     /*!< DMA stream x configuration register      */

  __IO uint32_t NDTR;   /*!< DMA stream x **number of data register**     */

  __IO uint32_t PAR;    /*!< DMA stream x peripheral address register */

  __IO uint32_t M0AR;   /*!< DMA stream x memory 0 address register   */

  __IO uint32_t M1AR;   /*!< DMA stream x memory 1 address register   */

  __IO uint32_t FCR;    /*!< DMA stream x FIFO control register       */

} DMA_Stream_TypeDef;

这里写图片描述

接着,编写主函数中串口中断的处理函数。


int main(void)

{

  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();

  MX_DMA_Init();

  MX_USART1_UART_Init();

  while (1)

  {

        if(recv_end_flag ==1)

        {

            printf("rx_len=%d\r\n",rx_len);//打印接收长度

            HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);接收数据打印出来

            for(uint8_t i=0;i

                {

                    rx_buffer[i]=0;//清接收缓存

                }

            rx_len=0;//清除计数

            recv_end_flag=0;//清除接收结束标志位

        }

        HAL_UART_Receive_DMA(&huart1,rx_buffer,BUFFER_SIZE);//重新打开DMA接收     

  }

}



程序的运行效果如下图所示 ,输入任意长度数据,串口打印出接收的数据长度并打印出接收的数据。本程序设置的接收长度最大BUFFER_SIZE是200,若想接收更长的数据,也可以把BUFFER_SIZE和数组长度改大。 

这里写图片描述

关键字:STM32  cubeMX  DMA  USART  任意长度 引用地址:STM32—cubeMX+DMA+USART 接收任意长度的数据

上一篇:STM32—DMA使用
下一篇:STM32—printf函数重定义

推荐阅读最新更新时间:2024-03-16 16:23

STM32单片机的通用定时器
STM32中的定时器有多种,按功能分成2个高级控制器定时器,4个普通定时器,2个基本定时器,2个看门狗定时器,1个系统滴答定时器SysTick。 定时器的关键是定时时间的计算。比如用定时器控制继电器的开关的时候,需要延时一段时间才关闭或者开启,这时候离不开定时器定时。 通用定时器定时时间计算。1秒中断的基本实现: 通用定时器模块的入口时钟经过分频得到计数器的时钟,用CK_CNT表示,预分频器的系数为:TIMx_PSC,当TIMx_PSC=0时,表示不分频,=1时,2分频。以此类推。 公式为:CK_CNT=fclk_PSC/(PSC +1),其中PSC最大为65535. 其次是TIM5计数器的计数值的设置,TIM5计数器以
[单片机]
Stm32RS232串口通信——中断接收发送数据
main.c配置: /* *说明: *PA0:KEY1;PA1:KEY2; *PA2:LED1;PA3:LED2; *PA9:USART1_TX;PA10:USART1_RX */ #include stm32f10x.h #include stm32f10x_rcc.h #include stm32f10x_gpio.h #include stm32f10x_usart.h #include stm32f10x_exti.h #include system_stm32f10x.h #include misc.h void RCC_Configurati
[单片机]
STM32的启动模式配置与应用
三种BOOT模式 所谓启动,一般来说就是指我们下好程序后,重启芯片时,SYSCLK的第4个上升沿,BOOT引脚的值将被锁存。用户可以通过设置BOOT1和BOOT0引脚的状态,来选择在复位后的启动模式。 Main Flash memory 是STM32内置的Flash,一般我们使用JTAG或者SWD模式下载程序时,就是下载到这个里面,重启后也直接从这启动程序。 System memory 从系统存储器启动,这种模式启动的程序功能是由厂家设置的。一般来说,这种启动方式用的比较少。系统存储器是芯片内部一块特定的区域,STM32在出厂时,由ST在这个区域内部预置了一段BootLoader, 也就是我们常说的ISP程序, 这是一块RO
[单片机]
STM32 高级定时器-PWM简单使用
高级定时器与通用定时器比较类似,下面是一个TIM1 的PWM 程序,TIM1是STM32唯一的高级定时器。共有4个通道有 死区有互补。 先是配置IO脚: GPIO_InitTypeDef GPIO_InitStructure; /* PA8设置为功能脚(PWM) */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(
[单片机]
<font color='red'>STM32</font> 高级定时器-PWM简单使用
安全启动 - STM32安全启动应用
安全启动实现了信任根。 为了整体安全的需要,需要将信任传递到下一级。这个信任传递是通过加解密技术完成的。 在启动时,我们要至少保证下一级固件的完整可靠性。意味着,我们要使用认证技术,对用户固件进行验证。对用户固件进行验证可以使用哈希函数,也可以使用基于对称密钥的验证码 AES-GCM。 系统在安全启动前,需要保存已经烧录到 Flash 里的用户固件的哈希值。这个哈希值,通过前面所提到的 STM32 安全技术,保证它不会被内外攻击所改变。 系统在安全启动时,利用前面所构造的安全执行环境,对需要进一步执行的用户固件,进行一个哈希运算。哈希运算一般是采用 SHA256。 系统比较这两个值。如果计算出来的哈希值,与存储的哈希值相同,我们
[单片机]
基于STM32原子战舰板内存管理源码详解
简介:走到今天,已经开始涉及到计算机核心一点的东西了---内存管理。通过本实验的学习,能够较为深刻体会到“指针是c语言的灵魂”这句话的分量。自然对c语言的能力要求就高很多了。本文是基于原子老师的c源码,自己的学习的心得,只是对源码作出自己的学习理解,同时也插补了一些涉及到的c语言知识。贴出本文不为别的,一来但愿能有有缘人看到本文,提出指正;二来,为了那些不眠的夜,安慰一下自己。 1, 内存管理简介 内存管理,是指软件运行时对计算机内存资源的分配和使用的技术。其最主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源。内存管理的实现方法有很多种,他们其实最终都是要实现2个函数:malloc和free;malloc函
[单片机]
STM32中断优先级(默认和不默认情况)
可能对于刚接触抢占式优先级和响应优先级的人来说学习STM32的中断优先级有点障碍,这里先介绍下优先级: 具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。 当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。 STM32 可以支持的 68 个外部中断通道,已经固
[单片机]
<font color='red'>STM32</font>中断优先级(默认和不默认情况)
如何利用定时器产生PWM波
摘要:利用定时器产生PWM波。然后利用32的外部中断和定时器来测量32输出的波形硬件:STM32F103C8T6核心板、示波器、串口调试助手所用到的的引脚为PA8和PA0。 测量方案:在第一次外部中断(上升沿触发)到之时,开启定时器,同时计数器清零。然后等待第二次中断到来,在第二次外部中断(上升沿触发)到之时,获取计数器的计数值,同时关闭计数器。因为知道了计数器计数一个数的时间,所以在第二次外部中断(上升沿触发)到之时,获取计数器的计数值,通过这个值就知道一个脉冲的时间周期。时间周期的倒数就是外部信号的频率。 一、利用TIM1的CH1产生PWM波 pwm.c #include pwm.h voidTIM1_PWM_Init
[单片机]
如何利用定时器产生PWM波
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved