(STM32)AD功能的連線配置方式------單AD多通道實現
為了能夠使用數位電路處理模擬訊號,必須將模擬訊號轉換成相應的數字訊號,方能送入數字系統(例如微型計算機)進行處理,而這一種從模擬訊號到數字訊號的轉換稱為模—數轉換,或簡稱為A/D(Analog to Digital)轉換[1]。當作為感測器的電路系統產出模擬訊號時,AD模組無疑是直觀顯示感測器功能狀態的最佳選擇。
STM32F4xx系列的AD最高可配置12位的解析度,同時可在其規則通道轉換期間可產生 DMA 請求來減輕CPU負擔。
STM32的AD採集主要區別在於使用的AD數量和AD使用的通道數量,多AD的採集優勢在於可以增加感測器的掃描頻率,獲得更加多的AD採集資料,如在AD通道數量比較緊缺而且對資料量沒那麼多的情況下,單AD多通道採集無疑是比較好的方法。本次主要討論的就是單AD多通道採集資料的方法。由於規則通道組只有一個數據暫存器,因此,對於多個規則通道的轉換,使用 DMA 非常有幫助。這樣可以避免丟失在下一次寫入之前還未被讀出的 ADC_DR 暫存器中的資料[2]
二、AD初始化的方式
STM32F429中提供了3個AD可供使用,其中DMA2是直接對ADC提供服務的,DMA2的請求對映分別對應的是:ADC1:資料流0通道0和資料流4通道0,ADC2:資料流2通道1和資料流3通道1,ADC3:資料流0通道2和資料流1通道2,詳情可參考CPU手冊。
首先需要初始化的是ADC所引出的GPIO引腳,沒啥需要注意的,只要沒有搞錯引腳就行,配置方法可見上一篇(STM32)GPIO庫函式使用一覽 。
第二步時配置所需要使用的DMA,配置的時候需要注意的幾項:1.ADC的外設基址,負責獲取ADC的資料;2.讀取資料的地址,從這裡可以讀出DMA的ADC資料,即是設定一個與通道數相應匹配的大小的陣列;3.搞清楚DMA的請求對映。
最後就是配置ADC,STM32F4中的AD初始化庫函式:ADC_CommonInit()和ADC_Init()配置的分別是通用型別變數和ADC的初始化
typedef struct
{
uint32_t ADC_Mode;
uint32_t ADC_Prescaler;
uint32_t ADC_DMAAccessMode;
uint32_t ADC_TwoSamplingDelay;
}ADC_CommonInitTypeDef;
ADC_CommonInit()中包含的是ADC模式選擇,分頻,DMA模式配置和取樣延遲。
1.ADC模式主要針對於ADC數量的選擇,獨立模式可選ADC_Mode_Independent。
2.分頻可選ADC_Prescaler_Div2/Div4/Div6/Div8。
3.DMA模式,是針對於多ADC中配置的,獨立模式選擇ADC_DMAAccessMode_Disabled。
4.取樣延遲可配置5-20的任意值,ADC_TwoSamplingDelay_10Cycles。
typedef struct
{
uint32_t ADC_Resolution;
FunctionalState ADC_ScanConvMode;
FunctionalState ADC_ContinuousConvMode;
uint32_t ADC_ExternalTrigConvEdge;
uint32_t ADC_ExternalTrigConv;
uint32_t ADC_DataAlign;
uint8_t ADC_NbrOfConversion;
}ADC_InitTypeDef;
ADC_Init()中包含的是ADC解析度,是否掃描,是否連續轉換,觸發極性和觸發選擇,資料對齊和通道數目。
1.解析度可從12/10/8/6中做選擇,ADC_Resolution_12/10/8/6b.
2.在多通道時需要對掃描轉換使能,單通道的不需要。
3.連續轉換指的是在各個通道讀值完畢後繼續讀值。
4.外部觸發的條件有很多,需要根據外設來具體分析
5.資料對齊有兩種,左對齊和右對齊,一般是選擇右對齊。
6.通道數目為對應配置的通道數。
三、AD的配置功能實現
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 2, ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 3, ADC_SampleTime_56Cycles);
ADC_RegularChannelConfig();設定ADC通道的轉換順序及時間。 ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE); 該函式僅在單ADC模式中使用,功能是在ADC最後傳輸後DMA啟用或禁用請求。
ADC_DMACmd(ADC1, ENABLE);ADC是否使用DMA的請求。
ADC_Cmd(ADC1, ENABLE);使用ADC的請求。
在初始化後,接上ADC的功能請求函式即可完成對ADC功能的配置。
此時ADC的資料全部由DMA中配置的讀取地址中獲取,就是當時所寫的陣列中獲取。
功能示例中表現的是單AD多通道的例子:
#include "bsp.h"
#include <stdio.h>
static void ADC_Configuration(void);
uint16_t ADC_Value[7]={0};//AD資料
uint16_t local[7]={0};
int main()
{
while(1){
local[0]=(float)(ADC_Value[0]*3.3/4096);
local[1]=(float)(ADC_Value[1]*3.3/4096);
local[2]=(float)(ADC_Value[2]*3.3/4096);
printf("channel 1 value = %fV\r\n",local[0]);
printf("channel 2 value = %fV\r\n",local[1]);
printf("channel 3 value = %fV\r\n",local[2]);
}
}
/*獨立模式多通道 電壓採集*/
static void ADC_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure_C;
GPIO_InitTypeDef GPIO_InitStructure_A;
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
/* 使能 GPIOC clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
GPIO_InitStructure_C.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure_C.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure_C.GPIO_PuPd = GPIO_PuPd_NOPULL; //不上拉不下拉
GPIO_Init(GPIOC, &GPIO_InitStructure_C);
/* 使能 GPIOA clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStructure_A.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;
GPIO_InitStructure_A.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure_A.GPIO_PuPd = GPIO_PuPd_NOPULL; //不上拉不下拉
GPIO_Init(GPIOA, &GPIO_InitStructure_A);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
/* DMA Init 結構體初始化 DMA2 Stream 0 channel 0 配置用於ADC1*/
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA2_Stream0);
DMA_InitStructure.DMA_Channel = DMA_Channel_0; //選擇DMA通道
DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)(0x40012000+0x4c); //外設基址->ADC
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ADC_Value; //儲存器地址->讀取資料地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; //資料傳輸方向為外設到儲存器
DMA_InitStructure.DMA_BufferSize = 7; //緩衝區大小,即一次傳輸的資料項
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外部暫存器只有一個,地址不用遞增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //儲存器地址遞增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外設資料大小為一個字元,四個位元組(可改HalfWord為半個字,兩個位元組)
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //儲存器資料大小與外設一致
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //迴圈傳輸模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA優先順序最高
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //DMA直連模式
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; //FIFO大小,FIFO模式禁止,不用配置
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //儲存器突發單次傳輸
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外設突發單次傳輸
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
DMA_Cmd(DMA2_Stream0, ENABLE); //使能DMA資料流
/* DMA Init 結構體初始化 DMA2 Stream 0 channel 0 配置用於ADC1*/
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE); //ADC1復位
RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE); //復位結束
/* ADC Common結構體引數初始化*/
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent; //獨立模式
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; //時鐘分頻
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //禁止DMA直接訪問模式
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_10Cycles; //取樣時間間隔
ADC_CommonInit(&ADC_CommonInitStructure);
/*ADC Init結構體引數初始化*/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; //解析度
ADC_InitStructure.ADC_ScanConvMode = ENABLE; //多通道採集,開啟掃描模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //連續轉換
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //禁止外部邊沿觸發
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //右對齊
ADC_InitStructure.ADC_NbrOfConversion = 7; //轉換通道數
ADC_Init(ADC1, &ADC_InitStructure);
/* 配置ADC1 的通道轉換順序和取樣時間週期*/
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_56Cycles); //引腳PC0
ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 2, ADC_SampleTime_56Cycles); //引腳PC2
ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 3, ADC_SampleTime_56Cycles); //引腳PC3
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_56Cycles); //引腳PA3
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5, ADC_SampleTime_56Cycles); //引腳PA4
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6, ADC_SampleTime_56Cycles); //引腳PA5
ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 7, ADC_SampleTime_56Cycles); //引腳PA6
ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE); //使能DMA請求
ADC_DMACmd(ADC1, ENABLE); //使能ADC1 DMA
ADC_Cmd(ADC1, ENABLE); //使能ADC1
ADC_SoftwareStartConv(ADC1); //開啟軟體使能
}
實現後,可以打印出3個通道的電壓值,電壓的計算主要與參考電壓VREF有關;計算公式為:
電壓=(VREF*掃描值)/2^12
[1]閻石.數位電子技術基礎(第五版)[M].高等教育出版社,2006.
[2]STM32F407, 429參考手冊.