查看: 2098|回复: 1
打印 上一主题 下一主题

USART&DMA乒乓操作接收任意长度数据

[复制链接]
跳转到指定楼层
沙发
发表于 2016-6-22 18:57:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
RT,相关说明都是在工程内部。
/**
  ******************************************************************************
  * @file    USART.h
  * @author  
  * @version 0.1
  * @date    1-Dec-2012
  * @brief   
  ******************************************************************************
  * @attention
  *
  *
  *
  ******************************************************************************
  */

/** @addtogroup User
  * @{
  */
  
/**
  * @brief Define to prevent recursive inclusion
  */
#ifndef __USART_H
#define __USART_H

#ifdef __cplusplus
extern "C" {
#endif

#include "stm32f10x.h"

#define USEUSART2
   
#define USART_BufferChannel 8
#define USART_BufferChannelVal  0x1<<(USART_BufferChannel-1)
   
#define USART_BufferLength 512   
   

/* 整个结构体对内核而言都是只读的,内核不能进行任何写操作 */
  typedef struct
  {
    /* 表示当前通道数据准备完成,可以被CPU读出 */
    /* EG. 0x1表示通道1数据可读,0x2表示通道2数据可读,0X4表示通道3数据可读 */
   
    uint32_t RecBufChaRdy;
   
    /* 表示当前通道是否被选中作为注入通道 */
    /* EG.0x4,表示被选中的是通道3 */
   
    uint32_t RecBufPingPang;
   
    /* 表示该通道由于硬件原因导致数据错误 */
   
    uint32_t RecBufChaErr;
   
    /* 数据溢出,标志为READY的通道未在规定的时间移出,而新的数据需要使用该通道。*/
   
    ErrorStatus RecBufOverFlow;
   
    /* 缓冲区 */
    uint8_t RecBuf[USART_BufferChannel][USART_BufferLength];
   
    uint16_t RecBufValLen[USART_BufferChannel];
  } USARTRecBufDef;
  
  #if defined USEUSART1
  extern USARTRecBufDef USART1Buf;
#endif
#if defined USEUSART2
  extern USARTRecBufDef USART2Buf;
#endif
#if defined USEUSART3
  extern USARTRecBufDef USART3Buf;
#endif
#if defined USEUART4
  extern USARTRecBufDef UART4Buf;
#endif
#if defined USEUART5
  extern USARTRecBufDef UART5Buf;
#endif

  
  void StdPeriphUSART1Init(void);
  void StdPeriphUSART2Init(void);
  void StdPeriphUSART3Init(void);
  void StdPeriphUART4Init(void);
  void StdPeriphUART5Init(void);
  
  void USART1_IRQHandler(void);
  void USART2_IRQHandler(void);
  void USART3_IRQHandler(void);
  void UART4_IRQHandler(void);
  void UART5_IRQHandler(void);
/* Private define ------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/         
/* Private functions ---------------------------------------------------------*/
#ifdef __cplusplus
}
#endif

#endif /*__USART_H */

/**
  * @}
  */
  
/**
  * @}
  */  
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/


/**
  ******************************************************************************
  * @file    usart.c
  * @author  Author
  * @version V0.1
  * @date    01-DEC-2012
  * @brief   usart LIB body
  ******************************************************************************
  * @attention: 接受未知长度的数据,只有一个起点,即串口数据接受中断,在此函数中
  *             初始化DMA开始传输。终点无非两个,一,DMA没有接受完成,串口进入总  
  *             线空闲中断,在空闲中断中获取收到的数据量,然后结束DMA传输,二,
  *             DMA接受完成,进入DMA接收完成中断,关闭DMA接收。
  *             在其中涉及到了各种中断的切换,一,触发串口接收中断后,关串口接收
  *             中断,打开串口总线空闲中断和DMA传输完成中断。二,进入DMA完成中断
  *             后,关闭总线空闲中断,打开串口接收中断,准备下一次接收,同时结束
  *             本次DMA传输。三,如果进入了总线空闲中断,打开串口接收中断,准备
  *             下一次接收,同时结束本次DMA传输。
  *             考虑到HEX数据流,缓冲结构体内引入了指示有效数据长度的变量。
  *             缓冲结构体内引入了乒乓操作,数据被依次注入到结构体中的缓冲数组内
  *             。同时为了指示通道的可读性,引入了标志位。结构体内的标志位对CPU
  *             来说都是“只读”的,修改将导致错误。
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "USART.h"
#include "DMA.h"
/** @addtogroup User
  * @{
  */
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/******************************************************************************/
/*         USART OR UART on board initialization and Exception Handler        */
/******************************************************************************/

