我之前写过三篇有关ADC的文章。ADC构件制作,代码是基于STM32L431芯片。HAL ADC 代码基于STM32F103芯片。这两篇都属于单通道单次转换模式,独立ADC模式通过轮询(poll)方式完成ADC采样。后来写的第三篇ADC文章——High-resolution timer ,HRTIM(二),代码基于STM32G474,这篇文章属于Dual ADC模式,PWM中心触发ADC采样,DMA进行数据传输。前两篇属于软件触发ADC采样,第三篇属于通过硬件事件触发ADC采样。同时,第一篇属于Independent ADC,后两篇属于Dual ADC。本篇文章,将在STM32F103芯片上,分别实现Independent ADC+DMA+ Software,Dual ADC+DMA+Software/Hardware Trigger。
1.1 Independent ADC+DMA+ Software
独立ADC模式,我选择ADC1模块,5,7,9,15通道(PTA5,PTA7,PTC5,PTB1引脚),并采用DMA进行半字传输(每次传输2个字节,一个通道数据)。进行数据演示,CubeIDE配置如下图。
int main(void)
{
/* USER CODE BEGIN 1 */
extern int adcSampleCount;
uint32_t volArr[4]={0};
/* 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_TIM1_Init();
MX_USART1_UART_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
printf("indepent adc 0711\r\n");
printf(" start dma adc\r\n");
/* USER CODE END 2 */
HAL_ADCEx_Calibration_Start(&hadc1); //adc calibration,must add
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1,100);
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)gAdcSampleBuf,4); //16
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(500);
// HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4);
printf("independent adc test %d\r\n",adcSampleCount);
for(int i=0;i<4;i++){
printf("adc[%d]=%d ",i,gAdcSampleBuf[i]);
}
printf("\n");
HAL_ADC_Start(&hadc1); //开启新一轮ADC采样,must
}
}
1.2 Dual ADC+DMA+Software
dual ADC模式下,ADC1作为主ADC,ADC2作为从ADC,分别开启2个通道,一次传输一个字,2个通道数据。主模块数据在低16位,从模块数据在高16位,这一点和STM32G474芯片不同。而且,单次转换结束后,需要分别开启ADC1,ADC2模块。开启DMA的方式也与独立ADC模式调用的函数不同。规则转换模式下的External Trigger Conversion Source选项需要配置为软件触发选项。
int main(void)
{
/* USER CODE BEGIN 1 */
// extern int adcSampleCount;
uint32_t volArr[4]={0};
/* 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_TIM1_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
MX_ADC1_Init();
MX_TIM8_Init();
MX_TIM2_Init();
MX_ADC2_Init();
/* USER CODE BEGIN 2 */
printf("pwm & dual adc,software as trigger\r\n");
test_PWM_ADC_init();
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADCEx_Calibration_Start(&hadc2);
HAL_ADC_Start(&hadc1);
HAL_ADC_Start(&hadc2);
HAL_ADC_PollForConversion(&hadc1,100);
volArr[0]=0;
volArr[1]=0;
HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t *)volArr,2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(500);
// HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_4);
// printf("dual adc test %d\r\n",adcSampleCount);
printf("dual adc,software as trigger\r\n");
for(int i=0;i<2;i++){
// printf("volArr[%d] %d %d %x ",i,(volArr[i]>>16),volArr[i]&0xFFFF,volArr[i]);
printf("volArr[%d] %d %d ",i,(int)(volArr[i]>>16),(int)volArr[i]&0xFFFF);
}
printf("\n");
// HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t *)volArr,2);
HAL_ADC_Start(&hadc1);
HAL_ADC_Start(&hadc2);
// LL_ADC_REG_StartConversion(ADC1);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
1.3 Dual ADC+DMA +Hardware Trigger
Dual ADC 硬件触发ADC转换,我这里选择的转换源为Timer1 Capture Compare 3 Event。为此,需要再配置TIM1模块。此外,必须开启Timer1定时器3通道的输出功能,否则无法触发ADC采样。另外,设置TIM1模块3通道占空比,会改变adc数据的传输顺序,很奇怪,需要再看芯片手册。
int main(void)
{
/* USER CODE BEGIN 1 */
extern int adcSampleCount;
uint32_t volArr[4]={0};
/* 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_TIM1_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
MX_ADC1_Init();
MX_ADC2_Init();
/* USER CODE BEGIN 2 */
printf("pwm & dual adc,external trigger event test\r\n");
test_PWM_ADC_init();
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADCEx_Calibration_Start(&hadc2);
HAL_ADC_Start(&hadc1);
HAL_ADC_Start(&hadc2);
HAL_ADC_PollForConversion(&hadc1,100);
volArr[0]=0;
volArr[1]=0;
HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t *)volArr,2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(500);
printf("external trigger event test\r\n");
for(int i=0;i<2;i++){
printf("volData[%d] %d %d ",i,(int)(volArr[i]>>16),(int)volArr[i]&0xFFFF);
}
printf("\n");
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
......
void test_PWM_ADC_init(void)
{
int PWM_PERIOD = 319;
// HAL_TIM_PWM_Init(&htim1);
HAL_TIM_Base_Start(&htim1);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3); //must
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,0.2*PWM_PERIOD);
__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_3,0.6*PWM_PERIOD); // affect adc data order
}
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM1){
HAL_ADC_Start(&hadc1);
HAL_ADC_Start(&hadc2);
}
}
.....