STM32的ADC轉換仍是很強大的,它具備多個通道選擇,這裏我就不細說,不瞭解的能夠自行百度,這裏只是選取單通道,實現ADC轉換。在文章開始以前,我說一下數據左對齊跟右對齊的差異,之前一直糊里糊塗的,記錄下來以避免之後本身忘記。12位二進制最大值爲 0x0FFF 左對齊操做後的結果是 0xFFF0,右對齊後仍是0x0FFF。反過來看 ,若寄存器裏左對齊的數據值X (至關於實際數據*16,因此左對齊轉換的值要/16纔是實際的值),則X>>4纔是實際的數據。而右對齊,則是數據保持不變,採集到多少就多少。至因而按左對齊保存到寄存器仍是按照右對齊,就看你的配置裏如何選了。html
好了,下面就開始說明怎麼用STM32CUBEMX實現ADC單通道轉換吧。函數
利用中斷模式ui
一、配置ADC引腳spa
二、開定時跟串口,定時器用來定時打開ADC轉換,這樣能夠達到1S內控制ADC轉換次數的目的,不過有個限制,這裏樣子控制ADC轉換次數的話,若是採樣次數多,配置ADC採樣速度時必定要夠 快,正常配置ADC的採樣頻率能夠經過改變其採樣速度來設置的,這裏我是爲了方便處理,就直接用定時器去開啓了;而串口則是打印轉換後的電壓用的。3d
三、配置時鐘code
四、配置ADC設置htm
`blog
五、開啓中斷模式get
六、串口配置默認便可回調函數
七、定時器配置,定時器配置的是進入定時器中斷的頻率,定時時間能夠根據這個頻率換算出來,這裏定時器的頻率 = 72M / 72 /1000 =1000Hz,因此定時時間爲 T = 1S/f = 1S/1000 = 1ms,因此我這裏配置定時爲1ms。
八、基本配置咱們完成了,如今咱們生成工程用KEIL5打開
九、打開工程,咱們如今進入代碼部分
這裏咱們只須要重寫定時器中斷回調函數跟,ADC轉換回調中斷函數便可。在main文件裏添加這下面這兩個函數
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) //定時器中斷回調 { HAL_ADC_Start_IT(&hadc1); //定時器中斷裏面開啓ADC中斷轉換,1ms開啓一次採集 } void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) //ADC轉換完成回調 { HAL_ADC_Stop_IT(&hadc1); //關閉ADC HAL_TIM_Base_Stop_IT(&htim3); //關閉定時器 AD_Value=HAL_ADC_GetValue(&hadc1); //獲取ADC轉換的值 Value_1=(float)(AD_Value*3.3/4096); //ADC換算,這裏參考電壓3.3V,12位的ADC滿量程爲2^12=4096,轉換出來的單位是V printf("%.4f\r\n",Value_2[j-10000]); //串口打印信息 HAL_TIM_Base_Start_IT(&htim3); //開啓定時器 }
到這裏就完成單通道ADC中斷轉換的全部步驟啦,經過串口助手實測轉換結果偏差爲0.0008v。
至於串口查看信息打印輸出重定向能夠看我這篇文章:http://www.javashuo.com/article/p-xgbapsoq-kz.html
不使用中斷模式
不使用中斷模式的狀況下跟使用中斷的相似的,首先配置的過程當中不須要開啓中斷,至於定時器開不開看我的須要,想利用定時器定時採集的能夠開,不想的不用開,其餘的配置同樣。生成代碼後,在main文件的main函數中的while循環裏添加下面代碼:
/* USER CODE BEGIN 3 */ for(char n=0;n<22;n++) { //取22個值作濾波用 HAL_ADC_Start(&hadc2); HAL_ADC_PollForConversion(&hadc2, 10); //等待轉換完成,第二個參數表示超時時間,單位ms if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc2), HAL_ADC_STATE_REG_EOC)) { Value[n]=HAL_ADC_GetValue(&hadc2); AD_Value += Value[n]; } } max=Value[0]; min=Value[0]; for(char n=0;n<22;n++)//取最大值、最小值 { max=(Value[n]<max)?max:Value[n]; min=(min<Value[n])?min:Value[n]; } printf("PC0 ADC : %.4f \r\n",(float)((AD_Value -max-min)/20)*(3.1/4096)); AD_tr=(float)((AD_Value -max-min)/20)*(3.1/4096); //這裏我作了個去掉最大最小值後,取均值的軟件濾波 AD_Value=0;
這裏面的一些變量就大家本身去定義了,我就不列出來了,實測偏差在0.001v之內。
補充注意事項:
一、ADC初始化後要進行校準,使用下面函數校準,能夠放在ADC初始化函數後面校準
HAL_ADCEx_Calibration_Start(&hadc2); //AD校準
二、傳入ADC的電壓不能夠超過3.3V,就是不能夠超過你的參考電壓,否則結果不許,還有可能燒壞ADC引腳
使用DMA模式【轉:http://www.stm32cube.com/article/37】
再次寫寫stm32cubemx中AD採集的問題,此次不用while裏面的查詢,也不用中斷採樣了,直接用DMA
先說下用DMA的好處:不管是中斷採樣仍是查詢採樣,都須要在主程序中佔用好多時間出來,嗯,你能夠這樣理解
那種採樣都須要調用HAL_ADC_GetValue()這個函數,,,就是要取得轉換後的值,中斷還好點,要是查詢的話,有可能會丟失數據啊. 用dma就能夠避免了
DMA用的事總線時間,無線cpu干預,額,這種說法貌似有點問題.管它呢
在AD轉換結束的時候自動鏈接你準備存取的變量的地址,數據一步到位.額,省了多少事..
使用stm32cubemx對AD的配置
而後對她的DMA配置,並開啓DMA的中斷
而後生成代碼吧
打開main.c文件,在這個地方添加代碼
/[i] USER CODE BEGIN 0 [/i]/ __IO uint16_t uhADCxConvertedValue = 0; /[i] USER CODE END 0 [/i]/
在main()函數裏添加
/[i] USER CODE BEGIN 2 [/i]/ HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&uhADCxConvertedValue, 1); /[i] USER CODE END 2 [/i]/
意思是開啓dma傳輸,傳送一個字的數據到uhADCxConvertedValue這個變量裏面
而後再文件的末尾處添加
/[i] USER CODE BEGIN 4 [/i]/ void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle) { /[i] Turn LED1 on: Transfer process is correct [/i]/ // BSP_LED_On(LED1); HAL_GPIO_WritePin (GPIOF,GPIO_PIN_6,GPIO_PIN_SET ); } /[i] USER CODE END 4 [/i]/
意思是AD轉換完成調用這個函數,函數裏使能led
也許,你會問,爲毛是HAL_ADC_ConvCpltCallback()這個函數啊,這個函數不是當開啓AD的中斷的時候才調用的嗎?
嗯,對,這個函數是這樣的,可是你仔細去分析下開啓AD的DMA中斷函數裏面,就會發現這個函數也在啊
以下圖.進入HAL_ADC_Start_DMA函數裏面,看到
在進入到圖中的ADC_DMAConvCplt函數裏面看到
OK,疑問解決,之後用到AD就能夠直接調用這個CALL了,不要糾結了.