很多STM32芯片里往往內(nèi)置了專用的ADC通道,比方用來測量Vrefint,VBAT的分壓或溫度傳感器的輸出電壓信號(hào)。不同系列所內(nèi)置的模擬信號(hào)通道可能有差異。這里以STM32G4系列為例,它內(nèi)置了對應(yīng)于Vrefint,VBAT的三分之一分壓和溫度傳感器的輸出電壓的專用模擬通道。


下面的示例就是針對上述3個(gè)通道進(jìn)行AD,并測量相關(guān)電壓和片內(nèi)溫度,最終得到3個(gè)結(jié)果,分別是VRefint電壓,VBAT的電壓,片內(nèi)溫度。

實(shí)現(xiàn)過程是這樣的,大體分四步:【有點(diǎn)點(diǎn)麻雀雖小五臟俱全的味道】
1、TIMER1 更新事件觸發(fā)ADC的轉(zhuǎn)換;
2、CPU基于EOC中斷獲取ADC結(jié)果;
3、對ADC結(jié)果進(jìn)行換算,得到電壓值和溫度值存放在特定內(nèi)存位置;
4、基于DMA傳輸通過UART將最終結(jié)果在串口終端顯示;
其中,TIMER1的CH1輸出PWM波形,其更新事件做ADC的轉(zhuǎn)換啟動(dòng)信號(hào)。每次的TIMER更新事件觸發(fā)ADC,3個(gè)通道掃描方式轉(zhuǎn)換。這里的UART使用片內(nèi)LPUART,使用它主要是考慮它跟板載虛擬串口直接相連,沒有其它特別用意。

我使用STM32G474Nucleo板來進(jìn)行下面實(shí)驗(yàn)。其中VDD=3.3v,VBAT與VDD相連。另外,ADC模塊的參考電壓也是3.3v.
使用CubeMx圖形化工具進(jìn)行配置,先看TIMER配置:

再看看ADC的基本配置:

LPUART的基本配置:

因?yàn)橐褂肁DC中斷和UART的DMA傳輸,記得做ADC的中斷響應(yīng)使能配置和LPUART的DMA配置,這里只使用UART的TX DMA功能。

使用CubeMx主要配置主要是上面這些。
在組織用戶代碼前,先簡單介紹下片內(nèi)溫度傳感器的內(nèi)容。該溫度傳感器針對不同溫度有不同電壓輸出,其輸出電壓跟溫度呈線性關(guān)系。ST公司針對片內(nèi)溫度傳感器在兩個(gè)特定溫度【30℃和110℃或30℃和130℃】、基于特定參考電壓【3v或3.3v,不同系列以數(shù)據(jù)手冊為準(zhǔn)】生成了1組校準(zhǔn)值并存放于片內(nèi)特定FLASH位置。
STM32G4系列的校準(zhǔn)值是在參考電壓為3v,30℃和110℃條件下的兩個(gè)值,在數(shù)據(jù)手冊里還給出了校準(zhǔn)值的片內(nèi)存放地址。

針對這個(gè)溫度傳感器的使用,ST公司在參考手冊里還給出了計(jì)算公式。其實(shí),有無這個(gè)公式無所謂,我們不難自行推理出來。【TS_DATA代表某時(shí)刻測得的傳感器輸出電壓對應(yīng)的轉(zhuǎn)換值,TS_CAL1/TS_CAL2分別表示在30℃和110℃條件下基于傳感器輸出電壓的轉(zhuǎn)換值。】

另外,前面提過,ST公司在手冊里給出了溫度傳感器的兩個(gè)溫度下的校準(zhǔn)值,但要注意生成校準(zhǔn)值的ADC模塊所用參考電壓跟我們實(shí)際應(yīng)用時(shí)AD模塊所用的參考基準(zhǔn)電壓可能不一致。如果不一致,就必須將ADC值換算成同一基準(zhǔn)參考電壓條件下的數(shù)據(jù)。目前在ST手冊里也特別強(qiáng)調(diào)這點(diǎn)了。我把上面一副圖再貼一遍于此【見黃色語句提醒】。

關(guān)于這點(diǎn),我們也不難理解。同一待測信號(hào)、同一ADC模塊在不同基準(zhǔn)參考電壓下轉(zhuǎn)換值往往是不一樣的。見下面示意圖加以理解。

