本文將深入探討STM32 ADC的Continuous Conversion Mode(連續轉換模式)。這種模式,正如其名,支持連續的資料轉換。文章首先解釋連續轉換模式的概念、操作方法以及資料提取過程。其次,我們將探討Scan Mode與連續轉換模式之間的關聯,並設置如何透過DMA將資料存放至SRAM內。瞭解這些功能後,我們會設計一個實驗來展示連續轉換模式的應用,並通過程式碼與實驗電路來完成此實驗。此篇的目的是為了確保讀者能夠有效利用此模式,同時避免任何非預期的結果。
Outline
ADC 連續轉換模式介紹
在連續轉換模式下,ADC一完成一次轉換就立即開始另一次。這種模式可以通過外部觸發啟動,或者在ADC_CR2寄存器中設置ADON位,同時CONT位為1。 每次轉換完成後:
- 如果轉換的是regular channel:
- 轉換後的數據存儲在16位的ADC_DR寄存器中
- EOC(轉換結束)標誌被設置
- 如果設置了EOCIE,則會生成一個中斷。
- 如果轉換的是injected channel:
- 轉換後的數據存儲在16位的ADC_DRJ1寄存器中
- JEOC(注入轉換結束)標誌被設置
- 如果設置了JEOCIE位,則會生成一個中斷。
Scan Mode介紹
此模式用於掃描一組analog channel。 通過設置ADC_CR1寄存器中的SCAN bit來選擇掃描模式。一旦設置了,ADC就會掃描在ADC_SQRx寄存器中選擇的所有通道(for regular channel)或在ADC_JSQR中選擇的通道(injeceted channel)。對組中的每個通道進行單次轉換。每次轉換結束後,該組的下一個通道會自動轉換。如果設置了CONT bit,轉換不會在選擇的最後一個組通道處停止,而是會從第一個選擇的組通道重新開始。 使用掃描模式時,必須設置DMA bit,並使用直接內存訪問控制器在每次更新ADC_DR寄存器後將常規組通道的轉換數據傳輸到SRAM。 注入通道的轉換數據總是存儲在ADC_JDRx寄存器中。
ADC 連續轉換模式實驗規劃
實驗目的: 熟悉ADC連續轉換程式碼應用之方式,並利用DMA將資料放置指定位置。
實驗描述: 以軟體觸發方式,進行ADC的轉換,再透過DMA將ADC_DR將放置指定位置,以避免資料覆蓋。
實驗條件:
以ADC1進行實驗,設定參數如下圖
在DMA Settings中需要注意一點,DMA中斷需要關閉。(如將Interrupt開啟會導致STM32會不斷處理發生中斷的函數內容)
實驗電路圖:
下面是一個串聯電路的電路圖,其量測點分別在兩電阻之間(IN1)和地(IN0)。
接下來看看程式碼和實驗的結果。
ADC 連續轉換模式實驗結果
程式碼:
在CubeMX專案建立完成後,需加入的程式碼如下
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 |
/* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ typedef struct { uint32_t ADC; float Volt; }IN_CH; /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define ADC1_CH_SIZE 2 /* USER CODE END PD */ /* USER CODE BEGIN PV */ uint32_t u32_ADC_Data[ADC1_CH_SIZE] ; IN_CH ADC_IN[ADC1_CH_SIZE]; /* USER CODE END PV */ /* USER CODE BEGIN PFP */ void Cal_ADC_Values(IN_CH*, uint16_t); /* USER CODE END PFP */ /* USER CODE BEGIN 4 */ void Cal_ADC_Values(IN_CH* IN_X, uint16_t ADC_Value) { IN_X->ADC = ADC_Value; IN_X->Volt = ADC_Value * 0.000806f; } /* USER CODE END 4 */ |
需要將上述程式碼放置Global的指定位置。其中IN_CH結構是方便在程式碼中呼叫和查看的數據結構,等等觀察結果能夠一次性的看出量測出ADC的值和換算成電壓的值。Cal_ADC_Values函數是用來保存和計算ADC Channel所量測出來的數值。
下方是ADC初始化函數的內容:
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 47 48 49 50 51 52 53 54 55 56 57 |
/** * @brief ADC1 Initialization Function * @param None * @retval None */ 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_ENABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 2; 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; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_1; sConfig.Rank = ADC_REGULAR_RANK_2; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC1_Init 2 */ HAL_ADCEx_Calibration_Start(&hadc1); Usr_AsmDelay_us(2); HAL_ADC_Start_DMA(&hadc1, u32_ADC_Data, ADC1_CH_SIZE); /* USER CODE END ADC1_Init 2 */ } |
在上方ADC初始化函數中,第54行是HAL函數庫啟動ADC開始量測的函數,其不同之處是在ADC1轉換完成之後會將在ADC_DR中的數值透過內部硬體DMA的方式將資料傳至指定的SRAM位置中(u32_ADC_Data)。
下方是main函數內部需修改的部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* USER CODE BEGIN 2 */ uint16_t* CIN = (uint16_t*)u32_ADC_Data; /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ Cal_ADC_Values(ADC_IN + 0, CIN[0]); Cal_ADC_Values(ADC_IN + 1, CIN[1]); } /* USER CODE END 3 */ |
在main函數中將u32_ADC_Data轉換成16 bit的陣列。(寫法有很多種方式,沒有一定)
在while迴圈中將量測的值和ADC_IN數據結構位置個別帶入Cal_ADC_Values函數內,用於計算電壓值和儲存ADC數值。
接下來看看實驗結果。
注意到在ADC此模式中,一旦啟動了就會不段的運行,時時刻刻的將ADC中的每個channel的數值更新到SRAM內,且能夠將其作運用,以達到不斷監視的作用等等。
結論
在本篇文章中,介紹了STM32 ADC Continuous Conversion Mode的使用方式,並且規劃了簡單易懂的實驗內容,利用ADC1透過兩個Channnel執行參數的設置,最後在實驗部分確實的展現出實驗的結果,其中還強調需要注意的部分如:DMA Settings中,為何Interrupt需要關閉等等。
在學習此篇文章的內容,希望程序猿們需要理解的部分:
- STM32 ADC Continuous Mode/Scan Mode的關係
- STM32 DMA的概念
- 以程式碼實現Continuous Mode並利用DMA將數據傳至指定的SRAM內
以上細節可參考reference manual以加深學習內容。