USARTRecBufDef  USART2Buf = { 0,1,0,SUCCESS,{{0}} };

/**
  * @brief  StdPeriphUSART2Init program.
  * @param  None
  * @retval None
  */
void StdPeriphUSART2Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  /* Enable CLK */        
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
        
  /* Configurate GPIO */
    /* Configurate GPIOA_PIN9 as TX pin of USART2 */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Speed        = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA,&GPIO_InitStructure);
    /* Configurate GPIOA_PIN10 as RX pin of USART2 */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Speed        = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;;
  GPIO_Init(GPIOA,&GPIO_InitStructure);
        
  /* USART2 Initil        */
  USART_InitStructure.USART_BaudRate = 115200;
  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(USART2,&USART_InitStructure);
  
  USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
  USART_ClearFlag(USART2,USART_FLAG_RXNE);
  USART_ClearFlag(USART2,USART_FLAG_TC);
  
  USART_DMACmd(USART2,USART_DMAReq_Tx|USART_DMAReq_Rx,ENABLE);
  
  USART_Cmd(USART2,ENABLE);
}
/**
  * @brief  This function handles USART2 interrupt request.
  * @param  None
  * @retval None
  */
void USART2_IRQHandler(void)
{
  uint16_t index=0;
  uint16_t buffer=0;
  if(USART_GetITStatus(USART2,USART_IT_RXNE))
  {
    /* 清除中断挂起 */
    USART_ClearITPendingBit(USART2,USART_IT_RXNE);
    /* 屏蔽接收中断,开启IDLE中断 */
    USART_ITConfig(USART2,USART_IT_RXNE,DISABLE);
    USART_ITConfig(USART2,USART_IT_IDLE,ENABLE);
    /* 初始化DMA接受数据 */
    StdPeriphDMA1Channel6Init();
  }
  else if(USART_GetITStatus(USART2,USART_IT_IDLE))
  {
    /* 清除中断挂起 */
    USART_ClearITPendingBit(USART2,USART_IT_IDLE);
    /* 接收完成,恢复接收中断,准备下一次接受 */
    USART_ITConfig(USART2,USART_IT_IDLE,DISABLE);
    USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
   
    /* 获取当前通道号 */
    while(USART2Buf.RecBufPingPang>>index!=0)
      index++;
    /* 获取当前通道号的剩余空间 */
    buffer=DMA_GetCurrDataCounter(DMA1_Channel6);

    /* 设置新数据的长度 */
    USART2Buf.RecBufValLen[index-1] = USART_BufferLength-buffer;
    /* 将当前通道号设置可读 */
    USART2Buf.RecBufChaRdy |= USART2Buf.RecBufPingPang;
    /* 停止DMA传输 */
    DMA_DeInit(DMA1_Channel6);   
  }
}
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
/**
  ******************************************************************************
  * @file    dma.c
  * @author  Author
  * @version V0.1
  * @date    01-DEC-2012
  * @brief   usart LIB body
  ******************************************************************************
  * @attention:乒乓操作位总是指向被注入的通道,当该通道被选中注入后,通道可读被
  *             复位,直到在DMA接受中断和IDLE中断中结束本次传输后,会重新被设置
  *             可读。乒乓操作位,总是在DMA接收完成中断中被移位,指向下一个通道。
  *            
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "DMA.h"
#include "USART.h"
/** @addtogroup User
  * @{
  */
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/******************************************************************************/
/*         DMA Initialization and Exception Handler        */
/******************************************************************************/
/**
  * @brief  StdPeriphDMA1Channel6Init program.
  * @param  None
  * @retval None
  */
