1、前言
蓝桥杯的国赛会遇到多路AD采集的情况,这时候之前的单路采集的方式就不可用了,下面介绍两种多路采集的方式。
以第13届国赛为例
2、方法一(配置通道)
2.1 使用CubeMx配置
设置IN13与IN17为Single-ended
在Parameter Settings中
设置Clock Prescaler为Asynchronous clock mode divided by 2
设置Rank-Sampling Time为640.6 Cycles
2.2 bsp_adc.h代码编写
#include "main.h"extern ADC_HandleTypeDef hadc2;void ADC2_Init(void);uint32_t Get_Adc(void);uint32_t Get_PA4(void);
uint32_t Get_PA5(void);
2.3 bsp_adc.c代码编写
每次进行adc采集之前,重新配置一遍参数
ADC_ChannelConfTypeDef sConfig = {0};sConfig.Channel = ADC_CHANNEL_17;sConfig.Rank = ADC_REGULAR_RANK_1;sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;sConfig.SingleDiff = ADC_SINGLE_ENDED;sConfig.OffsetNumber = ADC_OFFSET_NONE;sConfig.Offset = 0;if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK){Error_Handler();}GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_4;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
记住不要重复进行RCC的配置,否侧会卡死
//这两个,不用加了
__HAL_RCC_ADC12_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();
2.3.1 完整代码
#include "ADC/bsp_adc.h"
/********************************************************************************* @file adc.c* @brief This file provides code for the configuration* of the ADC instances.******************************************************************************* @attention** <h2><center>© Copyright (c) 2024 STMicroelectronics.* All rights reserved.</center></h2>** This software component is licensed by ST under BSD 3-Clause license,* the "License"; You may not use this file except in compliance with the* License. You may obtain a copy of the License at:* opensource.org/licenses/BSD-3-Clause********************************************************************************//* Includes ------------------------------------------------------------------*//* USER CODE BEGIN 0 *//* USER CODE END 0 */ADC_HandleTypeDef hadc2;/* ADC2 init function */
void ADC2_Init(void)
{/* USER CODE BEGIN ADC2_Init 0 *//* USER CODE END ADC2_Init 0 */ADC_ChannelConfTypeDef sConfig = {0};/* USER CODE BEGIN ADC2_Init 1 *//* USER CODE END ADC2_Init 1 *//** Common config*/hadc2.Instance = ADC2;hadc2.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;hadc2.Init.Resolution = ADC_RESOLUTION_12B;hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;hadc2.Init.GainCompensation = 0;hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;hadc2.Init.LowPowerAutoWait = DISABLE;hadc2.Init.ContinuousConvMode = DISABLE;hadc2.Init.NbrOfConversion = 1;hadc2.Init.DiscontinuousConvMode = DISABLE;hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;hadc2.Init.DMAContinuousRequests = DISABLE;hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED;hadc2.Init.OversamplingMode = DISABLE;if (HAL_ADC_Init(&hadc2) != HAL_OK){Error_Handler();}/** Configure Regular Channel*/sConfig.Channel = ADC_CHANNEL_17;sConfig.Rank = ADC_REGULAR_RANK_1;sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;sConfig.SingleDiff = ADC_SINGLE_ENDED;sConfig.OffsetNumber = ADC_OFFSET_NONE;sConfig.Offset = 0;if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK){Error_Handler();}/* USER CODE BEGIN ADC2_Init 2 *//* USER CODE END ADC2_Init 2 */}void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(adcHandle->Instance==ADC2){/* USER CODE BEGIN ADC2_MspInit 0 *//* USER CODE END ADC2_MspInit 0 *//* ADC2 clock enable */__HAL_RCC_ADC12_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/**ADC2 GPIO ConfigurationPA4 ------> ADC2_IN17PA5 ------> ADC2_IN13*/GPIO_InitStruct.Pin = GPIO_PIN_4;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* USER CODE BEGIN ADC2_MspInit 1 *//* USER CODE END ADC2_MspInit 1 */}
}void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{if(adcHandle->Instance==ADC2){/* USER CODE BEGIN ADC2_MspDeInit 0 *//* USER CODE END ADC2_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_ADC12_CLK_DISABLE();/**ADC2 GPIO ConfigurationPA4 ------> ADC2_IN17PA5 ------> ADC2_IN13*/HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4);/* USER CODE BEGIN ADC2_MspDeInit 1 *//* USER CODE END ADC2_MspDeInit 1 */}
}uint32_t Get_Adc(void)
{uint32_t Adc_Value;HAL_ADC_Start(&hadc2);HAL_Delay(1);Adc_Value = HAL_ADC_GetValue(&hadc2);return Adc_Value;
}
uint32_t Get_PA4(void)
{ADC_ChannelConfTypeDef sConfig = {0};sConfig.Channel = ADC_CHANNEL_17;sConfig.Rank = ADC_REGULAR_RANK_1;sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;sConfig.SingleDiff = ADC_SINGLE_ENDED;sConfig.OffsetNumber = ADC_OFFSET_NONE;sConfig.Offset = 0;if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK){Error_Handler();}GPIO_InitTypeDef GPIO_InitStruct = {0};/**ADC2 GPIO ConfigurationPA4 ------> ADC2_IN17PA5 ------> ADC2_IN13*/GPIO_InitStruct.Pin = GPIO_PIN_4;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);return Get_Adc();
}
uint32_t Get_PA5(void)
{ADC_ChannelConfTypeDef sConfig = {0};sConfig.Channel = ADC_CHANNEL_13;sConfig.Rank = ADC_REGULAR_RANK_1;sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;sConfig.SingleDiff = ADC_SINGLE_ENDED;sConfig.OffsetNumber = ADC_OFFSET_NONE;sConfig.Offset = 0;if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK){Error_Handler();}GPIO_InitTypeDef GPIO_InitStruct = {0};/**ADC2 GPIO ConfigurationPA4 ------> ADC2_IN17PA5 ------> ADC2_IN13*/GPIO_InitStruct.Pin = GPIO_PIN_5;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);return Get_Adc();
}/* USER CODE BEGIN 1 *//* USER CODE END 1 *//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
2.4 测试
测试结果表明实验成功。
3、方法二(扫描模式)
3.1 使用CubeMx配置
设置IN13与IN17为Single-ended
在Parameter Settings中
设置Clock Prescaler为Synchronous clock mode divided by 2
这里要将Number Of Conversion设置为2
这样就可以采集两个不同的通道了
3.2 bsp_adc.h代码编写
因为需要循环采集两个ADC值,所以GetADC函数的参数是一个uint32_t指针类型
#include "main.h"extern ADC_HandleTypeDef hadc2;void ADC2_Init(void);
void GetADC(uint32_t *ADC_Val);
3.3 bsp_adc.c代码编写
HAL_ADC_Start之后,在for循环内进行连续的HAL_ADC_GetValue,在这之前先等待一下不然可能出现通道AD对应错误的情况。
void GetADC(uint32_t *ADC_Val)
{HAL_ADC_Start(&hadc2);int i;for(i=0;i<2;i++){HAL_Delay(1);ADC_Val[i] = HAL_ADC_GetValue(&hadc2);}
}
3.3.1 完整代码
#include "ADC/bsp_adc.h"
ADC_HandleTypeDef hadc2;
void ADC2_Init(void)
{/* USER CODE BEGIN ADC2_Init 0 *//* USER CODE END ADC2_Init 0 */ADC_ChannelConfTypeDef sConfig = {0};/* USER CODE BEGIN ADC2_Init 1 *//* USER CODE END ADC2_Init 1 *//** Common config*/hadc2.Instance = ADC2;hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;hadc2.Init.Resolution = ADC_RESOLUTION_12B;hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;hadc2.Init.GainCompensation = 0;hadc2.Init.ScanConvMode = ADC_SCAN_ENABLE;hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;hadc2.Init.LowPowerAutoWait = DISABLE;hadc2.Init.ContinuousConvMode = DISABLE;hadc2.Init.NbrOfConversion = 2;hadc2.Init.DiscontinuousConvMode = DISABLE;hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;hadc2.Init.DMAContinuousRequests = DISABLE;hadc2.Init.Overrun = ADC_OVR_DATA_PRESERVED;hadc2.Init.OversamplingMode = DISABLE;if (HAL_ADC_Init(&hadc2) != HAL_OK){Error_Handler();}/** Configure Regular Channel*/sConfig.Channel = ADC_CHANNEL_17;sConfig.Rank = ADC_REGULAR_RANK_1;sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;sConfig.SingleDiff = ADC_SINGLE_ENDED;sConfig.OffsetNumber = ADC_OFFSET_NONE;sConfig.Offset = 0;if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK){Error_Handler();}/** Configure Regular Channel*/sConfig.Channel = ADC_CHANNEL_13;sConfig.Rank = ADC_REGULAR_RANK_2;if (HAL_ADC_ConfigChannel(&hadc2, &sConfig) != HAL_OK){Error_Handler();}/* USER CODE BEGIN ADC2_Init 2 *//* USER CODE END ADC2_Init 2 */}void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(adcHandle->Instance==ADC2){/* USER CODE BEGIN ADC2_MspInit 0 *//* USER CODE END ADC2_MspInit 0 *//* ADC2 clock enable */__HAL_RCC_ADC12_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/**ADC2 GPIO ConfigurationPA4 ------> ADC2_IN17PA5 ------> ADC2_IN13*/GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* USER CODE BEGIN ADC2_MspInit 1 *//* USER CODE END ADC2_MspInit 1 */}
}void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{if(adcHandle->Instance==ADC2){/* USER CODE BEGIN ADC2_MspDeInit 0 *//* USER CODE END ADC2_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_ADC12_CLK_DISABLE();/**ADC2 GPIO ConfigurationPA4 ------> ADC2_IN17PA5 ------> ADC2_IN13*/HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4|GPIO_PIN_5);/* USER CODE BEGIN ADC2_MspDeInit 1 *//* USER CODE END ADC2_MspDeInit 1 */}
}void GetADC(uint32_t *ADC_Val)
{HAL_ADC_Start(&hadc2);int i;for(i=0;i<2;i++){HAL_Delay(1);ADC_Val[i] = HAL_ADC_GetValue(&hadc2);}
}
3.4 测试
测试结果表明实验成功。
4、总结
本文介绍了两种不同的AD多通道采集的办法,并实现了相关代码以及进行了验证,效果表明成功实现了多路的AD采集功能。