單芯片解決方案,開(kāi)啟全新體驗(yàn)——W55MH32 高性能以太網(wǎng)單片機(jī)
W55MH32是WIZnet重磅推出的高性能以太網(wǎng)單片機(jī),它為用戶帶來(lái)前所未有的集成化體驗(yàn)。這顆芯片將強(qiáng)大的組件集于一身,具體來(lái)說(shuō),一顆W55MH32內(nèi)置高性能Arm? Cortex-M3核心,其主頻最高可達(dá)216MHz;配備1024KB FLASH與96KB SRAM,滿足存儲(chǔ)與數(shù)據(jù)處理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP協(xié)議棧、內(nèi)置MAC以及PHY,擁有獨(dú)立的32KB以太網(wǎng)收發(fā)緩存,可供8個(gè)獨(dú)立硬件socket使用。如此配置,真正實(shí)現(xiàn)了All-in-One解決方案,為開(kāi)發(fā)者提供極大便利。
在封裝規(guī)格上,W55MH32 提供了兩種選擇:QFN100和QFN68。
W55MH32L采用QFN100封裝版本,尺寸為12x12mm,其資源豐富,專為各種復(fù)雜工控場(chǎng)景設(shè)計(jì)。它擁有66個(gè)GPIO、3個(gè)ADC、12通道DMA、17個(gè)定時(shí)器、2個(gè)I2C、5個(gè)串口、2個(gè)SPI接口(其中1個(gè)帶I2S接口復(fù)用)、1個(gè)CAN、1個(gè)USB2.0以及1個(gè)SDIO接口。如此豐富的外設(shè)資源,能夠輕松應(yīng)對(duì)工業(yè)控制中多樣化的連接需求,無(wú)論是與各類傳感器、執(zhí)行器的通信,還是對(duì)復(fù)雜工業(yè)協(xié)議的支持,都能游刃有余,成為復(fù)雜工控領(lǐng)域的理想選擇。 同系列還有QFN68封裝的W55MH32Q版本,該版本體積更小,僅為8x8mm,成本低,適合集成度高的網(wǎng)關(guān)模組等場(chǎng)景,軟件使用方法一致。更多信息和資料請(qǐng)進(jìn)入網(wǎng)站或者私信獲取。
此外,本W(wǎng)55MH32支持硬件加密算法單元,WIZnet還推出TOE+SSL應(yīng)用,涵蓋TCP SSL、HTTP SSL以及 MQTT SSL等,為網(wǎng)絡(luò)通信安全再添保障。
為助力開(kāi)發(fā)者快速上手與深入開(kāi)發(fā),基于W55MH32L這顆芯片,WIZnet精心打造了配套開(kāi)發(fā)板。開(kāi)發(fā)板集成WIZ-Link芯片,借助一根USB C口數(shù)據(jù)線,就能輕松實(shí)現(xiàn)調(diào)試、下載以及串口打印日志等功能。開(kāi)發(fā)板將所有外設(shè)全部引出,拓展功能也大幅提升,便于開(kāi)發(fā)者全面評(píng)估芯片性能。
若您想獲取芯片和開(kāi)發(fā)板的更多詳細(xì)信息,包括產(chǎn)品特性、技術(shù)參數(shù)以及價(jià)格等,歡迎訪問(wèn)官方網(wǎng)頁(yè),我們期待與您共同探索W55MH32的無(wú)限可能。

第十九章 ADC——電壓采集
本章參考資料:《W55MH32參考手冊(cè)》ADC章節(jié)。學(xué)習(xí)本章時(shí), 配合《W55MH32參考手冊(cè)》ADC章節(jié)一起閱讀,效果會(huì)更佳,特別是涉及到寄存器說(shuō)明的部分。
1 ADC簡(jiǎn)介
12 位 ADC 是一種逐次逼近型模擬數(shù)字轉(zhuǎn)換器。它有多達(dá) 18 個(gè)通道,可測(cè)量 16 個(gè)外部和 2 個(gè)內(nèi)部信號(hào)源。各通道的 A/D 轉(zhuǎn)換可以單次、連續(xù)、掃描或間斷模式執(zhí)行。ADC 的結(jié)果可以左對(duì)齊或右對(duì)齊方式存儲(chǔ)在 16 位數(shù)據(jù)寄存器中。模擬看門狗特性允許應(yīng)用程序檢測(cè)輸入電壓是否超出用戶定義的高/低閥值。
ADC 的輸入時(shí)鐘不得超過(guò) 14MHz,它是由 PCLK2 經(jīng)分頻產(chǎn)生。
2 ADC功能框圖剖析
ADC功能框圖如下:

ADC3 的規(guī)則轉(zhuǎn)換和注入轉(zhuǎn)換觸發(fā)與 ADC1 和 ADC2 的不同。
| 名稱 | 信號(hào)類型 | 注解 |
| VREF+ | 輸入,模擬參考正極 | ADC 使用的高端 / 正極參考電壓,2.4V≤VREF+≤VDDA |
| VDDA?1? | 輸入,模擬電源 | 等效于 VDD 的模擬電源且:2.4V≤VDDA≤VDD (3.6V) |
| VREF- | 輸入,模擬參考負(fù)極 | ADC 使用的低端 / 負(fù)極參考電壓,VREF-=VSSA |
| VSSA?1? | 輸入,模擬電源地 | 等效于 VSS 的模擬電源地 |
| ADCx_IN[15:0] | 模擬輸入信號(hào) | 16 個(gè)模擬輸入通道 |
VDDA 和 VSSA 應(yīng)該分別連接到 VDD 和 VSS。
2.1 電壓輸入范圍
ADC輸入范圍為:VREF- ≤ VIN ≤ VREF+。由VREF-、 VREF+ 、VDDA 、VSSA、這四個(gè)外部引腳決定。
我們?cè)谠O(shè)計(jì)原理圖的時(shí)候一般把VSSA和VREF-接地, 把VREF+和VDDA 接3V3,得到ADC的輸入電壓范圍為:0~3.3V。
如果我們想讓輸入的電壓范圍變寬,去到可以測(cè)試負(fù)電壓或者更高的正電壓,我們可以在外部加一個(gè)電壓調(diào)理電路, 把需要轉(zhuǎn)換的電壓抬升或者降壓到0~3.3V,這樣ADC就可以測(cè)量。
2.2 輸入通道
我們確定好ADC輸入電壓之后,那么電壓怎么輸入到ADC?這里我們引入通道的概念,W55MH32的ADC多達(dá)18個(gè)通道, 其中外部的16個(gè)通道就是框圖中的ADCx_IN0、ADCx_IN1…ADCx_IN5。這16個(gè)通道對(duì)應(yīng)著不同的IO口,具體是哪一個(gè)IO口可以從手冊(cè)查詢到。 其中ADC1/2/3還有內(nèi)部通道:ADC1的通道16連接到了芯片內(nèi)部的溫度傳感器,Vrefint連接到了通道17。 ADC2的模擬通道16和17連接到了內(nèi)部的VSS。ADC3的模擬通道9、14、15、16和17連接到了內(nèi)部的VSS。
| ADC1 | IO | ADC2 | IO | ADC3 | IO |
| 通道 0 | PA0 | 通道 0 | PA0 | 通道 0 | PA0 |
| 通道 1 | PA1 | 通道 1 | PA1 | 通道 1 | PA1 |
| 通道 2 | PA2 | 通道 2 | PA2 | 通道 2 | PA2 |
| 通道 3 | PA3 | 通道 3 | PA3 | 通道 3 | PA3 |
| 通道 4 | PA4 | 通道 4 | PA4 | 通道 4 | 沒(méi)有通道 4 |
| 通道 5 | PA5 | 通道 5 | PA5 | 通道 5 | 沒(méi)有通道 5 |
| 通道 6 | PA6 | 通道 6 | PA6 | 通道 6 | 沒(méi)有通道 6 |
| 通道 7 | PA7 | 通道 7 | PA7 | 通道 7 | 沒(méi)有通道 7 |
| 通道 8 | PB0 | 通道 8 | PB0 | 通道 8 | 沒(méi)有通道 8 |
| 通道 9 | PB1 | 通道 9 | PB1 | 通道 9 | 連接內(nèi)部 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 | 連接內(nèi)部 VSS |
| 通道 15 | PC5 | 通道 15 | PC5 | 通道 15 | 連接內(nèi)部 VSS |
| 通道 16 | 連接內(nèi)部溫度傳感器 | 通道 16 | 連接內(nèi)部 VSS | 通道 16 | 連接內(nèi)部 VSS |
| 通道 17 | 連接內(nèi)部 Vrefint | 通道 17 | 連接內(nèi)部 VSS | 通道 17 | 連接內(nèi)部 VSS |
外部的16個(gè)通道在轉(zhuǎn)換的時(shí)候又分為規(guī)則通道和注入通道,其中規(guī)則通道最多有16路,注入通道最多有4路。那這兩個(gè)通道有什么區(qū)別?在什么時(shí)候使用?
規(guī)則通道
規(guī)則通道:顧名思意,規(guī)則通道就是很規(guī)矩的意思,我們平時(shí)一般使用的就是這個(gè)通道,或者應(yīng)該說(shuō)我們用到的都是這個(gè)通道,沒(méi)有什么特別要注意的可講。
注入通道
注入,可以理解為插入,插隊(duì)的意思,是一種不安分的通道。它是一種在規(guī)則通道轉(zhuǎn)換的時(shí)候強(qiáng)行插入要轉(zhuǎn)換的一種通道。 如果在規(guī)則通道轉(zhuǎn)換過(guò)程中,有注入通道插隊(duì),那么就要先轉(zhuǎn)換完注入通道,等注入通道轉(zhuǎn)換完成后,再回到規(guī)則通道的轉(zhuǎn)換流程。 這點(diǎn)跟中斷程序很像,都是不安分的主。所以,注入通道只有在規(guī)則通道存在時(shí)才會(huì)出現(xiàn)。
2.3 轉(zhuǎn)換順序
規(guī)則序列
規(guī)則序列寄存器有3個(gè),分別為SQR3、SQR2、SQR1。SQR3控制著規(guī)則序列中的第一個(gè)到第六個(gè)轉(zhuǎn)換, 對(duì)應(yīng)的位為:SQ1[4:0]~SQ6[4:0],第一次轉(zhuǎn)換的是位4:0 SQ1[4:0],如果通道16想第一次轉(zhuǎn)換,那么在SQ1[4:0]寫16即可。 SQR2控制著規(guī)則序列中的第7到第12個(gè)轉(zhuǎn)換, 對(duì)應(yīng)的位為:SQ7[4:0]~SQ12[4:0],如果通道1想第8個(gè)轉(zhuǎn)換,則SQ8[4:0]寫1即可。SQR1控制著規(guī)則序列中的第13到第16個(gè)轉(zhuǎn)換, 對(duì)應(yīng)位為:SQ13[4:0]~SQ16[4:0],如果通道6想第10個(gè)轉(zhuǎn)換,則SQ10[4:0]寫6即可。 具體使用多少個(gè)通道,由SQR1的位L[3:0]決定,最多16個(gè)通道。
| 寄存器 | 寄存器位 | 功能 | 取值 |
| SQR3 | SQ1[4:0] | 設(shè)置第 1 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR3 | SQ2[4:0] | 設(shè)置第 2 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR3 | SQ3[4:0] | 設(shè)置第 3 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR3 | SQ4[4:0] | 設(shè)置第 4 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR3 | SQ5[4:0] | 設(shè)置第 5 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR3 | SQ6[4:0] | 設(shè)置第 6 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR3 | SQ7[4:0] | 設(shè)置第 7 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR3 | SQ8[4:0] | 設(shè)置第 8 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR2 | SQ9[4:0] | 設(shè)置第 9 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR2 | SQ10[4:0] | 設(shè)置第 10 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR2 | SQ11[4:0] | 設(shè)置第 11 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR2 | SQ12[4:0] | 設(shè)置第 12 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR1 | SQ13[4:0] | 設(shè)置第 13 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR1 | SQ14[4:0] | 設(shè)置第 14 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR1 | SQ15[4:0] | 設(shè)置第 15 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR1 | SQ16[4:0] | 設(shè)置第 16 個(gè)轉(zhuǎn)換的通道 | 通道 1~16 |
| SQR1 | LQL[3:0] | 需要轉(zhuǎn)換多少個(gè)通道 | 1~16 |
注入序列
注入序列寄存器JSQR只有一個(gè),最多支持4個(gè)通道,具體多少個(gè)由JSQR的JL[1:0]決定。如果JL的 值小于4的話, 則JSQR跟SQR決定轉(zhuǎn)換順序的設(shè)置不一樣,第一次轉(zhuǎn)換的不是JSQR1[4:0],而是JCQRx[4:0] ,x = 4-JL),跟SQR剛好相反。 如果JL=00(1個(gè)轉(zhuǎn)換),那么轉(zhuǎn)換的順序是從JSQR4[4:0]開(kāi)始,而不是從JSQR1[4:0]開(kāi)始,這個(gè)要注意,編程的時(shí)候不要搞錯(cuò)。當(dāng)JL等于4時(shí),跟SQR一樣。
| 寄存器 | 寄存器位 | 功能 | 取值 |
| JSQR | JSQ1[4:0] | 設(shè)置第 1 個(gè)轉(zhuǎn)換的通道 | 通道 1~4 |
| JSQR | JSQ2[4:0] | 設(shè)置第 2 個(gè)轉(zhuǎn)換的通道 | 通道 1~4 |
| JSQR | JSQ3[4:0] | 設(shè)置第 3 個(gè)轉(zhuǎn)換的通道 | 通道 1~4 |
| JSQR | JSQ4[4:0] | 設(shè)置第 4 個(gè)轉(zhuǎn)換的通道 | 通道 1~4 |
| JSQR | JLQ[4:0] | 需要轉(zhuǎn)換多少個(gè)通道 | 1~4 |
2.4 觸發(fā)源
通道選好了,轉(zhuǎn)換的順序也設(shè)置好了,那接下來(lái)就該開(kāi)始轉(zhuǎn)換了。ADC轉(zhuǎn)換可以由ADC控制寄存器2: ADC_CR2的ADON這個(gè)位來(lái)控制, 寫1的時(shí)候開(kāi)始轉(zhuǎn)換,寫0的時(shí)候停止轉(zhuǎn)換,這個(gè)是最簡(jiǎn)單也是最好理解的開(kāi)啟ADC轉(zhuǎn)換的控制方式。
除了上述的控制方法,ADC還支持觸發(fā)轉(zhuǎn)換,這個(gè)觸發(fā)包括內(nèi)部定時(shí)器觸發(fā)和外部IO觸發(fā)。觸發(fā)源有很多,具體選擇哪一種觸發(fā)源, 由ADC控制寄存器2:ADC_CR2的EXTSEL[2:0]和JEXTSEL[2:0]位來(lái)控制。EXTSEL[2:0]用于選擇規(guī)則通道的觸發(fā)源, JEXTSEL[2:0]用于選擇注入通道的觸發(fā)源。選定好觸發(fā)源之后,觸發(fā)源是否要激活,則由ADC控制寄存器2:ADC_CR2的EXTTRIG和JEXTTRIG這兩位來(lái)激活。
2.5 轉(zhuǎn)換時(shí)間
ADC時(shí)鐘
ADC輸入時(shí)鐘ADC_CLK由PCLK2經(jīng)過(guò)分頻產(chǎn)生,最大是14M,分頻因子由RCC時(shí)鐘配置寄存器RCC_CFGR的位15:14 ADCPRE[1:0]設(shè)置, 可以是2/4/6/8分頻,注意這里沒(méi)有1分頻。一般我們?cè)O(shè)置PCLK2=HCLK=72M。
采樣時(shí)間
ADC使用若干個(gè)ADC_CLK周期對(duì)輸入的電壓進(jìn)行采樣, 采樣的周期數(shù)可通過(guò)ADC 采樣時(shí)間寄存器ADC_SMPR1和ADC_SMPR2中的SMP[2:0]位設(shè)置,ADC_SMPR2控制的是通道0~9,ADC_SMPR1控制的是通道10~17。每個(gè)通道可以分別用不同的時(shí)間采樣。其中采樣周期最小是1.5個(gè), 即如果我們要達(dá)到最快的采樣,那么應(yīng)該設(shè)置采樣周期為1.5個(gè)周期,這里說(shuō)的周期就是1/ADC_CLK。
ADC的轉(zhuǎn)換時(shí)間跟ADC的輸入時(shí)鐘和采樣時(shí)間有關(guān),公式為:Tconv = 采樣時(shí)間 + 12.5個(gè)周期。當(dāng)ADCLK = 14MHZ (最高), 采樣時(shí)間設(shè)置為1.5周期(最快),那么總的轉(zhuǎn)換時(shí)間(最短)Tconv = 1.5周期 + 12.5周期 = 14周期 = 1us。
一般我們?cè)O(shè)置PCLK2=72M,經(jīng)過(guò)ADC預(yù)分頻器能分頻到最大的時(shí)鐘只能是12M,采樣周期設(shè)置為1.5個(gè)周期, 算出最短的轉(zhuǎn)換時(shí)間為1.17us,這個(gè)才是最常用的。
2.6 數(shù)據(jù)寄存器
一切準(zhǔn)備就緒后,ADC轉(zhuǎn)換后的數(shù)據(jù)根據(jù)轉(zhuǎn)換組的不同,規(guī)則組的數(shù)據(jù)放在ADC_DR寄存器,注入組的數(shù)據(jù)放在JDRx。
規(guī)則數(shù)據(jù)寄存器
ADC規(guī)則組數(shù)據(jù)寄存器ADC_DR只有一個(gè),是一個(gè)32位的寄存器,低16位在單ADC時(shí)使用,高16位是在ADC1中雙模式下保存ADC2轉(zhuǎn)換的規(guī)則數(shù)據(jù), 雙模式就是ADC1和ADC2同時(shí)使用。在單模式下,ADC1/2/3都不使用高16位。因?yàn)锳DC的精度是12位,無(wú)論ADC_DR的高16或者低16位都放不滿, 只能左對(duì)齊或者右對(duì)齊,具體是以哪一種方式存放,由ADC_CR2的11位ALIGN設(shè)置。
規(guī)則通道可以有16個(gè)這么多,可規(guī)則數(shù)據(jù)寄存器只有一個(gè),如果使用多通道轉(zhuǎn)換,那轉(zhuǎn)換的數(shù)據(jù)就全部都擠在了DR里面,前一個(gè)時(shí)間點(diǎn)轉(zhuǎn)換的通道數(shù)據(jù), 就會(huì)被下一個(gè)時(shí)間點(diǎn)的另外一個(gè)通道轉(zhuǎn)換的數(shù)據(jù)覆蓋掉,所以當(dāng)通道轉(zhuǎn)換完成后就應(yīng)該把數(shù)據(jù)取走,或者開(kāi)啟DMA模式,把數(shù)據(jù)傳輸?shù)絻?nèi)存里面, 不然就會(huì)造成數(shù)據(jù)的覆蓋。最常用的做法就是開(kāi)啟DMA傳輸。
注入數(shù)據(jù)寄存器
ADC注入組最多有4個(gè)通道,剛好注入數(shù)據(jù)寄存器也有4個(gè),每個(gè)通道對(duì)應(yīng)著自己的寄存器,不會(huì)跟規(guī)則寄存器那樣產(chǎn)生數(shù)據(jù)覆蓋的問(wèn)題。 ADC_JDRx是32位的,低16位有效,高16位保留,數(shù)據(jù)同樣分為左對(duì)齊和右對(duì)齊,具體是以哪一種方式存放,由ADC_CR2的11位ALIGN設(shè)置。
2.7 中斷
轉(zhuǎn)換結(jié)束中斷
數(shù)據(jù)轉(zhuǎn)換結(jié)束后,可以產(chǎn)生中斷,中斷分為三種:規(guī)則通道轉(zhuǎn)換結(jié)束中斷,注入轉(zhuǎn)換通道轉(zhuǎn)換結(jié)束中斷,模擬看門狗中斷。 其中轉(zhuǎn)換結(jié)束中斷很好理解,跟我們平時(shí)接觸的中斷一樣,有相應(yīng)的中斷標(biāo)志位和中斷使能位,我們還可以根據(jù)中斷類型寫相應(yīng)配套的中斷服務(wù)程序。
模擬看門狗中斷
當(dāng)被ADC轉(zhuǎn)換的模擬電壓低于低閾值或者高于高閾值時(shí),就會(huì)產(chǎn)生中斷,前提是我們開(kāi)啟了模擬看門狗中斷, 其中低閾值和高閾值由ADC_LTR和ADC_HTR設(shè)置。例如我們?cè)O(shè)置高閾值是2.5V,那么模擬電壓超過(guò)2.5V的時(shí)候,就會(huì)產(chǎn)生模擬看門狗中斷,反之低閾值也一樣。
DMA請(qǐng)求
規(guī)則和注入通道轉(zhuǎn)換結(jié)束后,除了產(chǎn)生中斷外,還可以產(chǎn)生DMA請(qǐng)求,把轉(zhuǎn)換好的數(shù)據(jù)直接存儲(chǔ)在內(nèi)存里面。 要注意的是只有ADC1和ADC3可以產(chǎn)生DMA請(qǐng)求。有關(guān)DMA請(qǐng)求需要配合《W55MH32參考手冊(cè)》DMA控制器這一章節(jié)來(lái)學(xué)習(xí)。 一般我們?cè)谑褂肁DC的時(shí)候都會(huì)開(kāi)啟DMA傳輸。
2.8 電壓轉(zhuǎn)換
模擬電壓經(jīng)過(guò)ADC轉(zhuǎn)換后,是一個(gè)12位的數(shù)字值,如果通過(guò)串口以16進(jìn)制打印出來(lái)的話,可讀性比較差,那么有時(shí)候我們就需要把數(shù)字電壓轉(zhuǎn)換成模擬電壓, 也可以跟實(shí)際的模擬電壓(用萬(wàn)用表測(cè))對(duì)比,看看轉(zhuǎn)換是否準(zhǔn)確。
我們一般在設(shè)計(jì)原理圖的時(shí)候會(huì)把ADC的輸入電壓范圍設(shè)定在:0~3.3v,因?yàn)锳DC是12位的,那么12位滿量程對(duì)應(yīng)的就是3.3V, 12位滿量程對(duì)應(yīng)的數(shù)字值是:2^12。數(shù)值0對(duì)應(yīng)的就是0V。如果轉(zhuǎn)換后的數(shù)值為 X ,X對(duì)應(yīng)的模擬電壓為Y, 那么會(huì)有這么一個(gè)等式成立: 2^12 / 3.3 = X/ Y,=> Y = (3.3 * X ) / 2^12。
3 ADC初始化結(jié)構(gòu)體詳解
標(biāo)準(zhǔn)庫(kù)函數(shù)對(duì)每個(gè)外設(shè)都建立了一個(gè)初始化結(jié)構(gòu)體xxx_InitTypeDef(xxx為外設(shè)名稱),結(jié)構(gòu)體成員用于設(shè)置外設(shè)工作參數(shù), 并由標(biāo)準(zhǔn)庫(kù)函數(shù)xxx_Init()調(diào)用這些設(shè)定參數(shù)進(jìn)入設(shè)置外設(shè)相應(yīng)的寄存器,達(dá)到配置外設(shè)工作環(huán)境的目的。
結(jié)構(gòu)體xxx_InitTypeDef與庫(kù)函數(shù)xxx_Init()的協(xié)同工作機(jī)制體現(xiàn)了模塊化設(shè)計(jì)的核心思想。結(jié)構(gòu)體xxx_InitTypeDef定義在w55mh32_xxx.h文件中,庫(kù)函數(shù)xxx_Init()定義在w55mh32_xxx.c文件中,編程時(shí)我們可以結(jié)合這兩個(gè)文件內(nèi)注釋使用。
ADC_InitTypeDef結(jié)構(gòu)體
ADC_InitTypeDef結(jié)構(gòu)體定義在w55mh32_adc.h文件內(nèi),具體定義如下:
typedef struct
{
uint32_t ADC_Mode; // ADC 工作模式選擇
FunctionalState ADC_ScanConvMode; /* ADC 掃描(多通道)
或者單次(單通道)模式選擇 */
FunctionalState ADC_ContinuousConvMode; // ADC 單次轉(zhuǎn)換或者連續(xù)轉(zhuǎn)換選擇
uint32_t ADC_ExternalTrigConv; // ADC 轉(zhuǎn)換觸發(fā)信號(hào)選擇
uint32_t ADC_DataAlign; // ADC 數(shù)據(jù)寄存器對(duì)齊格式
uint8_t ADC_NbrOfChannel; // ADC 采集通道數(shù)
} ADC_InitTypeDef;
ADC_Mode:配置ADC的模式,當(dāng)使用一個(gè)ADC時(shí)是獨(dú)立模式,使用兩個(gè)ADC時(shí)是雙模式,在雙模式下還有很多細(xì)分模式可選,我們一般使用一個(gè)ADC的獨(dú)立模式。
ScanConvMode:可選參數(shù)為ENABLE和DISABLE,配置是否使用掃描。如果是單通道AD轉(zhuǎn)換使用DISABLE,如果是多通道AD轉(zhuǎn)換使用ENABLE。
ADC_ContinuousConvMode:可選參數(shù)為ENABLE和DISABLE,配置是啟動(dòng)自動(dòng)連續(xù)轉(zhuǎn)換還是單次轉(zhuǎn)換。使用ENABLE配置為使能自動(dòng)連續(xù)轉(zhuǎn)換; 使用DISABLE配置為單次轉(zhuǎn)換,轉(zhuǎn)換一次后停止需要手動(dòng)控制才重新啟動(dòng)轉(zhuǎn)換。一般設(shè)置為連續(xù)轉(zhuǎn)換。
ADC_ExternalTrigConv:參數(shù)用于配置模數(shù)轉(zhuǎn)換器的外部觸發(fā)源選擇機(jī)制。該配置項(xiàng)提供多種可編程觸發(fā)模式,包括定時(shí)器輸出信號(hào)、外部引腳事件等硬件觸發(fā)源,以及軟件自主觸發(fā)模式。在實(shí)際工程應(yīng)用中,基于簡(jiǎn)化系統(tǒng)設(shè)計(jì)和提高觸發(fā)精度的考量,通常采用軟件自動(dòng)觸發(fā)(SWSTART)方式實(shí)現(xiàn)轉(zhuǎn)換控制,該模式通過(guò)直接調(diào)用庫(kù)函數(shù)即可精準(zhǔn)啟動(dòng)轉(zhuǎn)換過(guò)程,有效規(guī)避外部信號(hào)干擾風(fēng)險(xiǎn)。
ADC_DataAlign:轉(zhuǎn)換結(jié)果數(shù)據(jù)對(duì)齊模式,可選右對(duì)齊ADC_DataAlign_Right或者左對(duì)齊ADC_DataAlign_Left。一般我們選擇右對(duì)齊模式。
ADC_NbrOfChannel:AD轉(zhuǎn)換通道數(shù)目,根據(jù)實(shí)際設(shè)置即可。
4 單通道 ADC 轉(zhuǎn)換
4.1 代碼分析
1. 頭文件和宏定義
#include #include #include #include "delay.h" #include "w55mh32.h" #include "math.h" #define CONV_CHANNEL_NUM 1 #define VREF (3300) #define ADC_TEST_CHANNEL_PIN (GPIO_Pin_6) uint8_t ADC_CovChannel[1] = {ADC_Channel_6}; uint8_t ADC_SampleTIME[1] = {ADC_SampleTime_239Cycles5}; uint32_t DAM_ADC_Value[1];
頭文件:引入了標(biāo)準(zhǔn)庫(kù)頭文件和自定義頭文件,像stdlib.h、string.h、stdio.h這類標(biāo)準(zhǔn)庫(kù),delay.h和w55mh32.h屬于自定義頭文件,math.h是數(shù)學(xué)庫(kù)頭文件。
宏定義:
CONV_CHANNEL_NUM:定義了 ADC 轉(zhuǎn)換的通道數(shù)量,這里是 1 個(gè)通道。
VREF:參考電壓值,單位為 mV,這里是 3300mV。
ADC_TEST_CHANNEL_PIN:定義了 ADC 測(cè)試通道對(duì)應(yīng)的 GPIO 引腳,為GPIO_Pin_6。
數(shù)組:
ADC_CovChannel:存放要轉(zhuǎn)換的 ADC 通道,這里是ADC_Channel_6。
ADC_SampleTIME:存放每個(gè)通道的采樣時(shí)間,這里是ADC_SampleTime_239Cycles5。
DAM_ADC_Value:用于存儲(chǔ) DMA 搬運(yùn)過(guò)來(lái)的 ADC 轉(zhuǎn)換結(jié)果。
2. 函數(shù)聲明
void UART_Configuration(void); void ADC_Configuration(void); void DMA_Configuration(void);
聲明了用于配置串口、ADC 和 DMA 的函數(shù)。
3. main()函數(shù)
int main(void)
{
RCC_ClocksTypeDef clocks;
delay_init();
UART_Configuration();
RCC_GetClocksFreq(&clocks);
printf("n");
printf("SYSCLK: %3.1fMhz, HCLK: %3.1fMhz, PCLK1: %3.1fMhz, PCLK2: %3.1fMhz, ADCCLK: %3.1fMhzn",
(float)clocks.SYSCLK_Frequency / 1000000, (float)clocks.HCLK_Frequency / 1000000,
(float)clocks.PCLK1_Frequency / 1000000, (float)clocks.PCLK2_Frequency / 1000000, (float)clocks.ADCCLK_Frequency / 1000000);
printf("ADC Single Testn");
ADC_Configuration();
while (1)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
delay_ms(1000);
}
}
初始化延時(shí)函數(shù)delay_init()。
調(diào)用UART_Configuration()配置串口通信。
獲取系統(tǒng)時(shí)鐘頻率并通過(guò)串口輸出。
調(diào)用ADC_Configuration()配置 ADC。
進(jìn)入無(wú)限循環(huán),每秒通過(guò)軟件觸發(fā)一次 ADC1 的轉(zhuǎn)換。
4. GetCmd()函數(shù)
uint8_t GetCmd(void)
{
uint8_t tmp = 0;
if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE))
{
tmp = USART_ReceiveData(USART1);
}
return tmp;
}
此函數(shù)用于從串口接收數(shù)據(jù),若串口 1 接收到數(shù)據(jù),就將其讀取并返回。
5. UART_Configuration()函數(shù)
void UART_Configuration(void)
{
//GPIO port settings
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
使能 USART1 和 GPIOA 的時(shí)鐘。
配置 GPIOA 的Pin_9為復(fù)用推挽輸出,用于串口發(fā)送;Pin_10為浮空輸入,用于串口接收。
配置 USART1 的波特率、數(shù)據(jù)位、停止位、校驗(yàn)位等參數(shù),并使能 USART1。
6. ADC_Configuration()函數(shù)
void ADC_Configuration(void)
{
uint32_t i;
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
GPIO_InitStructure.GPIO_Pin = ADC_TEST_CHANNEL_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
ADC_DeInit(ADC1);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = CONV_CHANNEL_NUM;
ADC_Init(ADC1, &ADC_InitStructure);
for (i = 0; i < CONV_CHANNEL_NUM; i++)
{
ADC_RegularChannelConfig(ADC1, ADC_CovChannel[i], i + 1, ADC_SampleTIME[i]);
}
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
DMA_Configuration();
}
使能 GPIOA 和 ADC1 的時(shí)鐘。
配置GPIOA_Pin_6為模擬輸入模式。
配置 ADC1 的時(shí)鐘,復(fù)位 ADC1。
配置 ADC1 的工作模式、掃描模式、連續(xù)轉(zhuǎn)換模式等參數(shù)。
配置 ADC1 的規(guī)則通道。
啟動(dòng)一次 ADC 轉(zhuǎn)換,使能 ADC1。
對(duì) ADC1 進(jìn)行校準(zhǔn)操作。
調(diào)用DMA_Configuration()配置DMA。
7.DMA_Configuration()函數(shù)
void DMA_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)DAM_ADC_Value;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = CONV_CHANNEL_NUM;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA1_Channel1, DMA1_IT_TC1, ENABLE);
}
使能 DMA1 的時(shí)鐘,復(fù)位 DMA1 通道 1。
配置 DMA 的源地址(ADC1 的數(shù)據(jù)寄存器)、目標(biāo)地址(DAM_ADC_Value數(shù)組)、傳輸方向、緩沖區(qū)大小等參數(shù)。
使能 DMA1 通道 1 和 ADC1 的 DMA 功能。
配置 DMA1 通道 1 的中斷優(yōu)先級(jí)并使能中斷。
8. DMA1_Channel1_IRQHandler()函數(shù)
void DMA1_Channel1_IRQHandler(void)
{
if (DMA_GetITStatus(DMA1_IT_TC1) != RESET)
{
DMA_ClearITPendingBit(DMA1_IT_TC1);
DMA_ClearFlag(DMA1_FLAG_TC1);
printf("Code Value = %d ,voltage value = %2.4fn", DAM_ADC_Value[0],
(float)VREF * DAM_ADC_Value[0] / 4095 / 1000);
}
}
當(dāng) DMA1 通道 1 傳輸完成中斷發(fā)生時(shí),清除中斷標(biāo)志和標(biāo)志位。
通過(guò)串口輸出 ADC 轉(zhuǎn)換后的數(shù)字值和對(duì)應(yīng)的電壓值。
9. SER_PutChar()和fputc()函數(shù)
//Retarget Printf
int SER_PutChar(int ch)
{
while (!USART_GetFlagStatus(USART1, USART_FLAG_TC));
USART_SendData(USART1, (uint8_t)ch);
return ch;
}
int fputc(int c, FILE *f)
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
if (c == 'n')
{
SER_PutChar('r');
}
return (SER_PutChar(c));
}
這兩個(gè)函數(shù)用于重定向printf(),讓printf的輸出通過(guò)串口發(fā)送出去。
4.2 下載驗(yàn)證
這段代碼實(shí)現(xiàn)了對(duì)ADC_Channel_6的單通道模擬信號(hào)采集,利用 DMA 將 ADC 轉(zhuǎn)換結(jié)果搬運(yùn)到指定數(shù)組,通過(guò)串口輸出轉(zhuǎn)換后的數(shù)字值和對(duì)應(yīng)的電壓值,每秒進(jìn)行一次轉(zhuǎn)換,以下是轉(zhuǎn)換結(jié)果:

5 雙重ADC同步規(guī)則模式采集實(shí)驗(yàn)
AD轉(zhuǎn)換包括采樣階段和轉(zhuǎn)換階段,在采樣階段才對(duì)通道數(shù)據(jù)進(jìn)行采集;而在轉(zhuǎn)換階段只是將采集到的數(shù)據(jù)進(jìn)行轉(zhuǎn)換為數(shù)字量輸出,此刻通道數(shù)據(jù)變化不會(huì)改變轉(zhuǎn)換結(jié)果。
獨(dú)立模式的ADC采集需要在一個(gè)通道采集并且轉(zhuǎn)換完成后才會(huì)進(jìn)行下一個(gè)通道的采集。而雙重ADC的機(jī)制就是使用兩個(gè)ADC同時(shí)采樣一個(gè)或者多個(gè)通道。 雙重ADC模式較獨(dú)立模式一個(gè)最大的優(yōu)勢(shì)就是提高了采樣率,彌補(bǔ)了單個(gè)ADC采樣不夠快的缺點(diǎn)。
啟用雙ADC模式的時(shí)候,通過(guò)配置ADC_CR1寄存器的DUALMOD[3:0]位,可以有幾種不同的模式, 具體見(jiàn)如下表格,雙ADC模式的各種模式匯總 :
| 模式 | 簡(jiǎn)要說(shuō)明 |
| 同步注入模式 | ADC1 和 ADC2 同時(shí)轉(zhuǎn)換一個(gè)注入通道組,其中 ADC1 為主,ADC2 為從。轉(zhuǎn)換的數(shù)據(jù)存儲(chǔ)在每個(gè) ADC 接口的 ADC_JDRx 寄存器中。 |
| 同步規(guī)則模式 | ADC1 和 ADC2 同時(shí)轉(zhuǎn)換一個(gè)規(guī)則通道組,其中 ADC1 為主,ADC2 為從。ADC1 轉(zhuǎn)換的結(jié)果放在 ADC1_DR 的低 16 位,ADC2 轉(zhuǎn)換的結(jié)果放在 ADC1_DR 的高十六位。 |
| 快速交叉模式 | ADC1 和 ADC2 交替采集一個(gè)規(guī)則通道組(通常為一個(gè)通道)。當(dāng) ADC2 觸發(fā)之后,ADC1 需要等待 7 個(gè) ADCCLK 之后才能觸發(fā)。 |
| 慢速交叉模式 | ADC1 和 ADC2 交替采集一個(gè)規(guī)則通道組(只能為一個(gè)通道)。當(dāng) ADC2 觸發(fā)之后,ADC1 需要等待 14 個(gè) ADCCLK 之后才能觸發(fā)。 |
| 交替觸發(fā)模式 | ADC1 和 ADC2 輪流采集注入通道組,當(dāng) ADC1 所有通道采集完畢之后再采集 ADC2 的通道,如此循環(huán)。跟交叉采集不一樣。 |
| 混合的規(guī)則 / 注入同步模式 | 規(guī)則組同步轉(zhuǎn)換被中斷,以啟動(dòng)注入組的同步轉(zhuǎn)換。分開(kāi)兩個(gè)模式來(lái)理解即可,區(qū)別是注入組可中斷規(guī)則組的轉(zhuǎn)換。 |
| 混合的同步規(guī)則 + 交替觸發(fā)模式 | 規(guī)則組同步轉(zhuǎn)換被中斷,以啟動(dòng)注入組交替觸發(fā)轉(zhuǎn)換。分開(kāi)兩個(gè)模式理解即可,區(qū)別是注入組可中斷規(guī)則組的轉(zhuǎn)換。 |
| 混合同步注入 + 交叉模式 | 交叉轉(zhuǎn)換可被同步注入模式中斷,此時(shí)交叉轉(zhuǎn)換中斷,注入轉(zhuǎn)換啟動(dòng)。 |
這里我們選取同步規(guī)則模式來(lái)作為實(shí)驗(yàn)講解。同步規(guī)則模式是ADC1和ADC2同時(shí)轉(zhuǎn)換一個(gè)規(guī)則通道組,ADC1是主,ADC2是從, ADC1轉(zhuǎn)換的結(jié)果放在ADC1_DR的低16位,ADC2轉(zhuǎn)換的結(jié)果放在ADC1_DR的高十六位。并且必須開(kāi)啟DMA功能。
外部觸發(fā)來(lái)自ADC1的規(guī)則組多路開(kāi)關(guān)(由ADC1_CR2寄存器的EXTSEL[2:0]選擇), 它同時(shí)給ADC2提供同步觸發(fā)。 為了簡(jiǎn)單起見(jiàn),ADC1跟ADC2我們選擇軟件觸發(fā)。
為了實(shí)驗(yàn)的簡(jiǎn)單起見(jiàn),實(shí)驗(yàn)中我們選取ADC1和ADC2各采集一個(gè)通道 :