void StdPeriphDMA1Channel6Init(void)
{
  uint16_t index = 0;
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  DMA_InitTypeDef DMA_InitStructure;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  /* 分配注入通道,确定通道内的剩余空间 */
  {
  /* 获取当前通道号 */
  while(USART2Buf.RecBufPingPang>>index!=0)
    index++;
  /* 将当前通道号置忙 */
  USART2Buf.RecBufChaRdy &= ~USART2Buf.RecBufPingPang;
  /* 如果当前通道是正在使用的通道,继续注入数据,如果是过期通道清空数据*/
  if(USART2Buf.RecBufValLen[index-1] == USART_BufferLength)
    USART2Buf.RecBufValLen[index-1]=0;
  else
    USART2Buf.RecBufValLen[index-1]=USART2Buf.RecBufValLen[index-1];
  }
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART2Buf.RecBuf[index-1]+ (uint32_t)USART2Buf.RecBufValLen[index-1];
  DMA_InitStructure.DMA_BufferSize = USART_BufferLength - (uint32_t)USART2Buf.RecBufValLen[index-1];
   
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_PeripheralBaseAddr = USART2_BASE + 0X04;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
  DMA_Init(DMA1_Channel6,&DMA_InitStructure);   
  DMA_ITConfig(DMA1_Channel6,DMA_IT_TC,ENABLE);
  DMA_Cmd(DMA1_Channel6,ENABLE);
}
/**
  * @brief  DMA1_Channel6 Exception Handler.
  * @param  None
  * @retval None
  */
void DMA1_Channel6_IRQHandler(void)
{
  uint16_t index = 0;
  if(DMA_GetITStatus(DMA1_IT_TC6))
  {
    /* 清除中断挂起 */
    DMA_ClearITPendingBit(DMA1_IT_TC6);

    /* 获取当前通道号 */
    while(USART2Buf.RecBufPingPang>>index!=0)
      index++;  
    /* 当前的通道号存储结束,设置有效数据大小 */
    USART2Buf.RecBufValLen[index-1] = USART_BufferLength;
    /* 将当前通道号设置可读 */
    USART2Buf.RecBufChaRdy |= USART2Buf.RecBufPingPang;
    /* 指向下一个通道号 */
    if(USART2Buf.RecBufPingPang==USART_BufferChannelVal)
      USART2Buf.RecBufPingPang=0x1;
    else
      USART2Buf.RecBufPingPang<<=0x1;   
    DMA_DeInit(DMA1_Channel6);
    /* 关闭IDLE中断,打开接收中断,为下一次数据准备,如果产生DMA传输中断的同时*/
    /* 又触发了总线空闲中断,即,通道填满后数据流恰好结束 ,如果不禁止IDLE中断*/
    /* 就会发生两次接收结束,两个函数都处理了数据就会导致错误 */
    USART_ITConfig(USART2,USART_IT_IDLE,DISABLE);
    USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
  }
}   



/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

/**
  ******************************************************************************
  * @file    NVIC.c
  * @author  Author
  * @version V0.1
  * @date    02-DEC-2012
  * @brief   usart LIB body
  ******************************************************************************
  * @attention
  *
  *
  *
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "NVIC.h"

/** @addtogroup User
  * @{
  */
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/******************************************************************************/
/*                              NVIC Initialization                           */
/******************************************************************************/
void StdPeriphNVICInit(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 15;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_Init(&NVIC_InitStructure);  
  
  
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn ;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 14;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_Init(&NVIC_InitStructure);
}






/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

/**
  ******************************************************************************
  * @file    main.c
  * @author  MCD Application Team
  * @version V3.5.0
  * @date    08-April-2011
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
  ******************************************************************************
  */  

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdio.h>
#include <string.h>

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#include "USART.h"
#include "DMA.h"
#include "NVIC.h"
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
int main(void)
{
  SystemInit(); /* If the hse can not startup successful,you can add your code in the end of this function.*/
  /* Add your application code here */

  StdPeriphUSART2Init();
  StdPeriphNVICInit();

        
  /* Infinite loop */
  while (1)
  {           
  }
}
/**
  * @brief  
  * @param  
  * @retval
  */

#ifdef  USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

/**
  * @}
  */


/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入中科因仑

本版积分规则

快速回复 返回顶部 返回列表