Bootstrap

ADC和DMA--详细代码示例(超详细注释)


#include "stm32f1xx_hal.h"
#include "adc.h"



ADC_HandleTypeDef adc1_handle;     //包含ADC所有属性(ADC句柄)
ADC_TypeDef adc1_Type;             //包含ADC控制寄存器
DMA_Channel_TypeDef dma1_channel;  //包含DMA控制寄存器
DMA_HandleTypeDef dma1_handle;     //包含DMA的所有属性(DMA句柄)
uint8_t adc_dma_sta;			   //DMA是否搬运完成的状态位

void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc);


/**
 * @brief       初始化ADC
 * @param       无
 * @retval      无
 */
void adc_init(uint32_t mar)
{
	ADC_ChannelConfTypeDef adc_ch_config;
	adc_dma_init();                                                //初始化DMA(DMA初始化+DMA-ADC句柄连接)
	HAL_ADC_MspInit(&adc1_handle);

  //ADC工作参数	配置
	adc1_handle.Instance                   = ADC1;                 //实例(寄存器基地址)
	adc1_handle.Init.DataAlign             = ADC_DATAALIGN_RIGHT;  //右对齐
	adc1_handle.Init.ScanConvMode          = ADC_SCAN_ENABLE;      //扫描模式(多通道)
	adc1_handle.Init.ContinuousConvMode    = ENABLE ;    	//连续模式(另一种是单次模式)
	adc1_handle.Init.NbrOfConversion       = 4;          			//转换通道数目
	adc1_handle.Init.DiscontinuousConvMode = DISABLE;   			//禁用间断模式
	adc1_handle.Init.NbrOfDiscConversion   = 0;              		//间断模式通道转换次数
	adc1_handle.Init.ExternalTrigConv      = ADC_SOFTWARE_START;   //软件触发
	
  HAL_ADC_Init(&adc1_handle);                                    //默认初始化函数,初始化adc
	
	HAL_ADCEx_Calibration_Start(&adc1_handle);                     //数据校准	
	
	//ADC相关通道的相关参数(多通道有几个通道就要配置几个)
	adc_ch_config.Channel      = ADC_CHANNEL_0;                    //通道选择0
	adc_ch_config.Rank         = ADC_REGULAR_RANK_1;               //通道排名序列1
	adc_ch_config.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;       //采样时间
	HAL_ADC_ConfigChannel(&adc1_handle,&adc_ch_config);            //配置 ADC 通道的相关参数
	
	adc_ch_config.Channel      = ADC_CHANNEL_1;                    //通道选择1
	adc_ch_config.Rank         = ADC_REGULAR_RANK_2;               //通道排名序列2
	HAL_ADC_ConfigChannel(&adc1_handle,&adc_ch_config);            //配置 ADC 通道的相关参数
	
	adc_ch_config.Channel      = ADC_CHANNEL_2;                    //通道选择2
	adc_ch_config.Rank         = ADC_REGULAR_RANK_3;               //通道排名序列3
	HAL_ADC_ConfigChannel(&adc1_handle,&adc_ch_config);            //配置 ADC 通道的相关参数
	
	adc_ch_config.Channel      = ADC_CHANNEL_3;                    //通道选择3
	adc_ch_config.Rank         = ADC_REGULAR_RANK_4;               //通道排名序列4
	HAL_ADC_ConfigChannel(&adc1_handle,&adc_ch_config);            //配置 ADC 通道的相关参数
	
	//DMA中断
	HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,3,3);                  //设置DMA中断优先级
  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);                        //使能DMA中断
	
	//DMA开启
	HAL_DMA_Start_IT(&dma1_handle,(uint32_t)&ADC1->DR,mar,0);      //DMA的搬运目的地址确定
	HAL_ADC_Start_DMA(&adc1_handle,&mar,0);                        //触发ADC转换,使用DMA传输数据
	
}


/**
 * @brief       初始化DMA
 * @param       无
 * @retval      无
 */
