正点原子STM32H743单片机实现ADC多通道检测
目标
使用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 9uint16_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 */
}
共勉!!!