RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

CKS32F4xx系列ADC多通道DMA電壓采集

jf_pJlTbmA9 ? 來源:中科芯MCU ? 作者:中科芯MCU ? 2023-11-06 16:53 ? 次閱讀

在上一講單通道ADC電壓采集的基礎上,本節(jié)主要介紹CKS32F4xx系列產(chǎn)品基于DMA傳輸?shù)?a target="_blank">ADC多通道電壓采集轉(zhuǎn)換實現(xiàn)。

DMA傳輸在ADC中的應用

DMA是直接存儲器存取,通常在使用ADC時,需要通過MCU內(nèi)核不停的讀取數(shù)據(jù),如果使用DMA,那么讀取的過程會繞過MCU,減輕MCU內(nèi)核的處理壓力,這樣有利于資源的充分利用,提高ADC數(shù)據(jù)的處理效率。由于ADC規(guī)則通道組只有一個數(shù)據(jù)寄存器中,當轉(zhuǎn)換多個通道時,使用DMA還可以避免丟失已經(jīng)存儲在ADC_DR寄存器中的數(shù)據(jù)。在使能DMA模式的情況下,每完成規(guī)則通道組中的一個通道轉(zhuǎn)換后,都會生成一個DMA請求,便可將轉(zhuǎn)換的數(shù)據(jù)從ADC_DR寄存器傳輸?shù)接弥付ǖ哪繕藘?nèi)存位置。這樣取代單通道實驗使用中斷服務的讀取方法,可以實現(xiàn)多通道ADC應用中高速高效的采集。

軟件設計要點

跟單通道例程一樣,編寫兩個ADC驅(qū)動文件,bsp_adc.h和bsp_adc.c,用來存放ADC所用IO引腳的初始化函數(shù)以及ADC和DMA相關配置函數(shù),主要流程為:

(1)初始化配置ADC目標引腳為模擬輸入模式;

(2)使能ADC時鐘和DMA時鐘;

(3)配置DMA從ADC數(shù)據(jù)寄存器傳輸數(shù)據(jù)到指定的存儲區(qū);

(4)配置通用ADC為獨立模式;

(5)設置ADC為12位分辨率,啟動掃描,連續(xù)轉(zhuǎn)換,不需要外部觸發(fā);

(6)設置ADC轉(zhuǎn)換通道順序及采樣時間;

(7)使能DMA請求,DMA在AD轉(zhuǎn)換完自動傳輸數(shù)據(jù)到指定的存儲區(qū);

(8)啟動ADC模塊;

(9)軟件使能觸發(fā)ADC轉(zhuǎn)換。

這里需要注意的是,在使用ADC+DMA功能時,如果在啟動ADC轉(zhuǎn)換之后使能DMA,ADC采樣數(shù)據(jù)可能會出現(xiàn)異常。因此建議先配置ADC及DMA相關參數(shù),最后啟動ADC轉(zhuǎn)換。

代碼實現(xiàn)

受篇幅限制,這里只介紹核心的部分代碼,有些變量的設置,頭文件的包含等并沒有涉及到,完整的代碼請參考本課程配套的例程。相關核心代碼實現(xiàn)如下:

(1)ADC宏定義

#defineTEMP_NOFCHANEL3
/*=====================通道1IO======================*/
//PB0ADCIO宏定義,可用杜邦線接3V3或者GND來實驗
#defineTEMP_ADC_GPIO_PORT1GPIOB
#defineTEMP_ADC_GPIO_PIN1GPIO_Pin_0
#defineTEMP_ADC_GPIO_CLK1RCC_AHB1Periph_GPIOB
#defineTEMP_ADC_CHANNEL1ADC_Channel_8
/*=====================通道2IO======================*/
//PB1ADCIO宏定義,可用杜邦線接3V3或者GND來實驗
#defineTEMP_ADC_GPIO_PORT2GPIOB
#defineTEMP_ADC_GPIO_PIN2GPIO_Pin_1
#defineTEMP_ADC_GPIO_CLK2RCC_AHB1Periph_GPIOB
#defineTEMP_ADC_CHANNEL2ADC_Channel_9
/*=====================通道3IO======================*/
//PA6ADCIO宏定義,可用杜邦線接3V3或者GND來實驗
#defineTEMP_ADC_GPIO_PORT3GPIOA
#defineTEMP_ADC_GPIO_PIN3GPIO_Pin_6
#defineTEMP_ADC_GPIO_CLK3RCC_AHB1Periph_GPIOA
#defineTEMP_ADC_CHANNEL3ADC_Channel_6
//ADC序號宏定義
#defineTEMP_ADCADC1
#defineTEMP_ADC_CLKRCC_APB2Periph_ADC1
//ADCDR寄存器宏定義,ADC轉(zhuǎn)換后的數(shù)字值則存放在這里
#defineTEMP_ADC_DR_ADDR((u32)ADC1+0x4c)
//ADCDMA通道宏定義,使用DMA傳輸
#defineTEMP_ADC_DMA_CLKRCC_AHB1Periph_DMA2
#defineTEMP_ADC_DMA_CHANNELDMA_Channel_0
#defineTEMP_ADC_DMA_STREAMDMA2_Stream0