void adc_dma_init(void)
{
	__HAL_RCC_DMA1_CLK_ENABLE();                                  //开启DMA1的时钟
	 dma1_handle.Instance                 = DMA1_Channel1;          //使用的DMA通道1
	 dma1_handle.Init.Direction           = DMA_PERIPH_TO_MEMORY;   //外存到内设
	 dma1_handle.Init.PeriphInc           = DMA_PINC_DISABLE;  //外设地址寄存器不递增--固定
	 dma1_handle.Init.MemInc              = DMA_MINC_ENABLE;       //内存地址寄存器自动递增,不递增的话若有新数据来就会直接在这个基础上直接覆盖

	 dma1_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; //外设数据宽度--半字
	 dma1_handle.Init.MemDataAlignment    = DMA_MDATAALIGN_HALFWORD; //内存数据宽度--半字
	 dma1_handle.Init.Mode                = DMA_NORMAL ;             //正常模式(循环模式仅当“内存到内存”的情况下才使用)
	 dma1_handle.Init.Priority            = DMA_PRIORITY_MEDIUM;     //优先级--中等	
	 HAL_DMA_Init(&dma1_handle);
	
	 __HAL_LINKDMA(&adc1_handle,DMA_Handle,dma1_handle);             //ADC-DMA关联函数(三个参数分别为:adc句柄,adc结构体内dma名称,dma句柄)
	
}

/**
 * @brief       初始化ADC外设的硬件资源
 * @param       ADC_HandleTypeDef* hadc(ADC句柄)
 * @retval      无
 */
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
	if(hadc->Instance == ADC1)
	{
		//GPI0配置
		GPIO_InitTypeDef gpio_init_struct;                                          //GPIO句柄
		__HAL_RCC_GPIOC_CLK_ENABLE();                                               //IO口PC时钟使能
		gpio_init_struct.Pin  = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;  //多通道的时候都需要初始化
		gpio_init_struct.Mode = GPIO_MODE_ANALOG;                                   //模拟功能
		HAL_GPIO_Init(GPIOC, &gpio_init_struct);                                    //GPIO配置完成,调用默认初始化函数
		
		//ADC配置--时钟
		RCC_PeriphCLKInitTypeDef adc_clk_init = {0};  //结构体用于配置 STM32 微控制器的外设时钟
		adc_clk_init.PeriphClockSelection     = RCC_PERIPHCLK_ADC;       //时钟源为ADC
		adc_clk_init.AdcClockSelection        = RCC_ADCPCLK2_DIV6;      //ADC的分频系数		
		HAL_RCCEx_PeriphCLKConfig(&adc_clk_init);                       //时钟分频函数(根据传入的参数配置各种外设的时钟)
	}
}


/**
 * @brief       获取ADC转换后的结果
 * @param       无
 * @retval      无
 */
uint32_t adc_get_result(void)
{
	HAL_ADC_Start(&adc1_handle);                           //ADC转化开始
	HAL_ADC_PollForConversion(&adc1_handle,10); //10ms     //等待读取结束,此时的ADC1数据寄存器中就有值了
	return (uint16_t)HAL_ADC_GetValue(&adc1_handle);       //读取数据寄存器中的值
}


	/**
 * @brief       使能一次ADC-DMA传输函数
 * @param       uint16_t cndtr
 * @retval      无
 */
void adc_dma_enable(uint16_t cndtr)
{ 
	ADC1->CR2 &= ~(1<<0);                  //停止ADC的工作(寄存器操作)
	DMA1_Channel1->CCR &= ~(1<<0);         //停止DMA的工作(寄存器操作)
	while(DMA1_Channel1->CCR & (1<<0));    //寄存器位是否为0,通道是否关闭
	
	DMA1_Channel1->CNDTR = cndtr;          //DMA通道1传输数量寄存器
	DMA1_Channel1->CCR |= (1<<0);          //开启DMA
	
	ADC1->CR2 |= (1<<0);                   //开启ADC
	ADC1->CR2 |= 1<<22;                    //开启转化规则通道

/****第2种方法,直接用宏定义函数	
	__HAL_ADC_DISABLE(&adc1_handle);       //宏停止ADC
	__HAL_DMA_DISABLE(&dma1_handle);       //宏停止DMA
	while(__HAL_DMA_GET_FLAG(&dma1_handle,__HAL_DMA_GET_TC_FLAG_INDEX(&dma1_handle)));
	DMA1_Channel1->CNDTR = cndtr;          //DMA通道1传输数量寄存器
	__HAL_DMA_ENABLE(&dma1_handle);
	__HAL_ADC_ENABLE(&adc1_handle);
	HAL_ADC_Start(&adc1_handle);
****/	

}

;