ashwatermelon

ashwatermelon

【學習筆記】stm32單片機ADC功能的使用及配置方法

今天繼續學習筆記。
前面幾天學完了 ADC 模塊,於是在寫完定時器後就接著把 ADC 模塊也寫了。

(一)ADC 是什麼#

在網上稍微查一下我們就知道 ADC 的定義:模數轉換,即 Analog-to-Digital Converter,常稱 ADC,是指將連續變量的模擬信號轉換為離散的數字信號的器件,例如,通過 ADC 把溫度傳感器產生的電信號轉化為數字信號 0101 之類的。
與 ADC 模塊對應的就是 DAC 模塊,DAC 模塊可以把數字信號轉化為模擬信號,stm32 有 ADC 模塊但沒有 DAC 模塊。

(二)stm32 上的 ADC 功能#

我們用的芯片 STM32F103C8T6 的 ADC 資源有 ADC1、ADC2,10 個外部輸入通道,其中注入組有 4 個通道,其餘為規則組。
注入組的四個通道互不干擾,可以同時使用和轉換。
規則組則須按列表依次轉換,並且只有一個儲存位置,後轉換的數據將會頂頂掉前一個數據的位置,需要 DMA 的配合才能完成多通道的 ADC 轉換。
此外,規則組的配置還有多種模式選擇,主要是是否開啟連續轉換和掃描模式。
連續轉換就是在完成一次轉換後立刻銜接下一次轉換,掃描模式則是接著掃描規則組配置的列表的其他通道,若不開啟則只轉換一個通道。

(三)AD 單通道配置#

首先我們學習如何配置單通道轉換。
先看結構圖
image
根據結構圖我們知道了如何配置 AD 單通道。
第一步,我們需要開啟 ADC 和 GPIO 的時鐘:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

第二步,我們需要設置 ADC 時鐘,調整其預分頻,因為 ADC 的最大頻率是 14Hz,所以我們只能配置 6 分頻往上:
RCC_ADCCLKConfig(RCC_PCLK2_Div6);

第三步,初始化 GPIO 口,配置為 ADC 模式:
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

第四步,配置規則組通道(注入組沒用過):
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);

第五步,ADC 初始化,其中配置了 ADC 獨立模式、不連續非掃描模式,無外部觸發源(軟件觸發),只有一個通道,數據右對齊:
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);

第六步,啟動 ADC:
ADC_Cmd(ADC1, ENABLE);

第七步,ADC 校驗,這個是固定流程:
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);

自此,ADC 配置完成,然後我們可以開啟轉換:
ADC_SoftwareStartConvCmd(ADC1, ENABLE);

轉換過程需要時間,我們可以檢查標誌位判斷轉換是否完成:
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);

最後,我們通過獲取數據:
ADC_GetConversionValue(ADC1);

(四)AD 多通道#

AD 多通道就是同時開啟多個通道轉換,需要用到 DMA。
DMA 結構圖如下:

image

那麼如何配置 AD 多通道呢?
前三步與 AD 單通道基本一樣,不過需要多開啟一個 DMA 時鐘並且多初始化幾個引腳:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

RCC_ADCCLKConfig(RCC_PCLK2_Div6);

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

接著我們配置規則組通道,也要多配置幾個,並且規定好順序:
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);

接下來初始化 ADC,這次我們要開啟連續掃描模式,通道數設置為 4:
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_NbrOfChannel = 4;
ADC_Init(ADC1, &ADC_InitStructure);

然後我們初始化 DMA,這裡。外設和儲存器都設置為半個字大小(即 16 位),外設地址為指向寄存器 DR 的指針(前面說的儲存數據的位置就是它),外設地址不自增(始終讀取 DR 地址),儲存器指向儲存數據的數組,開啟循環:
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 4;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);

接著我們開啟 DMA 並且使 ADC1 觸發 DMA1 的信號使能,最後開啟 ADC:
DMA_Cmd(DMA1_Channel1, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);

還有 ADC 校驗也是必不可少:
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);

最後開啟轉換,我們就能在儲存數據的數組裡得到想要的數據:
ADC_SoftwareStartConvCmd(ADC1, ENABLE);

那麼 ADC 的功能就這麼多,886。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。