STM32F103基于DMA接收不定帧长USART数据

发布者:DataExplorer最新更新时间:2017-10-09 来源: eefocus关键字:STM32F103  DMA  USART数据 手机看文章 扫描二维码
随时随地手机看文章

DMA是一种不使用CPU而将数据从一片地址空间复制到另一片地址空间的总线,这样就减少了CPU的负担,使其能够更加专注于数据运算。为了能够减少CPU的负担,DMA应该采取中断方式而非查询模式。但是非常不幸的是,STM32F103只为DMA提供了三种中断:半步中断、完成中断和错误中断。如果UART接收的是定帧长的数据,则可以开启DMA半步中断,并且目标地址长度为帧长两倍。这样每接收完一帧进一次中断,进行某些操作,是很理想的。然而当遇到如同GPS一样不定帧长的数据时,如果仍用半步中断则难以确定目标地址的长度。所以在此放弃使用DMA的中断,转而使用的是另一种比较特别的中断:UART空闲中断。

先来介绍一下UART空闲中断。UART常用的接收中断响应有:接收数据 就绪可读中断RXNE(这是最常用的)、数据溢出中断(ORE)、奇偶校验错中断(PE)和空闲中断(IDLE)。空闲中断是指当总线检测到一帧发完后, 总线空闲则会将此位置一,如果USART_CR1中的IDLEIE为’1’,则产生中断。空闲中断有两个比较有意思的特点:

1、清零方式:软件清零,先读USART_SR,然后读USART_DR

2、直到RXNE被置一后IDLE才能被重读置一,即IDLE被置一并软件清零后,只有之后再次接收到数据,IDLE才能被置一。这样就防止了总线长时间空闲而多次引发空闲中断。

好的废话不多说上例程。


以下都是通过DMA接收GPS串口的子模块程序

#define UART_RX_LEN     128
static char Uart_Rx[UART_RX_LEN];//GPS接收数据


void GPS_Init(void)
{
   RCC_Configuration();//时钟打开
   GPIO_Configuration();//GPIO配置   
   DMA_Configuration();//DMA配置
   UART_Configuration();//UART配置
   NVIC_Configuration();//中断优先级配置
}

 

void RCC_Configuration(void)
{
   //打开串口对应的外设时钟   
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);     
    //启动DMA时钟 
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 
}

void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

void DMA_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;
 //DMA1通道5配置 
    DMA_DeInit(DMA1_Channel5); 
    //外设地址 
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART1->DR); 
    //内存地址 
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Uart_Rx; 
    //dma传输方向单向 
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 
    //设置DMA在传输时缓冲区的长度 
    DMA_InitStructure.DMA_BufferSize = UART_RX_LEN; 
    //设置DMA的外设递增模式,一个外设 
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
    //设置DMA的内存递增模式 
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
    //外设数据字长 
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; 
    //内存数据字长 
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; 
    //设置DMA的传输模式 
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; 
    //设置DMA的优先级别 
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; 
    //设置DMA的2个memory中的变量互相访问 
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
    DMA_Init(DMA1_Channel5,&DMA_InitStructure); 
 
    //使能通道5 
    DMA_Cmd(DMA1_Channel5,ENABLE);
}

void UART_Configuration(void)
{
    USART_InitTypeDef USART_InitStructure;
 //初始化参数      
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;   
    USART_InitStructure.USART_StopBits = USART_StopBits_1;   
    USART_InitStructure.USART_Parity = USART_Parity_No;   
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;   
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;     
    USART_InitStructure.USART_BaudRate = 9600;  
    //初始化串口  
    USART_Init(USART1,&USART_InitStructure);   
     
    //中断配置 
    USART_ITConfig(USART1,USART_IT_TC,DISABLE); 
    USART_ITConfig(USART1,USART_IT_RXNE,DISABLE); 
    USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
 //采用DMA方式接收 
    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
}


void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
 //配置UART1中断   
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3); 
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;               //通道设置为串口1中断   
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;       //中断占先等级0   
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;              //中断响应优先级0   
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //打开中断   
    NVIC_Init(&NVIC_InitStructure); 
}

 

void USART1_IRQHandler(void)                                
{    
    uint32_t Length = 0;//数据长度    
    if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) 
    { 
        DMA_Cmd(DMA1_Channel5,DISABLE);
        Length = USART1->SR; 
        Length = USART1->DR; //清USART_IT_IDLE标志 
        Length = UART_RX_LEN - DMA_GetCurrDataCounter(DMA1_Channel5); 

//设置传输数据长度 
        DMA1_Channel5->CNDTR = UART_RX_LEN;//重装填,并让接收地址偏址从0开始
        DMA_Cmd(DMA1_Channel5, ENABLE);//处理完,重开DMA  
    }  
    __nop();  
}

void GPS_Cmd(FunctionalState NewState)
{
 USART_Cmd(USART1, NewState);
}

 

以下是调用函数,一般在main函数中

GPS_Init();    
GPS_Cmd(ENABLE);


关键字:STM32F103  DMA  USART数据 引用地址:STM32F103基于DMA接收不定帧长USART数据

上一篇:STM32F405与STM32F407CAN配置
下一篇:stm32通过i2c存储数据在eeprom

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

