正点原子STM32H743单片机实现ADC多通道检测

发布于:2025-06-29 ⋅ 阅读:(21) ⋅ 点赞:(0)

目标

使用STM32CubeMX工具,配置ADC相关参数,实现在STM32H743单片机上获取ADC多通道电压值。共14个ADC引脚,ADC2有5个,ADC3有9个,全部设置单通道

ADC引脚

PF3
PF4
PF5
PF10
PC0
PC2
PC3
PH2
PH3
PA3
PB0
PB1
PA4
PA5
PA6

 STM32cubeMX配置ADC

ADC2配置5个模拟输入IO,多通道轮询,配置各通道参数,使能中断

ADC3配置9个模拟输入IO,多通道轮询,配置各通道参数,使能中断

  时钟频率配置

在处理ADC时发现ADC时钟配置需要处理,可能默认即可,这里试了下是没问题的,一开始使用的HSE作为ADC时钟,导致无法获取ADC参数。在ADC3的属性配置中,Resolution对应12位分辨率有可能错误,如果有问题可以尝试加大改为16位分辨率,不过改动分辨率之后,在代码中就需要修改对应的算法,即12位算法(电压值= adc值*参考电压/2的12次方-1),16位算法(电压值= adc值*参考电压/2的16次方-1)。

 代码

启动adc转换前必须先校准adc,在HAL_ADC_ConvCpltCallback中断回调函数中,处理对应ADC的代码,由于HAL_ADC_Start_IT调用后会一直不间断轮询,通过HAL_ADC_GetValue函数可直接获取ADC值,HAL_ADC_Stop_IT函数作用关闭当前ADC转换。

#define ADC2_CHANNELS 5
#define ADC3_CHANNELS 9

uint16_t adc2_values[ADC2_CHANNELS];
uint16_t adc3_values[ADC3_CHANNELS];
volatile uint8_t adc_ready = 0; // 数据就绪标志位

void Start_ADC2_DMA(void) {
	/* 初始化后校准ADC */
	HAL_ADCEx_Calibration_Start(&hadc2, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED); // 执行ADC校准

	/* 启动ADC连续转换(不间断轮询) */
	HAL_ADC_Start_IT(&hadc2);
}

void Start_ADC3_DMA(void) {
	/* 初始化后校准ADC */
	HAL_ADCEx_Calibration_Start(&hadc3, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED); // 执行ADC校准

	/* 启动ADC连续转换(不间断轮询) */
	HAL_ADC_Start_IT(&hadc3);
}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
	if (hadc->Instance == ADC2)  // 确认是ADC2的转换完成
	{
		for (int i = 0; i < ADC2_CHANNELS; i++) {
			adc2_values[i] = HAL_ADC_GetValue(&hadc2); // 读取转换结果
//			HAL_ADC_PollForConversion(&hadc2, 100);
		}
		adc_ready |= 0x01; // 标记ADC2数据就绪
		HAL_ADC_Stop_IT(&hadc2);
	} else if (hadc->Instance == ADC3)  // 确认是ADC3的转换完成
	{
		for (int i = 0; i < ADC3_CHANNELS; i++) {
			adc3_values[i] = HAL_ADC_GetValue(&hadc3); // 读取转换结果
//			HAL_ADC_PollForConversion(&hadc3, 100);
		}
		adc_ready |= 0x02; // 标记ADC3数据就绪
		HAL_ADC_Stop_IT(&hadc3);
	}
}

 AdcTask线程任务当ADC2和ADC3都进行转换之后,在当前线程中处理所有ADC数值并转换为电压值输出打印,结束后清除标志位,等待下次转换触发。该线程使用最小栈内存大小128Words。

void AdcTask(void *argument)
{
  /* USER CODE BEGIN AdcTask */
	Start_ADC2_DMA();
	Start_ADC3_DMA();
	int i = 0;
	float voltage;
	/* Infinite loop */
	for (;;) {
		if (adc_ready == 0x03) { // 等待两组ADC数据就绪
			/* 打印ADC2数据 */
			for (i = 0; i < ADC2_CHANNELS; i++) {
				voltage = adc2_values[i] * 3.3f / 4095.0f;
				printf("ADC2[%d] = %d.%dV\r\n", i, (uint32_t) voltage,
								(uint32_t) (voltage * 100) % 100);
			}
			printf("\n");

			/* 打印ADC3数据 */
			for (i = 0; i < ADC3_CHANNELS; i++) {
				voltage = adc3_values[i] * 3.3f / 4095.0f;
				printf("ADC3[%d] = %d.%dV\r\n", i, (uint32_t) voltage,
								(uint32_t) (voltage * 100) % 100);
			}
			printf("\n\n");

			adc_ready = 0; // 清除标志位
		}
		osDelay(10);
	}
  /* USER CODE END AdcTask */
}

共勉!!!

附上ADC+DMA多通道检测方法STM32H743单片机实现ADC+DMA多通道检测-CSDN博客


网站公告

今日签到

点亮在社区的每一天
去签到