5.1 代碼分析
1. 頭文件和宏定義
#include #include #include #include "delay.h" #include "w55mh32.h" #include "math.h" #define CONV_CHANNEL_NUM 1 #define VREF (3300)
頭文件:
引入了標(biāo)準(zhǔn) C 庫(kù)的頭文件以及自定義的頭文件,用于實(shí)現(xiàn)基本的庫(kù)函數(shù)調(diào)用、延時(shí)功能等。
宏定義:
CONV_CHANNEL_NUM:定義了 ADC 轉(zhuǎn)換的通道數(shù)量,這里設(shè)置為 1,表示每個(gè) ADC 使用一個(gè)通道進(jìn)行轉(zhuǎn)換。
VREF:定義了參考電壓值,單位為 mV,這里設(shè)置為 3300mV,用于后續(xù)將 ADC 轉(zhuǎn)換的數(shù)字值轉(zhuǎn)換為實(shí)際的電壓值。
函數(shù)聲明
void UART_Configuration(void); void ADC_Configuration(void); void DMA_Configuration(void);
聲明了三個(gè)函數(shù),分別用于配置串口通信、ADC 模塊和 DMA 模塊。
3. 全局變量
uint32_t DAM_ADC_Value[1];
定義了一個(gè)全局?jǐn)?shù)組DAM_ADC_Value,用于存儲(chǔ) DMA 從 ADC1 的數(shù)據(jù)寄存器搬運(yùn)過(guò)來(lái)的轉(zhuǎn)換結(jié)果。
4. main()函數(shù)
int main(void)
{
RCC_ClocksTypeDef clocks;
delay_init();
UART_Configuration();
RCC_GetClocksFreq(&clocks);
printf("n");
printf("SYSCLK: %3.1fMhz, HCLK: %3.1fMhz, PCLK1: %3.1fMhz, PCLK2: %3.1fMhz, ADCCLK: %3.1fMhzn",
(float)clocks.SYSCLK_Frequency / 1000000, (float)clocks.HCLK_Frequency / 1000000,
(float)clocks.PCLK1_Frequency / 1000000, (float)clocks.PCLK2_Frequency / 1000000, (float)clocks.ADCCLK_Frequency / 1000000);
printf("ADC Double Test(ADC1 & ADC2)n");
ADC_Configuration();
while (1)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
delay_ms(1000);
}
}
初始化:
初始化延時(shí)函數(shù)delay_init(),用于后續(xù)的延時(shí)操作。
調(diào)用UART_Configuration()函數(shù)配置串口通信,以便后續(xù)通過(guò)串口輸出信息。
獲取系統(tǒng)時(shí)鐘頻率信息并通過(guò)串口輸出,方便調(diào)試和查看系統(tǒng)時(shí)鐘配置。
輸出提示信息,表示開(kāi)始進(jìn)行 ADC 雙模式測(cè)試。
調(diào)用ADC_Configuration()函數(shù)配置 ADC 模塊。
主循環(huán):
通過(guò)軟件觸發(fā) ADC1 開(kāi)始轉(zhuǎn)換操作。
延時(shí) 1 秒,控制 ADC 轉(zhuǎn)換的頻率。
5. GetCmd()函數(shù)
uint8_t GetCmd(void)
{
uint8_t tmp = 0;
if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE))
{
tmp = USART_ReceiveData(USART1);
}
return tmp;
}
該函數(shù)用于從串口接收數(shù)據(jù)。如果串口 1 接收到數(shù)據(jù)(USART_FLAG_RXNE標(biāo)志置位),則讀取該數(shù)據(jù)并返回。
6. UART_Configuration()函數(shù)
void UART_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
時(shí)鐘使能:使能 USART1 和 GPIOA 的時(shí)鐘,因?yàn)?USART1 使用 GPIOA 的引腳進(jìn)行通信。
GPIO 配置:
配置 GPIOA 的 Pin 9 為復(fù)用推挽輸出模式,用于 USART1 的發(fā)送功能。
配置 GPIOA 的 Pin 10 為浮空輸入模式,用于 USART1 的接收功能。
USART 配置:
設(shè)置 USART1 的波特率為 115200,數(shù)據(jù)位為 8 位,停止位為 1 位,無(wú)校驗(yàn)位,無(wú)硬件流控制,支持收發(fā)模式。
初始化 USART1 并使能該模塊。
7. ADC_Configuration()函數(shù)
void ADC_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
ADC_DeInit(ADC1);
ADC_DeInit(ADC2);
ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult; //synchronization rule mode
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Init(ADC2, &ADC_InitStructure);
/* channel configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5);
/* module enablement */
ADC_Cmd(ADC1, ENABLE);
ADC_Cmd(ADC2, ENABLE);
/* adc calibration */
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
ADC_ResetCalibration(ADC2);
while (ADC_GetResetCalibrationStatus(ADC2));
ADC_StartCalibration(ADC2);
while (ADC_GetCalibrationStatus(ADC2));
DMA_Configuration();
}
時(shí)鐘使能:使能 GPIOA、ADC1 和 ADC2 的時(shí)鐘。
GPIO 配置:配置 GPIOA 的 Pin 0 和 Pin 1 為模擬輸入模式,分別用于 ADC1 的通道 0 和 ADC2 的通道 1。
ADC 時(shí)鐘配置和復(fù)位:配置 ADC 的時(shí)鐘,將 PCLK2 分頻 8 作為 ADC 的時(shí)鐘源。復(fù)位 ADC1 和 ADC2,將它們的寄存器恢復(fù)到默認(rèn)狀態(tài)。
ADC 初始化:
設(shè)置 ADC 工作模式為ADC_Mode_RegSimult,即規(guī)則同步模式,使 ADC1 和 ADC2 可以同時(shí)對(duì)各自的通道進(jìn)行轉(zhuǎn)換。
禁用掃描模式和連續(xù)轉(zhuǎn)換模式,采用軟件觸發(fā)轉(zhuǎn)換。
數(shù)據(jù)右對(duì)齊,每個(gè) ADC 使用 1 個(gè)通道進(jìn)行轉(zhuǎn)換。
分別初始化 ADC1 和 ADC2。
通道配置:
配置 ADC1 的規(guī)則通道為通道 0,轉(zhuǎn)換順序?yàn)?1,采樣時(shí)間為 239.5 個(gè)周期。
配置 ADC2 的規(guī)則通道為通道 1,轉(zhuǎn)換順序?yàn)?1,采樣時(shí)間為 239.5 個(gè)周期。
使能 ADC 模塊:使能 ADC1 和 ADC2。
ADC 校準(zhǔn):對(duì) ADC1 和 ADC2 分別進(jìn)行復(fù)位校準(zhǔn)和開(kāi)始校準(zhǔn)操作,并等待校準(zhǔn)完成。
調(diào)用 DMA 配置函數(shù):調(diào)用DMA_Configuration()函數(shù)配置 DMA 模塊。
8.DMA_Configuration()函數(shù)
void DMA_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)DAM_ADC_Value;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = CONV_CHANNEL_NUM;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA1_Channel1, DMA1_IT_TC1, ENABLE);
}
時(shí)鐘使能和 DMA 復(fù)位:
使能 DMA1 的時(shí)鐘。
復(fù)位 DMA1 的通道 1。
DMA 初始化:
設(shè)置 DMA 的源地址為 ADC1 的數(shù)據(jù)寄存器ADC1->DR。
設(shè)置 DMA 的目標(biāo)地址為DAM_ADC_Value數(shù)組。
數(shù)據(jù)傳輸方向?yàn)閺耐庠O(shè)(ADC1 的數(shù)據(jù)寄存器)到內(nèi)存。
緩沖區(qū)大小為CONV_CHANNEL_NUM,即 1。
外設(shè)地址不遞增,內(nèi)存地址遞增。
數(shù)據(jù)傳輸大小為字(32 位)。
DMA 工作模式為循環(huán)模式,即完成一次傳輸后自動(dòng)重新開(kāi)始。
設(shè)置 DMA 優(yōu)先級(jí)為高。
禁用內(nèi)存到內(nèi)存的傳輸模式。
初始化 DMA1 的通道 1 并使能該通道。
使能 ADC1 的 DMA 功能。
NVIC 配置:
配置 DMA1 通道 1 的中斷優(yōu)先級(jí),搶占優(yōu)先級(jí)和子優(yōu)先級(jí)都設(shè)置為 0。
使能 DMA1 通道 1 的中斷。
使能 DMA1 通道 1 的傳輸完成中斷。
9. DMA1_Channel1_IRQHandler()函數(shù)
void DMA1_Channel1_IRQHandler(void)
{
if (DMA_GetITStatus(DMA1_IT_TC1) != RESET)
{
DMA_ClearITPendingBit(DMA1_IT_TC1);
DMA_ClearFlag(DMA1_FLAG_TC1);
printf("ADC1 Code Value = %d ,voltage value = %2.4fn", DAM_ADC_Value[0] & 0xFFFF,
(float)VREF * (DAM_ADC_Value[0] & 0xFFFF) / 4095 / 1000);
printf("ADC2 Code Value = %d ,voltage value = %2.4fn", (DAM_ADC_Value[0] >> 16) & 0xFFFF,
(float)VREF * ((DAM_ADC_Value[0] >> 16) & 0xFFFF) / 4095 / 1000);
}
}
中斷處理:
當(dāng) DMA1 通道 1 的傳輸完成中斷發(fā)生時(shí),清除中斷標(biāo)志和標(biāo)志位。
數(shù)據(jù)處理和輸出:
從DAM_ADC_Value[0]中提取 ADC1 和 ADC2 的轉(zhuǎn)換結(jié)果。ADC1 的結(jié)果存儲(chǔ)在低 16 位,ADC2 的結(jié)果存儲(chǔ)在高 16 位。
將提取的數(shù)字值轉(zhuǎn)換為對(duì)應(yīng)的電壓值,并通過(guò)串口輸出 ADC1 和 ADC2 的數(shù)字值和電壓值。
10. SER_PutChar和fputc()函數(shù)
//Retarget Printf
int SER_PutChar(int ch)
{
while (!USART_GetFlagStatus(USART1, USART_FLAG_TC));
USART_SendData(USART1, (uint8_t)ch);
return ch;
}
int fputc(int c, FILE *f)
{
if (c == 'n')
{
SER_PutChar('r');
}
return (SER_PutChar(c));
}
SER_PutChar()函數(shù):將一個(gè)字符發(fā)送到 USART1,并等待發(fā)送完成。
fputc()函數(shù):重定向printf()函數(shù)的輸出到 USART1。當(dāng)輸出換行符n時(shí),先發(fā)送回車符r,以確保在終端上正確顯示換行。
這段代碼通過(guò)配置 ADC1 和 ADC2 在規(guī)則同步模式下同時(shí)對(duì)不同通道進(jìn)行模擬信號(hào)采集,利用 DMA 將轉(zhuǎn)換結(jié)果傳輸?shù)絻?nèi)存,最后通過(guò)串口輸出轉(zhuǎn)換后的數(shù)字值和對(duì)應(yīng)的電壓值,實(shí)現(xiàn)了 ADC 雙模式測(cè)試的功能。
5.2 下載驗(yàn)證

