1. 程式人生 > >stm32f407之三ADC交替取樣(操作暫存器)

stm32f407之三ADC交替取樣(操作暫存器)

三ADC交替取樣

在多ADC模式中,ADC1為主,ADC2或ADC3為從,交替或者同時觸發,工作模式取決於ADC_CCR暫存器的MULTI[4:0]。

       多ADC模式中,轉換後的資料可以多模式的資料暫存器(ADC_CDR)中讀取。狀態可以在多模式的狀態暫存器(ADC_CSR)讀取。

多ADC模式下的DMA傳輸方式:

    方式1:每個AD轉換完都發出DMA請求,多模式的資料暫存器(ADC_CDR)用低位儲存轉換結果。

1st request: ADC_CDR[31:0] = ADC1_DR[15:0]

2nd request: ADC_CDR[31:0] = ADC2_DR[15:0]

3rd request: ADC_CDR[31:0] = ADC3_DR[15:0]

4th request: ADC_CDR[31:0] = ADC1_DR[15:0]

方式2:每兩個AD轉換完都發出DMA請求。

雙ADC模式:

高十六位儲存ADC2結果,低十六位儲存ADC1結果

1st request: ADC_CDR[31:0] = ADC2_DR[15:0] |ADC1_DR[15:0]

2nd request: ADC_CDR[31:0] = ADC2_DR[15:0] |ADC1_DR[15:0]

三ADC模式:

1st request: ADC_CDR[31:0] = ADC2_DR[15:0] |ADC1_DR[15:0]

2nd request: ADC_CDR[31:0] = ADC1_DR[15:0] |ADC3_DR[15:0]

3rd request: ADC_CDR[31:0] = ADC3_DR[15:0] |ADC2_DR[15:0]

4th request: ADC_CDR[31:0] = ADC2_DR[15:0] |ADC1_DR[15:0]

方式2:每兩個AD轉換完都發出DMA請求。與方式2相似,但是DMA以半字方式傳輸。

用於6位或者8位解析度中。

 雙ADC模式:

高8位儲存ADC2結果,低8位儲存ADC1結果

1st request: ADC_CDR[15:0] = ADC2_DR[7:0] | ADC1_DR[7:0]

2nd request: ADC_CDR[15:0] = ADC2_DR[7:0] | ADC1_DR[7:0]

 三ADC模式:

1st request: ADC_CDR[15:0] = ADC2_DR[7:0] | ADC1_DR[7:0]

2nd request: ADC_CDR[15:0] = ADC1_DR[7:0] | ADC3_DR[7:0]

3rd request: ADC_CDR[15:0] = ADC3_DR[7:0] | ADC2_DR[7:0]

4th request: ADC_CDR[15:0] = ADC2_DR[7:0] | ADC1_DR[7:0]

多ADC轉換模式:

1.     注入同步模式

2.     規則同步模式

3.     交替模式

4.     交替觸發模式

5.     規則同步+注入同步模式

6.     規則同步+交替觸發模式

交替模式配置步驟:

1. 配置相關輸入通道的IO口。

2. 設定DMA

3. 如果雙重ADC或三重取樣,設定ADC的公共暫存器

       a.     設定公共暫存器首先要開啟任意一個ADC的時鐘,否則這部分數位電路是沒有開始工作的。

        b.     設定DMA模式

        c.     設定ADC轉換完成後,傳送DMA請求

        d.     設定多ADC模式

        e.     設定兩次取樣間隔週期

4. 配置要使用到的ADC(必須ADC1為主,其他為從)。

 程式:

/************************************
    標題:ADC
    軟體平臺:IAR for ARM6.21
    硬體平臺:stm32f4-discovery
    主頻:168M
    
    author:小船
    data:2012-02-16
*************************************/

#include <stm32f4xx.h> 
#include "MyDebugger.h"

__IO uint16_t ADCConvertedVault[10000];
char TXbuffer[] = "PC1輸入電壓為:x.xxxV\n\r";

void ADC_IO_Config(void);
void ADC_DMA_Config(void);

void ADC_Common_Config(void);

void ADC3_IN11_Config(void);
void ADC2_IN11_Config(void);
void ADC1_IN11_Config(void);

void main ()
{   
  SCB->AIRCR = 0x05FA0000 | 0x400;  //中斷優先順序分組 搶佔:響應=3:1
 
  ADC_IO_Config();
  ADC_DMA_Config();
  
  ADC_Common_Config();
  
  ADC3_IN11_Config();
  ADC2_IN11_Config(); 
  ADC1_IN11_Config();
  
  ADC3->CR2 |= (1<<0);   //開啟ADC3轉換
  ADC2->CR2 |= (1<<0);   //開啟ADC2轉換
  ADC1->CR2 |= (1<<0);   //開啟ADC1轉換
   
  ADC1->CR2 |= (1<<30); //觸發轉換開始 
  
  MyDebugger_Init();

  while(1)
  {
  };
}