定義多個通道進行多通道ADC實驗,并且定義DMA相關配置。

(2)ADC GPIO初始化

staticvoidTemp_ADC_GPIO_Config(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
/*=====================通道1======================*/
RCC_AHB1PeriphClockCmd(TEMP_ADC_GPIO_CLK1,ENABLE);//使能GPIO時鐘
GPIO_InitStructure.GPIO_Pin=TEMP_ADC_GPIO_PIN1;//配置IO
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不上拉不下拉
GPIO_Init(TEMP_ADC_GPIO_PORT1, GPIO_InitStructure);
/*=====================通道2======================*/
RCC_AHB1PeriphClockCmd(TEMP_ADC_GPIO_CLK2,ENABLE);//使能GPIO時鐘
GPIO_InitStructure.GPIO_Pin=TEMP_ADC_GPIO_PIN2;//配置IO
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不上拉不下拉
GPIO_Init(TEMP_ADC_GPIO_PORT2, GPIO_InitStructure);
/*=====================通道3=======================*/
RCC_AHB1PeriphClockCmd(TEMP_ADC_GPIO_CLK3,ENABLE);//使能GPIO時鐘
GPIO_InitStructure.GPIO_Pin=TEMP_ADC_GPIO_PIN3;//配置IO
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//不上拉不下拉
GPIO_Init(TEMP_ADC_GPIO_PORT3, GPIO_InitStructure);
}

使用到GPIO時候都必須開啟對應的GPIO時鐘,GPIO用于AD轉(zhuǎn)換功能必須配置為模擬輸入模式。

(3)配置ADC工作模式