6 ADC 模擬看門狗功能
6.1 代碼解析
1. 頭文件與全局聲明
w55mh32.h:包含 STM32 外設(shè)寄存器定義(如 ADC1、USART1)。
delay.h:提供毫秒級(jí)延時(shí)函數(shù):delay_ms()。
2. main()函數(shù):初始化與主循環(huán)
int main(void) {
// 初始化
delay_init(); // 延時(shí)初始化
UART_Configuration(); // 串口配置(115200波特率)
ADC_Configuration(); // ADC配置(含模擬看門狗)
// 打印系統(tǒng)時(shí)鐘
printf("SYSCLK: %3.1fMhz...n", (float)clocks.SYSCLK_Frequency / 1000000);
// 主循環(huán):周期性觸發(fā)ADC轉(zhuǎn)換
while (1) {
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 啟動(dòng)軟件觸發(fā)轉(zhuǎn)換
delay_ms(200); // 延時(shí)200ms
}
}
3. ADC_Configuration:ADC 與模擬看門狗配置
void ADC_Configuration(void) {
// 使能時(shí)鐘:ADC1、GPIOA
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
// ADC時(shí)鐘:PCLK2/8(假設(shè)PCLK2=72MHz → ADCCLK=9MHz)
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// ADC初始化:獨(dú)立模式,單通道,單次轉(zhuǎn)換
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE); // 使能ADC
// 中斷配置:ADC1_2_IRQn(模擬看門狗中斷)
NVIC_Init(&NVIC_InitStructure);
// 配置通道10:采樣時(shí)間239.5周期
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5);
// 模擬看門狗配置:
ADC_AnalogWatchdogThresholdsConfig(ADC1, 2048, 1024); // 閾值:1024(下限)~2048(上限)
ADC_AnalogWatchdogSingleChannelConfig(ADC1, ADC_Channel_10); // 監(jiān)控通道10
ADC_AnalogWatchdogCmd(ADC1, ADC_AnalogWatchdog_SingleRegEnable); // 使能單通道看門狗
// 校準(zhǔn)ADC(必須步驟)
ADC_ResetCalibration(ADC1);
ADC_StartCalibration(ADC1);
}
4. 中斷處理函數(shù):ADC1_2_IRQHandler()
void ADC1_2_IRQHandler(void) {
ADC_ITConfig(ADC1, ADC_IT_AWD, DISABLE); // 禁用中斷,避免嵌套
if (ADC_GetFlagStatus(ADC1, ADC_FLAG_AWD)) { // 檢測(cè)看門狗標(biāo)志
ADC_ClearFlag(ADC1, ADC_FLAG_AWD); // 清除標(biāo)志
printf("ADC Awd is Happened. Code Value = %d rn", ADC1->DR); // 輸出ADC值
}
ADC_ITConfig(ADC1, ADC_IT_AWD, ENABLE); // 重新使能中斷
}
5. printf重定向:串口輸出
該代碼實(shí)現(xiàn)了W55MH32的 ADC 模擬看門狗功能,通過(guò)串口輸出系統(tǒng)信息和電壓越界報(bào)警。核心流程:配置 ADC 和串口 → 周期性觸發(fā) ADC 轉(zhuǎn)換 → 監(jiān)控電壓閾值 → 中斷響應(yīng)。適用于需要實(shí)時(shí)監(jiān)控模擬信號(hào)的場(chǎng)景(如電池電壓監(jiān)測(cè)、傳感器輸入保護(hù))。
6.2 下載驗(yàn)證