void ADC_Common_Config(void)
{
  RCC->APB2ENR |= ( (1<<8) | (1<<9) | (1<<10) ); //使能ADC時鐘
  ADC->CCR &= 0x00000000;
  
  /*
  DMA模式1
  最後一次ADC轉換後發出dma請求
  交錯模式
  2次取樣之間的延遲5個週期
  */
  ADC->CCR |= ( 0x00004000 | (1<<13) | 0x00000017 | 0x00000000);
    
}

/***ADC1設定***/
void ADC1_IN11_Config(void)
{   
  ADC1->SQR1 = 0x00000000;//轉換一個通道
  ADC1->SQR3 = 0x0000000B;//第一個通道為ADC1_in11
  ADC1->CR1 &= 0x00000000; 
  ADC1->CR2 &= 0x00000000;  
  ADC1->CR2 |= (1<<1);  //連續轉換
  ADC1->CR2 |= (1<<9); //最後一次ADC轉換後發出dma請求

  ADC1->CR2 |= (1<<8);//ADC dma傳送模式使能
}

/***ADC2設定***/
void ADC2_IN11_Config(void)
{   
  ADC2->SQR1 = 0x00000000;//轉換一個通道
  ADC2->SQR3 = 0x0000000B;//第一個通道為ADC1_in11
  ADC2->CR1 &= 0x00000000; 
  ADC2->CR2 &= 0x00000000;  
  ADC2->CR2 |= (1<<1);  //連續轉換
  ADC2->CR2 |= (1<<9); //最後一次ADC轉換後發出dma請求
}

/***ADC3設定***/
void ADC3_IN11_Config(void)
{   
  ADC3->SQR1 = 0x00000000;//轉換一個通道
  ADC3->SQR3 = 0x0000000B;//第一個通道為ADC3_in11
  ADC3->CR1 &= 0x00000000; 
  ADC3->CR2 &= 0x00000000;  
  ADC3->CR2 |= (1<<1);  //連續轉換
  ADC3->CR2 |= (1<<9); //最後一次ADC轉換後發出dma請求
}

/***GPIO設定***/
void ADC_IO_Config(void)
{
  RCC->AHB1ENR |= (1<<2); //開啟GPIOC時鐘
  GPIOC->MODER &= 0xfffffff3;//PC1模擬模式
  GPIOC->MODER |= 0x0000000C;
  GPIOC->PUPDR &= 0xfffffff3;//無上拉無下拉  
}

/***DMA設定***/
void ADC_DMA_Config(void)
{   
  RCC->AHB1ENR |= (1<<22); //使能DMA2時鐘
  ADC3->CR2 &= ~(1<<8);//ADC3 dma傳送模式除能
  DMA2_Stream0->CR &= 0xFFFFFFFE; //除能DMA2_Stream0
  while(DMA2_Stream0->CR & 0x00000001);//確保DMA可以被設定 
  DMA2->LIFCR |= 0x0000003D;//傳送前清空DMA2_Stream0所有中斷標誌 
  DMA2_Stream0->PAR = (uint32_t)&ADC->CDR;//設定外設地址
  DMA2_Stream0->M0AR = (uint32_t)ADCConvertedVault; //設定記憶體地址
  DMA2_Stream0->CR |= 0x0002800;//16位資料
  DMA2_Stream0->NDTR = 10000; //設定dma傳輸資料的數量
  /*
    設定dma2通道0,即ADC1
    優先順序Medium
    傳輸方向外設到記憶體
    記憶體遞增模式
    迴圈模式
    傳輸完成中斷
  */
  DMA2_Stream0->CR |= ( 0x00000000 | 0x00010000 | 0x0 | (1<<10) | (1<<8) | (1<<4) ); 
  
  NVIC->IP[56] = 0xB0;
  NVIC->ISER[1] |= (1<<(56-32));
  
  DMA2_Stream0->CR |= 1; //DMA2資料流0使能
}

void DMA2_Stream0_IRQHandler (void)
{
  uint32_t i;
  uint32_t Average;
  if(DMA2->LISR & 0x00000010)
  {
      DMA2->LIFCR |= 0x00000010;
      for(i = 0; i < 10000; i++)  // 對一萬個資料取平均值
        Average += ADCConvertedVault[i];
      Average *= 3;
      Average /= 40960;
      TXbuffer[14] = ( Average / 1000 ) % 10 + 0x30;//轉換成ASCII碼
      TXbuffer[16] = ( Average / 100 ) % 10 + 0x30;
      TXbuffer[17] = ( Average / 10 ) % 10 + 0x30;
      TXbuffer[18] = Average % 10 + 0x30;
      MyDebugger_Message(TXbuffer, sizeof(TXbuffer)/sizeof(char));  
  }
}



 執行結果: