welcom ! Handel home

2014年7月3日 星期四

ST32 ADC 3 channel by ADC1 for DMA Demo code 說明

//RCC部分:(忽略系統時鐘配置)
   //
啟動DMA時鐘 
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 
    //
啟動ADC1時鐘    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); 

//GPIO
部分:(ADC引腳參見上表)
    //ADC_CH10--> PC0    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//
模擬輸入 
    GPIO_Init(GPIOC, &GPIO_InitStructure); 
    // PC2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; 
    GPIO_Init(GPIOC, &GPIO_InitStructure);   

//ADC1配置:(兩外部輸入,另採樣內部溫度感測器)
void ADC1_Configuration(void) 

    ADC_InitTypeDef ADC_InitStructure;  
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //
轉換模式為獨立,還有交叉等非常多樣的選擇 
    ADC_InitStructure.ADC_ScanConvMode = ENABLE; 
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;  //
連續轉換開啟    
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; 
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 
    ADC_InitStructure.ADC_NbrOfChannel = 3;     //
設置轉換序列長度為3,三通道    
    ADC_Init(ADC1, &ADC_InitStructure); 
 
 //ADC內置溫度感測器使能(要使用片內溫度感測器,切忌要開啟它)    
    ADC_TempSensorVrefintCmd(ENABLE);   

    //
常規轉換序列1:通道10    
    ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1,ADC_SampleTime_239Cycles5); 
    //
常規轉換序列2:通道16(內部溫度感測器),採樣時間>2.2us,(239cycles)    
    ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 2, ADC_SampleTime_239Cycles5); 
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 3, ADC_SampleTime_239Cycles5);
    //
輸入參數:ADC外設,ADC通道,轉換序列順序,採樣時間 
    
    // Enable ADC1    
    ADC_Cmd(ADC1, ENABLE);
  
    // 開啟ADCDMA支持(要實現DMA功能,還需獨立配置DMA通道等參數)
     ADC_DMACmd(ADC1, ENABLE);
    //
下面是ADC自動校準,開機後需執行一次,保證精度    
    // Enable ADC1 reset calibaration register    
    ADC_ResetCalibration(ADC1); 
    // Check the end of ADC1 reset calibration register    
    while(ADC_GetResetCalibrationStatus(ADC1)); 
 
    // Start ADC1 calibaration    
    ADC_StartCalibration(ADC1); 
    // Check the end of ADC1 calibration    
    while(ADC_GetCalibrationStatus(ADC1)); 
    // ADC
自動校準結束---------------    
     ADC_SoftwareStartConvCmd(ADC1, ENABLE); //ADC
啟動    
}

DMA
配置:(無軟體濾波)
void DMA_Configuration(void) 

    DMA_InitTypeDef DMA_InitStructure; 
    
    DMA_DeInit(DMA1_Channel1); 
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;   //DMA
外設地址,在頭部定義
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value;         //
記憶體位址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                 //
外設至記憶體模式
    //BufferSize=2
,因為ADC轉換序列有2個通道    
    //
如此設置,使序列1結果放在AD_Value[0],序列2結果放在AD_Value[1]    
    DMA_InitStructure.DMA_BufferSize = 3;                                           //
一次轉換三個
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //
接受一次後,設備位址不後移
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;        //
接受一次後,記憶體位址後移
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;   //
每次傳輸半字
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 
    //
迴圈模式開啟,Buffer寫滿後,自動回到初始位址開始傳輸    
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 
    DMA_InitStructure.DMA_Priority = DMA_Priority_High; 
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
    DMA_Init(DMA1_Channel1, &DMA_InitStructure); 
    //
配置完成後,啟動DMA通道    
    DMA_Cmd(DMA1_Channel1, ENABLE); 
} 

//此DMA常式用於單次ADC轉換,配合軟體濾波可做如下改動:
//全局聲明:
vu16 AD_Value[30][3];   //AD
採樣值
vu16 After_filter[3];        //AD
濾波後
//DMA部分:(帶中斷濾波)
void DMA_Configuration(void) 

    DMA_InitTypeDef DMA_InitStructure; 
    
    DMA_DeInit(DMA1_Channel1); 
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; 
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value; 
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 
    //BufferSize=2
,因為ADC轉換序列有2個通道    
    //
如此設置,使序列1結果放在AD_Value[0],序列2結果放在AD_Value[1]    
    DMA_InitStructure.DMA_BufferSize = 90; 
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; 
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 
    
    //迴圈模式開啟,Buffer寫滿後,自動回到初始位址開始傳輸    
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 
    DMA_InitStructure.DMA_Priority = DMA_Priority_High; 
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
    DMA_Init(DMA1_Channel1, &DMA_InitStructure); 
    
    //配置完成後,啟動DMA通道    
    DMA_Cmd(DMA1_Channel1, ENABLE);
    DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); //
使能DMA傳輸完成中斷 
} 

// NVIC
部分:
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQChannel; 
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    NVIC_Init(&NVIC_InitStructure);          // Enable the DMA Interrupt 

//stm32f10x_it.c文件:
void DMA1_Channel1_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA1_IT_TC1) != RESET)
    {
        filter();
        DMA_ClearITPendingBit(DMA1_IT_TC1);
     }
}

//濾波部分:(均值濾波)
#define N 30
void filter(void)
{
   int  sum = 0;
   u8 count,i;
   for(i=0;i<2 br="" i="">    {
    for ( count=0;count     {
       sum += AD_Value[count][i];
    }
    After_filter[i]=sum/N;
    sum=0;
   }
 
}

//採樣資料與實際電壓/溫度轉換:
u16 GetTemp(u16 advalue) 

    u32 Vtemp_sensor; 
    s32 Current_Temp; 
    
//    ADC
轉換結束以後,讀取ADC_DR寄存器中的結果,轉換溫度值計算公式如下:    
//          V25 - VSENSE    
//  T(
) = ------------  + 25    
//           Avg_Slope    
//   V25
  溫度感測器在25 的輸出電壓,典型值1.43 V    
//  VSENSE
:溫度感測器的當前輸出電壓,與ADC_DR 寄存器中的結果ADC_ConvertedValue之間的轉換關係為:    
//            ADC_ConvertedValue * Vdd    
//  VSENSE = --------------------------    
//            Vdd_convert_value(0xFFF)    
//  Avg_Slope
:溫度感測器輸出電壓和溫度的關聯參數,典型值4.3 mV/    
 
    Vtemp_sensor = advalue * 330 / 4096; 
    Current_Temp = (s32)(143 - Vtemp_sensor)*10000/43 + 2500; 
    return (s16)Current_Temp; 
}    
    
u16 GetVolt(u16 advalue) 
{
 
    return (u16)(advalue * 330 / 4096); 
} 


/* note by code
濾波部分思路為:ADC正常連續採樣三個通道,由DMA進行搬運,一次搬運90個資料,即為1-2-3-1-2-3迴圈,每個通道各30次,存在 AD_Value[30][3]中,30為每通道30個資料,3為三個通道,根據二維陣列存儲方式此過程自動完成。而每當一次DMA過程結束後,觸發 DMA完成中斷,進入濾波函數將30個資料均值成一個, 存入After_filter[3]。整個過程濾波計算需要CPU參與,而在程式中採樣結果值隨時均為最新,盡力解決程式複雜性和CPU負載。 x=GetVolt(After_filter[0]);即可得到即時電壓值。
*/

沒有留言: