欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32CubeMX ADC多通道DMA(循环传输Circular,单次Normal)

程序员文章站 2024-02-21 21:27:28
...

Cube配置
STM32CubeMX ADC多通道DMA(循环传输Circular,单次Normal)
代码

uint16_t AD_Value[20];
//main.c文件
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)AD_Value,20);

上面配置如果是word,则更改一下定义就好了,cube生成的代码会随着变:

uint32_t AD_Value[20];
//main.c文件
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)AD_Value,20);

分析一下函数原型

HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length)

有网友就简单看到原型是uint32_t就认为必须是32位了,其实ad只有12位,数据定义成16位才是物尽其用。产生这个试验想法是基于std库用过一次就是16位的,另外uint16_t AD_Value[20]也可以换成二维数组uint16_t AD_Value[10][2],二者本质没什么区别,好处是通道更多了就只需要改变第二个下标就行了,再其他地方处理AD数据的时候也很方便。
采样的数据:
STM32CubeMX ADC多通道DMA(循环传输Circular,单次Normal)
再来看看normal模式吧(调试遇到问题了)
代码如下

/* USER CODE BEGIN 0 */
uint16_t AD_Value[20];
uint8_t Rec_Flag;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	Rec_Flag=1;
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	HAL_ADC_Start_DMA(&hadc1,(uint32_t *)AD_Value,20);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		if(Rec_Flag==1)
		{
			Rec_Flag=0;
			HAL_ADC_Start_DMA(&hadc1,(uint32_t *)AD_Value,20);
		}
		HAL_Delay(500);
  }
  /* USER CODE END 3 */
}

STM32CubeMX ADC多通道DMA(循环传输Circular,单次Normal)
补贴:
Normal模式下,结果多次尝试,最终解决了
讨论一下单次传输的好处:DMA传输的时候如果读取内存片段,会有仲裁器的问题,在以前做过FFT的例子中,需要获取一个连续间隔的AD,如取1024点,假设前面的500个点是DMA刚传输的,而后面的点是上个时刻的数据,电压数据导出到excel显示波形就有断点,但这并不影响FFT本身,前后是循环是接在一起的,出现误差的影响的是恰好500这个点会有时钟偏差(影响不太大,最多一个时钟周期,可查阅相关数据手册)。采集直流信号二者无差别!
加了一句关闭DMA的语句,更改后代码如下

/* USER CODE BEGIN 0 */
uint16_t AD_Value[20];
uint8_t Rec_Flag;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	Rec_Flag=1;
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	HAL_ADC_Start_DMA(&hadc1,(uint32_t *)AD_Value,20);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		if(Rec_Flag==1)
		{
			Rec_Flag=0;
			HAL_ADC_Stop_DMA(&hadc1);
			HAL_ADC_Start_DMA(&hadc1,(uint32_t *)AD_Value,20);
		}
		HAL_Delay(500);
  }
  /* USER CODE END 3 */
}

欢迎交流,Q:aaa@qq.com