说明:驱动基于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:
- uint8_t STM32ActivateADC1(void)
- {
- __IO uint32_t wait_loop_index = 0U;
- __IO uint32_t backup_setting_adc_dma_transfer = 0U;
- uint32_t Timeout = 0U; /* Variable used for timeout management */
- /*## Operation on ADC hierarchical scope: ADC instance #####################*/
- /* Note: Hardware constraint (refer to description of the functions */
- /* below): */
- /* On this STM32 serie, setting of these features is conditioned to */
- /* ADC state: */
- /* ADC must be disabled. */
- /* Note: In this example, all these checks are not necessary but are */
- /* implemented anyway to show the best practice usages */
- /* corresponding to reference manual procedure. */
- /* Software can be optimized by removing some of these checks, if */
- /* they are not relevant considering previous settings and actions */
- /* in user application. */
- if (LL_ADC_IsEnabled(ADC1) == 0)
- {
- /* Enable ADC internal voltage regulator */
- LL_ADC_EnableInternalRegulator(ADC1);
- /* Delay for ADC internal voltage regulator stabilization. */
- /* Compute number of CPU cycles to wait for, from delay in us. */
- /* Note: Variable divided by 2 to compensate partially */
- /* CPU processing cycles (depends on compilation optimization). */
- /* Note: If system core clock frequency is below 200kHz, wait time */
- /* is only a few CPU processing cycles. */
- wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
- while(wait_loop_index != 0)
- {
- wait_loop_index--;
- }
- /* Disable ADC DMA transfer request during calibration */
- /* Note: Specificity of this STM32 serie: Calibration factor is */
- /* available in data register and also transfered by DMA. */
- /* To not insert ADC calibration factor among ADC conversion data */
- /* in DMA destination address, DMA transfer must be disabled during */
- /* calibration. */
- backup_setting_adc_dma_transfer = LL_ADC_REG_GetDMATransfer(ADC1);
- LL_ADC_REG_SetDMATransfer(ADC1, LL_ADC_REG_DMA_TRANSFER_NONE);
- /* Run ADC self calibration */
- LL_ADC_StartCalibration(ADC1);
- /* Poll for ADC effectively calibrated */
- Timeout = ADC_CALIBRATION_TIMEOUT_MS;
- while (LL_ADC_IsCalibrationOnGoing(ADC1) != 0)
- {
- /* Check Systick counter flag to decrement the time-out value */
- if (LL_SYSTICK_IsActiveCounterFlag())
- {
- if(Timeout-- == 0)
- {
- return 0;
- }
- }
- }
- /* Restore ADC DMA transfer request after calibration */
- LL_ADC_REG_SetDMATransfer(ADC1, backup_setting_adc_dma_transfer);
- /* Delay between ADC end of calibration and ADC enable. */
- /* Note: Variable divided by 2 to compensate partially */
- /* CPU processing cycles (depends on compilation optimization). */
- wait_loop_index = (ADC_DELAY_CALIB_ENABLE_CPU_CYCLES >> 1);
- while(wait_loop_index != 0)
- {
- wait_loop_index--;
- }
- /* Enable ADC */
- LL_ADC_Enable(ADC1);
- /* Poll for ADC ready to convert */
- Timeout = ADC_ENABLE_TIMEOUT_MS;
- while (LL_ADC_IsActiveFlag_ADRDY(ADC1) == 0)
- {
- /* Check Systick counter flag to decrement the time-out value */
- if (LL_SYSTICK_IsActiveCounterFlag())
- {
- if(Timeout-- == 0)
- {
- return 0;
- }
- }
- }
- /* Note: ADC flag ADRDY is not cleared here to be able to check ADC */
- /* status afterwards. */
- /* This flag should be cleared at ADC Deactivation, before a new */
- /* ADC activation, using function "LL_ADC_ClearFlag_ADRDY()". */
- }
- return 1;
- }
复制代码
因为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采样求平均值。
|