完成各項(xiàng)配置后,創(chuàng)建軟件工程。添加必需的用戶代碼:
#define TX_Timeout (9999) #define TS_CAL1_ADDR (0x1FFF75A8) //用于計(jì)算溫度傳感器數(shù)據(jù) #define TS_CAL2_ADDR (0x1FFF75CA) //用于計(jì)算溫度傳感器數(shù)據(jù) #define size1 (40) char WDVol[size1],BatVol[size1],InVol[size1]; uint16_t ts_c30,ts_c110; uint16_t ADCResult[3],convCNT; volatile uint32_t Completed,EndofCon_Flag; floatVBATVolt;//存放BBAT電壓最終結(jié)果 floatVRefint;//存放Vrefint電壓最終結(jié)果 floatTemperature;//存放片外溫度℃最終結(jié)果 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_LPUART1_UART_Init(); MX_TIM1_Init(); /* USER CODE BEGIN 2 */ ts_c30=*(uint16_t*)(TS_CAL1_ADDR);//讀取30℃時(shí)的ADC校準(zhǔn)值 ts_c110 = *(uint16_t *)(TS_CAL2_ADDR);//讀取110℃時(shí)的ADC校準(zhǔn)值 HAL_ADCEx_Calibration_Start(&hadc1 , ADC_SINGLE_ENDED);//ADC校準(zhǔn) HAL_ADC_Start_IT(&hadc1);//啟動(dòng)ADC并開啟轉(zhuǎn)換中斷 HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ if (EndofCon_Flag!=0) { VBATVolt=(ADCResult[0]/4095.)* 3.3 * 3.; VRefint=(ADCResult[1]/4095.) * 3.3; Temperature = 30.+ (88.*(ADCResult[2]-((ts_c30/1.1))))/(ts_c110 - ts_c30); EndofCon_Flag=0; //HAL_UART_Transmit(&hlpuart1, (uint8_t *)WDVol ,sizeof(WDVol), TX_Timeout); HAL_GPIO_WritePin(GPIOC,GPIO_PIN_3,GPIO_PIN_RESET);//forauxiliarytest HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)WDVol ,sizeof(WDVol)); while(Completed==0){} Completed =0; //HAL_UART_Transmit(&hlpuart1, (uint8_t *)InVol ,sizeof(InVol), TX_Timeout); HAL_UART_Transmit_DMA(&hlpuart1,(uint8_t*)InVol,sizeof(InVol)); while(Completed==0) {} Completed =0; //HAL_UART_Transmit(&hlpuart1, (uint8_t *)BatVol ,sizeof(BatVol), TX_Timeout); HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)BatVol ,sizeof(BatVol)); while(Completed==0){} Completed =0; HAL_GPIO_WritePin( GPIOC,GPIO_PIN_3,GPIO_PIN_SET); //for auxiliary test } } /* USER CODE END 3 */ } //ADCEOC 中斷處理函數(shù) void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { ADCResult[convCNT]=HAL_ADC_GetValue(&hadc1); //獲取轉(zhuǎn)換結(jié)果并存入數(shù)組 convCNT++; if(convCNT==3) { convCNT=0; EndofCon_Flag=0xff; sprintf(WDVol,"Internal PN Temperature: %5.3f ",Temperature); sprintf(InVol,"Internal Reference Volt: %5.3f ",VRefint); sprintf(BatVol,"Current Battery Volt: %5.3f ",VBATVolt); } } //UART DMA傳輸完成處理函數(shù) void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { Completed=0xff; }
基于上面的配置和測試代碼,我們就可以看到最終的結(jié)果了。定時(shí)器周期性地觸發(fā)ADC,每得到3個(gè)ADC結(jié)果就進(jìn)行數(shù)據(jù)處理,然后通過UART以DMA方式傳輸?shù)酱诮K端。注意VBat電壓是測量結(jié)果再乘以3得到的。


