STM32F407ADC多通道+定時器觸發+DMA模式設置

#include "adc.h"


/* 數據定義 */
u8 UpdataTIM = 0;        //更新TIM2定時器標誌
u16 CurrentFreq = 500;//默認市電頻率,單位爲0.1hz
ADBASE_TYPE uAD_Buff_A[ADC_CHANNEL];        //ADC採集緩存A
ADBASE_TYPE uAD_Buff_B[ADC_CHANNEL];        //ADC採集緩存B
//考慮到可能出現的數據處理時間較長的問題,臨時添加緩存
//u16 uAD_IN_BUFF[ADC_BUFFSIZE][ADC_CHANNEL];
ADBASE_TYPE *CurrentBuffPtr = NULL;        //當前緩存指針
/*
 * Function    : static void ADCInit_GPIO(void)
 * Description : ADCGPIO初始化
 * Arguments   : 無
 * Returns     : 無
 * Other       :
 */
static void ADCInit_GPIO(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;


    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOF時鐘


    //ADC通道初始化
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|  \
                                    GPIO_Pin_9|GPIO_Pin_10; //PF3,PF4,PF5,PF6,PF7,PF8,PF9,PF10 ADC通道
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;  //模擬輸入
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  //不帶上下拉
    GPIO_Init(GPIOF, &GPIO_InitStructure);  //初始化     
}
/*
 * Function    : static void ADCInit_ADC(void)
 * Description : ADC模式初始化
 * Arguments   : 無
 * Returns     : 無
 * Other       :
 */
static void ADCInit_ADC(void)
{
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    ADC_InitTypeDef       ADC_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE); //使能ADC3時鐘
    
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,ENABLE);      //ADC3復位
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC3,DISABLE); //復位結束     


    ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//獨立模式
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; //兩個採樣階段之間的延遲5個時鐘(三重模式或雙重模式下使用)
    ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //DMA失能(對於多個ADC模式)
    ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//預分頻4分頻。ADCCLK=PCLK2/4=84/4=21Mhz,ADC時鐘最好不要超過36Mhz 
    ADC_CommonInit(&ADC_CommonInitStructure);//初始化
    
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;//掃描模式(多通道ADC採集要用掃描模式)    
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//關閉連續轉換
//    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //軟件觸發
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; //上升沿觸發
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;  //定時器事件2觸發ADC
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右對齊    
    ADC_InitStructure.ADC_NbrOfConversion = ADC_CHANNEL;    //8個轉換在規則序列中
    ADC_Init(ADC3, &ADC_InitStructure);//ADC初始化
    
    //連續模式下,通道的配置
    ADC_RegularChannelConfig(ADC3, ADC_Channel_9, 1, ADC_SampleTime_15Cycles);  //PF3,VIN1,通道9,UA,rank=1,表示連續轉換中第一個轉換的通道,採樣時間15個週期(如果數據不穩定可以延時採樣時間)
    ADC_RegularChannelConfig(ADC3, ADC_Channel_14, 2, ADC_SampleTime_15Cycles); //PF4,VIN2,通道14,UB
    ADC_RegularChannelConfig(ADC3, ADC_Channel_15, 3, ADC_SampleTime_15Cycles); //PF5,VIN3,通道15,AC220
    ADC_RegularChannelConfig(ADC3, ADC_Channel_4, 4, ADC_SampleTime_15Cycles);     //PF6,VIN4,通道4,I0
    ADC_RegularChannelConfig(ADC3, ADC_Channel_5, 5, ADC_SampleTime_15Cycles);     //PF7,VIN5,通道5,IA
    ADC_RegularChannelConfig(ADC3, ADC_Channel_6, 6, ADC_SampleTime_15Cycles);     //PF8,VIN6,通道6,IB
    ADC_RegularChannelConfig(ADC3, ADC_Channel_7, 7, ADC_SampleTime_15Cycles);     //PF9,VIN7,通道7,IC
    ADC_RegularChannelConfig(ADC3, ADC_Channel_8, 8, ADC_SampleTime_15Cycles);     //PF10,VIN8,通道8,暫時未接入信號


    ADC_DMARequestAfterLastTransferCmd(ADC3, ENABLE); //連續使能DMA
    ADC_DMACmd(ADC3, ENABLE);  //使能ADC_DMA
    ADC_Cmd(ADC3, ENABLE);//開啓AD轉換器    
}
/*
 * Function    : static void ADCInit_DMA(void)
 * Description : ADC使能DMA模式
 * Arguments   : 無
 * Returns     : 無
 * Other       :
 */