STM32F103C8T6+温湿度传感器DHT11实现温湿度采集
通信原理 单总线通信 DHT11器件采用简化的单总线通信。单总线只有一根数据线,主从机之间的数据交换、控制命令等均由单总线完成。在单总线系统中,只有当主机呼叫从机时,从机才能应答。 挂载于单总线上的设备,必须通过一个漏极开路或三态端口连接至该数据线,以允许设备在不发生数据时能够释放总线。单总线通常要求外接一个4.7kΩ的上拉电阻,这样,当总线闲置时,总线上始终是高电平 传输数据位定义 一次传送40位数据,高位先出。数据格式位: 8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验位。 注:其中湿度小数部分为0。 校验位的数据定义: “8bit湿度整数数据+8bit
[单片机]
<font color='red'>STM32F103</font>C8T6+温湿度传感器DHT11实现温湿度采集
mini2440裸机DMA(1)
第8章 直接存储器存取DMA 在DMA章接种一共有四个通道的DMA源,而每一种源由包括9个寄存器。则我们只需要配置好久个寄存器就可以操作好DMA了。 这里主要以通道0位讲解 第一个寄存器 DISRC pDMA- DISRC=srcAddr; //设置源地址 第二个 寄存器DISRCC pDMA- DISRCC=(0 1)|(0 0); //设置源控制寄存器 inc,AHB 第三个寄存器 DIDST pDMA- DIDST=dstAddr; //设置目的地址 第4个寄存器 DIDSTC0 pDMA- DIDSTC=(0 1)|(0 0); //设置目的控制寄存器 inc,AHB
[单片机]
mini2440裸机<font color='red'>DMA</font>(1)
STM32F103内部FLASH及地址表
在我们应用开发时,经常会有一些程序运行参数需要保存,如一些修正系数。这些数据的特点是:数量少而且不需要经常修改,但又不能定义为常量,因为每台设备可能不一样而且在以后还有修改的可能。将这类数据存在指定的位置,需要修改时直接修改存储位置的数值,需要使用时则直接读取,会是一种方便的做法。考虑到这些数据量比较少,使用专门的存储单元既不经济,也没有必要,而STM32F103内部的Flash容量较大,而且ST的库函数中还提供了基本的Flash操作函数,实现起来也比较方便。 以大容量产品STM32F103VE为例,其Flash容量达到512K,可以将其中一部分用作数据存储。如下是大容量的Flash组织模式: 根据上面的Flash组织模式,我们
[单片机]
<font color='red'>STM32F103</font>内部FLASH及地址表
STM32 USART串口DMA接收和发送模式
串口DMA发送: 发送数据的流程: 前台程序中有数据要发送,则需要做如下几件事 1. 在数据发送缓冲区内放好要发送的数据,说明:此数据缓冲区的首地址必须要在DMA初始化的时候写入到DMA配置中去。 2. 将数据缓冲区内要发送的数据字节数赋值给发送DMA通道,(串口发送DMA和串口接收DAM不是同一个DMA通道) 3. 开启DMA,一旦开启,则DMA开始发送数据,说明一下:在KEIL调试好的时候,DMA和调试是不同步的,即不管Keil 是什么状态,DMA总是发送数据。 4. 等待发送完成标志位,即下面的终端服务函数中的第3点设置的标志位。或者根据自己的实际情况来定,是否要一直等待这个标志位,也可以通过状态机的方式来循
[单片机]
STM32 <font color='red'>USART</font>串口<font color='red'>DMA</font>接收和发送模式
STM32F103V 4串口电路
最近做东西,需要用到4个串口,就用了STM32F103V,画了个电路 原理图: PCB: 实物图: 串口中断相关的程序段: void GPIO_Configuration(void) { RCC_APB2PeriphClockCmd( RCC_APB2Periph_USART1 |RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE, ENABLE);
[单片机]
<font color='red'>STM32F103</font>V 4串口电路
STM32f103 双串口配置和中断
//代码仅仅是配置使能串口和相应的中断处理函数,具体功能需要自己定义 //IAR 7.1 #include stm32_uart.h uint8_t card_ture=0; uint16_t add_count=0; uint8_t Key_Data ={0}; uint8_t Media_Flag=0; uint8_t card_code ; // save the card SN, valid or invalid uint8_t Temp_Card_Num ; uint8_t cardcode_rx_complete = 0; uint32_t uart_config_record_map = { 0, UAR
[单片机]
STM32H7 DMA USART空闲中断接收不定长数据
1.关键设置 2.代码 2.1 bsp_usart.h /*********************************************************************************** bsp_usart.h ***********************************************************************************/ #ifndef __BSP_USART_H__ #define __BSP_USART_H__ #include stm32h7xx_hal.h #include main.h #define
[单片机]
STM32H7 <font color='red'>DMA</font> <font color='red'>USART</font>空闲中断接收不定长<font color='red'>数据</font>
ADSP2106x中DMA的应用
   摘 要: 直接内存存取(DMA)是DSP芯片中用于快速数据交换的重要技术,对AD公司的浮点系列芯片ADSP2106x中的DMA的应用进行了详细介绍,并给出实际应用中的一些例子。     关键词: DMA 浮点系列芯片ADSP2106x     1 DMA概述     直接内存存取(DMA)对计算机系统是非常重要的。它可以使CPU在运行指令的同时,系统能实现从外部存储器或设备中存取数据,也可以在CPU不参与的情况下,由专用的DMA设备存取数据。     对于浮点DSP芯片来讲,DMA的作用更是重要。众所周知,DSP芯片主要是面向实时的信号处理,其核心的运算部件具有很高的运算速度,常以MFLOPS(每秒百万次浮点
[应用]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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