STM32双路ADC注入通道和规则通道采样技巧详解

电机控制使用四路注入通道采集,参考ST官方库,使用定时器10us触发一次,使用ADC1和ADC2各2路注入通道。

需要一路ADC进行规则采样油门信号,使用中断的话会和注入通道中断放在同一个函数里面 ,我不喜欢,所以使用了DMA中断。

PreKnowledge:

规则通道:最多16个规则通道,采样数据存储ADCx–>DR

注入通道:最多4个注入通道,采样数据存储ADCx–>JDR。注入通带顾名思义是在规则通道转换中插队的通道。在规则通道转换的时候有注入通道的信息进来,则先将注入通道转换结束再回到规则通道,所以注入通道只有在规则通道存在时才会出现。

DMA通道:DMA转换注入通道还是规则通道,外设地址进行不同设置就行。还有一个,就是DMA只有在规则通道转换结束的时候才会被触发,记不清在哪篇博客里面看到的了,但是官方文档中没找到这句话。

使用芯片:STM32F103C8T6    软件:keil5

1.ADC设置

    ADC_InitTypeDef ADC_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 |RCC_APB2Periph_ADC2, ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);  		//ADC时钟=(晶振频率/分频)72Mhz/6 = 12Mhz
	
	ADC_InitStructure.ADC_Mode = ADC_Mode_RegInjecSimult; 	//混合的同步规则和注入
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;   //规则组的外部触发  关闭
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfChannel = 1;                    //规则组通道数量
	ADC_Init(ADC1, &ADC_InitStructure);

	ADC_InitStructure.ADC_NbrOfChannel = 2;
	ADC_Init(ADC2, &ADC_InitStructure);            //ADC2的规则通道,因为使用ADC2的注入通道
	
	ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_71Cycles5);					//ADC1规则通道设置,ADC1的规则通道使用所以配置,ADC2的规则通道实际上没有使用
	ADC_Cmd(ADC1, ENABLE);
	ADC_Cmd(ADC2, ENABLE);
	
	ADC_ResetCalibration(ADC1);
	ADC_ResetCalibration(ADC2);
	while(ADC_GetResetCalibrationStatus(ADC1) & ADC_GetResetCalibrationStatus(ADC2)) ;
	
	ADC_StartCalibration(ADC1);
	ADC_StartCalibration(ADC2);
	while(ADC_GetCalibrationStatus(ADC1) & ADC_GetCalibrationStatus(ADC2)) ;
	
/******************************注入通道配置*************************/	
	ADC_InjectedSequencerLengthConfig(ADC1, 2);
    ADC_InjectedSequencerLengthConfig(ADC2, 2);
	
	ADC_InjectedChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_7Cycles5);			
	ADC_InjectedChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_7Cycles5);
    ADC_InjectedChannelConfig(ADC1, ADC_Channel_2, 2, ADC_SampleTime_7Cycles5);
	ADC_InjectedChannelConfig(ADC2, ADC_Channel_3, 2, ADC_SampleTime_7Cycles5);

/******************************外部触发源设置**************************************/
	ADC_ExternalTrigInjectedConvConfig(ADC1, ADC_ExternalTrigInjecConv_T1_CC4); 						
	ADC_ExternalTrigInjectedConvConfig(ADC2, ADC_ExternalTrigInjecConv_T1_CC4);
	
	ADC_ExternalTrigInjectedConvCmd(ADC1, ENABLE);		//注入使能
    ADC_ExternalTrigInjectedConvCmd(ADC2, ENABLE);
	ADC_ClearITPendingBit(ADC1, ADC_IT_JEOC);        
	
	ADC_ITConfig(ADC1, ADC_IT_JEOC, ENABLE);        //注入中断使能
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);        //规则通道使能
	
/*********************ADC注入通道中断,规则通道不使用ADC中断**********************/
	NVIC_InitTypeDef NVIC_InitStruct ;
	NVIC_InitStruct.NVIC_IRQChannel =  ADC1_2_IRQn ;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0 ;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1 ;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;
	NVIC_Init(&NVIC_InitStruct);

2. DMA配置

    DMA_InitTypeDef DMA_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	
	DMA_DeInit(DMA1_Channel1);
	
	DMA_InitStructure.DMA_BufferSize =1;																										//DMA缓冲区大小
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;																			//DMA数据来源外设
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;																						//内存到内存失能
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(&Value_Regular);											//内存基地址
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;											//内存数据大小
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;																	//存储器地址递增
	DMA_InitStructure.DMA_Mode =DMA_Mode_Circular;
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&( ADC1->DR ));
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	DMA_InitStructure.DMA_PeripheralInc = DISABLE;
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	DMA_Init(DMA1_Channel1,&DMA_InitStructure);
	
	DMA_ITConfig(DMA1_Channel1,DMA1_IT_TC1,ENABLE);
	DMA_Cmd(DMA1_Channel1,ENABLE);
	ADC_DMACmd(ADC1,ENABLE);
	
	/***********************************规则通道的DMA中断******************************************/
	NVIC_InitTypeDef NVIC_InitStruct ;
	NVIC_InitStruct.NVIC_IRQChannel =  DMA1_Channel1_IRQn ;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0 ;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2 ;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE ;
	NVIC_Init(&NVIC_InitStruct);

3.DMA中断

  在DMA中断中收集数据,10个数据进行求取平均值滤波。此处不贴代码了,简单的求和取平均值。

调试过程中遇到的问题:

1. 有数据,数据变化很快,但是没有办法执行原来的主程序;

        原因:在使用DMA传输数据时会下意识的使用ADC连续转换模式,这样会导致注入通道也连续转换,自然就在ADC的中断里出不来了。

解决:将连续转换更改为单次转换,DMA中使用全局变量进行滤波。

2.数据中有0,也有正常数据

        原因:之前是电机控制那边写的底层,ADC1中定义了2个规则通道,所以导致规则通道会采集两个数据,另外一个通道没有数据,自然是0;

解决:在ADC_Structure中的数量中,将ADC1的值改为1。

3.采集的数据没有问题,但是滤波后的数据恒溢出

        原因:求和数据定义在函数中,导致每次DMA中断进行数据求和时,sum变量都重新变成了0,又进行除法运算,所以会溢出。

解决:将sun定义成全局变量。

ADC配置说明

ADC1中使用了1路规则通道,2路注入通道,由于注入通道的数据设置外部TIM触发,所以必须设置为单次触发模式。

原本我以为.ADC_NbrOfChannel是指ADC中所有的通道,将这个值设置成了3,1路规则通道,2路注入通道,导致在采集的时候会有2个数据为0。后来在浏览博客的时候偶然发现这个设置是单指规则通道的,所以改成1了。

而ADC2中配置成2,但是没有使用ADC_RegularChannelConfig函数进行配置,没有打开ADC2的规则通道,其实并不受影响。

作者:然仔吃西瓜

物联沃分享整理
物联沃-IOTWORD物联网 » STM32双路ADC注入通道和规则通道采样技巧详解

发表评论