在實(shí)際的開(kāi)發(fā)中需要使用各式各樣的傳感器,這些傳感器可以采集周?chē)沫h(huán)境信息,比如溫度、濕度、氣壓、光照等,這些信息本質(zhì)上是物理的模擬信號(hào),計(jì)算機(jī)處理信息時(shí)對(duì)數(shù)字信號(hào)比較敏感,因此把模擬信號(hào)轉(zhuǎn)換為數(shù)字信號(hào)是有必要的。ADC就起到了這樣的作用,本節(jié)將對(duì)ADC功能原理以及ADC數(shù)據(jù)采集時(shí)涉及到的DMA技術(shù)進(jìn)行詳解。
- ADC的概念:Analog-to-Digital Converter的縮寫(xiě)。指模/數(shù)轉(zhuǎn)換器或者模擬/數(shù)字轉(zhuǎn)換器。是指將連續(xù)變量的模擬信號(hào)轉(zhuǎn)換為離散的數(shù)字信號(hào)的器件。
- ADC的作用:采集傳感器的數(shù)據(jù),測(cè)量輸入電壓,檢查電池電量剩余,監(jiān)測(cè)溫濕度等。典型的模擬數(shù)字轉(zhuǎn)換器將模擬信號(hào)轉(zhuǎn)換為表示一定比例電壓值的數(shù)字信號(hào)。
- ADC的性能指標(biāo):
量程:能測(cè)量的電壓范圍,一般來(lái)收量程越大越好
分辨率:ADC的分辨率通常以輸出二進(jìn)制數(shù)的位數(shù)表示,位數(shù)越多,分辨率越高,精度越大,外部微小的變化都可以被顯示。一般來(lái)說(shuō)分辨率越高,轉(zhuǎn)化時(shí)間越長(zhǎng)。
轉(zhuǎn)化時(shí)間:模擬輸入電壓在允許的最大變化范圍內(nèi),從轉(zhuǎn)換開(kāi)始到獲得穩(wěn)定的數(shù)字量輸出所需要的時(shí)間稱(chēng)為轉(zhuǎn)換時(shí)間,希望時(shí)間越短越好。
- STM32F4的ADC配置:
STM32F40X有3個(gè)ADC,每個(gè)可配置 12 位、10 位、8 位或 6 位分辨率
每個(gè)ADC 有16個(gè)外部通道。另外還有兩個(gè)內(nèi)部 ADC源(直接測(cè)量?jī)?nèi)部溫度和電壓信號(hào)) 和 V BAT 通道(測(cè)量電池的剩余電量)掛在 ADC1上
這些通道的 A/D 轉(zhuǎn)換可以單次、連續(xù)、掃描或間斷模式執(zhí)行。
ADC具有獨(dú)立模式(單個(gè)ADC工作)、雙重模式(兩個(gè)ADC配合工作完成采樣)和三重模式(三個(gè)ADC配合工作完成采樣),對(duì)于不同 AD轉(zhuǎn)換要求幾乎都有合適的模式可選
ADC 的結(jié)果可以左對(duì)齊或右對(duì)齊方式存儲(chǔ)在 16 位數(shù)據(jù)寄存器中。采集到的數(shù)據(jù)精度最大為12位,不夠16位,因此,需要選擇合適的存儲(chǔ)方式。
- ADC功能框圖分析:
1、電壓輸入范圍:ADC 輸入范圍為:V REF- ≤ V IN ≤ V REF+ 。由 V REF- 、V REF+ 、V DDA 、V SSA 、這四個(gè)外部引腳決定。我們?cè)谠O(shè)計(jì)原理圖的時(shí)候一般把 V SSA 和 V REF- 接地,把 V REF+ 和 V DDA 接 3.3V,得到ADC 的輸入電壓范圍為:03.3V。如果我們想讓輸入的電壓范圍變寬,去到可以測(cè)試負(fù)電壓或者更高的正電壓,我們可以在外部加一個(gè)電壓調(diào)理電路(線性的轉(zhuǎn)換關(guān)系,如根據(jù)一定的轉(zhuǎn)換關(guān)系將-10V10V轉(zhuǎn)換為03.3V),把需要轉(zhuǎn)換的電壓抬升或者降壓到 03.3V,這樣 ADC 就可以測(cè)量了
2、輸入通道:每個(gè)ADC 有16個(gè)外部通道。特別是ADC1還有兩個(gè)內(nèi)部 ADC 源 和 V BAT 通道掛在 ADC1上,V BAT 通道也屬于內(nèi)部通道,兩個(gè)內(nèi)部 ADC 源沒(méi)有對(duì)應(yīng)外部管腳,直接測(cè)量?jī)?nèi)部信息。一個(gè)連接內(nèi)部溫度傳感器,主要測(cè)量CPU以及芯片內(nèi)部的一些關(guān)鍵電路的溫度。另一個(gè)連接VREFINT,測(cè)量電源模塊的電壓值,V BAT 通道用來(lái)測(cè)量備用電池的電池容量。
3、轉(zhuǎn)換順序
a.規(guī)則通道組:顧名思意,規(guī)則通道就是很規(guī)矩的意思,我們平時(shí)一般使用的就是這個(gè)通道。相當(dāng)于正常運(yùn)行的程序,最多16個(gè)通道,在使用過(guò)程中按順序進(jìn)行轉(zhuǎn)換,按順序采集完一個(gè)通道進(jìn)行轉(zhuǎn)換后再采集下一個(gè)通道進(jìn)行轉(zhuǎn)換。規(guī)則通道和它的轉(zhuǎn)換順序在ADC_SQRx寄存器中選擇,規(guī)則組轉(zhuǎn)換的總數(shù)應(yīng)寫(xiě)入ADC_SQR1寄存器的L[3:0]中。
ADC像這樣的規(guī)則序列寄存器有3個(gè),每個(gè)規(guī)則序列寄存器都能設(shè)定第n次轉(zhuǎn)換的具體通道,共有16個(gè)外部通道,最多設(shè)置16次。如上圖,規(guī)則序列寄存器3(ADC_SQR3)可以設(shè)定第一次到第六次順序轉(zhuǎn)換的通道,規(guī)則序列寄存器2(ADC_SQR2)可以設(shè)定第七次到第十二次順序轉(zhuǎn)換的通道,規(guī)則序列寄存器1(ADC_SQR1)可以設(shè)定第十三次到第十六次順序轉(zhuǎn)換的通道,且ADC_SQR1寄存器的L[3:0]中(20位到23位)用來(lái)設(shè)定要順序轉(zhuǎn)換的通道個(gè)數(shù)。例:有如下轉(zhuǎn)換順序要求,有4個(gè)通道,第一次轉(zhuǎn)換通道2,第二次轉(zhuǎn)換通道3,第三次轉(zhuǎn)換通道4,第四次轉(zhuǎn)換通道1,則ADC_SQR1寄存器的L[3:0]的值位0100,ADC_SQR3中SQ1的值設(shè)為2,SQ2的值設(shè)為3,SQ3的值設(shè)為4,SQ4的值設(shè)為1。具體的操作在Cube MX中可以配置
b.注入通道組:注入,可以理解為插入,插隊(duì)的意思,是一種不安分的通道。相當(dāng)于中斷。最多4個(gè)通道。把某一通道配置位注入通道時(shí),它的優(yōu)先級(jí)就比規(guī)則通道高,暫停規(guī)則通道組的工作,優(yōu)先轉(zhuǎn)換注入通道組采集到的信號(hào)。注入組和它的轉(zhuǎn)換順序在ADC_JSQR寄存器中選擇。注入組里轉(zhuǎn)化的總數(shù)應(yīng)寫(xiě)入ADC_JSQR寄存器的L[1:0]中。該通道組的配置方法于規(guī)則通道組相同。
4、轉(zhuǎn)換時(shí)間:ADC 輸入時(shí)鐘 ADC_CLK 由 PCLK2 經(jīng)過(guò)分頻產(chǎn)生,最大值是 36MHz,即最大工作時(shí)鐘不能超過(guò)36MHz,典型值為30MHz。對(duì)于 STM32F407我們一般設(shè)置PCLK2=HCLK/2=84MHz,最少需要4分頻。所以程序一般使用 4分頻或者 6分頻。
ADC 的總轉(zhuǎn)換時(shí)間Tconv = 采樣時(shí)間 + 12個(gè)周期(轉(zhuǎn)換時(shí)間),采樣時(shí)間最少不小于3個(gè)ADC_CLK,轉(zhuǎn)換時(shí)間一般就是12個(gè)ADC_CLK,如果對(duì)時(shí)間沒(méi)有太過(guò)苛刻的要求,應(yīng)當(dāng)把采樣時(shí)間設(shè)置的稍長(zhǎng)一些,這樣得到的結(jié)果才會(huì)更加準(zhǔn)確。最小采樣時(shí)間: T =3 + 112= 15個(gè)周期=0.42us(ADC時(shí)鐘=36MHz下得到)。
5、數(shù)據(jù)寄存器:規(guī)則數(shù)據(jù)寄存器 ADC_DR
ADC_DR只有一個(gè),是一個(gè)32 位的寄存器,只有低 16 位有效并且只是用于獨(dú)立模式存放轉(zhuǎn)換完成數(shù)據(jù)。因?yàn)?ADC 的最大精度是 12 位,ADC_DR 是16 位有效,這樣允許 ADC存放數(shù)據(jù)時(shí)候選擇左對(duì)齊或者右對(duì)齊,具體是以哪一種方式存放,由 ADC_CR2的 11 位 ALIGN 設(shè)置。對(duì)于規(guī)則通道組來(lái)說(shuō),所有的規(guī)則通道都使用這一個(gè)數(shù)據(jù)寄存器,實(shí)際采樣點(diǎn)時(shí)候,如果開(kāi)啟了多個(gè)通道,每轉(zhuǎn)換完成一個(gè)通道要及時(shí)把數(shù)據(jù)從寄存器中取走。如果不及時(shí)取走,下一次轉(zhuǎn)換完成的數(shù)據(jù)就會(huì)覆蓋原數(shù)據(jù)。而對(duì)于注入通道組來(lái)說(shuō),每一個(gè)注入通道都對(duì)應(yīng)一個(gè)數(shù)據(jù)寄存器。
使用 DMA:由于規(guī)則通道組只有一個(gè)數(shù)據(jù)寄存器,因此,對(duì)于多個(gè)規(guī)則通道的轉(zhuǎn)換,使用 DMA 非常有幫助。這樣可以避免丟失在下一次寫(xiě)入之前還未被讀出的 ADC_DR 寄存器中的數(shù)據(jù)。在使能 DMA 模式的情況下(ADC_CR2 寄存器中的 DMA 位置 1),每完成規(guī)則通道組中的一個(gè)通道轉(zhuǎn)換后,都會(huì)生成一個(gè) DMA 請(qǐng)求。
6、中斷
a.轉(zhuǎn)換結(jié)束中斷:規(guī)則通道和注入通道的數(shù)據(jù)轉(zhuǎn)換結(jié)束后,都可以產(chǎn)生中斷。通道轉(zhuǎn)換完成后,ADC 狀態(tài)寄存器 ADC_SR的EOC位會(huì)置1,可以不斷輪詢此位來(lái)判斷是否觸發(fā)中斷,也可以使能中斷,完成后就根據(jù)此位的狀態(tài)觸發(fā)中斷。此中斷的使用是最多的,可以在此中斷處理程序中獲取我們想要采集的數(shù)據(jù)。
b.模擬看門(mén)狗中斷:當(dāng)被 ADC 轉(zhuǎn)換的模擬電壓低于低閾值或者高于高閾值時(shí),就會(huì)產(chǎn)生中斷
c.溢出中斷:如果發(fā)生 DMA傳輸數(shù)據(jù)丟失,會(huì)置位 ADC 狀態(tài)寄存器 ADC_SR的 OVR位,如果同時(shí)使能了溢出中斷,那在轉(zhuǎn)換結(jié)束后會(huì)產(chǎn)生一個(gè)溢出中斷。
d.DMA 請(qǐng)求:規(guī)則和注入通道轉(zhuǎn)換結(jié)束后,除了產(chǎn)生中斷外,還可以產(chǎn)生 DMA請(qǐng)求,把轉(zhuǎn)換好的數(shù)據(jù)直接存儲(chǔ)在內(nèi)存里面。
7、觸發(fā)源
a.軟件觸發(fā):ADC轉(zhuǎn)換可以由ADC 控制寄存器 2: ADC_CR2的 ADON這個(gè)位來(lái)控制,寫(xiě) 1的時(shí)候開(kāi)始轉(zhuǎn)換,寫(xiě) 0 的時(shí)候停止轉(zhuǎn)換。此方法使用最多
b.外部事件觸發(fā):觸發(fā)包括內(nèi)部定時(shí)器觸發(fā)和外部 IO觸發(fā)。觸發(fā)源有很多,具體選擇哪一種觸發(fā)源,由 ADC控制寄存器ADC_CR2的 EXTSEL[2:0]和 JEXTSEL[2:0]位來(lái)控制
- ADC的工作模式
單次轉(zhuǎn)換模式:ADC每次工作只轉(zhuǎn)換一次,至于這一次轉(zhuǎn)換幾個(gè)通道并不關(guān)心,如果想要再次轉(zhuǎn)換,必須重新啟動(dòng)ADC。
連續(xù)轉(zhuǎn)換模式:在連續(xù)轉(zhuǎn)換模式下,ADC結(jié)束一個(gè)轉(zhuǎn)換后立即啟動(dòng)一個(gè)新的轉(zhuǎn)換,直到用戶想要停止為止。(僅適用于規(guī)則通道)。
掃描模式:該模式主要針對(duì)多個(gè)通道進(jìn)行轉(zhuǎn)換。例如使用單次轉(zhuǎn)換模式又開(kāi)啟掃描模式,從第1個(gè)通道開(kāi)始掃描,掃描第n個(gè)通道結(jié)束后不再掃描;如果使用單次轉(zhuǎn)換模式而不開(kāi)啟掃描模式,這多個(gè)通道很有可能只轉(zhuǎn)換第1個(gè)通道;使用連續(xù)轉(zhuǎn)換模式又開(kāi)啟掃描模式,從第1個(gè)通道開(kāi)始掃描,掃描第n個(gè)通道結(jié)束后再?gòu)牡?個(gè)通道開(kāi)始掃描,循環(huán)往復(fù)。
不連續(xù)采樣模式:有多個(gè)通道需要轉(zhuǎn)換,此模式下一次只轉(zhuǎn)換其中的幾個(gè),這個(gè)值n需要用戶自己設(shè)定,假設(shè)有0、1、2、3、6、7、9、10這幾個(gè)通道需要轉(zhuǎn)換,n設(shè)置為3,則
- STM32ADC單通道采集實(shí)例
實(shí)驗(yàn):利用ADC采集FSM4中電位器的數(shù)據(jù)
說(shuō)明:電位器本質(zhì)上就是一個(gè)滑動(dòng)變阻器,通過(guò)調(diào)節(jié)電阻就可以輸出不同的電壓值,電壓值通過(guò)PC3進(jìn)入ADC的輸入通道。
步驟:
1.配置RCC,ADC依賴(lài)于時(shí)鐘APB2
2.配置PC3為ADC1的通道13
3.配置ADC1
4.使能中斷,轉(zhuǎn)換完成觸發(fā)中斷
5.編寫(xiě)代碼
//main.c
uint32_t adc_value = 0;//全局變量外部才可以使用
int main(){
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();//ADC1初始化配置,仍然采用結(jié)構(gòu)體元素賦值的形式
MX_USART1_UART_Init();
while(){
/***方法一:輪詢采集ADC的值,也就是輪詢判斷EOC是否置位***/
//置位說(shuō)明轉(zhuǎn)換完成就可以讀值
//啟動(dòng)ADC1,軟件觸發(fā)方式,將對(duì)應(yīng)的啟動(dòng)位置位
HAL_ADC_Start(&hadc1);
//HAL_ADC_PollForConversion(&hadc1, 100)該函數(shù)內(nèi)部循環(huán)判斷
//EOC是否置位,沒(méi)有置位就一直等待,直到超時(shí)
if( HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK ){
adc_value = HAL_ADC_GetValue(&hadc1);//讀取數(shù)據(jù)寄存器里的值
printf("adc_value = %dn",adc_value);
}
HAL_Delay(1000);//每過(guò)1s鐘重新啟動(dòng)ADC
/***方法二:轉(zhuǎn)換完成后觸發(fā)中斷,在中斷中接收數(shù)值***/
HAL_ADC_Start_IT(&hadc1);//啟動(dòng)ADC1并使能中斷
HAL_Delay(1000);//每過(guò)1s鐘重新啟動(dòng)ADC
}
}
//adc.c
//重寫(xiě)轉(zhuǎn)換結(jié)束中斷回調(diào)函數(shù),這里對(duì)應(yīng)方法二
extern uint32_t adc_value;//全局變量
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
if(hadc- >Instance == ADC1) {
adc_value = HAL_ADC_GetValue(&hadc1);//讀取數(shù)據(jù)寄存器里的值
printf("adc_value = %dn",adc_value);
}
}
- STM32 ADC多通道采集實(shí)例
實(shí)驗(yàn)要求:利用ADC采集電位器及STM32內(nèi)部溫度傳感器的數(shù)據(jù)。
說(shuō)明:采集內(nèi)部溫度傳感器使用的是內(nèi)部專(zhuān)用通道,選擇通道16或者通道18均可采集內(nèi)部溫度,需要注意的是,實(shí)際中多路通道的采集一般使用DMA來(lái)進(jìn)行數(shù)據(jù)的搬移,因?yàn)橐?guī)則通道的數(shù)據(jù)寄存器只有一個(gè),如果不及時(shí)取走數(shù)據(jù),上一次采集的數(shù)據(jù)可能被覆蓋,DMA的知識(shí)將在后期進(jìn)行講解,因此本節(jié)仍采用輪詢的方式查詢標(biāo)志位,及時(shí)將數(shù)據(jù)取出。
步驟:
1.配置時(shí)鐘RCC
2.配置PC3位ADC1的通道13,配置內(nèi)部溫度傳感器通道.
3.配置ADC
4.編寫(xiě)代碼
//mian.c
int main(){
uint32_t adc_value = 0;
uint8_t i;
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
MX_USART1_UART_Init();
while(){
//啟動(dòng)ADC1,軟件觸發(fā)方式,將對(duì)應(yīng)的啟動(dòng)位置位
HAL_ADC_Start(&hadc1);
for(i=0;i< 2;i++){ //使用了幾個(gè)通道就應(yīng)該輪詢幾次
//首先采集外部通道電位器的數(shù)值,第二次采集內(nèi)部溫度傳感器的值
//HAL_ADC_PollForConversion(&hadc1, 100)該函數(shù)內(nèi)部循環(huán)判斷
//EOC是否置位,沒(méi)有置位就一直等待,直到超時(shí)
if( HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK ){
adc_value = HAL_ADC_GetValue(&hadc1);//讀取數(shù)據(jù)寄存器里的值
printf("adc_value = %dn",adc_value);
}
}
HAL_Delay(1000);//每過(guò)1s鐘重新啟動(dòng)ADC
}
}
- STM32數(shù)據(jù)搬運(yùn)工DMA專(zhuān)題講解
DMA專(zhuān)門(mén)用于數(shù)據(jù)搬運(yùn),在開(kāi)發(fā)中經(jīng)常會(huì)遇到外設(shè)與內(nèi)存、內(nèi)存與內(nèi)存進(jìn)行大量的數(shù)據(jù)交互的情況,這些情況一般都是由CPU進(jìn)行控制的,如果數(shù)據(jù)交互非常頻繁且數(shù)據(jù)量巨大,那么CPU就會(huì)被大量占用用于數(shù)據(jù)交互而無(wú)法完成其他工作,為了把CPU從這種單一繁瑣的工作中釋放出來(lái),很多微控制器中都有專(zhuān)門(mén)用于數(shù)據(jù)交互的器件,就是DMA。
DMA,全稱(chēng)為:Direct Memory Access,即直接存儲(chǔ)器訪問(wèn)。DMA 傳輸方式無(wú)需 CPU 直接控制傳輸,也沒(méi)有中斷處理方式那樣保留現(xiàn)場(chǎng)和恢復(fù)現(xiàn)場(chǎng)的過(guò)程,通過(guò)硬件為RAM 與 I/O 設(shè)備開(kāi)辟一條直接傳送數(shù)據(jù)的通路,無(wú)需CPU的參與,CPU將這條通路的控制權(quán)釋放,轉(zhuǎn)交由DMA控制器控制,能使 CPU 的效率大為提高。DMA控制器只用于數(shù)據(jù)交互,無(wú)其他功能。
- STM32F4-DMA功能框圖分析
①外設(shè)通道:STM32F4xx 系列資源豐富,具有兩個(gè) DMA 控制器,同時(shí)外設(shè)繁多,為實(shí)現(xiàn)正常傳輸,DMA需要通道選擇控制。每個(gè) DMA控制器具有 8個(gè)數(shù)據(jù)流,每個(gè)數(shù)據(jù)流對(duì)應(yīng) 8個(gè)外設(shè)請(qǐng)求。
外設(shè)通道選擇要解決的主要問(wèn)題是決定哪一個(gè)外設(shè)作為該數(shù)據(jù)流的源地址或者目標(biāo)地址。宏觀上一個(gè)數(shù)據(jù)流的所有通道可以同時(shí)工作,微觀上通道異步前進(jìn)進(jìn)行工作,或者根據(jù)通道優(yōu)先級(jí)進(jìn)行工作
DMA1外設(shè)通道表如下:
DMA2外設(shè)通道表如下:
每個(gè)數(shù)據(jù)流都與一個(gè) DMA 請(qǐng)求相關(guān)聯(lián),此 DMA 請(qǐng)求可以從 8 個(gè)可能的通道請(qǐng)求中選出。此選擇由 DMA_SxCR 寄存器中的 CHSEL[2:0] 位控制,3位用來(lái)控制8個(gè)通道的選擇。
②數(shù)據(jù)流仲裁:一個(gè) DMA控制器對(duì)應(yīng) 8個(gè)數(shù)據(jù)流,數(shù)據(jù)流包含要傳輸數(shù)據(jù)的源地址、目標(biāo)地址、數(shù)據(jù)長(zhǎng)度等等信息。如果我們需要同時(shí)使用同一個(gè)DMA 控制器(DMA1 或 DMA2)多個(gè)外設(shè)請(qǐng)求時(shí),那必然需要同時(shí)使用多個(gè)數(shù)據(jù)流,那究竟哪一個(gè)數(shù)據(jù)流具有優(yōu)先傳輸?shù)臋?quán)利呢?這就需要仲裁器來(lái)管理判斷
每個(gè)數(shù)據(jù)流的優(yōu)先級(jí)都可以通過(guò)配置 DMA_SxCR寄存器 PL[1:0]位,設(shè)置為非常高、高、中和低四個(gè)級(jí)別,由于8個(gè)數(shù)據(jù)流只有4個(gè)優(yōu)先級(jí),如果兩個(gè)或以上數(shù)據(jù)流軟件設(shè)置優(yōu)先級(jí)一樣,則他們優(yōu)先級(jí)取決于數(shù)據(jù)流編號(hào),編號(hào)越低越具有優(yōu)先權(quán)。
③數(shù)據(jù)FIFO:每個(gè)數(shù)據(jù)流都有一個(gè)獨(dú)立的 4 字 FIFO(先進(jìn)先出存儲(chǔ)器緩沖區(qū)), DMA傳輸具有 FIFO模式和直接模式。
a.直接模式:每個(gè) DMA 請(qǐng)求會(huì)立即啟動(dòng)對(duì)存儲(chǔ)器的傳輸。當(dāng)在直接模式(禁止 FIFO)下將 DMA請(qǐng)求配置為以存儲(chǔ)器到外設(shè)模式傳輸數(shù)據(jù)時(shí),DMA 僅會(huì)將一個(gè)數(shù)據(jù)從存儲(chǔ)器預(yù)加載到內(nèi)部 FIFO,從而確保一旦外設(shè)觸發(fā) DMA 請(qǐng)求時(shí)則立即傳輸數(shù)據(jù)。
b.FIFO模式:可通過(guò)控制寄存器 DMA_SxFCR 的 FTH[1:0]位來(lái)設(shè)置FIFO 閾值級(jí)別為 FIFO 大小的 1/4、1/2 或 3/4。如果數(shù)據(jù)存儲(chǔ)量達(dá)到閾值級(jí)別時(shí),F(xiàn)IFO 內(nèi)容將傳輸?shù)侥繕?biāo)中。如果對(duì)傳輸速度要求不是很苛刻,建議使用此模式、直接模式傳輸效率太低,一次傳輸?shù)臄?shù)據(jù)量少而工作量大。
④存儲(chǔ)器端口:DMA 控制器提供兩個(gè) AHB 主端口,分別為AHB 存儲(chǔ)器端口(用于連接存儲(chǔ)器)和 AHB 外設(shè)端口(用于連接外設(shè))。存儲(chǔ)器端口用來(lái)連接外部存儲(chǔ)器,實(shí)現(xiàn)內(nèi)存與外存的數(shù)據(jù)交互。
⑤外設(shè)端口:用于連接外設(shè),實(shí)現(xiàn)內(nèi)存與外設(shè)的數(shù)據(jù)交互.
注意:DMA1 控制器 AHB 外設(shè)端口與 DMA2 控制器的情況不同,DMA1 控制器 AHB 外設(shè)端口沒(méi)有連接到總線矩陣,因此,僅 DMA2 數(shù)據(jù)流能夠執(zhí)行存儲(chǔ)器到存儲(chǔ)器的傳輸,DMA1 不能實(shí)現(xiàn)存儲(chǔ)器到存儲(chǔ)器傳輸。
- STM32F4-DMA傳輸
1.傳輸模式 :DMA1 只有外設(shè)到存儲(chǔ)器和存儲(chǔ)器到外設(shè)兩種模式,DMA2 除前面兩種傳輸模式外還支持存儲(chǔ)器到存儲(chǔ)器的傳輸模式。模式選擇可以通過(guò) DMA_SxCR 寄存器的 DIR[1:0]位(方向選擇,規(guī)定誰(shuí)是源,誰(shuí)是目的)進(jìn)行控制。
2.DMA傳輸模式的源、目的、長(zhǎng)度:
a.DMA_SxPAR寄存器: 設(shè)置外設(shè)寄存器地址
b.DMA_SxM0AR寄存器:設(shè)置存儲(chǔ)器地址
c.DMA_SxCR 寄存器 :DIR[1:0]位配置數(shù)據(jù)的傳輸方向
d.DMA_CNDTRx 寄存器:寫(xiě)入需要傳輸?shù)臄?shù)據(jù)量, (0 到 65535),注意是數(shù)據(jù)的一個(gè)量,單位并不是字節(jié)
e.DMA_SxCR 寄存器中的 PSIZE 和 MSIZE 位:設(shè)置源和目的的數(shù)據(jù)寬度,兩邊的位寬盡量保持一致,位寬只一次傳輸多大的位寬(如一次傳輸2字節(jié),位寬16位),如果不能保持位寬,很有可能造成數(shù)據(jù)丟失,應(yīng)當(dāng)開(kāi)啟FIFO模式,保證數(shù)據(jù)不丟失。
3.DMA增量設(shè)置:
a.根據(jù)設(shè)置 DMA_SxCR 寄存器中 PINC 和 MINC 位的狀態(tài),外設(shè)和存儲(chǔ)器指針在每次傳輸后可以自動(dòng)向后遞增或保持常量。
b.當(dāng)設(shè)置為增量模式時(shí),下一個(gè)要傳輸?shù)牡刂穼⑹乔耙粋€(gè)地址加上增量值,增量值取決與所選的數(shù)據(jù)寬度為1字節(jié)(8位) 、2 字節(jié)(16位)或 4字節(jié)(32位) 。如果不啟動(dòng),每一次取很有可能只取首地址對(duì)應(yīng)數(shù)據(jù),而不會(huì)向后取值。
c.一般情況下外設(shè)并不需要遞增,每一次都是同一個(gè)地址,要不要配置外設(shè)的增量模式依具體情況而定。
4.DMA循環(huán)模式:
a.循環(huán)模式用于處理循環(huán)緩沖區(qū)和連續(xù)的數(shù)據(jù)傳輸 ( 如 ADC 的連續(xù)循環(huán)掃描模式 ) 。可以使用 DMA_SxCR 寄存器中的 CIRC 位使能此特性。
b.當(dāng)啟動(dòng)了循環(huán)模式,一組的數(shù)據(jù)傳輸完成時(shí),計(jì)數(shù)寄存器將會(huì)自動(dòng)地被恢復(fù)成配置該通道時(shí)設(shè)置的初值, DMA 操作將會(huì)繼續(xù)進(jìn)行。
5.DMA單次傳輸和突發(fā)傳輸:
a.DMA傳輸類(lèi)型有單次(Single)傳輸和突發(fā)(Burst)傳輸。DMA 控制器可以產(chǎn)生單次傳輸或 4 個(gè)、8 個(gè)和 16 個(gè)節(jié)拍的增量突發(fā)傳輸。一個(gè)節(jié)拍對(duì)應(yīng)著用戶配置的一個(gè)數(shù)據(jù)寬度,一般突發(fā)傳輸要配合FIFO來(lái)使用,突發(fā)傳輸?shù)臄?shù)據(jù)量不可能超過(guò)FIFO的大小
b.突發(fā)大小通過(guò)軟件針對(duì)兩個(gè) AHB 端口獨(dú)立配置,配置時(shí)使用 DMA_SxCR 寄存器中的MBURST[1:0] 和 PBURST[1:0] 位。
c.為確保數(shù)據(jù)一致性,形成突發(fā)的每一組傳輸都不可分割:在突發(fā)傳輸序列期間,AHB 傳輸會(huì)鎖定,并且 AHB 總線矩陣的仲裁器不解除對(duì) DMA 主總線的授權(quán)。
6.DMA中斷: 對(duì)于每個(gè) DMA 數(shù)據(jù)流,可在達(dá)到半傳輸、傳輸完成、傳輸錯(cuò)誤、FIFO 錯(cuò)誤(上溢、下溢或 FIFO 級(jí)別錯(cuò)誤)、直接模式錯(cuò)誤時(shí)產(chǎn)生中斷。這些標(biāo)志位都在中斷狀態(tài)寄存器DMA_xISR中設(shè)置。
- ADC_DMA多路采集實(shí)例
實(shí)驗(yàn)要求:利用ADC采集電位器以及芯片內(nèi)部溫度傳感器的數(shù)據(jù),在main函數(shù)中啟動(dòng)ADC轉(zhuǎn)換以及DMA傳輸,最后在DMA完成中斷中打印采集到的數(shù)據(jù)。
說(shuō)明:之前使用ADC采集兩路數(shù)據(jù)是使用輪詢的方式判斷采集,需要CPU一直去判斷,消耗CPU資源,顯然這并不是ADC多路采集最好的辦法,ADC多路采集一般使用DMA來(lái)進(jìn)行傳輸,規(guī)則通道組采集數(shù)據(jù)時(shí)只有一個(gè)數(shù)據(jù)寄存器ADC_DR,讀取數(shù)據(jù)不及時(shí)很有可能發(fā)生數(shù)據(jù)覆蓋。
采用DMA傳輸,每當(dāng)一路數(shù)據(jù)采集完成后都會(huì)產(chǎn)生一個(gè)DMA請(qǐng)求,及時(shí)把數(shù)據(jù)寄存器中的值搬移到內(nèi)存中相應(yīng)的buffer中去
步驟:
1.配置RCC
2.配置PC3位ADC1的通道13,配置內(nèi)部溫度傳感器通道
3.配置DMA
4.配置ADC
5.配置中斷
5.編寫(xiě)代碼
//main.c
uint16_t adc_value[2] = {0};//定義一個(gè)全局的接受區(qū)域,以便外部調(diào)用
int mian(){
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_ADC1_Init();
printf("this is adc dma testn");
while(1){
//此函數(shù)既啟動(dòng)ADC,又使能DMA
HAL_ADC_Start_DMA(&hadc1, (uint32_t*) adc_value, 2);
//2表示傳輸了2個(gè)數(shù)據(jù)的量,一個(gè)量是我們?cè)O(shè)定的位寬
//內(nèi)部有一個(gè)專(zhuān)門(mén)的寄存器來(lái)記錄這個(gè)量,每傳輸完成一次,寄存器的值減1
//減到0就會(huì)觸發(fā)DMA的傳輸完成中斷
HAL_Delay(1000); //每過(guò)1s啟動(dòng)一次
}
}
關(guān)于DMA傳輸完成中斷處理函數(shù)是哪一個(gè),先將函數(shù)HAL_ADC_Start_DMA(&hadc1, (uint32_t*) adc_value, 2);追進(jìn)去可以看到一段代碼設(shè)置了DMA傳輸完成的回調(diào)函數(shù),將這個(gè)函數(shù)賦給了一個(gè)指針,這個(gè)指針是DMA_Handle下的一個(gè)指針,DMA可以用于很多的外設(shè),不同的外設(shè)的轉(zhuǎn)換完成函數(shù)是不一樣的,DMA沒(méi)有一個(gè)固定的處理函數(shù),這個(gè)函數(shù)需要在外設(shè)配置的時(shí)候自己去初始化,DMA只提供一個(gè)接口,一個(gè)傳輸轉(zhuǎn)換完成的函數(shù)指針,不同的外設(shè)對(duì)這個(gè)結(jié)構(gòu)賦不同的處理函數(shù)的指針,這里對(duì)ADC來(lái)說(shuō)自己封裝了一個(gè)DMA傳輸完成處理中斷的函數(shù),當(dāng)DMA傳輸完成中斷觸發(fā)的時(shí)候自己去調(diào)用這個(gè)接口下的對(duì)應(yīng)的函數(shù)。ConvCplt的意思是ConverseComplete
將void DMA2_Stream0_IRQHandler(void)這個(gè)中斷處理函數(shù)入口追進(jìn)去可以看到DMA有各種不同的中斷處理請(qǐng)求,我們?cè)趥鬏斖瓿芍袛啵猅ransfer Complete Interrupt management***這一部分里可以看到hdma->XferCpltCallback(hdma);這樣一個(gè)指針函數(shù),但是用戶無(wú)法使用這個(gè)指針函數(shù),這個(gè)指針在HAL_ADC_Start_DMA(&hadc1, (uint32_t*) 這個(gè)函數(shù)中已經(jīng)賦值,實(shí)際上這個(gè)函數(shù)最終進(jìn)入了HAL_ADC_ConvCpltCallback函數(shù),也就是ADC傳輸完成函數(shù)。
//adc.c
extern uint16_t adc_value[2] ;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
//每一次采集完成后都會(huì)將數(shù)據(jù)傳輸?shù)剑觯幔欤酰逯?
if(hadc- >Instance == ADC1) {
printf("adc_value[0]=%d, adc_value[1]=%dn",adc_value[0],adc_value[1]);
}
}
-
dma
+關(guān)注
關(guān)注
3文章
561瀏覽量
100583 -
STM32F4
+關(guān)注
關(guān)注
3文章
194瀏覽量
28056 -
模擬數(shù)字轉(zhuǎn)換器
+關(guān)注
關(guān)注
1文章
74瀏覽量
12485 -
ADC采樣電壓
+關(guān)注
關(guān)注
0文章
4瀏覽量
2814 -
信號(hào)采集傳感器
+關(guān)注
關(guān)注
0文章
2瀏覽量
1240
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論