在本篇文章中會講解STM32 ADC Single Conversion Mode的基礎應用,首先會介紹ADC單次轉換模式以及如何操作並透過Data Register取得ADC轉換好的資料。接者規劃本次的實驗方式與步驟,其中包含ADC參數的設定和如何計算ADC轉換所需要的時間,最後按照實驗步驟將結果實驗出來,並說明如何增加ADC量測的準確性。
Outline
ADC單次轉換模式介紹
簡單來說,ADC單次轉換模式是指,ADC單次轉換完成後數據存至暫存器內,再透過DMA或是中斷方式讓使用者抓取數據。
ADC單次轉換流程
如何開始ADC的量測,首先需設置ADC_CR2中的ADON暫存器(for a regular channel only),或是透過外部觸發的方式(for a regular or injected channel)來開始進行ADC的轉換,同時CONT需Reset。
Regular Channel轉換完成後,取得數據方式:
- 數據存至16-bit ADC_DR內
- EOC flag會被設置
- 如果有設置EOCIE則會發生中斷
Injected Channel轉換完成後,取得數據方式:
- 數據存至16-bit ADC_DRJ1內
- JEOC flag會被設置
- 如果有設置JEOCIE則會發生中斷
以上完成後,ADC將會停止動作。
上述是ADC單次轉換的流程。
ADC單次轉換模式實驗規劃
軟體觸發ADC轉換
實驗目的: 熟悉ADC單次轉換程式碼應用之方式,並計算ADC轉換所需的時間。
實驗描述: 以軟體觸發方式,進行ADC的轉換,最後從ADC_DR將資料取出,且與電表做對比。
實驗條件
- 設定ADC1中的IN0
- Data Alignment : Right alignment
- Scan Conversion Mode : Disable
- Continuous Conversioin Mode : Disable
- Discontinuous Conversioin Mode : Disable
- Enable Regular Conversions : Enable
- Number of Conversion : 1
- External Trigger Conversion Source : Regular Conversion launched by software
- ADC Clock : 8 MHz
評估轉換時間
根據下方reference manual的公式,Tconv = sample time + 12.5 cycles = 1.5 cycles + 12.5 cycles = 14 cycles 一共有14個週期,換算成時間為14 / 8e6 = 1.75 微秒,大約2 us時間能夠把資料取出。
實驗環境
下方是實驗電路圖,在圖的上方是正電壓、下方為負電壓、電位差為3.3 Voltage,中間以兩顆可調式電阻串聯,ADC和三用電表量測點以兩顆電阻之間對地的量測。
ADC單次轉換模式實驗結果
軟體觸發ADC轉換
說明實驗程式碼
ADC Resolution為12bit,所以每個bit約為0.806 uVolt/bit。
其中測試結果能夠發現,量測值並不是非常準確。在透過校正後與實際量測值更加接近了(2.075 Volt)。
1 2 3 4 5 6 |
void Usr_AsmDelay_us(uint32_t us) { if(!Asm_Assert()) Asm_Delay_Error(); uint32_t val = us * _usAsmTick; while(--val); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
HAL_StatusTypeDef eStatus; uint32_t data = 0x0000; float mVolPerBit = 0.806; float totalmVol = 0.0f; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ eStatus = HAL_ADC_Start(&hadc1); Usr_AsmDelay_us(2); HAL_ADC_Stop(&hadc1); data = ADC1->DR; totalmVol = mVolPerBit * data; } /* USER CODE END 3 */ |
為什麼ADC需要校正?
簡單來說,ADC有內部自我校正功能。能夠減少寄生電容所帶來的量測誤差。會計算每個電容的誤差值並在每次ADC轉換後扣除電容誤差。校正時機點是在ADC Power-ON的時候進行校正,須注意校正過程需兩個ADC Clock Cycles的時間。
下面是ADC初始化完成後進行校正所呼叫的API。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
static void MX_ADC1_Init(void) { /* USER CODE BEGIN ADC1_Init 0 */ /* USER CODE END ADC1_Init 0 */ ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC1_Init 1 */ /* USER CODE END ADC1_Init 1 */ /** Common config */ hadc1.Instance = ADC1; hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; hadc1.Init.ContinuousConvMode = DISABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; //sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES_5; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC1_Init 2 */ HAL_StatusTypeDef calStatus = HAL_ADCEx_Calibration_Start(&hadc1); if(calStatus != HAL_OK) { while(1); } /* USER CODE END ADC1_Init 2 */ } |
下一步嘗試使用28.5Cycles Sample 量測值會更精確(2.157 Volt),但花費時間需約Tconv = 5.125 us ~= 6 us。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
HAL_StatusTypeDef eStatus; uint32_t data = 0x0000; float mVolPerBit = 0.806; float totalmVol = 0.0f; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ eStatus = HAL_ADC_Start(&hadc1); //Usr_AsmDelay_us(2); Usr_AsmDelay_us(6); HAL_ADC_Stop(&hadc1); data = ADC1->DR; totalmVol = mVolPerBit * data; Usr_AsmDelay_ms(100); } /* USER CODE END 3 */ |
還用多種Sample Time設定值,就給各位去試試囉~
結論
本實驗旨在深入理解ADC(模數轉換器)單次轉換過程。特別關注的是轉換過程中的程式碼撰寫方法,以及轉換時間計算的重要性。此外,本研究還探討了Sample Time選擇對ADC量測準確性的影響,並指出在ADC Power-ON時進行校正對提高量測精度的益處。
如有錯誤部分!幫忙留言或寫信通知我。謝謝!