STM32F030R8Tx使用HAL庫實現ADC DMA功能

  • 準備工程,本例程在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<ADC_CONVERTED_DATA_BUFFER_SIZE;i++)
			 {
					mvolts += aADCxConvertedData[i];
				  if(aADCxConvertedData[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 <stdbool.h>
#include <stdint.h>


#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下載鏈接,加了關注的可以私信要例程

https://download.csdn.net/download/mygod2008ok/12540714

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章