**串口传输大量数据时 总线空闲中断+DMA传输 为CPU减负**

串口传输大量数据时 总线空闲中断+DMA传输 为CPU减负
在使用串口接受数据时,如果用while在主函数等待,或者用if在主函数判断,传输少量的标志位可以,程序效率很低,如果用DMA+单字节串口接受中断,这样效率高了,但是当我们需要不间断传输大量数据时,单片机频繁进入中断,有时会影响main()函数的运行,如果采用串口总线空闲触发中断+DMA传输,可以完美的解决这两个问题。
USART_SR寄存器的IDLE位该位的作用时当检测到总线空闲时触发中断,用此标志位我们可以在传输完一帧数据时进入一次中断,这样进入中断次数缩减,main()效率增加
代码如下:

/********************************************************************************
  * @file    LSYY_Usart_Api.c
  * @author  绿水颖颖
  * @version V1.0
  * @date    2017.7.26
  * @brief   传输大量数据时  空闲中断+DMA传输 为CPU减负
  ******************************************************************************
  * @attention 
  *
  * 
********************************************************************************/
#include "LSYY_Usart_Api.h"
#include "LSYY_usart.h"
#include "LSYY_led.h"

/*内存池*/
uint8_t DMA_Rece_Buf[USART_RX_BUFF_SIZE];

/*
 *函数名`  : void USURT1_Config(void)
 *描述        :配置USART1
 *输入        :无
 *输出        :无
 */

void USART_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure ;
    USART_InitTypeDef USART_InitStructure ;

    //开启串口的时钟
    DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK ,ENABLE);
    //开启GPIO的时钟
    DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK,ENABLE);
    //配置串口1的寄存器

    //配置串口1所对应的GPIO口    
    //配置模式 复用推挽输出模式

    GPIO_InitStructure.GPIO_Pin=DEBUG_USART_TX_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF_PP ;
    //配置输出速率
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    //初始化GPIO口
    GPIO_Init(DEBUG_USART_TX_GPIO_PORT,&GPIO_InitStructure);


    //配置串口1GPIO口的模式
    //GPIOA10
    //GPIO_InitStructure.GPIO_Pin=DEBUG_USART_RX_GPIO_PORT_PIN;
    GPIO_InitStructure.GPIO_Pin=DEBUG_USART_RX_GPIO_PIN;
    //配置串口模式
    GPIO_InitStructure.GPIO_Mode =GPIO_Mode_IN_FLOATING ;
    //初始化GPIOA
    GPIO_Init(DEBUG_USART_RX_GPIO_PORT,&GPIO_InitStructure);

    //配置串口
    //设置波特率
    USART_InitStructure.USART_BaudRate =DEBUG_USART_BAUDRATE ;
    //设置传输字节
    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 ;
    //初始化串口1
    USART_Init(DEBUG_USARTx  ,&USART_InitStructure);

    /****************************************************注意**************************************************/


    /*开启空闲中断*/
    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
    /*开启DMA传输数据*/
    USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);   
    //使能串口
    USART_Cmd(DEBUG_USARTx  ,ENABLE);
    USART_ClearFlag(USART1, USART_FLAG_TC);         

}
/**
  * @brief  串口空闲中断(IDLE)无
  * @param  无
  * @retval 无
 **/
void USART_IDLE_NVIC_Configuration(void)
{

    NVIC_InitTypeDef NVIC_InitStructure;

    /* 配置中断源:IDLE */
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    /* 配置抢占优先级 */
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    /* 配置子优先级 */
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    /* 使能中断通道 */
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    //初始化
    NVIC_Init(&NVIC_InitStructure);

}
/**
  * @brief  USART1  DMA配置
  * @param  无
  * @retval 无
 **/
void USART_DMA_Config(void)
{

    DMA_InitTypeDef DMA_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  //使能DMA传输

    //相应的DMA配置
    DMA_DeInit(DMA1_Channel5);   //将DMA的通道5寄存器重设为缺省值  串口1对应的是DMA通道5
    //DMA外设ADC基地址
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;  
    //DMA内存基地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DMA_Rece_Buf;  
    //数据传输方向,从外设读取发送到内存
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 
    //DMA通道的DMA缓存的大小
    DMA_InitStructure.DMA_BufferSize = USART_RX_BUFF_SIZE;  
    //外设地址寄存器不变
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
    //内存地址寄存器递增
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
    //数据宽度为8位
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  
    //数据宽度为8位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    //工作在正常缓存模式
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  
    //DMA通道 x拥有中优先级 
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; 
    //DMA通道x没有设置为内存到内存传输
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
    //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
    DMA_Init(DMA1_Channel5, &DMA_InitStructure); 
     //正式驱动DMA传输
    DMA_Cmd(DMA1_Channel5, ENABLE); 


}
/**
  * @brief  串口DMA配置复位函数  恢复DMA指针
  * @param  无
  * @retval 无
 **/
void DeInit_USART_DMA(DMA_Channel_TypeDef*DMA_CHx)
{
    //串口DMA失能
    DMA_Cmd(DMA_CHx,DISABLE);
    /*DMA传输数值重装*/
    DMA_SetCurrDataCounter(DMA_CHx,USART_RX_BUFF_SIZE);
    //串口DMA使能
    DMA_Cmd(DMA_CHx,ENABLE);

}
/**
  * @brief  串口发送一个数组、字符串
  * @param  buf 字符串数组地址 len 数组字符串长度
  * @retval 无
 **/
void Usart1_Send(u8 *buf,u8 len)
{
    u8 t;
    //循环发送数据
    for(t=0;t<len;t++)      
    {          
        while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);   
        USART_SendData(USART1,buf[t]);
    }    
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);     
}
/**
  * @brief  串口中断
  * @param  无
  * @retval 无
 **/
/*用于计算不同长度数据的长度*/
uint32_t DMA_Buf_Cnt;
void USART1_IRQHandler(void)
{
    /*串口空闲标志位置1*/
    if(USART_GetITStatus(USART1,USART_IT_IDLE)==SET)
    {
        /* 必须得写,不然IDLE位清除不了 */
        USART_ReceiveData(USART1);
        /*计算出本帧数据长度*/
        DMA_Buf_Cnt=USART_RX_BUFF_SIZE-DMA_GetCurrDataCounter(DMA1_Channel5);

        /*测试程序*/
        printf("Length:%d\r\n",DMA_Buf_Cnt);
        printf("Data:\r\n");
        Usart1_Send((uint8_t *)DMA_Rece_Buf,DMA_Buf_Cnt);
        printf("\r\n \r\n");



        //清除中断标志位
        USART_ClearITPendingBit(USART1,USART_IT_IDLE);
        /*DMA使能*/
        DeInit_USART_DMA(DMA1_Channel5);
    }

}

/**
  * @brief  测试函数
  * @param  无
  * @retval 无
 **/
void USART_DMA_Test(void)
{
    USART_IDLE_NVIC_Configuration();
    USART_DMA_Config();
}

/**
  * @brief  主函数
  * @param  无
  * @retval 无
 **/
int main()
{

    All_Init();

    USART_DMA_Test();

    while(1)
    {

        /*所有要处理任务*/
//      TaskProcess();
    }

}

串口上位机截图
串口上位机截图

注意内容:
!IDLE位清零必须进行一个读USART_SR寄存器操作,接着进行一个读取USART_DR寄存器操作

本人菜鸟,正在学习中,有问题还请多多交流指正1558194318@qq.com,如有侵权立即删除。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值