關(guān)聯(lián):STM32總結(jié)超全筆記【秋招自用】
【引言】
我們在上一節(jié)已經(jīng)了解了ADC以及AD單通道采集的過程,那么既然有AD單通道,那么必然有AD多通道,上一節(jié)也已經(jīng)鋪墊了一下:
【問】如果一個規(guī)則組同時用多個通道采集數(shù)據(jù),那么數(shù)據(jù)如何讀取?
??????????????????????????????????????????? --DMA-- ????????????????????????????????????????????????????
按照規(guī)則組的順序:上一個通道轉(zhuǎn)換的數(shù)據(jù)會被下一個通道轉(zhuǎn)換的數(shù)據(jù)所覆蓋。
所以通道轉(zhuǎn)換完畢后要及時使用DMA把數(shù)據(jù)取走。
【問】CPU不是也可以訪問這條ADC采集的數(shù)據(jù)總線嗎?為什么一定要DMA去做?
?CPU相當于STM32的大腦,對于數(shù)據(jù)的復(fù)制和存儲這種“小事情”,完全可以讓他的小助手DMA去做。
【DMA】
DMA,全稱Direct Memory Access,即直接存儲器訪問。
DMA將數(shù)據(jù)從一個地址空間復(fù)制到另一個地址空間,提供在外設(shè)和存儲器之間的高速數(shù)據(jù)傳輸。
【DMA工作流程】
如圖所示:
【DMA數(shù)據(jù)傳輸方式】
1.增量模式:DMA數(shù)據(jù)傳輸?shù)臄?shù)據(jù)源和目的地址會自動遞增。
優(yōu)點:可以方便的連續(xù)傳輸數(shù)據(jù)塊
適用于:從連續(xù)內(nèi)存區(qū)域讀取或?qū)懭霐?shù)據(jù)
2.循環(huán)模式:DMA數(shù)據(jù)傳輸?shù)臄?shù)據(jù)源和目的地之在達到終點后會回到起始地址。
優(yōu)點:可以重復(fù)傳輸一定長度的數(shù)據(jù)
適用于:周期性傳輸數(shù)據(jù) 或 循環(huán)緩沖區(qū)
【STM32的DMA】
STM32F103具有2個DMA控制器 ,DMA1有7個通道,DMA2有5個通道。每個通道都可以配置一些外設(shè)的地址。
這是DMA1可以產(chǎn)生的7個通道的DMA請求 ,每個通道對應(yīng)不同的外設(shè)
【例程10】AD多通道+DMA轉(zhuǎn)運實驗
【GPIO的配置】
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //開啟GPIOA的時鐘
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//將PA0、PA1、PA2和PA3引腳初始化為模擬輸入
四個引腳都配置為模擬輸入
【ADC的配置】
/*開啟時鐘*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //開啟ADC1的時鐘
/*設(shè)置ADC時鐘*/
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //選擇時鐘6分頻,ADCCLK = 72MHz / 6 = 12MHz
/*規(guī)則組通道配置*/
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //規(guī)則組序列1的位置,配置為通道0
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); //規(guī)則組序列2的位置,配置為通道1
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5); //規(guī)則組序列3的位置,配置為通道2
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5); //規(guī)則組序列4的位置,配置為通道3
/*ADC初始化*/
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //獨立模式,單獨使用ADC1
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //數(shù)據(jù)右對齊
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //使用軟件觸發(fā)
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //連續(xù)轉(zhuǎn)換
ADC_InitStructure.ADC_ScanConvMode = ENABLE; //掃描模式使能,掃描規(guī)則組的序列,掃描數(shù)量由ADC_NbrOfChannel確定
ADC_InitStructure.ADC_NbrOfChannel = 4; //通道數(shù)為4,掃描規(guī)則組的前4個通道
ADC_Init(ADC1, &ADC_InitStructure);
規(guī)則組通道配置:看圖即可。
多通道(4個通道)使能了連續(xù)轉(zhuǎn)換和掃描模式 。
【DMA的配置】
uint16_t AD_Value[4]; //定義用于存放AD轉(zhuǎn)換結(jié)果的全局數(shù)組
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //開啟DMA1的時鐘
/*DMA初始化*/
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
//外設(shè)基地址,給定形參AddrA
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
//外設(shè)數(shù)據(jù)寬度,選擇半字,對應(yīng)16為的ADC數(shù)據(jù)寄存器
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
//外設(shè)地址自增,選擇失能,始終以ADC數(shù)據(jù)寄存器為源
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;
//存儲器基地址,給定存放AD轉(zhuǎn)換結(jié)果的全局數(shù)組AD_Value
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
//存儲器數(shù)據(jù)寬度,選擇半字,與源數(shù)據(jù)寬度對應(yīng)
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//存儲器地址自增,選擇使能,每次轉(zhuǎn)運后,數(shù)組移到下一個位置
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
//數(shù)據(jù)傳輸方向,選擇由外設(shè)到存儲器,ADC數(shù)據(jù)寄存器轉(zhuǎn)到數(shù)組
DMA_InitStructure.DMA_BufferSize = 4;
//轉(zhuǎn)運的數(shù)據(jù)大?。ㄞD(zhuǎn)運次數(shù)),與ADC通道數(shù)一致
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
//模式,選擇循環(huán)模式,與ADC的連續(xù)轉(zhuǎn)換一致
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
//存儲器到存儲器,選擇失能,數(shù)據(jù)由ADC外設(shè)觸發(fā)轉(zhuǎn)運到存儲器
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
//優(yōu)先級,選擇中等
DMA_Init(DMA1_Channel1, &DMA_InitStructure); //將結(jié)構(gòu)體變量交給DMA_Init,配置DMA1的通道1
DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
指的是DMA傳輸?shù)耐庠O(shè)基地址,本實驗是DMA轉(zhuǎn)運ADC的數(shù)據(jù),自然是從ADC1的DR寄存器讀數(shù)據(jù)。
DMA_PeripheralDataSize_HalfWord;???
每次從外設(shè)讀取或向外設(shè)寫入數(shù)據(jù)時,DMA傳輸?shù)臄?shù)據(jù)大小為16位(2字節(jié)),
DMA_PeripheralInc_Disable;??
外設(shè)地址自增失能,因為始終要以ADC數(shù)據(jù)寄存器為源
DMA_Priority_Medium
?當多個DMA通道同時請求訪問DMA控制器時,這個優(yōu)先級決定了哪個通道會被優(yōu)先服務(wù)。文章來源:http://www.zghlxwxcb.cn/news/detail-858923.html
【使能ADC和DMA,觸發(fā)ADC】
/*DMA和ADC使能*/
DMA_Cmd(DMA1_Channel1, ENABLE); //DMA1的通道1使能
ADC_DMACmd(ADC1, ENABLE); //ADC1觸發(fā)DMA1的信號使能
ADC_Cmd(ADC1, ENABLE); //ADC1使能
/*ADC觸發(fā)*/
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //軟件觸發(fā)ADC開始工作
【主函數(shù)】
while (1)
{
OLED_ShowNum(1, 5, AD_Value[0], 4); //顯示轉(zhuǎn)換結(jié)果第0個數(shù)據(jù)
OLED_ShowNum(2, 5, AD_Value[1], 4); //顯示轉(zhuǎn)換結(jié)果第1個數(shù)據(jù)
OLED_ShowNum(3, 5, AD_Value[2], 4); //顯示轉(zhuǎn)換結(jié)果第2個數(shù)據(jù)
OLED_ShowNum(4, 5, AD_Value[3], 4); //顯示轉(zhuǎn)換結(jié)果第3個數(shù)據(jù)
Delay_ms(100); //延時100ms,手動增加一些轉(zhuǎn)換的間隔時間
}
把數(shù)組中的數(shù)據(jù)在OLED上顯示出來文章來源地址http://www.zghlxwxcb.cn/news/detail-858923.html
到了這里,關(guān)于【第五章】STM32-ADC模數(shù)轉(zhuǎn)換(2.AD多通道+DMA轉(zhuǎn)運實驗)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!