電機控制使用四路注入通道采集,參考ST官方庫,使用定時器10us觸發(fā)一次,使用ADC1和ADC2各2路注入通道。
需要一路ADC進行規(guī)則采樣油門信號,使用中斷的話會和注入通道中斷放在同一個函數(shù)里面 ,我不喜歡,所以使用了DMA中斷。
PreKnowledge:
規(guī)則通道:最多16個規(guī)則通道,采樣數(shù)據(jù)存儲ADCx-->DR
注入通道:最多4個注入通道,采樣數(shù)據(jù)存儲ADCx-->JDR。注入通帶顧名思義是在規(guī)則通道轉(zhuǎn)換中插隊的通道。在規(guī)則通道轉(zhuǎn)換的時候有注入通道的信息進來,則先將注入通道轉(zhuǎn)換結(jié)束再回到規(guī)則通道,所以注入通道只有在規(guī)則通道存在時才會出現(xiàn)。
DMA通道:DMA轉(zhuǎn)換注入通道還是規(guī)則通道,外設(shè)地址進行不同設(shè)置就行。還有一個,就是DMA只有在規(guī)則通道轉(zhuǎn)換結(jié)束的時候才會被觸發(fā),記不清在哪篇博客里面看到的了,但是官方文檔中沒找到這句話。
使用芯片:STM32F103C8T6? ? 軟件:keil5
1.ADC設(shè)置
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; //混合的同步規(guī)則和注入
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //規(guī)則組的外部觸發(fā) 關(guān)閉
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1; //規(guī)則組通道數(shù)量
ADC_Init(ADC1, &ADC_InitStructure);
ADC_InitStructure.ADC_NbrOfChannel = 2;
ADC_Init(ADC2, &ADC_InitStructure); //ADC2的規(guī)則通道,因為使用ADC2的注入通道
ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_71Cycles5); //ADC1規(guī)則通道設(shè)置,ADC1的規(guī)則通道使用所以配置,ADC2的規(guī)則通道實際上沒有使用
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);
/******************************外部觸發(fā)源設(shè)置**************************************/
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); //規(guī)則通道使能
/*********************ADC注入通道中斷,規(guī)則通道不使用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緩沖區(qū)大小
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //DMA數(shù)據(jù)來源外設(shè)
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //內(nèi)存到內(nèi)存失能
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(&Value_Regular); //內(nèi)存基地址
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //內(nèi)存數(shù)據(jù)大小
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);
/***********************************規(guī)則通道的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中斷中收集數(shù)據(jù),10個數(shù)據(jù)進行求取平均值濾波。此處不貼代碼了,簡單的求和取平均值。
調(diào)試過程中遇到的問題:
1. 有數(shù)據(jù),數(shù)據(jù)變化很快,但是沒有辦法執(zhí)行原來的主程序;
? ? ? ? 原因:在使用DMA傳輸數(shù)據(jù)時會下意識的使用ADC連續(xù)轉(zhuǎn)換模式,這樣會導(dǎo)致注入通道也連續(xù)轉(zhuǎn)換,自然就在ADC的中斷里出不來了。
解決:將連續(xù)轉(zhuǎn)換更改為單次轉(zhuǎn)換,DMA中使用全局變量進行濾波。
2.數(shù)據(jù)中有0,也有正常數(shù)據(jù)
? ? ? ? 原因:之前是電機控制那邊寫的底層,ADC1中定義了2個規(guī)則通道,所以導(dǎo)致規(guī)則通道會采集兩個數(shù)據(jù),另外一個通道沒有數(shù)據(jù),自然是0;
解決:在ADC_Structure中的數(shù)量中,將ADC1的值改為1。
3.采集的數(shù)據(jù)沒有問題,但是濾波后的數(shù)據(jù)恒溢出
????????原因:求和數(shù)據(jù)定義在函數(shù)中,導(dǎo)致每次DMA中斷進行數(shù)據(jù)求和時,sum變量都重新變成了0,又進行除法運算,所以會溢出。
解決:將sun定義成全局變量。
ADC配置說明
ADC1中使用了1路規(guī)則通道,2路注入通道,由于注入通道的數(shù)據(jù)設(shè)置外部TIM觸發(fā),所以必須設(shè)置為單次觸發(fā)模式。
原本我以為.ADC_NbrOfChannel是指ADC中所有的通道,將這個值設(shè)置成了3,1路規(guī)則通道,2路注入通道,導(dǎo)致在采集的時候會有2個數(shù)據(jù)為0。后來在瀏覽博客的時候偶然發(fā)現(xiàn)這個設(shè)置是單指規(guī)則通道的,所以改成1了。文章來源:http://www.zghlxwxcb.cn/news/detail-851071.html
而ADC2中配置成2,但是沒有使用ADC_RegularChannelConfig函數(shù)進行配置,沒有打開ADC2的規(guī)則通道,其實并不受影響。文章來源地址http://www.zghlxwxcb.cn/news/detail-851071.html
到了這里,關(guān)于STM32雙路ADC注入通道和規(guī)則通道采樣的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!