7 ADC_VrefintTemper
7.1 代碼解析
1. 全局定義與變量
#define CONV_CHANNEL_NUM 2 // 轉(zhuǎn)換通道數(shù)(2個(gè)內(nèi)部通道)
#define VREF (3300) // 參考電壓(3.3V,單位:mV)
uint8_t ADC_CovChannel[2] = {ADC_Channel_16, ADC_Channel_17}; // 通道16(溫度)、17(VREFINT)
uint32_t DAM_ADC_Value[2]; // DMA存儲(chǔ)數(shù)組(2個(gè)通道數(shù)據(jù))
2. main()函數(shù):初始化與主循環(huán)
int main(void) {
delay_init(); // 延時(shí)初始化
UART_Configuration(); // 串口配置(115200波特率)
ADC_Configuration(); // ADC+DMA配置
// 打印系統(tǒng)時(shí)鐘
printf("SYSCLK: %3.1fMhz...n", (float)clocks.SYSCLK_Frequency / 1000000);
// 主循環(huán):周期性觸發(fā)ADC轉(zhuǎn)換(軟件觸發(fā))
while (1) {
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 啟動(dòng)轉(zhuǎn)換
delay_ms(1000); // 每秒觸發(fā)一次
}
}
3. ADC_Configuration:ADC 初始化
void ADC_Configuration(void) {
// 使能ADC1、GPIOA時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
// ADC時(shí)鐘:PCLK2/4(假設(shè)PCLK2=72MHz → ADCCLK=18MHz)
RCC_ADCCLKConfig(RCC_PCLK2_Div4);
// ADC配置:獨(dú)立模式、掃描模式(多通道)、單次轉(zhuǎn)換
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 掃描模式(多通道)
ADC_InitStructure.ADC_NbrOfChannel = CONV_CHANNEL_NUM; // 2通道
ADC_Init(ADC1, &ADC_InitStructure);
// 配置通道16(溫度)、17(VREFINT)
for (i=0; i
4. DMA_Configuration():DMA 初始化
void DMA_Configuration(void) {
// 配置DMA1通道1:ADC_DR → DAM_ADC_Value數(shù)組
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // 外設(shè)地址(ADC數(shù)據(jù)寄存器)
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)DAM_ADC_Value; // 內(nèi)存地址(存儲(chǔ)數(shù)組)
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 外設(shè)到內(nèi)存
DMA_InitStructure.DMA_BufferSize = CONV_CHANNEL_NUM; // 傳輸數(shù)據(jù)量(2個(gè)通道)
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循環(huán)模式(連續(xù)傳輸)
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE);
// 使能ADC的DMA請(qǐng)求
ADC_DMACmd(ADC1, ENABLE);
// 配置DMA中斷(傳輸完成觸發(fā))
NVIC_Init(&NVIC_InitStructure);
DMA_ITConfig(DMA1_Channel1, DMA1_IT_TC1, ENABLE); // 使能傳輸完成中斷
}
5. DMA 中斷處理函數(shù):DMA1_Channel1_IRQHandler()
void DMA1_Channel1_IRQHandler(void) {
if (DMA_GetITStatus(DMA1_IT_TC1)) { // 檢測(cè)傳輸完成中斷
DMA_ClearITPendingBit(DMA1_IT_TC1);
// 計(jì)算并打印結(jié)果(單位:mV)
printf("temperature AD: %d → %.4fVn", DAM_ADC_Value[0],
(float)VREF * DAM_ADC_Value[0] / 4095 / 1000);
printf("VREFINT AD: %d → %.4fVn", DAM_ADC_Value[1],
(float)VREF * DAM_ADC_Value[1] / 4095 / 1000);
}
}
該代碼利用 W55MH32 的內(nèi)部 ADC 通道(溫度傳感器和 VREFINT),結(jié)合 DMA 實(shí)現(xiàn)高效數(shù)據(jù)采集,通過(guò)串口輸出實(shí)時(shí)電壓值。適用于需要監(jiān)測(cè)內(nèi)部傳感器或校準(zhǔn) ADC 的場(chǎng)景(如工業(yè)控制、嵌入式系統(tǒng)診斷)。核心優(yōu)勢(shì):DMA 減輕 CPU 負(fù)載、內(nèi)部傳感器免外部接線、循環(huán)模式連續(xù)采集。
7.2 下載驗(yàn)證