staticvoidTemp_ADC_Mode_Config(void)
{
DMA_InitTypeDefDMA_InitStructure;
ADC_InitTypeDefADC_InitStructure;
ADC_CommonInitTypeDefADC_CommonInitStructure;
//--------------DMAInit結(jié)構(gòu)體參數(shù)初始化-------------
//ADC1使用DMA2,數(shù)據(jù)流0,通道0,
RCC_AHB1PeriphClockCmd(TEMP_ADC_DMA_CLK,ENABLE);//開啟DMA時鐘
DMA_InitStructure.DMA_PeripheralBaseAddr=TEMP_ADC_DR_ADDR;//外設基址為:ADC數(shù)據(jù)寄存器地址
DMA_InitStructure.DMA_Memory0BaseAddr=(u32)ADC_ConvertedValue;//AD值存儲地址
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;//數(shù)據(jù)傳輸方向為外設到存儲器
DMA_InitStructure.DMA_BufferSize=TEMP_NOFCHANEL;//緩沖區(qū)大小,指一次傳輸?shù)臄?shù)據(jù)量
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外設寄存器只有一個,地址不遞增
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//存儲器地址固定
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//外設數(shù)據(jù)大小為半字
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;//存儲器數(shù)據(jù)大小也為半字
DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//循環(huán)傳輸模式
DMA_InitStructure.DMA_Priority=DMA_Priority_High;//DMA傳輸通道優(yōu)先級為高
DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;//禁止DMAFIFO,使用直連模式
DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_HalfFull;//FIFO大小,F(xiàn)IFO禁止時不用配置
DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_Channel=TEMP_ADC_DMA_CHANNEL;//選擇DMA通道,通道存在于流中
DMA_Init(TEMP_ADC_DMA_STREAM, DMA_InitStructure);//初始化DMA流,
DMA_Cmd(TEMP_ADC_DMA_STREAM,ENABLE);//使能DMA流

RCC_APB2PeriphClockCmd(TEMP_ADC_CLK,ENABLE);//開啟ADC時鐘
//-------------ADCCommon結(jié)構(gòu)體參數(shù)初始化----------------
ADC_CommonInitStructure.ADC_Mode=ADC_Mode_Independent;//獨立ADC模式
ADC_CommonInitStructure.ADC_Prescaler=ADC_Prescaler_Div4;//時鐘為fpclkx分頻
ADC_CommonInitStructure.ADC_DMAAccessMode=ADC_DMAAccessMode_Disabled;//禁止DMA直接訪問模式
ADC_CommonInitStructure.ADC_TwoSamplingDelay=ADC_TwoSamplingDelay_20Cycles;//采樣時間間隔
ADC_CommonInit( ADC_CommonInitStructure);
//-------------------ADCInit結(jié)構(gòu)體參數(shù)初始化--------------------------
ADC_StructInit( ADC_InitStructure);
ADC_InitStructure.ADC_Resolution=ADC_Resolution_12b;//ADC分辨率
ADC_InitStructure.ADC_ScanConvMode=ENABLE;//掃描模式,多通道采集需要
ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//連續(xù)轉(zhuǎn)換
ADC_InitStructure.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_None;//禁止外部邊沿觸發(fā)
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T1_CC1;//外部觸發(fā)通道,使用軟件觸發(fā)時此值隨便賦值即可
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//數(shù)據(jù)右對齊ADC_InitStructure.ADC_NbrOfConversion=TEMP_NOFCHANEL;//轉(zhuǎn)換通道3個
ADC_Init(TEMP_ADC, ADC_InitStructure);


//配置ADC通道轉(zhuǎn)換順序和采樣時間周期
ADC_RegularChannelConfig(TEMP_ADC,TEMP_ADC_CHANNEL1,1,ADC_SampleTime_3Cycles);
ADC_RegularChannelConfig(TEMP_ADC,TEMP_ADC_CHANNEL2,2,ADC_SampleTime_3Cycles);
ADC_RegularChannelConfig(TEMP_ADC,TEMP_ADC_CHANNEL3,3,ADC_SampleTime_3Cycles);

ADC_DMARequestAfterLastTransferCmd(TEMP_ADC,ENABLE);//使能DMA請求
ADC_DMACmd(TEMP_ADC,ENABLE);//使能ADCDMA
ADC_Cmd(TEMP_ADC,ENABLE);//使能ADC
ADC_SoftwareStartConv(TEMP_ADC);//開始ADC轉(zhuǎn)換,軟件觸發(fā)
}

首先,使用DMA_InitTypeDef定義了DMA初始化類型變量,另外使用ADC_InitTypeDef和ADC_CommonInitTypeDef結(jié)構(gòu)體分別定義一個ADC初始化和ADC通用類型變量。

調(diào)用RCC_APB2PeriphClockCmd()開啟ADC時鐘以及RCC_AHB1PeriphClockCmd()開啟DMA時鐘。

對DMA進行必要的配置。首先設置外設基地址就是ADC的規(guī)則數(shù)據(jù)寄存器地址;存儲器的地址就是指定的數(shù)據(jù)存儲區(qū)空間,ADC_ConvertedValue是我們定義的一個全局數(shù)組名,它是一個無符號16位含有3個元素的整數(shù)數(shù)組;ADC規(guī)則轉(zhuǎn)換對應只有一個數(shù)據(jù)寄存器,所以地址不能遞增,而定義的存儲區(qū)是專門用來存放不同通道數(shù)據(jù)的,所以需要自動地址遞增。ADC的規(guī)則數(shù)據(jù)寄存器只有低16位有效,實際存放的數(shù)據(jù)只有12位而已,所以設置數(shù)據(jù)大小為半字大小。ADC配置為連續(xù)轉(zhuǎn)換模式,DMA也設置為循環(huán)傳輸模式。設置好DMA相關參數(shù)后就使能DMA的ADC通道。

