三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));
}
}
運行結果: