炸鸡派例程-ADC
main
int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_DMA_Init();MX_USART1_UART_Init();/*ADC初始化*/MX_ADC1_Init();HAL_UART_Receive_DMA(&huart1, RXbuf, 50);__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);while (1){printf("V:%.2f \r\n", VoltageCheck());HAL_Delay(500);}
}
ADC初始化
void MX_ADC1_Init(void)
{ADC_ChannelConfTypeDef sConfig = {0};hadc1.Instance = ADC1; // 指定 ADC 实例为 ADC1hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; // ADC 时钟为 PCLK/4hadc1.Init.Resolution = ADC_RESOLUTION_12B; // 设置分辨率为 12 位hadc1.Init.ScanConvMode = DISABLE; // 禁用扫描模式hadc1.Init.ContinuousConvMode = DISABLE; // 禁用连续转换模式,使用单次转换hadc1.Init.DiscontinuousConvMode = DISABLE; // 禁用不连续转换模式hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; // 不使用外部触发,由软件启动转换hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 转换由软件触发hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 数据右对齐hadc1.Init.NbrOfConversion = 1; // 转换序列中只有一个通道hadc1.Init.DMAContinuousRequests = DISABLE; // 禁用 DMA 连续请求hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // EOC 信号在单次转换完成后产生if (HAL_ADC_Init(&hadc1) != HAL_OK) //这里调用了MSP_Init{Error_Handler();}sConfig.Channel = ADC_CHANNEL_1; // 选择通道1(PA1)作为输入sConfig.Rank = 1; // 设置通道在转换序列中的优先级为第1位sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; // 设置采样时间为3个时钟周期if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){Error_Handler();}
}
ADC相关参数解释
时钟分频因子
ADC时钟分频因子:
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
PCLK是APB2总线的时钟。
分辨率
hadc1.Init.Resolution = ADC_RESOLUTION_12B; // 设置分辨率为 12 位
ADC的输出数据为12位,即可以分辨4096个不同的电压等级。
扫描模式
hadc1.Init.ScanConvMode = DISABLE; // 禁用扫描模式
禁用扫描模式意味着ADC不会自动依次转换多个通道,而是只转换指定的单个通道。
在扫描模式下,ADC可以按照预设的顺序依次对多个通道进行采样。适合需要同时采集多个信号的应用场景。
不连续转换模式
hadc1.Init.DiscontinuousConvMode = DISABLE; // 禁用不连续转换模式
不连续转换模式用于扫描模式下,每次转换后暂停一段时间。这里禁用该模式。
连续转换模式
hadc1.Init.ContinuousConvMode = DISABLE; // 禁用连续转换模式,使用单次转换
禁用连续转换模式表示ADC只进行一次转换,然后停止。每次需要转换时,必须手动启动。
设置外部触发转换的边沿
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; // 不使用外部触发,由软件启动转换
通过调用ADC启动函数(如HAL_ADC_Start()
)或直接写寄存器来启动ADC转换。
其他触发方式包括上升沿、下降沿、双边沿触发,检测到对应信号自动触发ADC转换。
设置外部触发源
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; // 转换由软件触发
转换由软件通过编程启动,而不是由外部信号触发。
外部信号触发一般是通过定时器的输出比较事件来触发。
定时器的输出比较事件作为ADC的触发源的配置示例:
// 配置定时器1,每10ms触发一次ADC采样
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Period = 999; // 自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler = 999; // 预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 999; // 比较值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);// 配置ADC外部触发源为定时器1通道1比较匹配事件
ADC_ExternalTrigConvConfig(ADC1, ADC_ExternalTrigConv_T1_TRGO);// 启动定时器
TIM_Cmd(TIM1, ENABLE);
ADC数据对齐方式
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; // 数据右对齐
右对齐则高位补零。
转换序列中的通道数量
hadc1.Init.NbrOfConversion = 1; // 转换序列中只有一个通道
采样序列是指ADC在一次完整的采样过程中,按照预先设定的顺序依次对多个通道进行采样的过程。包括:
通道数量(NbrOfConversion)
通道顺序(Rank)
采样时间(SamplingTime)
DMA连续请求
hadc1.Init.DMAContinuousRequests = DISABLE; // 禁用 DMA 连续请求
禁用DMA连续请求,表示不会自动触发DMA传输。
转换结束(EOC)信号的触发方式
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // EOC 信号在单次转换完成后产生
使用 ADC_EOC_SINGLE_CONV,每次采样完成后都会生成一个 EOC 信号。
使用 ADC_EOC_SEQ_CONV,只有在序列都采样完成后才会生成一个 EOC 信号
中断:当EOC信号被设置时,可以触发一个中断服务例程(ISR),处理器可以在ISR中读取ADC转换结果并进行进一步处理。
DMA:EOC信号可以触发DMA传输,将ADC转换结果自动传输到内存中,从而减少处理器的负担,提高系统的效率。
在STM32中,当ADC完成一次转换后,EOC信号会被设置,处理器可以通过检查EOC标志来判断是否可以读取转换结果。
通道配置
ADC通道。
通道在转换序列中的优先级。
采样时间。这里给的3个时钟周期。

ADC_MspInit
/*MCU板级支持,硬件初始化*/
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(adcHandle->Instance==ADC1){__HAL_RCC_ADC1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_1;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; //GPIO配置模拟模式GPIO_InitStruct.Pull = GPIO_NOPULL;//禁用上拉或下拉确保信号源的电压直接传递到ADC输入引脚HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);}
}
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{if(adcHandle->Instance==ADC1){__HAL_RCC_ADC1_CLK_DISABLE();HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1);}
}
获取ADC转换结果
例程用的是while中轮询。
float VoltageCheck()
{uint16_t dat; // 用于存储ADC转换结果float Voltage; // 用于存储计算后的电压值// 启动ADC转换HAL_ADC_Start(&hadc1);// 等待ADC转换完成,超时时间设置为5msHAL_ADC_PollForConversion(&hadc1, 5);// 获取ADC转换结果dat = HAL_ADC_GetValue(&hadc1);// 停止ADCHAL_ADC_Stop(&hadc1);// 将ADC值转换为电压值// 假设参考电压为3.3V,12位ADC的满量程为4096Voltage = dat * 3.3f / 4096.0f;return Voltage; // 返回计算后的电压值
}
这里也可以通过中断来自动获取结果,
1. 配置 ADC 为中断模式
HAL_ADC_Start_IT(&hadc1); // 启动 ADC 转换(中断模式)
2. 注册中断服务例程(ISR)
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{if (hadc->Instance == ADC1){uint32_t adcValue = HAL_ADC_GetValue(hadc); // 获取 ADC 转换结果float voltage = adcValue * 3.3f / 4096.0f; // 转换为电压值// 在这里处理电压值// 例如,可以将电压值存储到全局变量中,或者触发其他操作}
}
HAL_ADC_IRQHandler 函数会检查EOC标志位,并在确认转换完成后调用 HAL_ADC_ConvCpltCallback 回调函数。