static void ADCInit_DMA(void)
{
    DMA_InitTypeDef  DMA_InitStructure;
    
    //時鐘
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
    
    //DMA設置
    DMA_InitStructure.DMA_Channel = DMA_Channel_2; //選擇通道號
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC3->DR); //外圍設備地址,ADC_DR_DATA規則數據寄存器
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)(u16 *)uAD_Buff_A; //DMA存儲器地址,自己設置的緩存地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; //傳輸方向,外設->存儲器
    DMA_InitStructure.DMA_BufferSize = ADC_BUFFSIZE * ADC_CHANNEL; //DMA緩存大小,數據傳輸量32*8
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外設是否爲增量模式
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存儲器是否爲增量模式
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外設數據長度半個字(16位)
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存儲器數據長度半字(16位)
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //DMA模式,普通模式、循環模式,還有雙緩衝模式,需要特殊設置
    DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA優先級,高優先級
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //不使用FIFO
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; //FIFO閾值
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存儲器突發,單次傳輸
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外設突發,單次傳輸
    DMA_Init(DMA2_Stream0, &DMA_InitStructure); //初始化DMA2_Stream0,對應爲ADC3


    //雙緩衝模式設置
    DMA_DoubleBufferModeConfig(DMA2_Stream0,(uint32_t)(u16 *)(uAD_Buff_B),DMA_Memory_0);    //DMA_Memory_0首先被傳輸
    DMA_DoubleBufferModeCmd(DMA2_Stream0,ENABLE);
    
    //設置DMA中斷
    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TC); //清除中斷標誌   
    DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE); //傳輸完成中斷                                       
    DMA_Cmd(DMA2_Stream0, ENABLE); //使能DMA
    
}
/*
 * Function    : void ADCInit_Timer(void)
 * Description : ADC觸發定時器的設置
 * Arguments   : 無
 * Returns     : 無
 * Other       :
 */
void ADCInit_Timer(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;


    //時鐘
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);          


    //失能定時器
    TIM_Cmd(TIM2, DISABLE);
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); //初始化定時器
    
    //定時器設置,T=(84 * 625) / 84M = 625us = 20ms/32,50Hz信號,每週期採樣32個點,採樣頻率1600
    TIM_TimeBaseStructure.TIM_Prescaler = 84-1; //分頻係數,TIM2時鐘在分頻係數不爲1時,時鐘是APB1時鐘的兩倍84M
    TIM_TimeBaseStructure.TIM_Period = 312500/CurrentFreq - 1; //週期值1M/32=31250,CurrentFreq單位爲0.1hz,因此需擴大10倍
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //時鐘分頻因子
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up ; //向上計數模式
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //初始化定時器2
    
    //使能定時器中斷    
    TIM_ARRPreloadConfig(TIM2, ENABLE); //允許TIM2定時重載
    TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);  //選擇TIM2的UPDATA事件更新爲觸發源
//    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //配置TIM2中斷類型
    
    //使能TIM2
    TIM_Cmd(TIM2, ENABLE); 
    DebugLog("Enable TIM2, Set frequency is %d.", CurrentFreq);
}
/*
 * Function    : void ADCInit_Nvic(void)
 * Description : 中斷初始化
 * Arguments   : 無
 * Returns     : 無
 * Other       :
 */
static void ADCInit_Nvic(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    
    //定時器中斷設置
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  //定時器TIM2中斷通道
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;  //搶佔優先級0
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;        //子優先級1
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);    //根據指定的參數初始化NVIC寄存器    
    
    //DMA中斷設置
    NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;  //DMA2_Stream0中斷
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;  //搶佔優先級1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;        //子優先級1
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //IRQ通道使能
    NVIC_Init(&NVIC_InitStructure);    //根據指定的參數初始化NVIC寄存器    
}
/*
 * Function    : void  ADCInit(void)
 * Description : ADC初始化函
 * Arguments   : 無
 * Returns     : 無
 * Other       :
 */                                                           
void ADCInit(void)
{
    ADCInit_GPIO();
    ADCInit_DMA();
    ADCInit_ADC();
    ADCInit_Nvic();
    DebugLog("ADC Init is finish.");
}    
/*
 * Function    : void TIM2_IRQHandler(void) 
 * Description : TIM2中斷觸發函數
 * Arguments   : 無
 * Returns     : 無
 * Other       :
 */
void TIM2_IRQHandler(void)  
{
  OSIntEnter(); //進入中斷    
    
    if(TIM_GetITStatus(TIM2, TIM_IT_Update))  //判斷髮生update事件中斷  
    {         
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除update事件中斷標誌
//    ADC_SoftwareStartConv(ADC1);      
    }
    
    OSIntExit();  //退出中斷  
}
/*
 * Function    : void DMA2_Stream0_IRQHandler(void) 
 * Description : DMA2_Stream0中斷
 * Arguments   : 無
 * Returns     : 無
 * Other       :
 */
void DMA2_Stream0_IRQHandler(void)  
{
    u16 period = 0;
    
  OSIntEnter(); //進入中斷 
    if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))  //判斷DMA傳輸完成中斷  
    {
         DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
//         DMA_Cmd(DMA2_Stream0, ENABLE); //使能DMA,連續模式下不需要該使能
         //數據轉移程序
         if(DMA_GetCurrentMemoryTarget(DMA2_Stream0) == DMA_Memory_0)
         {
             CurrentBuffPtr = uAD_Buff_A;
         }
         else
         {
             CurrentBuffPtr = uAD_Buff_B;
         }
         //遙測任務等待該信號量
         OSSemPost(SemAD);
         
         //判斷是否更新TIM2
         if(UpdataTIM)
         {
             period = 312500/CurrentFreq - 1;        //計算採樣頻率1M/32=31250;32爲採樣點數,31250/freq=採樣週期
             TIM_ARRPreloadConfig(TIM2, DISABLE); //關閉TIM2定時重載
             TIM2->ARR = period ;        //更新定時器週期
             TIM_ARRPreloadConfig(TIM2, ENABLE);     //打開TIM2定時重載
         }
    }
    OSIntExit();  //退出中斷  
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章