WIZnet 是一家無(wú)晶圓廠半導(dǎo)體公司,成立于 1998 年。產(chǎn)品包括互聯(lián)網(wǎng)處理器 iMCU?,它采用 TOE(TCP/IP 卸載引擎)技術(shù),基于獨(dú)特的專利全硬連線 TCP/IP。iMCU? 面向各種應(yīng)用中的嵌入式互聯(lián)網(wǎng)設(shè)備。
WIZnet 在全球擁有 70 多家分銷商,在香港、韓國(guó)、美國(guó)設(shè)有辦事處,提供技術(shù)支持和產(chǎn)品營(yíng)銷。
香港辦事處管理的區(qū)域包括:澳大利亞、印度、土耳其、亞洲(韓國(guó)和日本除外)。
-
單片機(jī)
+關(guān)注
關(guān)注
6076文章
45501瀏覽量
670805 -
寄存器
+關(guān)注
關(guān)注
31文章
5609瀏覽量
130039 -
adc
+關(guān)注
關(guān)注
100文章
7523瀏覽量
556128 -
電壓采集
+關(guān)注
關(guān)注
2文章
25瀏覽量
14709
發(fā)布評(píng)論請(qǐng)先 登錄
【紫光同創(chuàng)國(guó)產(chǎn)FPGA教程】【第十九章】ADDA測(cè)試?yán)?/a>
【MangoTree】芒果樹(shù)將參加第十九屆中國(guó)國(guó)際工業(yè)博覽會(huì)
第十九講 數(shù)據(jù)選擇器和分配器
2010年第十九屆波蘭國(guó)際建筑建材博覽會(huì)BUDMA 王薇
模擬電路網(wǎng)絡(luò)課件 第十九節(jié):金屬-氧化物-半導(dǎo)體場(chǎng)效應(yīng)管
第十九屆臺(tái)灣電路板展覽會(huì)即將開(kāi)幕
第十九屆中國(guó)通信集成電路技術(shù)應(yīng)用研討會(huì)暨青島微電子產(chǎn)業(yè)發(fā)展大會(huì)即將召開(kāi)
第十九屆中國(guó)半導(dǎo)體封裝測(cè)試技術(shù)與市場(chǎng)年會(huì)即將召開(kāi)
長(zhǎng)電科技舉辦第十九屆中國(guó)半導(dǎo)體封測(cè)年會(huì)
喜!聯(lián)誠(chéng)發(fā)成功入選第十九屆“深圳知名品牌”
景旺電子榮獲第十九屆“深圳知名品牌”稱號(hào)
美格智能亮相IOTE 2023第十九屆上海國(guó)際物聯(lián)網(wǎng)展
英飛特電子參加第十九屆中國(guó)道路照明論壇
第十九屆中博會(huì)圓滿閉幕,思爾芯“小巨人”展現(xiàn)EDA創(chuàng)新實(shí)力
第十九章 ADC——電壓采集
評(píng)論