• STM32使用串口1配合DMA接收不定长数据,减轻CPU载荷


    STM32使用串口1配合DMA接收不定长数据,减轻CPU载荷 http://www.openedv.com/thread-63849-1-1.html

    实现思路:采 用STM32F103的串口1,并配置成空闲中断模式且使能DMA接收,并同时设置接收缓冲区和初始化DMA。那么初始化完成之后,当外部给单片机发送数 据的时候,假设这帧数据长度是100个字节,那么在单片机接收到一个字节的时候并不会产生串口中断,而是DMA在后台把数据默默地搬运到你指定的缓冲区里 面。当整帧数据发送完毕之后串口才会产生一次中断,此时可以利用DMA_GetCurrDataCounter();函数计算出本次的数据接受长度,从而进行数据处理。

    关键代码分析:
    usart.H
    #ifndef __USART_H
    #define __USART_H
    #include "stdio.h"
    #include "sys.h" 
    
    #define DMA_Rec_Len 200      //定义一个长度为200个字节的数据缓冲区。(建议定义的长度比你可能接收到的最长单帧数据长度长!)
    
    void uart_init(u32 bound);
    void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx);
    
    #endif
    
    usart.C
    //初始化IO 串口1 
    //bound:波特率
    void uart_init(u32 bound)
    {
        //GPIO端口设置
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
        DMA_InitTypeDef DMA_InitStructure;
    
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
       RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输
       RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟
    
       USART_DeInit(USART1);  //复位串口1
       //USART1_TX   PA.9
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
        GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA9
       
        //USART1_RX  A.10
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA10
    
        //Usart1 NVIC 配置
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
      
       //USART 初始化设置
      USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
      USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
      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_Init(USART1, &USART_InitStructure); //初始化串口
        USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启空闲中断
        USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);   //使能串口1 DMA接收
        USART_Cmd(USART1, ENABLE);                    //使能串口 
     
        //相应的DMA配置
      DMA_DeInit(DMA1_Channel5);   //将DMA的通道5寄存器重设为缺省值  串口1对应的是DMA通道5
      DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;  //DMA外设ADC基地址
      DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DMA_Rece_Buf;  //DMA内存基地址
      DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,从外设读取发送到内存
      DMA_InitStructure.DMA_BufferSize = DMA_Rec_Len;  //DMA通道的DMA缓存的大小
      DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
      DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
      DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //数据宽度为8位
      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
      DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //工作在正常缓存模式
      DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级 
      DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
      DMA_Init(DMA1_Channel5, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道
    
        DMA_Cmd(DMA1_Channel5, ENABLE);  //正式驱动DMA传输
    }
    
    //串口中断函数
    void USART1_IRQHandler(void)                 //串口1中断服务程序
    {
    
         if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
          {
              USART_ReceiveData(USART1);//读取数据 注意:这句必须要,否则不能够清除中断标志位。
              Usart1_Rec_Cnt = DMA_Rec_Len-DMA_GetCurrDataCounter(DMA1_Channel5); //算出接本帧数据长度
       
             //***********帧数据处理函数************//
              printf ("The lenght:%d
    ",Usart1_Rec_Cnt);
              printf ("The data:
    ");
              Usart1_Send(DMA_Rece_Buf,Usart1_Rec_Cnt);
             printf ("
    Over! 
    ");
            //*************************************//
             USART_ClearITPendingBit(USART1, USART_IT_IDLE);         //清除中断标志
             MYDMA_Enable(DMA1_Channel5);                   //恢复DMA指针,等待下一次的接收
         } 
    
    } 

    这种方式和传统的uart接收中断里面处理数据(解析协议的比较):

    //普通方式
    uart_rcv_irq()
    {
        DISABLE_UARTX
        
        if G_Counter >= MAXLEN
            clear buffer and counter;
        else
            G_Buffer[G_Counter]= GetData(UARTX);
            G_Counter++;

            if OK==unpack(G_Buffer,G_Counter)
                clear buffer and counter;
                set flag;
                
        ENABLE_UARTX
    }

    //idle中断 + dma方式
    G_Buffer
    G_Counter
    G_DMARcvBuffer
    uart_idle_irq()
    {
        G_Counter += MAXLEN - DMAGetCurDataCounter(DMAx);
        copy G_DMARcvBuffer to G_Buffer;
        if OK==unpack(G_Buffer,G_Counter)
            clear buffers and counter;
            set flag;
                
        USART_ClearITPendingBit(USARTx, USART_IT_IDLE);
    }

    DMAx_OVERFLOW_IRQHandler()
    {
        G_Counter += MAXLEN - DMAGetCurDataCounter(DMAx);
        copy G_DMARcvBuffer to G_Buffer;
        if OK==unpack(G_Buffer,G_Counter)
            clear buffers and counter;
            set flag;
        
        RESET DMA
    }

  • 相关阅读:
    《Machine Learning in Action》—— 白话贝叶斯,“恰瓜群众”应该恰好瓜还是恰坏瓜
    《Machine Learning in Action》—— 女同学问Taoye,KNN应该怎么玩才能通关
    《Machine Learning in Action》—— Taoye给你讲讲决策树到底是支什么“鬼”
    深度学习炼丹术 —— Taoye不讲码德,又水文了,居然写感知器这么简单的内容
    《Machine Learning in Action》—— 浅谈线性回归的那些事
    《Machine Learning in Action》—— 懂的都懂,不懂的也能懂。非线性支持向量机
    《Machine Learning in Action》—— hao朋友,快来玩啊,决策树呦
    《Machine Learning in Action》—— 剖析支持向量机,优化SMO
    《Machine Learning in Action》—— 剖析支持向量机,单手狂撕线性SVM
    JVM 字节码指令
  • 原文地址:https://www.cnblogs.com/mylinux/p/5374134.html
Copyright © 2020-2023  润新知