1. 程式人生 > >(STM32)AD功能的連線配置方式------單AD多通道實現

(STM32)AD功能的連線配置方式------單AD多通道實現

一、為何使用ADC

  為了能夠使用數位電路處理模擬訊號,必須將模擬訊號轉換成相應的數字訊號,方能送入數字系統(例如微型計算機)進行處理,而這一種從模擬訊號到數字訊號的轉換稱為模—數轉換,或簡稱為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參考手冊.