一、ADC 簡介
ADC(Analog-to-Digital Converter)指模/數(shù)轉換器或者模擬/數(shù)字轉換器。 是指將連續(xù)變量的模擬信號轉換為離散的數(shù)字信號的器件。
也就是將模擬信號轉化為數(shù)字信號。
STM32f103 系列有3 個ADC,精度為12 位,每個ADC 最多有16 個外部通道和2個內部信號源。其中ADC1 和ADC2 都有16 個外部通道,ADC3 根據(jù)CPU 引腳的不同通道數(shù)也不同,一般都有8 個外部通道。
各通道的A/D轉換可以單次、連續(xù)、掃描或間斷模式執(zhí)行。
ADC的結果可以左對齊或右對齊方式存儲在16位數(shù)據(jù)寄存器中。
二、ADC功能框圖
電壓輸入范圍
ADC 輸入范圍為:VREF- ≤ VIN ≤ VREF+。
由VREF-、VREF+ 、VDDA 、VSSA、這四個外部引腳決定。
一般把VSSA 和VREF- 接地,把VREF+ 和VDDA 接3V3,得到ADC 的輸入電壓范圍為:0~3.3V。
如果想讓輸入的電壓范圍變寬,去到可以測試負電壓或者更高的正電壓,我們可以在外部加一個電壓調理電路,把需要轉換的電壓抬升或者降壓到0~3.3V,這樣ADC 就可以測量了。
輸入通道
STM32的ADC 多達18 個通道,其中外部的16 個通道就是框圖中的ADCx_IN0、ADCx_IN1 ? ADCx_IN5。
這16 個通道對應著不同的IO 口,具體是哪一個IO 口可以從手冊查詢到。
其中ADC1/2/3 還有內部通道:
ADC1 的通道16 連接到了芯片內部的溫度傳感器,Vrefint 連接到了通道17。
ADC2 的模擬通道16 和17 連接到了內部的VSS。
ADC3 的模擬通道9、14、15、16 和17 連接到了內部的VSS。
STM32F103ZET6 ADC IO 分配 :
ADC1 | IO | ADC2 | IO | ADC3 | IO |
---|---|---|---|---|---|
通道0 | PA0 | 通道0 | PA0 | 通道0 | PA0 |
通道1 | PA1 | 通道1 | PA1 | 通道2 | PA1 |
通道2 | PA2 | 通道2 | PA2 | 通道2 | PA2 |
通道3 | PA3 | 通道3 | PA3 | 通道3 | PA3 |
通道4 | PA4 | 通道4 | PA4 | 通道4 | PF6 |
通道5 | PA5 | 通道5 | PA5 | 通道5 | PF7 |
通道6 | PA6 | 通道6 | PA6 | 通道6 | PF8 |
通道7 | PA7 | 通道7 | PA7 | 通道7 | PF9 |
通道8 | PB0 | 通道8 | PB0 | 通道8 | PF10 |
通道9 | PB1 | 通道9 | PB1 | 通道9 | 連接內部VSS |
通道10 | PC0 | 通道10 | PC0 | 通道10 | PC0 |
通道11 | PC1 | 通道11 | PC1 | 通道11 | PC1 |
通道12 | PC2 | 通道12 | PC2 | 通道12 | PC2 |
通道13 | PC3 | 通道13 | PC3 | 通道13 | PC3 |
通道14 | PC4 | 通道14 | PC4 | 通道14 | 連接內部VSS |
通道15 | PC5 | 通道15 | PC5 | 通道15 | 連接內部VSS |
通道16 | 連接內部溫度傳感器 | 通道16 | 連接內部VSS | 通道16 | 連接內部VSS |
通道17 | 連接內部Vrefint | 通道17 | 連接內部VSS | 通道17 | 連接內部VSS |
外部的16 個通道在轉換的時候又分為規(guī)則通道和注入通道,其中規(guī)則通道最多有16 路,注入通道最多有4 路。
規(guī)則通道
普通通道,大部分時候都用這個。
注入通道
注入,可以理解為插入,插隊的意思。它是一種在規(guī)則通道轉換的時候強行插入要轉換的一種通道。
如果在規(guī)則通道轉換過程中,有注入通道插隊,那么就要先轉換完注入通道,等注入通道轉換完成后,再回到規(guī)則通道的轉換流程。
轉換順序
規(guī)則序列
規(guī)則序列寄存器有3 個,分別為SQR3、SQR2、SQR1。
SQR3 控制著規(guī)則序列中的第一個到第六個轉換,對應的位為:SQ1[4:0] ~ SQ6[4:0],第一次轉換的是位4:0 SQ1[4:0],如果通道16 想第一次轉換,那么在SQ1[4:0] 寫16 即可。
SQR2 控制著規(guī)則序列中的第7 到第12 個轉換,對應的位為:SQ7[4:0] ~ SQ12[4:0],如果通道1 想第8 個轉換,則SQ8[4:0] 寫1 即可。
SQR1 控制著規(guī)則序列中的第13 到第16 個轉換,對應位為:SQ13[4:0] ~ SQ16[4:0],如果通道6 想第10 個轉換,則SQ10[4:0] 寫6 即可。
具體使用多少個通道,由SQR1 的位L[3:0] 決定,最多16 個通道。
寄存器 | 寄存器位 | 功能 | 取值 |
---|---|---|---|
SQR3 | SQ1[4:0] | 設置第1個轉換的通道 | 通道1 ~ 16 |
SQR3 | SQ2[4:0] | 設置第2個轉換的通道 | 通道1 ~ 16 |
SQR3 | SQ3[4:0] | 設置第3個轉換的通道 | 通道1 ~ 16 |
SQR3 | SQ4[4:0] | 設置第4個轉換的通道 | 通道1 ~ 16 |
SQR3 | SQ5[4:0] | 設置第5個轉換的通道 | 通道1 ~ 16 |
SQR3 | SQ6[4:0] | 設置第6個轉換的通道 | 通道1 ~ 16 |
SQR2 | SQ7[4:0] | 設置第7個轉換的通道 | 通道1 ~ 16 |
SQR2 | SQ8[4:0] | 設置第8個轉換的通道 | 通道1 ~ 16 |
SQR2 | SQ9[4:0] | 設置第9個轉換的通道 | 通道1 ~ 16 |
SQR2 | SQ10[4:0] | 設置第10個轉換的通道 | 通道1 ~ 16 |
SQR2 | SQ11[4:0] | 設置第11個轉換的通道 | 通道1 ~ 16 |
SQR2 | SQ12[4:0] | 設置第12個轉換的通道 | 通道1 ~ 16 |
SQR1 | SQ13[4:0] | 設置第13個轉換的通道 | 通道1 ~ 16 |
SQR1 | SQ14[4:0] | 設置第14個轉換的通道 | 通道1 ~ 16 |
SQR1 | SQ15[4:0] | 設置第15個轉換的通道 | 通道1 ~ 16 |
SQR1 | SQ16[4:0] | 設置第16個轉換的通道 | 通道1 ~ 16 |
SQR1 | SQL[3:0] | 需要轉換多少個通道 | 通道1 ~ 16 |
注入序列
注入序列寄存器JSQR 只有一個,最多支持4 個通道,具體多少個由JSQR 的JL[2:0] 決定。
如果JL 的值小于4 的話,則JSQR 跟SQR 決定轉換順序的設置不一樣,第一次轉換的不是JSQR1[4:0],而是JCQRx[4:0] ,x = (4-JL),跟SQR 剛好相反。
如果JL=00(1 個轉換),那么轉換的順序是從JSQR4[4:0] 開始,而不是從JSQR1[4:0] 開始,這個要注意,編程的時候不要搞錯。當JL 等于4 時,跟SQR 一樣。
寄存器 | 寄存器位 | 功能 | 取值 |
---|---|---|---|
JSQR | JSQ1[4:0] | 設置第1個轉換的通道 | 通道 1 ~ 4 |
JSQR | JSQ2[4:0] | 設置第2個轉換的通道 | 通道 1 ~ 4 |
JSQR | JSQ3[4:0] | 設置第3個轉換的通道 | 通道 1 ~ 4 |
JSQR | JSQ4[4:0] | 設置第4個轉換的通道 | 通道 1 ~ 4 |
JSQR | JL[1:0] | 需要轉換多少個通道 | 通道 1 ~ 4 |
觸發(fā)源
ADC 轉換可以由ADC 控制寄存器2: ADC_CR2 的ADON 這個位來控制,寫1 的時候開始轉換,寫0 的時候停止轉換;
ADC 還支持觸發(fā)轉換,內部定時器觸發(fā)和外部IO 觸發(fā)。
觸發(fā)源有很多,具體選擇哪一種觸發(fā)源,由ADC 控制寄存器2:ADC_CR2 的EXTSEL[2:0] 和JEXTSEL[2:0] 位來控制。
EXTSEL[2:0] 用于選擇規(guī)則通道的觸發(fā)源,JEXTSEL[2:0] 用于選擇注入通道的觸發(fā)源。
選定好觸發(fā)源之后,由ADC 控制寄存器2:ADC_CR2 的EXTTRIG 和JEXTTRIG 這兩位來激活ADC。
其中ADC3 的規(guī)則轉換和注入轉換的觸發(fā)源與ADC1/2的有所不同。
轉換時間
ADC 時鐘
ADC 輸入時鐘ADC_CLK 由PCLK2 經(jīng)過分頻產(chǎn)生,最大是14M,分頻因子由RCC 時鐘配置寄存器RCC_CFGR 的位15:14 ADCPRE[1:0] 設置,可以是2/4/6/8 分頻,注意這里沒有1 分頻。一般我們設置PCLK2=HCLK=72M
采樣時間
ADC 使用若干個ADC_CLK 周期對輸入的電壓進行采樣,采樣的周期數(shù)可通過ADC 采樣時間寄存器ADC_SMPR1 和ADC_SMPR2 中的SMP[2:0] 位設置,ADC_SMPR2 控制的是通道0 ~ 9,ADC_SMPR1 控制的是通道10~17。
每個通道可以分別用不同的時間采樣。其中采樣周期最小是1.5 個,即如果我們要達到最快的采樣,那么應該設置采樣周期為1.5 個周期,這里說的周期就是1/ADC_CLK。
ADC 的轉換時間跟ADC 的輸入時鐘和采樣時間有關,公式為:Tconv = 采樣時間+ 12.5 個周期
當ADCLK = 14MHZ(最高),采樣時間設置為1.5 周期(最快),那么總的轉換時間(最短)Tconv = 1.5 周期+ 12.5 周期= 14 周期= 1us。
一般我們設置PCLK2=72M,經(jīng)過ADC 預分頻器能分頻到最大的時鐘只能是12M,采樣周期設置為1.5 個周期,算出最短的轉換時間為1.17us,這個才是最常用的。
數(shù)據(jù)寄存器
一切準備就緒后,ADC 轉換后的數(shù)據(jù)根據(jù)轉換組的不同,規(guī)則組的數(shù)據(jù)放在ADC_DR 寄存器,注入組的數(shù)據(jù)放在JDRx。
規(guī)則數(shù)據(jù)寄存器
ADC 規(guī)則組數(shù)據(jù)寄存器ADC_DR 只有一個,是一個32 位的寄存器,低16 位在單ADC 時使用,高16 位是在ADC1 中雙模式下保存ADC2 轉換的規(guī)則數(shù)據(jù),雙模式就是ADC1 和ADC2 同時使用。
在單模式下,ADC1/2/3 都不使用高16 位。因為ADC 的精度是12 位,無論ADC_DR 的高16 或者低16 位都放不滿,只能左對齊或者右對齊,具體是以哪一種方式存放,由ADC_CR2 的11 位ALIGN 設置。
規(guī)則通道可以有16 個這么多,可規(guī)則數(shù)據(jù)寄存器只有一個,如果使用多通道轉換,那轉換的數(shù)據(jù)就全部都擠在了DR 里面,前一個時間點轉換的通道數(shù)據(jù),就會被下一個時間點的另外一個通道轉換的數(shù)據(jù)覆蓋掉,所以當通道轉換完成后就應該把數(shù)據(jù)取走,或者開啟DMA 模式,把數(shù)據(jù)傳輸?shù)絻却胬锩?/strong>,不然就會造成數(shù)據(jù)的覆蓋。
對于多通道采集這里提出三個解決辦法:
(1)使用間斷模式,采集一個存儲一個
(2)使用中斷,采集到一個數(shù)據(jù),進入中斷,把這個數(shù)據(jù)保存
(3)使用DMA,直接將采集到的數(shù)據(jù)搬運到內存
注入數(shù)據(jù)寄存器
ADC 注入組最多有4 個通道,剛好注入數(shù)據(jù)寄存器也有4 個,每個通道對應著自己的寄存器,不會跟規(guī)則寄存器那樣產(chǎn)生數(shù)據(jù)覆蓋的問題。ADC_JDRx 是32 位的,低16 位有效,高16 位保留,數(shù)據(jù)同樣分為左對齊和右對齊,具體是以哪一種方式存放,由ADC_CR2 的11 位ALIGN 設置。
中斷
轉換結束中斷
數(shù)據(jù)轉換結束后,可以產(chǎn)生中斷,中斷分為三種:規(guī)則通道轉換結束中斷,注入轉換通道轉換結束中斷,模擬看門狗中斷。
其中轉換結束中斷很好理解,跟我們平時接觸的中斷一樣,有相應的中斷標志位和中斷使能位,我們還可以根據(jù)中斷類型寫相應配套的中斷服務程序。
模擬看門狗中斷
當被ADC 轉換的模擬電壓低于低閾值或者高于高閾值時,就會產(chǎn)生中斷,前提是我們開啟了模擬看門狗中斷,其中低閾值和高閾值由ADC_LTR 和ADC_HTR 設置。
例如我們設置高閾值是2.5V,那么模擬電壓超過2.5V 的時候,就會產(chǎn)生模擬看門狗中斷,反之低閾值也一樣。
DMA 請求
規(guī)則和注入通道轉換結束后,除了產(chǎn)生中斷外,還可以產(chǎn)生DMA 請求,把轉換好的數(shù)據(jù)直接存儲在內存里面。
要注意的是只有ADC1 和ADC3 可以產(chǎn)生DMA 請求。
一般我們在使用ADC 的時候都會開啟DMA 傳輸。
電壓轉換
模擬電壓經(jīng)過ADC 轉換后,是一個12 位的數(shù)字值,如果通過串口以16 進制打印出來的話,可讀性比較差,那么有時候我們就需要把數(shù)字電壓轉換成模擬電壓,也可以跟實際的模擬電壓(用萬用表測)對比,看看轉換是否準確。
我們一般在設計原理圖的時候會把ADC 的輸入電壓范圍設定在:0~3.3v,因為ADC 是12 位的,那么12 位滿量程對應的就是3.3V,12 位滿量程對應的數(shù)字值是:2^12。數(shù)值0 對應的就是0V。
如果轉換后的數(shù)值為X ,X 對應的模擬電壓為Y,那么會有這么一個等式成立: 2^12 / 3.3 = X/ Y,=> Y = (3.3 * X ) / 2^12。
三、STM32Cube MX配置
基礎STM32Cube MX的配置可以參考這篇博客:STM32 CubeMx教程 – 基礎知識及配置使用教程
配置RCC,選擇使用外部晶振模式
配置SYS,debug配置為Serial Wire
配置一個串口,使用異步通信模式
ADC界面:
IN0~IN15: 16路12位ADC采樣通道,外部模擬量信號輸入
Temperature Sensor Channel: MCU內置溫度傳感器采樣通道,用來測量器件周圍的溫度。在MCU內部與ADC1_IN16通道相連
Vrefint Channel: 內部參考電壓檢測通道,ADC 的參考電壓都是通過 Vref+ 引腳提供的并作為ADC轉換器的基準電壓,當Vref+直接取自VDD電壓時,易受VDD波動而影響,因此可以該通道對參考電壓進行校準,以提升ADC計算精度。在MCU內部與ADC1_IN17通道相連
EXTI Conversion Trigger: 外部觸發(fā)轉換。
ADC轉換可由外部事件觸發(fā),EXTSEL[2:0]和JEXTSEL[2:0]控制位允許應用程序選擇8個可能的事件中的某一個,觸發(fā)規(guī)則通道組合注入通道組的采樣。這里若選擇Disable,則可以在6個來自片上定時器的內部信號中選擇一個作為觸發(fā)源;
若選擇Injected Trigger/Regular Trigger/Injected and Regular Trigger,表示由外部引腳信號觸發(fā)相應的通道組。
ADCs_Common_Settings:(ADC模式設置)
Mode:Independent mode
獨立模式。此模式中,雙ADC同步不工作,ADC1和ADC2相互獨立工作。
如果不需要ADC同步或者只是用了一個ADC的時候,應該設成獨立模式,多個ADC同時使用時會有其他模式,如雙重ADC同步模式,兩個ADC同時采集一個或多個通道,可以提高采樣率。對應ADC控制寄存器1(ADC_CR1)中的DUALMOD[3:0]位。
ADC_Settings:(ADC設置)
Data Alignment:(數(shù)據(jù)對齊方式)
數(shù)據(jù)左對齊/右對齊,一般選擇使用右對齊。
Scan Conversion Mode:(掃描模式)
掃描模式使能。對應ADC控制寄存器1(ADC_CR1)中的SCAN位。
如果只是用了一個通道的話,設置為DISABLE;
如果使用了多個通道的話,可以選擇設置ENABLE或者DISABLE;(后面結合具體場景介紹)
Continuous Conversion Mode:(連續(xù)轉換模式)
數(shù)據(jù)的連續(xù)轉換,對應ADC控制寄存器2(ADC_CR2)中的CONT位。
設置為ENABLE,即使能連續(xù)轉換;設置為DISABLE,則是單次轉換。
兩者的區(qū)別在于連續(xù)轉換直到所有的數(shù)據(jù)轉換完成后才停止轉換,而單次轉換則只轉換一次數(shù)據(jù)就停止,要再次觸發(fā)轉換才可以進行轉換
Discontinuous Conversion Mode:(間斷模式)
間斷模式,對應ADC控制寄存器1(ADC_CR1)中的DISCEN位。
如果單通道不需要采用間斷,多通道具體分析,后面示例中具體介紹
ADC_Regular_ConversionMode:規(guī)則通道組采樣設置
Enable Regular Conversions:(常規(guī)轉換模式)
使能規(guī)則通道組轉換。
Number of Conversion:(轉換通道數(shù)量)
規(guī)則通道組序列長度為3,即包含3個采樣通道。
External Trigger Conversion Source:(外部觸發(fā)轉換源)
選擇外部觸發(fā)源,
Regular Conversion launched by software 規(guī)則的軟件觸發(fā) 調用函數(shù)觸發(fā)
Timer X Capture Compare X event 外部引腳觸發(fā),
Timer X Trigger Out event 定時器通道輸出觸發(fā)
Rank:ADC轉換通道順序
當使用多通道采集的時候,可以在這里設置每個通道采集的先后順序
ADC_Injected_ConversionMode:注入通道設置
參數(shù)和上面的規(guī)則通道一樣;
需要注意的是,注入通道的功能和規(guī)則通道的一樣,但是注入通道的優(yōu)先級要比規(guī)則通道的高;
WatchDog: 模擬看門狗中斷
四、應用示例
涉及到的HAL庫函數(shù)
開啟ADC 3種模式 ( 輪詢模式 中斷模式 DMA模式 )
? HAL_ADC_Start(&hadcx); ? ? ? //輪詢模式開啟ADC
? HAL_ADC_Start_IT(&hadcx); ? ? ? //中斷輪詢模式開啟ADC
? HAL_ADC_Start_DMA(&hadcx); ? ? ? //DMA模式開啟ADC
關閉ADC 3種模式 ( 輪詢模式 中斷模式 DMA模式 )
? HAL_ADC_Stop()
? HAL_ADC_Stop_IT()
? HAL_ADC_Stop_DMA()
ADC校準函數(shù) :
? HAL_ADCEx_Calibration_Start(&hadcx); ? ? ?//F4系列不支持
讀取ADC轉換值
? HAL_ADC_GetValue()
等待轉換結束函數(shù)
? HAL_ADC_PollForConversion(&hadc1, 50);
第一個參數(shù)為那個ADC,第二個參數(shù)為最大等待時間
ADC中斷回調函數(shù)
? HAL_ADC_ConvCpltCallback()
轉換完成后回調,DMA模式下DMA傳輸完成后和中斷中調用
規(guī)則通道及看門狗配置
? HAL_ADC_ConfigChannel() 配置規(guī)則組通道
? HAL_ADC_AnalogWDGConfig()
結合ADC的不同傳輸辦法;
這里給出六個例子
(1)單通道數(shù)據(jù)采集
(2)多通道間斷模式輪詢采集
(3)多通道中斷采集
(4)多通道定時器中斷采集
(5)多通道DMA采集
(6)多通道定時器MDA采集
如果使用串口打印數(shù)據(jù),要記得串口重定向,參考這兩篇博客:
STM32 HAL庫 STM32CubeMx – 串口的使用(USART/UART)
STM32 HAL庫 使用printf函數(shù) Use MicroLIB配置
(1)單通道數(shù)據(jù)采集
在STM32 Cube MX里面配置一個通道IN1;
ADC采集模式設置為獨立模式;
數(shù)據(jù)設置為右對齊模式;
由于只有單通道,數(shù)據(jù)都是一個通道的,設置為連續(xù)轉換模式;
由于只有一個通道,下面的規(guī)則通道設置,rank順序設置可以不用管;
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* 單通道 數(shù)據(jù)定義 */
uint16_t ADC_value; //ADC采集到的數(shù)據(jù)
float volt_value; //電壓值
/* USER CODE END PD */
/* USER CODE BEGIN 1 */
/* 自定義的數(shù)據(jù)采集函數(shù),需要在.h 函數(shù)里面聲明 */
/* 自定義了一個數(shù)據(jù)采集函數(shù),我放到了adc.c 里面,放到main.c里面也行*/
uint16_t ADC_X_Get()
{
HAL_ADC_Start(&hadc1); //啟動ADC轉換
HAL_ADC_PollForConversion(&hadc1, 50); //等待轉換完成,50為最大等待時間,單位為ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
{
return(HAL_ADC_GetValue(&hadc1)); //返回ADC的值
}
return 0;
}
/* USER CODE END 1 */
while (1)
{
/* 單通道數(shù)據(jù)采集 + 連續(xù)轉換模式 */
/* 在主函數(shù)中采集數(shù)據(jù),并且輸出數(shù)據(jù) */
ADC_value = ADC_X_Get();
volt_value = ADC_value*3.3f/4096; //內部電壓轉換公式
printf("ADC read value : %d \r\n",ADC_value);
printf("change voltage value : %.4f \r\n",volt_value);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
(2)多通道間斷模式輪詢采集
STM32Cube MX里面配置了五個通道;
設置為獨立模式;
在規(guī)則通道設置里面,設置5個通道;
可以在Rank里面設置每個通道采集的順序;
由于是多通道數(shù)據(jù)采集,必須使能掃描模式;
如果不使用中斷 DMA,要想采集到多通道的數(shù)據(jù),可以采用間斷模式;
所以使能間斷模式;
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* 多通道 間斷 輪詢模式 數(shù)據(jù)定義 */
#define ADC_value_max 5 //五通道數(shù)據(jù)
uint16_t ADC_value[ADC_value_max] = {0}; //ADC采集數(shù)值
float volt_value; //電壓值
float tem_value; //溫度值
/* USER CODE END PD */
/* USER CODE BEGIN 1 */
/* 自定義的數(shù)據(jù)采集函數(shù),需要在.h 函數(shù)里面聲明 */
/* 自定義了一個數(shù)據(jù)采集函數(shù),我放到了adc.c 里面,放到main.c里面也行*/
uint16_t ADC_X_Get()
{
HAL_ADC_Start(&hadc1); //啟動ADC轉換
HAL_ADC_PollForConversion(&hadc1, 50); //等待轉換完成,50為最大等待時間,單位為ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
{
return(HAL_ADC_GetValue(&hadc1)); //返回ADC的值
}
return 0;
}
/* USER CODE END 1 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1); //ADC校準
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* 多通道數(shù)據(jù)采集 + 掃描模式 + 間斷模式 */
for(uint8_t i=0;i<5;i++)
{
ADC_value[i] = ADC_X_Get(); //獲取ADC采集到的值
}
volt_value = ADC_value[3]*3.3f/4096; //內部電壓轉化公式
tem_value = (1.43 - ADC_value[4]*3.3f/4096) / 0.0043 + 25; //內部溫度轉換公式
printf("ADC value 0 : %d \r\n",ADC_value[0]);
printf("volt : %.4f \r\n",volt_value);
printf("tem : %.2f \r\n",tem_value);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
(3)多通道中斷采集
STM32Cube MX里面配置了五個通道;
設置為獨立模式;
在規(guī)則通道設置里面,設置5個通道;
可以在Rank里面設置每個通道采集的順序;
由于是多通道數(shù)據(jù)采集,必須使能掃描模式;
為了采集到多通道的數(shù)據(jù),這里使用的辦法是使用中斷;
配置使能連續(xù)轉換模式,配置打開ADC中斷;
這里觸發(fā)中斷的方式是軟件觸發(fā),也就是ADC每轉化一次觸發(fā)一次中斷;(這樣會很浪費資源)
打開中斷
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* 多通道 中斷 數(shù)據(jù)定義 */
/* 用到全局變量,所以在main.h里面聲明 */
uint16_t ADC_value[ADC_value_max] = {0}; //ADC采集數(shù)值
uint8_t ADC_value_flag = 0; //ADC標志位
float volt_value; //電壓值
float tem_value; //溫度值
/* USER CODE END PD */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
#define ADC_value_max 5 //3組ADC,每組最多存儲5個值
extern uint16_t ADC_value[ADC_value_max]; //ADC采集數(shù)值
extern uint8_t ADC_value_flag; //ADC標志位
/* USER CODE END ET */
/* USER CODE BEGIN 1 */
/* ADC轉換完成之后,觸發(fā)ADC中斷 */
/* 為了方便歸類,這里我把ADC處理函數(shù)放在了adc.c里面 */
/* 如果要更改一些數(shù)值,需要將變量設置為全局變量 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
ADC_value[ADC_value_flag++]=HAL_ADC_GetValue(hadc); //獲取值并存儲
if(ADC_value_flag == ADC_value_max) //最大值的下一位
{
ADC_value_flag=0;//清零下標
}
}
/* USER CODE END 1 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1); //ADC校準
HAL_ADC_Start_IT(&hadc1); //開啟ADC中斷
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* 多通道采集 + 掃描模式 + 連續(xù)轉換模式 + 中斷 */
volt_value = ADC_value[3]*3.3f/4096;
tem_value = (1.43 - ADC_value[4]*3.3f/4096) / 0.0043 + 25;
printf("tem : %.2f \r\n",tem_value);
printf("demo1 : %d \r\n",ADC_value[4]);
printf("volt : %.4f \r\n",volt_value);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
(4)多通道定時器中斷采集
由于直接使用中斷,每采集一次數(shù)據(jù),就會進入中斷一次,比較浪費資源,所以這里介紹,定時器觸發(fā)中斷采集數(shù)據(jù);
STM32Cube MX里面配置了五個通道;
設置為獨立模式;
在規(guī)則通道設置里面,設置5個通道;
可以在Rank里面設置每個通道采集的順序;
由于是多通道數(shù)據(jù)采集,必須使能掃描模式;
為了采集到多通道的數(shù)據(jù),這里使用的辦法是使用中斷;
配置使能連續(xù)轉換模式,配置打開ADC中斷;
這里觸發(fā)中斷的方式是定時器觸發(fā),也就是定時器沒溢出一次觸發(fā)一次中斷;
配置一個定時器,使用內部時鐘,自動重裝載值,配置為觸發(fā)事件更新
設置為定時器3 外部事件觸發(fā)
打開定時器的中斷
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* 多通道 中斷 數(shù)據(jù)定義 */
/* 用到全局變量,所以在main.h里面聲明 */
uint16_t ADC_value[ADC_value_max] = {0}; //ADC采集數(shù)值
uint8_t ADC_value_flag = 0; //ADC標志位
float volt_value; //電壓值
float tem_value; //溫度值
/* USER CODE END PD */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
#define ADC_value_max 5 //3組ADC,每組最多存儲5個值
extern uint16_t ADC_value[ADC_value_max]; //ADC采集數(shù)值
extern uint8_t ADC_value_flag; //ADC標志位
/* USER CODE END ET */
/* USER CODE BEGIN 1 */
/* 定時器回調函數(shù),定時器溢出以后觸發(fā)回調函數(shù) */
/* 在定時器里面開啟ADC中斷轉換 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
HAL_ADC_Start_IT(&hadc1); //定時器中斷里面開啟ADC中斷轉換,1s開啟一次采集
}
/* ADC轉換完成回調函數(shù),在回調函數(shù)里面,關閉中斷,保存數(shù)據(jù) */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
HAL_ADC_Stop_IT(&hadc1); //關閉ADC中斷
HAL_TIM_Base_Stop_IT(&htim3); //關閉定時器
ADC_value[ADC_value_flag++]=HAL_ADC_GetValue(hadc); //獲取值并存儲
if(ADC_value_flag == ADC_value_max) //最大值的下一位
{
ADC_value_flag=0;//清零下標
}
HAL_TIM_Base_Start_IT(&htim3); //開啟定時器
}
/* USER CODE END 1 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1); //ADC校準
HAL_TIM_Base_Start_IT(&htim3); //開啟定時器中斷
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* 多通道采集 + 掃描模式 + 連續(xù)轉換模式 + 中斷 */
volt_value = ADC_value[3]*3.3f/4096;
tem_value = (1.43 - ADC_value[4]*3.3f/4096) / 0.0043 + 25;
printf("tem : %.2f \r\n",tem_value);
printf("demo1 : %d \r\n",ADC_value[4]);
printf("volt : %.4f \r\n",volt_value);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
(5)多通道DMA采集
STM32Cube MX里面配置了五個通道;
設置為獨立模式;
在規(guī)則通道設置里面,設置5個通道;
可以在Rank里面設置每個通道采集的順序;
由于是多通道數(shù)據(jù)采集,必須使能掃描模式;
為了采集到多通道的數(shù)據(jù),這里使用的辦法是DMA;
配置DMA ,設置為循環(huán)模式
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* DMA 數(shù)據(jù)定義 */
uint16_t ADC_value[ADC_value_max] = {0}; //ADC采集數(shù)值
float volt_value; //電壓值
float tem_value; //溫度值
/* USER CODE END PD */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1); //ADC校準
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_value,sizeof(ADC_value) / sizeof(ADC_value[0])); //開啟DMA
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* 多通道采集 + 掃描模式 + DMA */
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_value,sizeof(ADC_value) / sizeof(ADC_value[0]));
volt_value = ADC_value[3]*3.3f/4096;
tem_value = (1.43 - ADC_value[4]*3.3f/4096) / 0.0043 + 25;
printf("tem : %.2f \r\n",tem_value);
printf("demo1 : %d \r\n",ADC_value[4]);
printf("volt : %.4f \r\n",volt_value);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
(6)多通道定時器MDA采集
STM32Cube MX里面配置了五個通道;
設置為獨立模式;
在規(guī)則通道設置里面,設置5個通道;
可以在Rank里面設置每個通道采集的順序;
由于是多通道數(shù)據(jù)采集,必須使能掃描模式;
為了采集到多通道的數(shù)據(jù),這里使用的辦法是DMA;
為了減少資源占用,選擇又定時器驅動DMA
配置一個定時器,使用內部時鐘,自動重裝載值,配置為觸發(fā)事件更新
打開定時器的中斷
配置ADC參數(shù),配置為定時器3觸發(fā)文章來源:http://www.zghlxwxcb.cn/news/detail-617523.html
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* DMA 數(shù)據(jù)定義 */
uint16_t ADC_value[ADC_value_max] = {0}; //ADC采集數(shù)值
float volt_value; //電壓值
float tem_value; //溫度值
/* USER CODE END PD */
/* 定時器 DMA */
/* 定時器回調函數(shù),定時器溢出以后觸發(fā)回調函數(shù) */
/* 在定時器里面開啟ADC DMA采集 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_value,sizeof(ADC_value) / sizeof(ADC_value[0]));
//定時器中斷里面開啟ADC DMA 轉換,1s開啟一次采集
}
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_USART1_UART_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1); //ADC校準
HAL_TIM_Base_Start_IT(&htim3); //開啟定時器
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_value,sizeof(ADC_value) / sizeof(ADC_value[0])); //開啟DMA
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* 多通道采集 + 掃描模式 + DMA + 定時器*/
volt_value = ADC_value[3]*3.3f/4096;
tem_value = (1.43 - ADC_value[4]*3.3f/4096) / 0.0043 + 25;
printf("tem : %.2f \r\n",tem_value);
printf("demo1 : %d \r\n",ADC_value[4]);
printf("volt : %.4f \r\n",volt_value);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
附錄
本文涉及到的程序:STM32 HAL庫 ADC數(shù)據(jù)采集(設置的0積分,無法下載,留言發(fā)給你)文章來源地址http://www.zghlxwxcb.cn/news/detail-617523.html
到了這里,關于STM32 HAL庫 STM32CubeMX -- ADC的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!