STM32-电阻转换,“ADC和DMA”的超详细代码,注释超详细

//#include "stm32f1xx_hal_adc.h"
//#include "stm32f1xx_hal_dma.h"
//#include "stm32f1xx_hal_adc_ex.h"
#include "stm32f1xx_hal.h"
#include "adc.h"
//#include "stm32f1xx_hal_def.h"


ADC_HandleTypeDef adc1_handle;     //包含ADC所有属性(ADC句柄)
DMA_HandleTypeDef dma1_handle;     //包含DMA的所有属性(DMA句柄)
uint8_t adc_dma_sta;							 //DMA是否搬运完成的状态位

//void adc_dma_init(void);
//void adc_init(uint32_t mar);
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc);
//uint32_t adc_get_result(void);
//void adc_dma_enable(uint16_t cndtr);
//void DMA1_Channel1_IRQHandler(void);


/**
 * @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_DISABLE;     //扫描模式(多通道)
	adc1_handle.Init.ContinuousConvMode    = ENABLE ;    				   //连续模式(另一种是单次模式)
	adc1_handle.Init.NbrOfConversion       = 1;          				   //转换通道数目
	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_10;                   //通道选择10
	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_11;                   //通道选择11
//	adc_ch_config.Rank         = ADC_REGULAR_RANK_2;               //通道排名序列2
//	HAL_ADC_ConfigChannel(&adc1_handle,&adc_ch_config);            //配置 ADC 通道的相关参数
//	
//	adc_ch_config.Channel      = ADC_CHANNEL_12;                   //通道选择12
//	adc_ch_config.Rank         = ADC_REGULAR_RANK_3;               //通道排名序列3
//	HAL_ADC_ConfigChannel(&adc1_handle,&adc_ch_config);            //配置 ADC 通道的相关参数
//	
//	adc_ch_config.Channel      = ADC_CHANNEL_13;                   //通道选择13
//	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的搬运目的地址确定
	
	
	//单个通道转换完成后,不产生任何标志位和中断,但它会产生 DMA 请求,触发 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时钟使能
		__HAL_RCC_ADC1_CLK_ENABLE();
		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转化开始,但是并不会自动让DMA还是运输
	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传输数量寄存器,也就是要传几个数据的意思,1个--2个--- 100个--1000个
//	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);        //只是使能DMA(没有运输)
	__HAL_ADC_ENABLE(&adc1_handle);        //只是使能ADC(没有转换)
	HAL_ADC_Start(&adc1_handle);           //ADC开始转换,不涉及DAM搬运
//****/	

}

/**
* @brief       ADC-DMA采集中断服务函数
* @param       void
* @retval      无
* @note        等待DMA搬运数据完成才进行一次处理,
						   所以使用传输完成中断,操作对应的寄存器ISR
						   TCIFx-这个是传输完成寄存器,DMA1对应x为1
*/
void DMA1_Channel1_IRQHandler(void)
{
	if(DMA1->ISR & (1)<<1)    //通道传输完成
	{
		adc_dma_sta = 1;        //全局变量--dma是否搬运完成的状态
		DMA1->IFCR |= 1<<1;     //清除ISR寄存器中搬运完成的状态
	}
}

然后在主函数中的应用函数:

#define ADC_DMA_BUFF_SIZE 100             /* ADC-DMA采集BUFF大小,应该等于ADC通道数量的整数倍 */
uint16_t adc_dma_buff[ADC_DMA_BUFF_SIZE];  /* 存放ADC-DMA采集数据 */
extern uint8_t adc_dma_sta;                /* DMA传输状态标志:0-未完成,1-已完成 */
uint16_t adcx;
uint32_t sum;

int main(void)
{
     HAL_Init();                         /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    delay_init(72);                     /* 延时初始化 */
	  spi2_init();                        /* 初始化SPI  */
    MCP_2515_init();                    /* 初始化MCP2515  */	
  //led_init();                         /* LED初始化 */
		gpio_init();                        /* GPIO初始化 */
	  //GPIO_PIN_TEST();                    /* GPIO输出测试 */
	  //HAL_GPIO_WritePin(GPIOE,GPIO_PIN_2 ,GPIO_PIN_RESET);  /* PE2 置0 */
	//创建开始任务
	
	uint16_t i,j;
	adc_init((uint32_t)adc_dma_buff);
	adc_dma_enable(ADC_DMA_BUFF_SIZE);
  while(1)
{
		if(adc_dma_sta == 1)
		{
				sum= 0;                                //清零
				for( i =0; i < ADC_DMA_BUFF_SIZE; i++) //每个通道采集40次数据,进行40次累加
				{
					adcx = adc_dma_buff[i];        //相同通道的转换数据累加
				}			
			adc_dma_sta = 0;                         //清除DMA采集完成状态标志
			adc_dma_enable(ADC_DMA_BUFF_SIZE);
		}
	delay_ms(200);
}
	

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值