接下來使用ADC_CommonInitTypeDef結(jié)構(gòu)體變量ADC_CommonInitStructure來配置ADC為獨立模式、分頻系數(shù)4、20個周期的采樣延遲,并調(diào)用ADC_CommonInit函數(shù)完成ADC通用工作環(huán)境配置。

使用ADC_InitTypeDef結(jié)構(gòu)體變量ADC_InitStructure來配置ADC1為12位分辨率、使能掃描模式、啟動連續(xù)轉(zhuǎn)換、使用內(nèi)部軟件觸發(fā)無需外部觸發(fā)事件、使用右對齊數(shù)據(jù)格式、轉(zhuǎn)換通道為3,并調(diào)用ADC_Init函數(shù)完成ADC1工作環(huán)境配置。

ADC_RegularChannelConfifig函數(shù)用來綁定ADC通道轉(zhuǎn)換順序和采樣時間。分別綁定3個ADC通道引腳并設置相應的轉(zhuǎn)換順序。

ADC_DMARequestAfterLastTransferCmd函數(shù)控制是否使能ADC的DMA請求,如果使能請求,并調(diào)用ADC_DMACmd函數(shù)使能DMA,則在ADC轉(zhuǎn)換完成后就請求DMA實現(xiàn)數(shù)據(jù)傳輸。ADC_Cmd函數(shù)控制ADC轉(zhuǎn)換啟動和停止。

最后使用軟件觸發(fā)調(diào)用ADC_SoftwareStartConvCmd函數(shù)進行使能配置。

(4)Main程序

/**主函數(shù)*/
intmain(void)
{
Debug_USART_Config();
Temp_Init();
while(1)
{
ADC_ConvertedValueLocal[0]=(float)ADC_ConvertedValue[0]/4096*(float)3.3;
ADC_ConvertedValueLocal[1]=(float)ADC_ConvertedValue[1]/4096*(float)3.3;
ADC_ConvertedValueLocal[2]=(float)ADC_ConvertedValue[2]/4096*(float)3.3;
printf("rnPB0value=%fVrn",ADC_ConvertedValueLocal[0]);
printf("rnPB1value=%fVrn",ADC_ConvertedValueLocal[1]);
printf("rnPA6value=%fVrn",ADC_ConvertedValueLocal[2]);
Delay(0xffffff);
}
}

主函數(shù)先調(diào)用Debug_USART_Config函數(shù)配置調(diào)試串口相關參數(shù),接下來調(diào)用Temp_Init函數(shù)進行ADC初始化配置并啟動ADC。配置了DMA數(shù)據(jù)傳輸,它會自動把ADC轉(zhuǎn)換完成后數(shù)據(jù)保存到數(shù)組ADC_ConvertedValue內(nèi),我們只要使用數(shù)組就可以了。經(jīng)過簡單地計算就可以得到每個通道對應的實際電壓。

來源:中科芯MCU

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 存儲器
    +關注

    關注

    38

    文章

    7484

    瀏覽量

    163761
  • adc
    adc
    +關注

    關注

    98

    文章

    6495

    瀏覽量

    544460
  • dma
    dma
    +關注

    關注

    3

    文章

    560

    瀏覽量

    100544
  • 電壓采集
    +關注

    關注

    2

    文章

    21

    瀏覽量

    14219
