上個章節介紹了ADC的基本框架和用法,本章節會較為全面地講解如何靈活地使用ADC功能。
通常來說,外設執行的各種命令都是由CPU發出的,比如我們需要進行AD轉換,就通過某個寄存器標志位啟動ADC,隨后用判斷函數去檢測執行情況,亦或是開啟中斷功能,轉換完成之后會提示CPU,再由CPU判斷接下來該做什么。
這當然沒問題,不過有些時候,我們需要實現一些循環重復的功能,比如在做傅里葉分析的時候,需要按照固定間隔采集一定數量的數據,比如采樣率1000Hz,共采集1024個數據。為了實現這個目標,當然可以使用軟件定時實現,也可以使用定時器外設,在中斷服務函數中直接進行AD轉換來定時獲取數據,但數據很多,若是還要進行快速傅里葉變換,CPU會在定時器中斷中花費很多時間來采集數據,留給計算的時間就少了很多。有一種方案可以完美解決這類問題,不僅可以保證數據采集的精確性,還幾乎不需要CPU參與,那就是使用定時器觸發ADC轉換,而AD轉換完成之后會由DMA進行數據搬運,若CPU需要使用這批數據,直接訪問數據進行讀取即可 。具體的邏輯關系如下圖所示。
這種組合涉及到DMA、ADC、定時器的使用,文章將詳細介紹上圖的聯動過程。
- 按照順序,首先是定時器觸發AD轉換。
前文也提到過,一般來講可以用軟件開關去啟動AD轉換,此處并沒有用到這一功能,而是使用定時器觸發,這是一種硬件觸發方式,且觸發源不屬于ADC外設本身,故而也是一種外部觸發方式。在ADC外設的配置項中,可以設置AD轉換的開啟是否由外部信號觸發,只要ADC能正常使用,再配置好外部觸發源,我們就能用外部硬件信號觸發AD采集了。
注意!在實際使用中,外部觸發源不一定非得是定時器,它也可以是某個片外模塊提供的事件電平(完成事件會改變指定IO的電平,就和中斷一樣),最簡單的就是按鍵觸發的IO中斷。
- 接下來是第二個部分,DMA功能的配置。
DMA,全名叫直接存儲器訪問,這個外設可以像CPU一樣訪問單片機內部的各個存儲區(包括RAM和外設寄存器),但它只能做一件事情,就是數據搬運。通俗來說,數據存放在0-9共10個格子里面,DMA可以把這10個數據搬運到其他地方(并不會改變原本的值,效果類似賦值語句),而其他地方可以是同一個地方(將10個數據按順序搬運10次,最終一層層覆蓋到同一個地址),也可以是不同地方(將10個數據搬運10次并最終存放在10個不同地址的存儲空間)。
總體上來講DMA只做搬運這一個功能,除了搬運轉換完成的AD數據,他還能用于各種數據接口(比如UART、SPI等),或是其他需要大量賦值的場合。
注意!****DMA并不能完全代替CPU進行數據轉移,因為DMA*不像* CPU那樣擁有全部存儲區域的訪問權限。
- 最后是定時器的配置,這一部分沒什么變化,就是選擇一個可以用來觸發AD采集的定時器,按需求配置即可。不過需要注意的是,記得把溢出中斷打開,這個是AD轉換的啟動開關 。
介紹完了每一步需要做的事情,下面說說代碼應該怎么寫。我會貼出主要代碼,對于一些變量我會做說明但不做代碼展示(變量什么的自己隨便定義一個就行了呀!)
這段就是正常配置一個定時器,本案例中選擇的是通用定時器2,根據手冊,它可以觸發AD采集。
除最后一行,其余代碼與上一章節的初始化過程沒太大差別,只需把DMA功能開啟即可。這里補充一下其他配置項的說明:
- 時鐘頻率和采樣時鐘周期,如上一章說到的,采樣時間當然是越長越好,其中的時鐘頻率就是ADC外設從內部時鐘電路獲得的時鐘信號,頻率越高,ADC速度越快,這個時鐘速度一定程度上決定了一個ADC的最大采樣速率(1秒內完成的轉換次數)。
- 右對齊設置。AD轉換的結果是存放在一個寄存器里面的,它本質上是個二進制數,右對齊就是將轉換結果的第0位放到最右邊,高位不為1的補0,若仍不清楚,可自行百度。
- 轉換結果累加。為滿足一些需求,ADC結果可能需要進行數據處理來減小誤差,求加權平均值是一種很常用的辦法,該功能開啟之后,每次轉換的結果都會直接累加,方便開發者取出后直接求平均值(所以實際上不要這個功能也可以)。
- 我們使用的是定時器觸發采樣,所以只需要使用單次采集模式就行了,ADC會在每次轉換完成之后停止并等待下一次采集的啟動信號(定時器溢出中斷)。
總的來說,一定記住要把外部觸發打開并綁定定時器2,隨后只要定時器2的標志位被置位一次,ADC就會啟動一次。
相對來說比較麻煩的是DMA的配置,要配置一個DMA,首先需要確定數據搬運的起點和終點 ,我們搬運的起點只有一個,就是ADC轉換結果寄存器,搬運的終點是一個1024大小的數組,其中起點被稱為源地址,終點被稱為目標地址,且這兩個地址都可以設置成自增模式(完成一次搬運之后,地址自動+1)。
關于DMA的初始化,DMA通常會有不止一個通道,每個通道都能獨立進行數據搬運,初始化函數需要開啟DMA的時鐘總線,打開要用的DMA通道的中斷。
關于DMA的啟動和配置:
傳輸模式 :DMA幫助CPU進行數據搬運,這難免會出現DMA和CPU傳輸沖突的情況,非鎖定傳輸會在DMA搬運數據的間隔內預留時間間隙,必要時候CPU會搶占對外設的訪問權限,屆時CPU可進行數據傳輸,DMA只能等待CPU放棄對該外設的使用權限后才能繼續自己的數據傳輸。相對應的,還有鎖定傳輸,具體的功能在用戶手冊DMA章節有詳細介紹。
傳輸位寬 :根據需要搬運的數據長度進行選擇即可。
觸發方式和觸發源 :由于我們需要的是在AD轉換完成之后立刻進行數據搬運,所以DMA的觸發方式選擇為硬件觸發,觸發源應該設置為ADC轉化為完成,這會讓DMA在每次ADC轉換完成之后都進行一次數據搬運,且不論ADC處于什么模式。
源地址和目標地址 :源地址設置為ADC數據寄存器,具體的地址有兩種辦法來獲取,一種是用圖中的辦法,對寄存器取地址,另一種辦法是直接查用戶手冊,找到ADC數據寄存器的基地址和偏移量計算得到地址(這種辦法最終填進去的是一個hex數)。目標地址也是直接取地址數組即可。
地址自增 :我們不希望源地址有變動,故源地址設置成不自增;目標地址是一個數組,所以每搬運一次數據都要讓目標地址自增一個元素,這樣下一次搬運的時候,數據就會被正確寫入下一個格子。
傳輸次數 :需求是采集1024個數據,那傳輸次數自然是1024次。
全部配置完后完成DMA的功能初始化,隨后只需要啟動ADC、定時器、DMA功能即可,圖中代碼做了一個開關啟動,方便隨時關閉。關閉的時候清零定時器計數器是為了在下次啟動的時候讓定時采集依然準確。
準備工作基本完成,接下來還剩一些小細節需要處理,我們打開了DMA和定時器的中斷功能,他們會在完成搬運之后進入中斷服務函數,至少得寫個清除標志位的語句,除此之外還要加一些小功能。
定時器的中斷服務函數只需要清除標志位即可,DMA的中斷函數除了清除標志位,還需要將采樣功能關掉(至少得把定時器關了)。如果使用的不是定時器觸發,而是ADC的連續采樣模式,需要在這里手動關閉ADC,不然即使DMA完成了搬運,ADC還會繼續進行AD轉換,由于DMA搬運已經完成了,自增的地址也不會自己變回去,之后就會出現“意想不到的”DMA錯誤搬運,但本案例中使用的是單次采集模式,ADC只在啟動之后采集一次,所以不必擔心ADC會連續采樣導致程序異常的問題。
現在快速編寫一個按鍵檢測函數并調用剛剛寫好的啟動代碼,其中的key_down變量會在按鍵中斷服務函數中被置位。
再在main函數中循環調用這個按鍵檢測函數,按鍵按下抬起后就會自動采集ADC數據,這里我用vofa+上位機顯示一下采集的數據。
我這里采集的是單片機上定時器1輸出的50Hz方波,占空比為50%,周期為20ms,效果還不錯。
審核編輯 黃宇
-
ADC
+關注
關注
0文章
110瀏覽量
16845 -
CW32
+關注
關注
1文章
203瀏覽量
626
發布評論請先 登錄
相關推薦
評論