说明:驱动基于STm32G031K6测试,其他型号需自行做改动。
ADC的初始化:
- #define ADCIO1_IN_CHANNEL LL_ADC_CHANNEL_5
- #define ADCIO2_IN_CHANNEL LL_ADC_CHANNEL_7
- uint8_t STM32LLADC1Init(void)
- {
- LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
- LL_ADC_InitTypeDef ADC_InitStruct = {0};
- LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
- /* Peripheral clock enable */
- LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC); //使能ADC时钟
- LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA); //谁能响应ADCioGpio时钟
- /**ADC1 GPIO Configuration
- PA5 ------> ADC1_IN5
- PA7 ------> ADC1_IN7
- */
- GPIO_InitStruct.Pin = gpioADCIO1_IN_PIN; //ADC检测IO初始化
- GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
- GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
- LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- GPIO_InitStruct.Pin = gpioADCIO2_IN_PIN;
- GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
- GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
- LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
- */
- ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE; //ADC定时转化触发条件来源,可以为软件触发或硬件(外部中断、定时器)触发。
- ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_ENABLE_2RANKS; //ADC顺序采集通道的个数,根据自己需要的通道个数设置
- ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE; //
- ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE; //采集方式,单次采集还是连续采集
- ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED; //使能DMA,并使用无限传输,如果DMA保存方式为循环覆盖的话才可以使用无限传输。
- ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN; //采集的数据循环覆盖模式
- LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
- LL_ADC_SetOverSamplingScope(ADC1, LL_ADC_OVS_DISABLE); //失能过采样
- LL_ADC_SetTriggerFrequencyMode(ADC1, LL_ADC_CLOCK_FREQ_MODE_HIGH); //采样时钟使用高频模式
- LL_ADC_REG_SetSequencerConfigurable(ADC1, LL_ADC_REG_SEQ_CONFIGURABLE); //adc通道和硬件adc in是否强制对应,因为adc的io使用时不是连续的,所以这里使用可自定义配置
- LL_ADC_SetSamplingTimeCommonChannels(ADC1, LL_ADC_SAMPLINGTIME_COMMON_1, LL_ADC_SAMPLINGTIME_160CYCLES_5); //设置通道共用取样时间,根据需要自行选择
- LL_ADC_DisableIT_EOC(ADC1); //禁用通道采样结束中断
- LL_ADC_DisableIT_EOS(ADC1); //禁用序列采样结束中断,因为使用的是单次软件触发所以这里关闭这些中断
- ADC_InitStruct.Clock = LL_ADC_CLOCK_SYNC_PCLK_DIV2; //选择采样时钟来源
- ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B; //采样分辨率
- ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT; //采样数据对齐方式,右对齐高位补0,左对齐低位补0.
- ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE; //低功耗模式,使用DMA的话无法使用,这里关闭
- LL_ADC_Init(ADC1, &ADC_InitStruct);
- /** Configure Regular Channel
- */
- //ADC_RegularChannelConfig
- LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, ADCIO1_IN_CHANNEL); //将硬件通道ADCIO1_IN_CHANNEL映射到ADC通道1
- LL_ADC_SetChannelSamplingTime(ADC1, ADCIO1_IN_CHANNEL, LL_ADC_SAMPLINGTIME_COMMON_1); //设置通道采样时间
- LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_2, ADCIO2_IN_CHANNEL); //将硬件通道ADCIO1_IN_CHANNEL映射到ADC通道2
- LL_ADC_SetChannelSamplingTime(ADC1, ADCIO2_IN_CHANNEL, LL_ADC_SAMPLINGTIME_COMMON_1); //设置通道采样时间
- /*采样数据转换时需要参考电压,参考电压可能是变化的,所以也有可能需要采集*/
- //LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_4, LL_ADC_CHANNEL_VREFINT);
- //LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_VREFINT, LL_ADC_SAMPLINGTIME_COMMON_1);
- return 1;
- }
复制代码
激活并校准ADC:
复制代码
因为ADC配置的是软件触发的单次采样,所以还需要有手动开始和结束采样的函数。
使能ADC采样:
- uint8_t STM32ADC1SampleEnable(void)
- {
- uint32_t Timeout = ADC_ENABLE_TIMEOUT_MS;
- LL_DMA_EnableChannel(DMA1,LL_DMA_CHANNEL_4); //先使能dma再使能adc,以防采样数据丢失
- LL_ADC_Enable(ADC1);
- Timeout = ADC_ENABLE_TIMEOUT_MS;
- while(LL_ADC_IsActiveFlag_ADRDY(ADC1) != SET)
- {
- if(Timeout-- == 0)
- {
- LOG(1,"STM32ADC1SampleEnable ERROR!!!");
- return 0;
- }
- }
- LL_ADC_REG_StartConversion(ADC1);
- return 1;
- }
复制代码
失能ADC采样:
- uint8_t STM32ADC1SampleDisable(void)
- {
- uint32_t Timeout = ADC_DISABLE_TIMEOUT_MS;
- LL_ADC_REG_StopConversion(ADC1);
- while(LL_ADC_REG_IsConversionOngoing(ADC1) != 0)
- {
- if(Timeout-- == 0)
- {
- LOG(1,"STM32ADC1SampleDisenable ERROR!!!");
- return 0;
- }
- }
- LL_ADC_Disable(ADC1); //先关闭adc再断开dma,以防采样数据丢失
- LL_DMA_DisableChannel(DMA1,LL_DMA_CHANNEL_4);
- return 1;
- }
复制代码
进行ADC数据采集流程(采用多次采样求平均值的方式):
1、当需要开始采样前,调用一次STM32ADC1SampleEnable()函数;
2、在一个定时函数内调用LL_ADC_REG_StartConversion(ADC1)进行数据的转换(因为使用的是单次采样,所以每次进入定时函数时都需要调用),取出DMA数据进行累加;
3、达到需要的采样次数之后,对得到的数据进行运算,并调用STM32ADC1SampleDisable()函数关闭ADC通道。
以上方式适用于需要间隔一段时间获取一次ADC数据时使用,例如需要每隔1分钟获取电池电压时,可以进行1分钟倒计时,然后连续进行十次间隔10ms的ADC采样求平均值。
|