- 准备工程,本例程在RTC例程上添加,参考链接如下
https://blog.csdn.net/mygod2008ok/article/details/106751919
- 将stm32f0xx_hal_adc.c,stm32f0xx_hal_adc_ex.c, stm32f0xx_hal_dma.c三个文件加入到工程中
- 在stm32f0xx_hal_conf.h中打开HAL_ADC_MODULE_ENABLED和HAL_DMA_MODULE_ENABLED宏

- 新建BSP_adc.c和BSP_adc.h文件并加入到工程中

- BSP_adc.c内容如下
#include "BSP_adc.h" #include "BSP_delay.h" #include "stm_log.h" /* Definition of ADCx conversions data table size */ #define ADC_CONVERTED_DATA_BUFFER_SIZE ((uint32_t) 6) /* Size of array aADCxConvertedData[] */ /* ADC handle declaration */ ADC_HandleTypeDef AdcHandle; /* ADC channel configuration structure declaration */ ADC_ChannelConfTypeDef sConfig; /* Variable containing ADC conversions data */ static uint16_t aADCxConvertedData[ADC_CONVERTED_DATA_BUFFER_SIZE]; static uint8_t s_adc_count; /** * @brief ADC MSP Init * @param hadc : ADC handle * @retval None */ void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc) { GPIO_InitTypeDef GPIO_InitStruct; static DMA_HandleTypeDef DmaHandle; /*##-1- Enable peripherals and GPIO Clocks #################################*/ /* Enable GPIO clock ****************************************/ __HAL_RCC_GPIOA_CLK_ENABLE(); /* ADC1 Periph clock enable */ ADCx_CLK_ENABLE(); /* Enable DMA1 clock */ __HAL_RCC_DMA1_CLK_ENABLE(); /*##- 2- Configure peripheral GPIO #########################################*/ /* ADC Channel GPIO pin configuration */ GPIO_InitStruct.Pin = ADCx_CHANNEL_PIN; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(ADCx_CHANNEL_GPIO_PORT, &GPIO_InitStruct); /*##- 3- Configure DMA #####################################################*/ /*********************** Configure DMA parameters ***************************/ DmaHandle.Instance = DMA1_Channel1; DmaHandle.Init.Direction = DMA_PERIPH_TO_MEMORY; DmaHandle.Init.PeriphInc = DMA_PINC_DISABLE; DmaHandle.Init.MemInc = DMA_MINC_ENABLE; DmaHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; DmaHandle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; DmaHandle.Init.Mode = DMA_CIRCULAR; DmaHandle.Init.Priority = DMA_PRIORITY_MEDIUM; /* Deinitialize & Initialize the DMA for new transfer */ HAL_DMA_DeInit(&DmaHandle); HAL_DMA_Init(&DmaHandle); /* Associate the DMA handle */ __HAL_LINKDMA(hadc, DMA_Handle, DmaHandle); /* NVIC configuration for DMA Input data interrupt */ HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 1, 0); HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn); } /** * @brief ADC MSP De-Initialization * This function frees the hardware resources used in this example: * - Disable the Peripheral's clock * - Revert GPIO to their default state * @param hadc: ADC handle pointer * @retval None */ void HAL_ADC_MspDeInit(ADC_HandleTypeDef *hadc) { /*##-1- Reset peripherals ##################################################*/ ADCx_FORCE_RESET(); ADCx_RELEASE_RESET(); /* ADC Periph clock disable (automatically reset all ADC instances of the ADC common group) */ __HAL_RCC_ADC1_CLK_DISABLE(); /*##-2- Disable peripherals and GPIO Clocks ################################*/ /* De-initialize the ADC Channel GPIO pin */ HAL_GPIO_DeInit(ADCx_CHANNEL_GPIO_PORT, ADCx_CHANNEL_PIN); } //-----------------获取ADC值---------------------------------- static int16_t get_adc_value(void) { int32_t mvolts; int16_t max,min; mvolts = 0; max = aADCxConvertedData[0]; min = aADCxConvertedData[0]; for(uint8_t i=0; i= max) max = aADCxConvertedData[i]; if(aADCxConvertedData[i] <= min) min = aADCxConvertedData[i]; } mvolts = mvolts-max-min; //去掉最大,最小值 mvolts /= (ADC_CONVERTED_DATA_BUFFER_SIZE-2); return (int16_t)mvolts; } /** * @brief adc初时化 */ void BSP_adc_init(void) { AdcHandle.Instance = ADCx; HAL_StatusTypeDef err_code = HAL_ADC_DeInit(&AdcHandle); APP_ERROR_CHECK(err_code); AdcHandle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; /* Synchronous clock mode, input ADC clock with prscaler 2 */ AdcHandle.Init.Resolution = ADC_RESOLUTION_12B; /* 12-bit resolution for converted data */ AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* Right-alignment for converted data */ AdcHandle.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */ AdcHandle.Init.EOCSelection = ADC_EOC_SINGLE_CONV; /* EOC flag picked-up to indicate conversion end */ AdcHandle.Init.LowPowerAutoPowerOff = DISABLE; AdcHandle.Init.LowPowerAutoWait = DISABLE; /* Auto-delayed conversion feature disabled */ AdcHandle.Init.ContinuousConvMode = DISABLE;//ENABLE; /* Continuous mode enabled (automatic conversion restart after each conversion) */ AdcHandle.Init.DiscontinuousConvMode = DISABLE; /* Parameter discarded because sequencer is disabled */ AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* Software start to trig the 1st conversion manually, without external event */ AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Parameter discarded because software trigger chosen */ AdcHandle.Init.DMAContinuousRequests = DISABLE;//ENABLE; /* ADC DMA continuous request to match with DMA circular mode */ AdcHandle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; /* DR register is overwritten with the last conversion result in case of overrun */ AdcHandle.Init.SamplingTimeCommon = ADC_SAMPLETIME_1CYCLE_5; /* Initialize ADC peripheral according to the passed parameters */ err_code = HAL_ADC_Init(&AdcHandle); APP_ERROR_CHECK(err_code); /* ### - 2 - Start calibration ############################################ */ err_code = HAL_ADCEx_Calibration_Start(&AdcHandle); APP_ERROR_CHECK(err_code); /* ### - 3 - Channel configuration ######################################## */ sConfig.Channel = ADCx_CHANNEL; /* Channel to be converted */ sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; err_code = HAL_ADC_ConfigChannel(&AdcHandle, &sConfig); APP_ERROR_CHECK(err_code); /* ### - 4 - Start conversion in DMA mode ################################# */ // err_code = HAL_ADC_Start_DMA(&AdcHandle, // (uint32_t *)aADCxConvertedData, // ADC_CONVERTED_DATA_BUFFER_SIZE // ); // APP_ERROR_CHECK(err_code); } /** * @brief adc反初时化 */ void BSP_adc_deinit() { HAL_ADC_DeInit(&AdcHandle); __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Pin = GPIO_PIN_0; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } /** * @brief 启动转换 */ void BSP_start_adc_count(uint8_t count) { if(s_adc_count == 0) { s_adc_count = count; } } //-----------------------电池电量测量在此函数触发,由2秒调用------------------------------------------------------------------ void batteryMessurePeroid(void) { static uint8_t s_batt_cnt = 0; if(s_adc_count) return; if(++s_batt_cnt >= MESSURE_BATTERY_PERIOD) { s_batt_cnt = 0; BSP_start_adc_count(1); } } /** * @brief ADC转换处理 */ void BSP_adc_convert_handler(void) { if(s_adc_count) { HAL_StatusTypeDef err_code = HAL_ADC_Start_DMA(&AdcHandle, (uint32_t *)aADCxConvertedData, ADC_CONVERTED_DATA_BUFFER_SIZE ); APP_ERROR_CHECK(err_code); if(--s_adc_count == 0) { int16_t adc = get_adc_value(); NRF_LOG_INFO("ADC=%d",adc); } } }
- BSP_adc.h内容如下
#ifndef __BSP_ADC_H_ #define __BSP_ADC_H_ #include "main.h" #include #include #ifdef __cplusplus extern "C" { #endif //#include "stm32f0xx_nucleo.h" /* Definition for ADCx clock resources */ #define ADCx ADC1 #define ADCx_CLK_ENABLE() __HAL_RCC_ADC1_CLK_ENABLE() #define ADCx_CHANNEL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() #define DMAx_CHANNELx_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE() #define ADCx_FORCE_RESET() __HAL_RCC_ADC1_FORCE_RESET() #define ADCx_RELEASE_RESET() __HAL_RCC_ADC1_RELEASE_RESET() /* Definition for ADCx Channel Pin */ #define ADCx_CHANNEL_PIN_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() #define ADCx_CHANNEL_PIN GPIO_PIN_0 #define ADCx_CHANNEL_GPIO_PORT GPIOA /* Definition for ADCx's Channel */ #define ADCx_CHANNEL ADC_CHANNEL_0 #define MESSURE_BATTERY_PERIOD 3 extern ADC_HandleTypeDef AdcHandle; void batteryMessurePeroid(void); void BSP_adc_init(void); void BSP_adc_deinit(void); void BSP_start_adc_count(uint8_t count); void BSP_adc_convert_handler(void); #ifdef __cplusplus } #endif #endif
- 在stm32f0xx_it.c中DMA1_Channel1_IRQHandler处理函数中调用HAL_DMA_IRQHandler函数
/** * @brief This function handles DMA1_Channel1_IRQHandler interrupt request. * @param None * @retval None */ void DMA1_Channel1_IRQHandler(void) { HAL_DMA_IRQHandler(AdcHandle.DMA_Handle); }
- 在main函数中调用BSP_adc_init初时化ADC
/* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ RTT_INIT(); HAL_Init(); SystemClock_Config(); BSP_adc_init(); BSP_wdt_init(5000); delay_init(); MX_RTC_Init(); BSP_start_adc_count(8); /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ if(s_wakeup_flag) //任务处理模式 { BSP_wdt_feed(); tick_25hz_handler(); tick_1hz_handler(); } else // 省电模式 { } /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
- 在tick_25hz_handler函数中调用BSP_adc_convert_handler转换处理函数
/** * @brief 25Hz handler * */ static void tick_25hz_handler(void) { if((s_wakeup_flag & TICK_FOR_25HZ) == 0) return; s_wakeup_flag &= CLEAR_TICK_FOR_25HZ; //#################################################################################### //---------TODO this to add 25hz event handler----------- BSP_adc_convert_handler(); }
- 在tick_1hz_handler函数中调用batteryMessurePeroid函数,此例程每隔3秒启动一次完整的ADC转换
/** * @brief 1Hz handler * */ static void tick_1hz_handler(void) { if((s_wakeup_flag & TICK_FOR_1HZ) == 0) return; s_wakeup_flag &= CLEAR_TICK_FOR_1HZ; //#################################################################################### //---------TODO this to add 1hz event handler----------- start_cali_rtc(); batteryMessurePeroid(); //电池测量 }
- 运行结果如下:

- demo下载链接,加了关注的可以私信要例程