<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > STM32 ADC結(jié)合DMA數(shù)據(jù)采樣與軟件濾波處理

          STM32 ADC結(jié)合DMA數(shù)據(jù)采樣與軟件濾波處理

          作者: 時間:2016-11-17 來源:網(wǎng)絡(luò) 收藏
          作為一個偏向工控的芯片,ADC采樣是一個十分重要的外設(shè)。STM32集成三個12位精度18通道的內(nèi)部ADC,最高速度1微秒,結(jié)合DMA可以解放CPU進行更好的處理。
          ADC接口上的其它邏輯功能包括:
          ●同步的采樣和保持
          ●交叉的采樣和保持
          ●單次采樣
          模擬看門狗功能允許非常精準地監(jiān)視一路、多路或所有選中的通道,當被監(jiān)視的信號超出預(yù)置的閥值時,將產(chǎn)生中斷。
          由標準定時器(TIMx)和高級控制定時器(TIM1和TIM8)產(chǎn)生的事件,可以分別內(nèi)部級聯(lián)到ADC的開始觸發(fā)和注入觸發(fā),應(yīng)用程序能使AD轉(zhuǎn)換與時鐘同步。

          12位ADC是一種逐次逼近型模擬數(shù)字數(shù)字轉(zhuǎn)換器。它有多達18個通道,可測量16個外部和2個內(nèi)部信號源。

          ADC的輸入時鐘不得超過14MHZ,它是由PCLK2經(jīng)分頻產(chǎn)生。

          如果被ADC轉(zhuǎn)換的模擬電壓低于低閥值或高于高閥值,AWD模擬看門狗狀態(tài)位被設(shè)置。

          關(guān)于ADC采樣與DMA關(guān)系,引用網(wǎng)上一段解釋:

          STM32 的優(yōu)點在哪里?
          除去宣傳環(huán)節(jié),細細分析。
          STM32 時鐘不算快,72MHZ,
          也不能擴展大容量的RAM FLASH,
          同樣沒有 DSP 那樣強大的指令集。
          它的優(yōu)勢在哪里呢?
          ---就在快速采集數(shù)據(jù),快速處理上。
          ARM 的特點就是方便。
          這個快速采集,高性能的ADC 就是一個很好的體現(xiàn),
          12 位精度,最快1uS 的轉(zhuǎn)換速度,通常具備2 個以上獨立的ADC 控制器,
          這意味著,
          STM32 可以同時對多個模擬量進行快速采集,
          這個特性不是一般的MCU具有的。
          以上高性能的 ADC,配合相對比較塊的指令集和一些特色的算法支持,
          就構(gòu)成了STM32 在電機控制上的強大特性。
          好了,正題,怎末做一個簡單的ADC,注意是簡單的,
          ADC 是個復雜的問題,涉及硬件設(shè)計,電源質(zhì)量,參考電壓,信號預(yù)處理等等問題。
          我們只就如何在MCU內(nèi)完成一次ADC 作討論。
          談到 ADC,我們還要第一次引入另外一個重要的設(shè)備DMA.
          DMA是什么東西呢。
          通常在 8 位單片機時代,很少有這個概念。
          在外置資源越來越多以后,
          我們把一個MCU內(nèi)部分為主處理器和 外設(shè)兩個部分。
          主處理器當然是執(zhí)行我們指令的主要部分,
          外設(shè)則是串口 I2C ADC 等等用來實現(xiàn)特定功能的設(shè)備
          回憶一下,8 位時代,我們的主處理器最常干的事情是什么?
          邏輯判斷?不是。那才幾個指令
          計算算法?不是。大部分時候算法都很簡單。
          事實上,主處理器就是作個搬運工,
          把 USART 的數(shù)據(jù)接收下來,存起來
          把 ADC 的數(shù)據(jù)接收下來,存起來
          把要發(fā)送的數(shù)據(jù),存起來,一個個的往USART 里放。
          …………
          為了解決這個矛盾,
          人們想到一個辦法,讓外設(shè)和內(nèi)存間建立一個通道,
          在主處理器允許下,
          讓外設(shè)和內(nèi)存直接讀寫,這樣就釋放了主處理器,
          這個東西就是DMA。
          打個比方:
          一個MCU是個公司。
          老板就是主處理器
          員工是外設(shè)
          倉庫就是內(nèi)存
          從前 倉庫的東西都是老板管的。
          員工需要原料工作,就一個個報給老板,老板去倉庫里一個一個拿。
          員工作好的東西,一個個給老板,老板一個個放進倉庫里。
          老板很累,雖然老板是超人,也受不了越來越多的員工和單子。
          最后老板雇了一個倉庫保管員,它就是DMA
          他專門負責入庫和出庫,
          只需要把出庫和入庫計劃給老板過目
          老板說 OK,就不管了。
          后面的入庫和出庫過程,
          員工只需要和這個倉庫保管員打交道就可以了。
          --------閑話,馬七時常想,讓設(shè)備與設(shè)備之間開DMA,豈不更牛X
          比喻完成。
          ADC 是個高速設(shè)備,前面提到。
          而且 ADC 采集到的數(shù)據(jù)是不能直接用的。即使你再小心的設(shè)計外圍電路,測的離譜的數(shù)據(jù)總會出現(xiàn)。
          那么通常來說,是采集一批數(shù)據(jù),然后進行處理,這個過程就是軟件濾波。
          DMA用到這里就很合適。讓ADC 高速采集,把數(shù)據(jù)填充到RAM 中,填充一定數(shù)量,比如32 個,64 個MCU再來使用。
          -----多一句,也可以說,單次ADC 毫無意義。
          下面我們來具體介紹,如何使用DMA來進行ADC 操作。
          初始化函數(shù)包括兩部分,DMA 初始化和ADC 初始化
          我們有多個管理員--DMA
          一個管理員當然不止管一個DMA 操作。所以DMA有多個Channel

          以下是程序分析:
          程序基于STM32F103VET6,庫函數(shù)實現(xiàn)
          RCC部分:(忽略系統(tǒng)時鐘配置)
          //啟動DMA時鐘
          RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
          //啟動ADC1時鐘
          RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
          GPIO部分:(ADC引腳參見上表)
          //ADC_CH10--> PC0
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模擬輸入
          GPIO_Init(GPIOC, &GPIO_InitStructure);
          // PC2
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
          GPIO_Init(GPIOC, &GPIO_InitStructure);
          ADC1配置:(兩外部輸入,另采樣內(nèi)部溫度傳感器
          void ADC1_Configuration(void)
          {
          ADC_InitTypeDef ADC_InitStructure;

          ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //轉(zhuǎn)換模式為獨立,還有交叉等非常多樣的選擇
          ADC_InitStructure.ADC_ScanConvMode = ENABLE;
          ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//連續(xù)轉(zhuǎn)換開啟
          ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
          ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
          ADC_InitStructure.ADC_NbrOfChannel = 3; //設(shè)置轉(zhuǎn)換序列長度為3,三通道
          ADC_Init(ADC1, &ADC_InitStructure);

          //ADC內(nèi)置溫度傳感器使能(要使用片內(nèi)溫度傳感器,切忌要開啟它)
          ADC_TempSensorVrefintCmd(ENABLE);

          //常規(guī)轉(zhuǎn)換序列1:通道10
          ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5);
          //常規(guī)轉(zhuǎn)換序列2:通道16(內(nèi)部溫度傳感器),采樣時間>2.2us,(239cycles)
          ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 2, ADC_SampleTime_239Cycles5);
          ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 3, ADC_SampleTime_239Cycles5);
          //輸入?yún)?shù):ADC外設(shè),ADC通道,轉(zhuǎn)換序列順序,采樣時間
          // Enable ADC1
          ADC_Cmd(ADC1, ENABLE);
          // 開啟ADC的DMA支持(要實現(xiàn)DMA功能,還需獨立配置DMA通道等參數(shù))
          ADC_DMACmd(ADC1, ENABLE);

          // 下面是ADC自動校準,開機后需執(zhí)行一次,保證精度
          // Enable ADC1 reset calibaration register
          ADC_ResetCalibration(ADC1);
          // Check the end of ADC1 reset calibration register
          while(ADC_GetResetCalibrationStatus(ADC1));

          // Start ADC1 calibaration
          ADC_StartCalibration(ADC1);
          // Check the end of ADC1 calibration
          while(ADC_GetCalibrationStatus(ADC1));
          // ADC自動校準結(jié)束---------------
          ADC_SoftwareStartConvCmd(ADC1, ENABLE); //ADC啟動
          }
          DMA配置:(無軟件濾波)
          void DMA_Configuration(void)
          {
          DMA_InitTypeDef DMA_InitStructure;

          DMA_DeInit(DMA1_Channel1);
          DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //DMA外設(shè)地址,在頭部定義
          DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value; //內(nèi)存地址
          DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外設(shè)至內(nèi)存模式
          //BufferSize=2,因為ADC轉(zhuǎn)換序列有2個通道
          //如此設(shè)置,使序列1結(jié)果放在AD_Value[0],序列2結(jié)果放在AD_Value[1]
          DMA_InitStructure.DMA_BufferSize = 3; //一次轉(zhuǎn)換三個
          DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //接受一次后,設(shè)備地址不后移
          DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //接受一次后,內(nèi)存地址后移
          DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //每次傳輸半字
          DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
          //循環(huán)模式開啟,Buffer寫滿后,自動回到初始地址開始傳輸
          DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
          DMA_InitStructure.DMA_Priority = DMA_Priority_High;
          DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
          DMA_Init(DMA1_Channel1, &DMA_InitStructure);
          //配置完成后,啟動DMA通道
          DMA_Cmd(DMA1_Channel1, ENABLE);
          }
          此DMA例程用于單次ADC轉(zhuǎn)換,配合軟件濾波可做如下改動:
          全局聲明:
          vu16 AD_Value[30][3]; //AD采樣值
          vu16 After_filter[3]; //AD濾波后
          DMA部分:(帶中斷濾波)
          void DMA_Configuration(void)
          {
          DMA_InitTypeDef DMA_InitStructure;

          DMA_DeInit(DMA1_Channel1);
          DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
          DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value;
          DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
          //BufferSize=2,因為ADC轉(zhuǎn)換序列有2個通道
          //如此設(shè)置,使序列1結(jié)果放在AD_Value[0],序列2結(jié)果放在AD_Value[1]
          DMA_InitStructure.DMA_BufferSize = 90;
          DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
          DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
          DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
          DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
          //循環(huán)模式開啟,Buffer寫滿后,自動回到初始地址開始傳輸
          DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
          DMA_InitStructure.DMA_Priority = DMA_Priority_High;
          DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
          DMA_Init(DMA1_Channel1, &DMA_InitStructure);
          //配置完成后,啟動DMA通道
          DMA_Cmd(DMA1_Channel1, ENABLE);
          DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); //使能DMA傳輸完成中斷

          }
          NVIC部分:
          NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQChannel;
          NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
          NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
          NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
          NVIC_Init(&NVIC_InitStructure); // Enable the DMA Interrupt
          stm32f10x_it.c文件:
          void DMA1_Channel1_IRQHandler(void)
          {
          if(DMA_GetITStatus(DMA1_IT_TC1) != RESET)
          {
          filter();
          DMA_ClearITPendingBit(DMA1_IT_TC1);
          }
          }
          濾波部分:(均值濾波)
          #define N 30
          void filter(void)
          {
          intsum = 0;
          u8 count,i;
          for(i=0;i<2;i++)
          {
          for ( count=0;count {
          sum += AD_Value[count][i];
          }
          After_filter[i]=sum/N;
          sum=0;
          }

          }
          采樣數(shù)據(jù)與實際電壓/溫度轉(zhuǎn)換:
          u16 GetTemp(u16 advalue)
          {
          u32 Vtemp_sensor;
          s32 Current_Temp;

          // ADC轉(zhuǎn)換結(jié)束以后,讀取ADC_DR寄存器中的結(jié)果,轉(zhuǎn)換溫度值計算公式如下:
          // V25 - VSENSE
          //T(℃) = ------------+ 25
          // Avg_Slope
          // V25:溫度傳感器在25℃時 的輸出電壓,典型值1.43 V。
          //VSENSE:溫度傳感器的當前輸出電壓,與ADC_DR 寄存器中的結(jié)果ADC_ConvertedValue之間的轉(zhuǎn)換關(guān)系為:
          // ADC_ConvertedValue * Vdd
          //VSENSE = --------------------------
          // Vdd_convert_value(0xFFF)
          //Avg_Slope:溫度傳感器輸出電壓和溫度的關(guān)聯(lián)參數(shù),典型值4.3 mV/℃。

          Vtemp_sensor = advalue * 330 / 4096;
          Current_Temp = (s32)(143 - Vtemp_sensor)*10000/43 + 2500;
          return (s16)Current_Temp;
          }

          u16 GetVolt(u16 advalue)
          {

          return (u16)(advalue * 330 / 4096);
          }
          濾波部分思路為:ADC正常連續(xù)采樣三個通道,由DMA進行搬運,一次搬運90個數(shù)據(jù),即為1-2-3-1-2-3循環(huán),每個通道各30次,存在 AD_Value[30][3]中,30為每通道30個數(shù)據(jù),3為三個通道,根據(jù)二維數(shù)組存儲方式此過程自動完成。而每當一次DMA過程結(jié)束后,觸發(fā) DMA完成中斷,進入濾波函數(shù)將30個數(shù)據(jù)均值成一個, 存入After_filter[3]。整個過程濾波計算需要CPU參與,而在程序中采樣結(jié)果值隨時均為最新,盡力解決程序復雜性和CPU負載。 x=GetVolt(After_filter[0]);即可得到即時電壓值。


          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();