新聞中心

        STM32_ADC+DMA

        作者: 時間:2016-12-02 來源:網(wǎng)絡(luò) 收藏
        ADC+DMA

        下面來講一下STM32的ADC應(yīng)用。

        本文引用地址:http://www.104case.com/article/201612/325009.htm

        先閑扯一點其他事情,是我自己的理解。
        STM32的優(yōu)點在哪里?
        除去宣傳環(huán)節(jié),細(xì)細(xì)分析。
        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是個復(fù)雜的問題,涉及硬件設(shè)計電源質(zhì)量,參考電壓,信號adclass=0&app_id=0&c=news&cf=1001&ch=0&di=128&fv=17&is_app=0&jk=86c1906558a285a7&k=%D4%A4%B4%A6%C0%ED&k0=%D4%A4%B4%A6%C0%ED&kdi0=0&luki=3&n=10&p=baidu&q=98059059_cpr&rb=0&rs=1&seller_id=1&sid=a785a2586590c186&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1831118&u=http%3A%2F%2Fwww%2E51hei%2Ecom%2Fmcu%2F1958%2Ehtml&urlid=0" id="6_nwl" mpid="6" target="_blank">預(yù)處理等等問題。
        我們只就如何在MCU內(nèi)完成一次ADC作討論。

        談到ADC,我們還要第一次引入另外一個重要的設(shè)備DMA.
        DMA是什么東西呢。
        通常在8位單片機時代,很少有這個概念。
        在外置資源越來越多以后,
        我們把一個MCU內(nèi)部分為 主處理器 和 外設(shè)兩個部分。
        主處理器當(dāng)然是執(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
        他專門負(fù)責(zé) 入庫和出庫,
        只需要把出庫 和入庫計劃給老板過目
        老板說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
        一個管理員當(dāng)然不止管一個DMA操作。所以DMA有多個Channel

        //ADC with DMA Init

        #define ADC_Channel ADC_Channel0
        #define ADC1_DR_Address ((u32)0x4001244C)

        void ADCWithDMAInit()
        {
        //DMA init; Using DMA channel 1

        DMA_DeInit(DMA1_Channel1); //開啟DMA1的第一通道
        DMA_InitStruct.DMA_PeripheralBaseAddr = ADC1_DR_Address; //DMA對應(yīng)的外設(shè)基地址,這個地址走Datasheet查
        DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //轉(zhuǎn)換結(jié)果的數(shù)據(jù)大小
        DMA_InitStruct.DMA_MemoryBaseAddr = (unsigned long)&ADC_ConvertedValue; //
        DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //DMA的轉(zhuǎn)換模式是SRC模式,就是從外設(shè)向內(nèi)存中搬運,
        DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //M2M模式禁止,memory to memory,這里暫時用不上,以后介


        DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //DMA搬運的數(shù)據(jù)尺寸,注意ADC是12位的,

        HalfWord就是16位
        DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Disable; //接收一次數(shù)據(jù)后,目標(biāo)內(nèi)存地址是否后移--重

        要概念,用來采集多個數(shù)據(jù)的
        DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //接收一次數(shù)據(jù)后,設(shè)備地址是否后移
        DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; //轉(zhuǎn)換模式,循環(huán)緩存模式,常用,M2M果果開啟了,這個模式失效


        DMA_InitStruct.DMA_Priority = DMA_Priority_High; //DMA優(yōu)先級,高
        DMA_InitStruct.DMA_BufferSize = 1; //DMA緩存大小,1個
        DMA_Init(DMA1_Channel1,&DMA_InitStruct);

        // Enable DMA1
        DMA_Cmd(DMA1_Channel1, ENABLE);
        }


        void ADCx_Init(unsigned char ADC_Channel)
        {
        ADC_DeInit(ADC1); //開啟ADC1
        ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; //轉(zhuǎn)換模式,為獨立轉(zhuǎn)換。轉(zhuǎn)換模式太多了,以后深究
        ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; //對齊方式,ADC結(jié)果是12位的,顯然有個對齊左邊還是右邊

        的問題。一般是右對齊
        ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; //連續(xù)轉(zhuǎn)換模式開啟
        ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //ADC外部出發(fā)開關(guān),關(guān)閉
        ADC_InitStruct.ADC_NbrOfChannel = 2; //開啟通道數(shù),2個
        ADC_InitStruct.ADC_ScanConvMode = ENABLE; //掃描轉(zhuǎn)換模式開啟
        ADC_Init(ADC1, &ADC_InitStruct);

        ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_239Cycles5); //規(guī)則組通道設(shè)置,關(guān)鍵函數(shù) 轉(zhuǎn)

        換器ADC1,選擇哪個通道channel,規(guī)則采樣順序,1到16,以后解釋詳細(xì)含義,最后一個參數(shù)是轉(zhuǎn)換時間,越長越準(zhǔn)越穩(wěn)定

        // ADC1 to DMA, Enable
        ADC_DMACmd(ADC1, ENABLE); //ADC命令,和DMA關(guān)聯(lián)。

        //ADC1 Enable
        ADC_Cmd(ADC1,ENABLE); //開啟ADC1

        //Reset the Calibration of ADC1
        ADC_ResetCalibration(ADC1); //重置校準(zhǔn)

        //wait until the Calibrations finish
        while(ADC_GetResetCalibrationStatus(ADC1)) //等待重置校準(zhǔn)完成
        ;

        ADC_StartCalibration(ADC1); //開始校準(zhǔn)

        while(ADC_GetCalibrationStatus(ADC1)) //等待校準(zhǔn)完成
        ;

        ADC_SoftwareStartConvCmd(ADC1, ENABLE); //連續(xù)轉(zhuǎn)換開始,從選擇開始,MCU可以不用管了,ADC將通過DMA不斷刷新

        制定RAM區(qū)
        // Attach them;
        }


        最后講講濾波算法
        濾波的方法以后會開個專題。
        特別提一下---沒有完美的濾波算法,只有合適的濾波算法。
        需要綜合考慮信號特點,噪聲特點,控制對象等等,
        這里用個最簡單的濾波算法,均值濾波。
        采樣16次,取平均值,吼吼,在豆皮上跳動還是蠻小的,合適,吼吼

        //16ms finish a ADC detection
        // return mv
        unsigned int ADC_filter(void)
        {
        unsigned int result="0";
        unsigned char i;

        for(i=16;i>0;i--)
        {
        Delay_xms(1);
        result += ADC_ConvertedValue;
        }

        return (unsigned int)(((unsigned long)(result>>4))*3300>>12);
        }



        關(guān)鍵詞: STM32ADCDM

        評論


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

        關(guān)閉
        主站蜘蛛池模板: 克东县| 南雄市| 金乡县| 津南区| 宝山区| 金沙县| 营口市| 弥勒县| 建湖县| 驻马店市| 平远县| 井研县| 祁东县| 日土县| 达州市| 南宫市| 鄯善县| 澜沧| 奎屯市| 凌云县| 南丰县| 扎赉特旗| 辉南县| 林周县| 丽水市| 兴海县| 宜春市| 满洲里市| 同仁县| 霍山县| 自贡市| 翁牛特旗| 天门市| 柳林县| 潍坊市| 大渡口区| 隆林| 澎湖县| 拜泉县| 响水县| 沙河市|