ADC (Analog-to-Digital Converter) 即數位類比轉換器,輸入類比的訊號,透過MCU轉換成數位離散訊號。STM32 ADC 為12bits的逐次逼近型。以Nucleo-L053為例,共有16個外部類比輸入。
時間在 ADC 的轉換與存取成了很重要的一點,採樣的時間與精準度是息息相關的,根據Nyquist Sampling Theorem奈奎斯特取樣定律,採樣的頻率必須是輸入信號的兩倍頻率,才可以使採樣訊號較完整。且採樣時間也不宜過快,否則會犧牲採樣的精準度。
下文將以STM32L053R8Tx為示範,使用意法半導體官方所提供的Nucleo開發板配合自行設計的STM32L031F6Px開發板完成該實驗,使用的IDE為Keil uVision5(MDK-ARM),而STM32CubeMX的版本為6.2.1。
在進入STM32CubeMX的專案建立前,先來談談同步與非同步的差異,在 ADC 或相關事件來說有很大的不同。同步主要是排隊等待待處理事件完成後再接著處理,逐次依序;而非同步是不須等待需求完成就可以先執行其他內容。
首先在CubeMX當中的Analog選單有 ADC ,將IN0勾選,則可以看到PA0被選取為ADC_IN0。下方設定非同步並除頻32,使 ADC 的基頻為1MHz進行採樣,並選擇12-Bit的解析度,因為暫存器為16位元,因此可以選擇靠左或是靠右對齊,若是靠左(MSB)對齊,則是將低4位元皆補0,在此選擇靠右對齊。
時脈設定好之後,就可以產生程式碼到Keil。在main當中可以看見多了 ADC 的初始化設定。
需先宣告一個全域變數voltage。接著while中先開啟 ADC ,並等待 ADC 轉換,將Timeout時間設定為1ms,判斷若轉換完成,則取得 ADC 的數值。可讀取0~3.3V的電壓值,轉換為12位元的數位訊號(0~4095)。
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc,0x01);
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc),HAL_ADC_STATE_REG_EOC)){
voltage = HAL_ADC_GetValue(&hadc);
}
若我們要將轉換的數值由0~4095轉成電壓數值,則將0~4095 mapping到0~3300即可,因此可以在voltage變數上做scale。
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc,0x01);
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc),HAL_ADC_STATE_REG_EOC)){
voltage = HAL_ADC_GetValue(&hadc);
voltage=voltage*3300/4095;
}
透過Debug Mode可以查看全域變數voltage的數值。使用可變電阻提供輸入電壓,使用FLUKE 289量測為1.6262V,從Watch視窗觀察到數值為1669,為16.69V。

若需要使用多通道,則回到CubeMX開啟IN1或更多 ADC 輸入。

回到Keil,把voltage改為陣列,並讀取兩次即可。
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc,0x01);
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc),HAL_ADC_STATE_REG_EOC)){
voltage[0] = HAL_ADC_GetValue(&hadc);
voltage[0]=voltage[0]*3300/4095;
}
HAL_ADC_PollForConversion(&hadc,0x01);
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc),HAL_ADC_STATE_REG_EOC)){
voltage[1] = HAL_ADC_GetValue(&hadc);
voltage[1]=voltage[1]*3300/4095;
}
若需要使用中斷的方式執行,可以在CubeMX開啟中斷致能,由Callback Function做ADC_GetValue即可,也歡迎嘗試看看,並一起交流!
文章寫的不錯
對我幫助很多希望下一次可以教兩個晶片通訊
也很常使用I2C UART SPI 謝謝
您好!沒問題~
未來I2C與SPI會先使用兩片開發版互相通訊,而UART預計會透過PC進行相關控制,固定每週至少會有一篇文章產出,再請您期待囉!