电机控制使用四路注入通道采集,参考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了。文章来源:https://www.toymoban.com/news/detail-851071.html
而ADC2中配置成2,但是没有使用ADC_RegularChannelConfig函数进行配置,没有打开ADC2的规则通道,其实并不受影响。文章来源地址https://www.toymoban.com/news/detail-851071.html
到了这里,关于STM32双路ADC注入通道和规则通道采样的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!