STM32 G431RB + LM35 ADC的取樣
在STM32 G431RB的板子上配置ADC對LM35溫度感測器進行溫度取樣。
程式碼放到Github上https://github.com/magicduan/demo_adc
STM32 Cube IDE 的ico檔案的配置:
- 配置freertos OS
- PA6配置為PWM呼吸燈模式 (在麵包板上加了一個LED等)
- 配置LED等是用來檢測ADC能否工作
- PC5配置為ADC2_11
- LM35的vout連線到PC5管腳,Vs管腳連線到板子的5V,GND接GND
-
將Chanel 11配置為Single-ended
-
Clock Prescaler配置為divided by16。由於我配置的系統時鐘是170MHZ,而ADC的最大配置時鐘是14MHZ,所以我將這個Prescaler配置為divided by 16
Resolution就是取樣對應的值範圍,系統預設的是12bit,這裡我配置為10bit。也就是說最大值為2^10 = 1024,溫度範圍有限,你也可以配置為8bit,具體影響到做數值轉換
配置好ICO後,生成程式碼。呼吸燈程式碼參考Demo_pwm的程式碼處理。
我先將PC5的ADC取樣直接連線到PA5的LED管腳上,可以取得值,可能是取樣頻率相關,只能取得0和一個值。具體為什麼不能取到不同的值沒有去深究了。
然後我將ADC連線到LM35的Vout管腳進行溫度取樣。程式碼中用的簡單的Polling模式。
main函式中進行Calibrate操作。
/* USER CODE BEGIN 2*/ HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1); HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED); /* USER CODE END 2 */
在StartDefaultTask中取得adc的值並通過串列埠輸出
HAL_ADC_Start(&hadc2); HAL_ADC_PollForConversion(&hadc2,1); adc_res = HAL_ADC_GetValue(&hadc2);//temperature = adc_res*0.488; //5/1024*100 temperature = adc_res*0.3225; //3.3/1024*100 sprintf(buffer,"ADC Result = %d Tempareture = %f\n",adc_res,temperature); HAL_UART_Transmit(&hlpuart1,buffer,strlen(buffer)+1,1000); osDelay(5);
整個程式碼實現中碰到的坑有幾個:
- ADC的取樣頻率最大為14MHZ,我的系統頻率為170MHZ,所以需要加Prescaler
- LM35的工作電壓為4v-30v,我用的板子上的5v,後來改用3.3v也可以正常工作,最終我還是選擇了5v
- 將LM35的工作電壓與ADC的取樣電壓搞混了,G431Rb的ADC取樣電壓是3.3v,工作電壓設定為5v或者3.3v不影響取樣的值。
- ADC取樣值到溫度的轉換計算。
LM35是線性的。ADC的Resolution設定為10bit,也就是說當Vout = 參考電壓3.3v 時,ADC的值是1023(2^10-1)。這樣溫度的轉換方法就變為
temperature = adc_res(ADC的取樣值)*3.3/1023*100 度
*剛開始錯誤的理解參考電壓為LM35的工作電壓(5v)這樣計算出來的溫度就太高了。
參考文章:
https://deepbluembedded.com/temperature-sensor-lm35-interfacing-with-pic-microcontrollers/
https://deepbluembedded.com/stm32-adc-tutorial-complete-guide-with-examples/