針對上面的應(yīng)用演示,最后給幾點(diǎn)相關(guān)應(yīng)用提醒:
1、針對溫度傳感器做測量時(shí),校準(zhǔn)時(shí)使用的參考電壓與實(shí)際應(yīng)用不一致時(shí)要做換算,換算成相同參考電壓的數(shù)據(jù)后再做計(jì)算。這點(diǎn)前面也提過了。
2、使用TIMER的TRGO觸發(fā)ADC,如果選擇類似比較事件、更新事件來觸發(fā)ADC時(shí),此時(shí)ADC對觸發(fā)極性的選擇是無效的,或者說ADC的轉(zhuǎn)換僅依賴于觸發(fā)事件時(shí)間點(diǎn)。如果是選擇TIMER的Ocref信號(hào)作為觸發(fā)源,此時(shí)ADC的硬件觸發(fā)的極性選擇是有效的,可以是上沿或下沿觸發(fā),甚至是雙沿觸發(fā)。這時(shí)就得根據(jù)需要選擇合適的觸發(fā)沿。【可以進(jìn)一步閱讀本公眾號(hào)文章《STM32定時(shí)器觸發(fā)ADC的時(shí)序話題》】
3、這里使用UART的DMA傳輸依次顯示三個(gè)結(jié)果于串口終端,三個(gè)啟動(dòng)UART DMA傳輸?shù)暮瘮?shù)須保留適當(dāng)時(shí)間間隔,即等上次傳輸完成后再啟動(dòng)下一次傳輸,因?yàn)檫@里每次傳輸使用的是同一DMA通道。否則沒法全部正常輸出。比如上面3次UART DMA傳輸?shù)拇a改成下面這樣子:
HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)WDVol ,sizeof(WDVol)); HAL_UART_Transmit_DMA(&hlpuart1,(uint8_t*)InVol,sizeof(InVol)); HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)BatVol ,sizeof(BatVol))
這時(shí)輸出結(jié)果會(huì)變成下面的情形,總是只能看到一個(gè)結(jié)果的輸出,即第一次啟動(dòng)的DMA傳輸結(jié)果。

如果想省事點(diǎn),直接在相鄰2次DMA傳輸間加上合適延時(shí)也行。我這里根據(jù)DMA傳輸完成事件來決定執(zhí)行下一次發(fā)送。在DMA傳輸完成中斷里設(shè)置Completed變量為非0值表示當(dāng)前一輪DMA傳輸完成。
4、對于那些在中斷和主程序里都會(huì)被訪問的變量,記得將它們冠以volatile。
下圖的三路波形是我調(diào)試時(shí)輔助使用的。
第一路表示計(jì)數(shù)器的計(jì)數(shù)變化,顯然是單向向上計(jì)數(shù)模式。
第二路是TIMER1通道1的PWM輸出波形。
第三路是我每次基于DMA實(shí)現(xiàn)UART發(fā)送時(shí)拉高拉低的波形。平常管腳電平為高,在實(shí)現(xiàn)DMA傳輸過程中拉低。

好,今天的分享就到這里,供君參考。下次再聊。
審核編輯:劉清
-
溫度傳感器
+關(guān)注
關(guān)注
48文章
3210瀏覽量
163083 -
輸出電壓
+關(guān)注
關(guān)注
2文章
2048瀏覽量
41105 -
PWM波
+關(guān)注
關(guān)注
0文章
101瀏覽量
17724 -
VDD
+關(guān)注
關(guān)注
1文章
318瀏覽量
37184 -
STM32芯片
+關(guān)注
關(guān)注
0文章
38瀏覽量
4892
原文標(biāo)題:基于STM32片內(nèi)信號(hào)的ADC應(yīng)用演示
文章出處:【微信號(hào):stmcu832,微信公眾號(hào):茶話MCU】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評(píng)論請先 登錄
2812片內(nèi)ADC采樣時(shí)間計(jì)算
STM32 ADC基礎(chǔ)內(nèi)容
AD7760:24位、2.5 MSPS、100 dB,Σ-Δ ADC,內(nèi)置片內(nèi)緩沖 數(shù)據(jù)手冊
STM32CubeMX | 28 - STM32片內(nèi)Flash的使用
STM32片內(nèi)FLASH燒寫錯(cuò)誤導(dǎo)致ST-li
STM32U5系列片內(nèi)ADC1和ADC4實(shí)現(xiàn)過程(上)
STM32U5系列片內(nèi)ADC1和ADC4實(shí)現(xiàn)過程(下)
基于STM32片內(nèi)信號(hào)的ADC應(yīng)用演示案例
評(píng)論