收藏 人收藏

    評論

    相關推薦

    MCU微課堂|CKS32F4xx系列產(chǎn)品時鐘配置

    作為MCU運行的基礎,時鐘是單片機各個模塊工作時序的最小時間單位,推動單片機的各指令執(zhí)行,是MCU選型的一個重要指標。CKS32F4xx系列產(chǎn)品具有眾多的外設,但并非所有的外設均需要系統(tǒng)時鐘的高頻率
    發(fā)表于 12-12 10:17 ?829次閱讀

    CKS32F4xx系列ETH通信詳解

    CKS32F4xx系列芯片自帶以太網(wǎng)模塊,該模塊包括帶專用DMA控制器的MAC 802.3(介質(zhì)訪問控制)控制器
    的頭像 發(fā)表于 11-10 11:13 ?991次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>ETH通信詳解

    CKS32F4xx系列DSP功能介紹

    CKS32F4xx系列使用高性能的32位內(nèi)核,支持浮點運算單元(FPU),同時還支持DSP指令以及存儲保護(MPU)用來加強應用的安全性。
    的頭像 發(fā)表于 03-04 13:43 ?1539次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>DSP功能介紹

    CKS32F4xx系列產(chǎn)品串口DMA傳輸

    在上一講,我們講過CKS32F4xx系列的6個串口都支持DMA傳輸。因此本節(jié)我們對CKS32F4xx系列
    的頭像 發(fā)表于 04-10 11:18 ?1031次閱讀

    CKS32F4xx系列RNG功能設置

    ? MCU 微課堂 CKS32F4xx 系 列RNG功能 隨機數(shù)發(fā)生器簡介 ? ? CKS32F4xx系列自帶了硬件隨機數(shù)發(fā)生器(RNG),RNG處理器是一個以連續(xù)模擬噪聲為基礎的隨機數(shù)發(fā)生器,在
    的頭像 發(fā)表于 09-08 10:01 ?602次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>RNG功能設置

    CKS32F4xx系列DAC功能

    CKS32F4xx系列DAC功能
    的頭像 發(fā)表于 11-06 16:56 ?845次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>DAC功能

    CKS32F4xx系列ADC通道電壓采集

    CKS32F4xx系列ADC通道電壓采集
    的頭像 發(fā)表于 11-06 16:54 ?980次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b><b class='flag-5'>ADC</b>單<b class='flag-5'>通道</b><b class='flag-5'>電壓</b><b class='flag-5'>采集</b>

    CKS32F4xx系列低功耗模式STANDBY模式

    CKS32F4xx系列低功耗模式STANDBY模式
    的頭像 發(fā)表于 11-06 16:57 ?471次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>低功耗模式STANDBY模式

    CKS32F4xx系列低功耗模式SLEEP模式

    CKS32F4xx系列低功耗模式SLEEP模式
    的頭像 發(fā)表于 11-06 16:59 ?672次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>低功耗模式SLEEP模式

    CKS32F4xx系列低功耗模式STOP模式

    CKS32F4xx系列低功耗模式STOP模式
    的頭像 發(fā)表于 11-06 17:08 ?620次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>低功耗模式STOP模式

    CKS32F4xx系列產(chǎn)品Timer的基本使用方法-比較輸出

    CKS32F4xx系列產(chǎn)品Timer的基本使用方法-比較輸出
    的頭像 發(fā)表于 11-09 17:39 ?848次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>產(chǎn)品Timer的基本使用方法-比較輸出

    CKS32F4xx系列產(chǎn)品Timer的基本使用方法-定時操作

    CKS32F4xx系列產(chǎn)品Timer的基本使用方法-定時操作
    的頭像 發(fā)表于 11-09 17:41 ?615次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>產(chǎn)品Timer的基本使用方法-定時操作

    MCU微課堂 | CKS32F4xx系列產(chǎn)品SPI通信

    MCU微課堂 | CKS32F4xx系列產(chǎn)品SPI通信
    的頭像 發(fā)表于 10-24 17:12 ?699次閱讀
    MCU微課堂 | <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>產(chǎn)品SPI通信

    MCU微課堂 | CKS32F4xx系列產(chǎn)品GPIO口配置

    MCU微課堂 | CKS32F4xx系列產(chǎn)品GPIO口配置
    的頭像 發(fā)表于 10-24 15:14 ?776次閱讀
    MCU微課堂 | <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>產(chǎn)品GPIO口配置

    CKS32F4xx系列FSMC功能簡介

    本課講為大家講解CKS32F4xx系列產(chǎn)品的FSMC應用實例,F(xiàn)SMC全稱是Flexible Static Memory Controller,讀作靈活的靜態(tài)存儲控制器,顧名思義,MCU可以通過FSMC擴展靜態(tài)內(nèi)存
    的頭像 發(fā)表于 04-14 15:06 ?932次閱讀
    <b class='flag-5'>CKS32F4xx</b><b class='flag-5'>系列</b>FSMC功能簡介
    RM新时代网站-首页