STM32 HAL庫學習(三)ADC取樣以及printf的使用
ADC輸出的電壓值經轉換後一般為一個浮點數,要將其列印到串列埠則需要對串列埠輸出函式做一個調整。
首先是printf函式的重定向,將一下程式碼加入到usart.c中,完成後便可以用printf函式輸出字串到串列埠中,而要輸出浮點數,則還需在“專案/建立設定/C Linker/Miscellaneous/Other options”中新增“-u _printf_float”
#include <stdio.h> #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) PUTCHAR_PROTOTYPE { HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,HAL_MAX_DELAY); return ch; } #endif int _write(int file,char*ptr,int len) { int Dataldx; for(Dataldx = 0;Dataldx < len;Dataldx++) { __io_putchar(*ptr++); } return len; }
接下來是配置ADC取樣,ADC取樣可以配置為單通道、多通道,連續、非連續等取樣模式,傳輸獲取取樣值的方式也有查詢獲取、中斷獲取以及DMA獲取等方式,都有提供相應的HAL庫函式。
STM32F070的ADC時鐘來源主要有兩種方式:
- 直接來源於HSI 14MHZ,也是可配置的最大時鐘頻率,對應在CubeMX中的Clock Prescaler配置為Asynchronous clock mode
- 來源於APB時鐘的2分頻或者4分頻(但最大都不能超過14MHZ)
獲取ADC取樣值的方式
1、查詢方式獲取ADC取樣值
查詢方式主要用到的函式是HAL_ADC_Start()、HAL_ADC_PollForConversion()以及HAL_ADC_GetValue(),其中,HAL_ADC_Start是軟體開始ADC轉換,PollForConversion則等待ADC轉換完成,當轉換完成後,既可在主函式中呼叫HAL_ADC_GetValue獲取取樣值,進行相應的轉換和輸出。
uint32_t value = 0;
float vol = 0;
while(1)
{
/*USER CODE BEGIN WHILE*/
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc,HAL_DELAY_MAX);
value = HAL_ADC_GetValue(&hadc);
vol = (float)(value *3.3/4096);
printf("%.2f",vol);
HAL_Delay(1000);
/*USER CODE END WHILE*/
}
2、DMA中斷方式
當ADC取樣方式配置為連續取樣時,可以藉助DMA對取樣值進行儲存,當DMA傳輸完成時產生中斷,再在中斷函式中對取樣到的資料進行處理。具體步驟是:在CubeMX中配置DMA Request為ADC,對應的選擇通道DMA1 Channel1,資料寬度選擇word(因為ADC取樣值型別為uint32_t),generate code。在main函式中呼叫HAL_ADC_Start_DMA(),配置DMA資料儲存的位置以及傳輸的資料個數。假設設定資料個數為100,則當ADC取樣並轉換100個數據後,DMA這邊接收到100個數據後則會產生DMA中斷。而當DMA中斷產生時,HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)先是判斷是傳輸一半資料中斷標誌還是傳輸完成中斷標誌,再根據繫結的控制代碼呼叫相應的回撥函式。而當選擇ADC DMA傳輸時,DMA傳輸完成後其回撥函式會呼叫 HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc),因此只需重寫該函式進行資料處理即可。(對於這一點,檢視DMA_IRQHandler可以發現其根據控制代碼呼叫相應的回撥函式。但是目前我還沒找到在哪裡呼叫了HAL_ADC_ConvCpltCallback........存疑)
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
uint32_t value = 0;
float vol = 0;
value = ADC_Data[0];
vol = (float)(3.3*value);
vol = (float)vol/4096;
printf("%.3f",vol);
printf("\r\n");
}