精华内容
下载资源
问答
  • 结构体是一种数据的归类方式,相比数组或变量更具有整体全面性,例如一个数组只可以放一些按照元素顺序存放的单元变量,即 buffer = {x, x, x, x, x…},i 有多大,数组内元素就有多少。那么我们这时候如果我们用这...
  • 我为什么要建这个帖子呢,因为我不想看到还有其他人跟我一样,为了调通DMA串口,而花上半天的时间,这很不利于大家高效率的开发,网上的经验都是从头教到尾的,内容极,对于有点小经验的人,或者是想很快达到...

      赠人玫瑰,手有余香;很感谢网上其他楼主的分享;我这个贴子是关于STM32 DMA USART 发送模式的调试分享,我为什么要建这个帖子呢,因为我不想看到还有其他人跟我一样,为了调通DMA串口,而花上大半天的时间,这很不利于大家高效率的开发,网上的经验都是从头教到尾的,内容极多,对于有点小经验的人,或者是想很快达到目的的人,这个很不适合他们;我的这个很简单(本帖不适合不熟悉配置STM32串口的玩家),他只是说串口的DMA怎么配置,还有我用的是DMA1_通道4,因为我的是串口1的TX长话短说:直接po代码:

      DMA_InitTypeDef DMA_InitStruct; //DMA类型声明
      RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); /打开RCC时钟,
      DMA_InitStruct.DMA_PeripheralBaseAddr= USART1_BASE+0x4;
      //串口外设基础地址,好像只能是这个数值,至于为啥是0x4,我还没找到相关资料
      DMA_InitStruct.DMA_MemoryBaseAddr= (u32)TEST;//这个我是一个字符串数组的首字母也就是u8  TEST[]
      =""
      DMA_InitStruct.DMA_DIR= DMA_DIR_PeripheralDST;//这个是发送模式
      DMA_InitStruct.DMA_BufferSize=0; //缓冲大小,实际我们使用可以改变,现在可以随便填
      DMA_InitStruct.DMA_PeripheralInc= DMA_PeripheralInc_Disable
      ;//这个是外设偏移,是外设的地址偏移
      DMA_InitStruct.DMA_MemoryInc= DMA_MemoryInc_Enable;//内存偏移,是保存在内存中的数据偏移
      DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
      DMA_InitStruct.DMA_MemoryDataSize= DMA_MemoryDataSize_Byte;
      DMA_InitStruct.DMA_Mode= DMA_Mode_Normal;//因为不需要循环发送所以使用这个模式就好
      DMA_InitStruct.DMA_Priority=DMA_Priority_High;//优先级,有最高,高,中,低的哥档位
      DMA_InitStruct.DMA_M2M= DMA_M2M_Disable; //关闭就好
      DMA_Init(DMA1_Channel4, & DMA_InitStruct);
      DMA_Cmd(DMA1_Channel4, DISABLE); //先关闭,要使用的时候才使能
      USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);//串口DMA使能,在串口的.h文档中可以找到。

      上面是我的DMA配置,接下来是实际在主函数中是怎么使用的:

      DMA_Cmd(DMA1_Channel4, DISABLE); //首先要关闭使能;
      DMA1_Channel4->CNDTR =13;  //给这个寄存器设定要发送的缓存大小,这个就是之前DMA配置的DMA_InitStruct.DMA_BufferSize=0;具体语句可以在dma.c中可以找到;
      DMA_Cmd(DMA1_Channel4, ENABLE);//设定好了缓冲长度之后使能DMA,这个时候串口就会自动发送
      DMA_InitStruct.DMA_MemoryBaseAddr=&TEST这个地址的内容;
      while(!DMA_GetFlagStatus(DMA1_FLAG_TC4)) ;//等待完成标志
      DMA_CleaRFlag(DMA1_FLAG_TC4); //清除完成标志

      可以我的代码就这两部分,最后说一说我花了大半天才得到的调试记录:

      1)使用DMA串口发送和单纯的串口发送方法不一样,传统的是printf(),DMA就是上面我的第二段代码的操作;

      2)DMA_PeripheralInc:要DIsable,因为这个是设定外设指向下个地址,而不是数据下个地址,设为Enable的话,系统会死机;

      3)DMA_MemoryInc:要Enable,这个才是移动到下个字节的标志;不然的话,即使串口通了,他只会发送第一个字节的内容,而不是发送你整个字符串;通过这个设定我想到了,说明数据是会存入内存中的;

      4)DMA_BufferSize:会自动识别,填写0也没问题;因为实际缓存多大取决于你实际使用时DMA1_Channel4->CNDTR的设定;

      5)USART_DMACmd():这个函数记得要打开,他在串口的.h文档中;

      6使用的方法就是我的第二段代码,先关闭DMA使能,再设定缓冲大小,再开启DMA使能;

      相信这些点你都注意了,串口就可以正常发送数据啦;希望能够帮助你。

      DMA的相关资料供大家参考

    - 深度剖析STM32:DMA专题讲解 -

    - 深度剖析STM32第四讲:DMA专题讲解 -

    stm32 如何用DMA搬运数据

    - 通信协议 - UART串口协议 -

    - STM32 USART串口的应用 -

    展开全文
  • 第一次写 希望各位博友指正 本次使用的是STM32F1的主控芯片,资料可在ST官网下载 DMA使用的目的:不用DMA发送...本次为了减少CPU的占用,在配置串口的时候使用DMA进行数据的收发。 不说 直接上干货!!! 本次使用的

    第一次写 希望各位博友指正

    本次使用的是STM32F1的主控芯片,资料可在ST官网下载
    DMA使用的目的:不用DMA发送是需要单片机实时参du与,由单片机一个一个地发送数据并进执行监控。但是如果用DMA,设置了起始地址,数据大小等参数后,就直接由专门的一个DMA模块进行数据发送,发送过程中单片机无需参与。发送完后会产生中断告知单片机。由此可知用DMA可以节省单片机资源,让单片可以在同一时间里干更多事。

    本次为了减少CPU的占用,在配置串口的时候使用DMA进行数据的收发。
    不多说 直接上干货!!!](https://img-blog.csdnimg.cn/20200729114624383.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1Mzg2OTQ2,size_16,color_FFFFFF,t_70)
    本次使用的DMA1的通道4和通道5,图中已标注。
    干货代码直接上:

    串口配置:

    unsigned char USART1_Tx_Buffer[USART_DMA_BUFFER_SIZE];
    unsigned char USART1_Rx_Buffer[USART_DMA_BUFFER_SIZE];
    unsigned char USART2_Tx_Buffer[USART_DMA_BUFFER_SIZE];
    unsigned char USART2_Rx_Buffer[USART_DMA_BUFFER_SIZE];
    #define	USART1_TX_PORT									GPIOA
    #define	USART1_TX_PIN									GPIO_Pin_9
    
    #define	USART1_RX_PORT									GPIOA
    #define	USART1_RX_PIN             						GPIO_Pin_10
    //语音模块通讯通道
    void USART1_Init(u16 BAUD)
    {
        GPIO_InitTypeDef GPIO_InitStructure;                      
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
    
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    
        USART_DeInit(USART1);
        //UART1_TX   									PA9
        GPIO_InitStructure.GPIO_Pin = USART1_TX_PIN;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(USART1_TX_PORT, &GPIO_InitStructure);
    
        //UART1_RX	  									PA10
        GPIO_InitStructure.GPIO_Pin = USART1_RX_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
        GPIO_Init(USART1_RX_PORT, &GPIO_InitStructure);
    
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//中断源
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
    
        USART_InitStructure.USART_BaudRate = BAUD;//可直接根据使用波特率大小直接设置 一般通常用9600
        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_Init(USART1, &USART_InitStructure);
    
        //IT config
        USART_ITConfig(USART1,USART_IT_TC,DISABLE);
        USART_ITConfig(USART1,USART_IT_RXNE,DISABLE);
        USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);//空闲中断 关系着后面的DMA配置
        USART_Cmd(USART1, ENABLE);
    
        USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
        USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
    }
    

    DMA配置

    void USART1_DMA_CONFIG(void)
    {
        DMA_InitTypeDef DMA_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
    
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
        DMA_DeInit(DMA1_Channel5);   //uart1 RX should use dma1 ch5
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;	// 初始化外设地址
        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_Rx_Buffer;	// 内存地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外设作为数据来源
        DMA_InitStructure.DMA_BufferSize = USART_DMA_BUFFER_SIZE ;	// 缓存容量
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;	// 外设地址不递增
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;	// 内存递增
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;	// 外设字节宽度
        DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;	// 内存字节宽度
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;	//正常模式,即满了就不在接收了,而不是循环存储
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;	//通道优先级高
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //内存与外设通信  而非内存到内存 
        DMA_Init(DMA1_Channel5, &DMA_InitStructure);
        DMA_Cmd(DMA1_Channel5,ENABLE);
    
        DMA_DeInit(DMA1_Channel4);	//uart1 TX should use dma1 ch4
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_Tx_Buffer;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //存储器作为数据来源
        DMA_InitStructure.DMA_BufferSize = USART_DMA_BUFFER_SIZE ;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel4, &DMA_InitStructure);
    
        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;//通道4作为中断源
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
    
        DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
    }
    
    
    ## 中断函数:
    void USART1_IRQHandler(void)//串口1的中断服务函数
    {
        uint32_t length;
    
        if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
        {
    
            length = USART1->SR;
            length = USART1->DR;
            length = length;
            DMA_Cmd(DMA1_Channel5,DISABLE);
    
            length = USART_DMA_BUFFER_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);
    
            USART_ClearITPendingBit(USART1, USART_IT_IDLE);
            DMA_SetCurrDataCounter(DMA1_Channel5,USART_DMA_BUFFER_SIZE);
            DMA_Cmd(DMA1_Channel5,ENABLE);
        }
    }
    void DMA1_Channel4_IRQHandler(void)//DMA通道4的中断服务函数
    {
        if(DMA_GetITStatus(DMA1_FLAG_TC4))
        {
            DMA_ClearFlag(DMA1_FLAG_GL4|DMA1_FLAG_TC4|DMA1_FLAG_TE4  );
            DMA_Cmd(DMA1_Channel4, DISABLE);
        }
    }
    

    特别强调:串口的空闲中断IDLE清除中断标志位和平常的接收发送中断标志位清除方法不一样,如代码上所写,先读取SR,再读取DR才能清除空闲中断标志位,而平常的接收发送中断只需要读取DR即可。

    其他辅助函数:

    //usart1发送函数
    void usart1_send_char(u8 data)
    {
        USART_SendData(USART1, (u8) data);
        while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
        {}
    }
    
    //usart1 dma发送函数
    void dma_usart1_send(int length)
    {
        DMA1_Channel4->CNDTR=length;//比如一共0-5 6个字节 数据 此时length=6 需要在第五个数据赋值后加1
        DMA_Cmd(DMA1_Channel4, ENABLE);
    }
    

    配置完成了现在就可以使用dma_usart1_send()函数发送所需要的的数据,如果接受数据使用的是DMA1的通道5,可用中断可不用

    遇到问题可随时交流,欢迎各位大佬指正,互相学习。

    展开全文
  • 该系统适合于超高速数据传输,具有电路简单、体积小等优点。FPGA技术与USB3.0的结合有极的灵活性和可扩展性,基于FPGA和USB3.0的突出优点,该设计方案必将应用在更广阔的领域。
  • 打开串口后,就开始了自动接收数据,接收完成后,按下“停 止接收数据”;如果要发送数据,请点击“发送键”,发送完成,会弹出“发送完成”。 软件测试情况:发送功能用“超级终端次测试”,10M内,没发生错误。...
  • 串口数据都有大量数据来时,我们如何最佳处理STM32串口通信数据? 可以通过FreeRTOS+队列的发送方式。 下面将串口DMA发送处理过程中心思想:1、建立一个的环形数组 2、发送的数据时,将数据存入到的数组 3...

    当多个串口数据都有大量数据来时,我们如何最佳处理STM32串口通信数据?
    可以通过FreeRTOS+队列的发送方式。
    下面将串口DMA发送处理过程
    中心思想:
    1、建立一个大的环形数组
    2、发送的数据时,将数据存入到大的数组
    3、需要发送数据的长度以及在大数组中的位置,通过队列,发送出去。
    4、通过队列,等待有数据进入队列。
    5、启动DMA,等待DMA传输完成。

    /******************************************************************
    将需要发送的数据存入一个大数组内,通过队列发送,将长度,以及数组内的地址
    发送出去。 数组的大小可以是队列项目数的N倍,一般5倍就好了,队列项目数5个
    已经不少了。
    即:假如创建5个队列消息,每个长度为4字节。数组大小 MAX_FRAME_COMM_BUFFER_SIZE 
    =5*每一次串口传输数据长度;
    static uint8_t txbuf_Blue_DMA[MAX_FRAME_COMM_BUFFER_SIZE]; /*缓存的数组大小*/
    DMA_MemoryBaseAddr=txbuf_Blue_tmp;
    *****************************************************************/
    void USART1_SendData(uint8_t *ps,uint16_t len)
    {
        uint16_t i;		
        BufferLoopData_Typedef buffer_loop;
        buffer_loop.start_addr = ps_tbwr_Blue;
        buffer_loop.len = len;
    
        for (i=0;i<len;i++)
        {
            if (ps_tbwr_Blue >= MAX_FRAME_COMM_BUFFER_SIZE)
            {
                ps_tbwr_Blue = 0;
            }        
            txbuf_Blue_DMA[ps_tbwr_Blue] = *(ps+i);//txbuf_Blue_DMA为
            ps_tbwr_Blue++;        
        }
        xQueueSendToBack(xQueue_Blue_tx,(void *)&buffer_loop,portMAX_DELAY);   
    }
    
    /******************************************************************
    队列接收到数据所在数组的地址以及长度,然后通过DMA发送出去
    *****************************************************************/
    void USART1_SendTask(void const * argument)
    {
        uint16_t i;
        BufferLoopData_Typedef buffer_loop;
        extern uint8_t txbuf_Blue_tmp[MAX_FRAME_COMM_LEN];   
          for (;;)
        {
            xQueueReceive(xQueue_Blue_tx,&buffer_loop,portMAX_DELAY);  
    		//SCB_CleanDCache();
            for (i=0;i<buffer_loop.len;i++)
            {
                if (buffer_loop.start_addr >= MAX_FRAME_COMM_BUFFER_SIZE)
                {
                    buffer_loop.start_addr = buffer_loop.start_addr - MAX_FRAME_COMM_BUFFER_SIZE;
                }
    
                txbuf_Blue_tmp[i] = txbuf_Blue_DMA[buffer_loop.start_addr];
                
                buffer_loop.start_addr += 1;
                
            }   
            //SCB_CleanInvalidateDCache();
            Uart1_DMASend_Start(&txbuf_Blue_tmp[0],buffer_loop.len);//通过DMA发送
            xSemaphoreTake(BinarySem_UART1_tx_finish_Handle,portMAX_DELAY); //等待DMA发送成功
            taskYIELD();  
        } 
    }
    

    串口DMA发送代码:

    /**********************************************************************
    串口USART1  DMA发送数据
    ********************************/
    uint8_t Uart1_DMASend_Start(uint8_t* buffer, u16 size)
    {
    	if(!size) return 0;
      while (DMA_GetCurrDataCounter(DMA1_Channel4));
      if(buffer) memcpy(txbuf_Blue_tmp, buffer,(size > 1024?1024:size));
    	
      //DMA发送数据,DMA
      DMA_Cmd(DMA1_Channel4, DISABLE);
      DMA1_Channel4->CNDTR = size;
      DMA_Cmd(DMA1_Channel4, ENABLE);  
      return size;
    }
    
    

    中断代码:
    //中断传输完成

    void DMA1_Channel4_IRQHandler(void)   
    {
    	portBASE_TYPE xHigherPriorityTaskWoken;
    	if(DMA_GetITStatus(DMA1_FLAG_TC4))
    	{
    		DMA_ClearFlag(DMA1_FLAG_TC4);
    		xSemaphoreGiveFromISR(BinarySem_UART1_tx_finish_Handle,&xHigherPriorityTaskWoken); 
    	}
    }
    

    串口初始化:

    USART_Config();
    UART_DMA_Config();
    	
    

    串口初始化详细代码

    //串口DMA初始化
    void UART_DMA_Config(void){
    	NVIC_InitTypeDef NVIC_InitStructure;
    
        DMA_Config(DMA1_Channel4,(u32)&USART1->DR,(u32)txbuf_Blue_tmp,DMA_DIR_PeripheralDST,DMA_Priority_Medium,0,DMA_Mode_Normal);
    //txbuf_Blue_tmp  USART1 DMA发送基地址
    	DMA_Config(DMA1_Channel5,(u32)&USART1->DR,(u32)rxbuf_Uart1_DMA,DMA_DIR_PeripheralSRC,DMA_Priority_Medium,MaxSize_FRAME_DISP,DMA_Mode_Circular);
      //rxbuf_Uart1_DMADMA接收基地址
      
    	//NVIC初始化
    	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=6 ;
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_Init(&NVIC_InitStructure);
    
    	DMA_ITConfig(DMA1_Channel4,DMA_IT_TC,ENABLE);
    	USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); 
    	USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
    
    	DMA_Cmd (USART_RX_DMA_CHANNEL,ENABLE);
    }
    
    //串口配置初始化
    void USART_Config(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	USART_InitTypeDef USART_InitStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2   Periph_AFIO, ENABLE);
    
    	//USART1_TX   GPIOA.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);
    
    	
       //USART1_RX GPIOA.10  
      	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=6 ;
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_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;
    	
    	USART_Init(USART1, &USART_InitStructure);
    	USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);
    	USART_Cmd(USART1, ENABLE);       
    }
    
    //DMA初始化 做成了一个封装函数
    void DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 PeripheralBaseAddr,u32 MemoryBaseAddr,u32 dma_dir,u32 priority,u16 bufsize,u32 mode)
    {
    	DMA_InitTypeDef DMA_InitStructure;
     	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
        DMA_DeInit(DMA_CHx);
       	DMA_InitStructure.DMA_PeripheralBaseAddr = PeripheralBaseAddr;
    	DMA_InitStructure.DMA_MemoryBaseAddr = MemoryBaseAddr;
    	DMA_InitStructure.DMA_DIR = dma_dir;
    	DMA_InitStructure.DMA_BufferSize = bufsize;
    	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    	DMA_InitStructure.DMA_Mode = mode;
    	DMA_InitStructure.DMA_Priority = priority;
    	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    	DMA_Init(DMA_CHx, &DMA_InitStructure);  
    } 
    
    

    下一篇文章来介绍如何通过DMA+FreeRTOS+IDLE接收数据

    展开全文
  • 紧接着上一篇文章,如何合理处理串口接收大量数据。此种方法,很厉害,很NB,首先,利用DMA 可节省大量CUP资源。其次,利用IDLE空闲中断来接收位置个数的数据。最后利用串口DMA环形数据的偏移量、长度,入队,出...

    紧接着上一篇文章,如何合理处理多个串口接收大量数据。此种方法,很厉害,很NB,首先,利用DMA 可节省大量CUP资源。其次,利用IDLE空闲中断来接收位置个数的数据。最后利用串口DMA环形数据的偏移量、长度,入队,出队处理数据。保证了任务的流畅处理。
    串口接收数据:
    中心思想
    1、开启DMA 环形接收数据模式。
    2、触发接收数据中断。
    3、假如数据有进来,将上面环形数据的偏移量与长度 入队。
    4、出队函数,处理数据。

    直接上代码
    两个任务完成
     

    #define MAX_FRAME_DISP_LEN       125       
    #define MAX_FRAME_DISP_ITEM      5         
    #define MaxSize_FRAME_DISP    (MAX_FRAME_DISP_LEN*MAX_FRAME_DISP_ITEM) 
    
    static void RecUart1Temp_Task(void* parameter)
    {	
    	uint16_t len;
    	uint16_t ndtr_last;//上次剩余个数
    	BufferLoopData_Typedef buffer_loop;
    	BaseType_t xReturn = pdPASS;	
    
    	buffer_loop.start_addr = 0;
    	buffer_loop.len = 0;
    	ndtr_last = MaxSize_FRAME_DISP;
            while (1)
            {
               //等待有数据消息
    	   xReturn = xSemaphoreTake(BinarySem_Handle,  portMAX_DELAY); 
    	   len = Reg_Usart1_CHANNEL_CNDTR;//DMA剩余个数
    	   //环形数组
    	   if (ndtr_last != len)//上次与这次不同,表示有新数据
    	   {
    		buffer_loop.start_addr = buffer_loop.start_addr + buffer_loop.len;
                    //环形数据地址偏移量
    		if (buffer_loop.start_addr >= MaxSize_FRAME_DISP)
    		{
    		     buffer_loop.start_addr = buffer_loop.start_addr - MaxSize_FRAME_DISP;
    		}	
    		if (ndtr_last > len)
    		{
    		    buffer_loop.len = ndtr_last - len;
                        //接收数据长度=上次长度-这次长度
    		}
    		else
    		{
    		    buffer_loop.len = MaxSize_FRAME_DISP  - len+ ndtr_last;
                        //环形数据到头后,总数-这次剩余+上次剩余
    		}
    
    		ndtr_last = len;
    					
    		if ((buffer_loop.len > 0)||(buffer_loop.len < MAX_FRAME_DISP_LEN))
    		{
    			xQueueSendToBack(xQueue_Smrj_rx,(void *)&buffer_loop,0);
    		}            
    	}
    	taskYIELD();        	
        }
    }
    
    

     任务出队,处理函数

    extern  uint8_t rxbuf_Uart1_DMA[MaxSize_FRAME_DISP]; 
    static void RecUart1DealTask(void* pvParameters)
    {
        uint16_t i;
        BufferLoopData_Typedef buffer_loop;   
        for (;;)
        {
            xQueueReceive(xQueue_Smrj_rx,&buffer_loop,portMAX_DELAY);  
            if ((buffer_loop.len > 0)&&(buffer_loop.len < MAX_FRAME_DISP_LEN))
            {
                for (i=0;i<buffer_loop.len;i++)
                {
                    if (buffer_loop.start_addr >= MaxSize_FRAME_DISP)
                    {
                        buffer_loop.start_addr = buffer_loop.start_addr - MaxSize_FRAME_DISP;
                    }
                    rxbuf_Uart1_tmp[i] = rxbuf_Uart1_DMA[buffer_loop.start_addr];                
                    buffer_loop.start_addr += 1;     
                }       
               __nop();
                /*此处处理接收的数据*/
                //Smrj_RecUserHandle(&rxbuf_Uart1_tmp[0],buffer_loop.len);
    	    //SMRJ_Data_Dec(&rxbuf_Smrj_tmp[0],buffer_loop.len);
            }
            taskYIELD(); 
        }  
    }
    

    中断处理函数:

    void USART1_IRQHandler(void)
    {
         uint32_t ulReturn;
         ulReturn = taskENTER_CRITICAL_FROM_ISR();
         if(USART_GetITStatus(DEBUG_USARTx,USART_IT_IDLE)!=RESET)
            {		
    		Uart_DMA_Rx_Data();   
    		USART_ReceiveData(DEBUG_USARTx); 
    		taskEXIT_CRITICAL_FROM_ISR( ulReturn );
             }
    }
    
    void Uart_DMA_Rx_Data(void)
    {
    	BaseType_t pxHigherPriorityTaskWoken;
    	DMA_Cmd(USART_RX_DMA_CHANNEL, DISABLE);      
    	DMA_ClearFlag( DMA1_FLAG_TC5 );          
            Reg_Usart1_CHANNEL_CNDTR=  USART_RX_DMA_CHANNEL->CNDTR;//循环数组里剩余个数
    	DMA_Cmd(USART_RX_DMA_CHANNEL, ENABLE);       
    	xSemaphoreGiveFromISR(BinarySem_Handle,&pxHigherPriorityTaskWoken);	
    	portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
    }
    
    

    串口初始化见上面一篇文章
    总结,从上面代码我们可以看到,我们是巧妙的利用的串口DMA环形模式,利用队列来处理数据。
    下一篇,我们直接利用环形缓存buf来实现数据的处理,是的更加的通用性。

    ————————————————
    版权声明:本文为CSDN博主「断雁孤鸿」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/oDuanYanGuHong/article/details/100576160

    展开全文
  • 串口数据协议解析

    万次阅读 2010-03-05 15:43:00
     一般来说,通过串口传输的单个数据包都不会太,否则,会导致数据被覆盖。对于通过串口传输的大数据,处理的办法是分割成个小的数据包。可能出现的情况是因为接收和读取的不同步,接收到的数据需要分为次读取...
  • 紧接着上一篇文章,如何合理处理串口接收大量数据。此种方法,很厉害,很NB可节省大量CUP资源。并且FreeRTOS任务处理的非常合理。 中心思想: 1、开启DMA 环形接收数据模式。 2、触发接收数据中断。 3、把...
  • 任何收发两端速度不一致的通讯,都需要在它们之间使用一个足够的FIFO缓冲区。 对任何FIFO缓冲区的使用,都需要仔细考虑接收端接收时超时无数据和发送端发送时FIFO缓冲区已...◆传输数据对应的每个字节到底的英文...
  • STM32 DMA接收串口数据

    2020-01-03 17:27:48
    当在串口多数据传输下,CPU会产生次中断来接收串口数据,这样会大大地降低CPU效率,同时又需要CPU去做其它更重要的事情,我们应该如何来优化? 比如四轴飞行器,当在不停地获取姿态控制方向时,又要去接收串口数据.答:...
  • 针对高速串口数据采集软件的设计要求,提出了基于线程技术和自定义消息机制的异步串口通信的设计思想.结合串口通信的机理和线程同步方式,分析了Win32系统下线程异步串口通信程序的开发方法.  1 引 言  串行...
  • 由于串行通讯方式具有使用线路少、成本低,特别是在远程传输时,避免了条线路特性的不一致而被广泛采用。在串行通讯时,要求通讯双方都采用一个标准接口,使不同的设备可以方便地连接起来进行通讯。RS-232-C接口...
  • 由于串口(COM)不支持热插拔及传输速率较低,目前部分新主板和部分便携电脑已取消该接口。现在串口多用于工业控制和测量设备以及部分通信设备中。 根据美国电子工业协会(EIA: Electronic Industry Associati...
  • 话不说进入正文,去年总是发文到微博也没几个人看,想来还是CSDN比较专业(老司机云集)。以后就在此混迹了,还望各位大佬多多提携 需求: 先说下用它来干嘛吧,众所周知2016年是VR的元年,头盔各种型号各种配置像...
  • 2一次性传输数据多、波特率高情况下,经常出现接受数据不完整、或者只能接受到很少一部分的数据。下面是针对这种情况的几种分析: (可能1):数据量太,缓冲区需要重新设计(不常见) (可能2)接收的数据较长,...
  • 描述:当在串口多数据传输下,CPU会产生次中断来接收串口数据,这样会大大地降低CPU效率,同时又需要CPU去做其它更重要的事情,我们应该如何来优化?比如四轴飞行器,当在不停地获取姿态控制方向时,又要去接收串口数据....
  • 要将现场控制网络和信息网络相连,就需要解决串口通信协议和因特网通信协议的转换问题,即把原有设备转换为具备网络接口的外设,这样可以将传统串行链路上的数据传输到信息网络上,而无需更换原有设备。如此,可以...
  • 当在串口多数据传输下,CPU会产生次中断来接收串口数据,这样会大大地降低CPU效率,同时又需要CPU去做其它更重要的事情,我们应该如何来优化? 比如四轴飞行器,当在不停地获取姿态控制方向时,又要去接收串口数据. 答...
  • 首先,我使用STM 32单片机有2 年左右的时间了,但是openmv却不足一个月的时间,由于近几天问我关于两者之间...openmv与单片机通讯,大多数时候都不是只发送一两个字符或数字,一般都需要进行大量数据传输,将识别到...
  • stm32数据传输

    2021-02-21 11:40:25
    DMA传输数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。它的作用就是解决大量数据转移过度消耗CPU资源的问题。 在stm32(容量)中有两个DMA,DMA1有7个...
  • STM32串口多机通信

    2020-10-17 23:44:53
    STM32 的UART数据寄存器是9位,数据传输先传低位(LSB)--实际应用发现9位数据时候有丢包错...利用USART可以进行机处理器通信,其原理就是使从机处于静默模式,由主机在需要的时候发送指令唤醒从机,并传输数据。STM
  • 该系统能够同时为8个串口设备提供以太网远程数据传输,为具有串行通信接口设备的网络控制提供了条件,实现了计算机远程监控。  目前工业领域中有大量的设备不具备以太网接口,但这些设备都提供RS-232串口或RS-...
  • 要将现场控制网络和信息网络相连,就需要解决串口通信协议和因特网通信协议的转换问题,即把原有设备转换为具备网络接口的外设,这样可以将传统串行链路上的数据传输到信息网络上,而无需更换原有设备。如此,可以...
  • DMA(Direct Memory Access)—直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数据,但是不需要占用 CPU,即在传输数据的时候,CPU 可以干其他的事情,好像是线程一样。 数据传输支持从外设到存储器或者...
  • Arduino串口缓冲区默认为64字节,如果你单次传输数据可以将arduino-1.0.5-r2\hardware\arduino\cores\arduino\HardwareSerial.cpp中的  #define SERIAL_BUFFER_SIZE 64  修改为 #define SERIAL_BUFFER_...
  • 摘要:在现代电子行业中无线通讯技术的应用越来越广泛,红外通讯作为无线通讯的一种技术备受各个领域的欢迎。...红外通讯以红外线作为通讯载体,通过红外光在空中的传播来传输数据,它由红外发射器和红外接收器来完

空空如也

空空如也

1 2 3 4 5 ... 17
收藏数 327
精华内容 130
关键字:

串口传输数据多大