因为规则通道转换的值一直存储在一个仅有的数据寄存器中,所以当转换多个规则通道时需要使用DMA,这可以避免丢失已经存储在ADC_DR寄存器中的数据
例程:
将ADC1的通道4,5,6使用DMA传输
总结
1.DMA外设基地址(DMA_MemoryBaseAddr),当只需要读取一个通道的值时,设置成某一自定义变量的地址;当需要读取多个通道的值时,设成某一自定义数组的地址。地址都是32位——(uint32_t)
例如 u16 RecBuff[3];
DMA_InitStructure.DMA_MemoryBaseAddr =(uint32_t)RecBuff;
2.DMA传送ADC采样值到定义的数组或者变量,如果需要得到采样值,不需要再使用ADC_GetConversionValue(ADCx);直接用数组或变量转化即可
temp1=(float)RecBuff[0]*(3.3/4096);
3.DMA_DIR_PeripheralDST 外设作为数据传输的目的地;
DMA_DIR_PeripheralSRC 外设作为数据传输的来源
4.ADC 设置成连续转换模式,若是多通道,使能扫描
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
5.ADC为12位,将外设数据宽度和存储器数据宽度设为半字
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
ADC1设置步骤
1)开启端口时钟和ADC1时钟
2)复位ADC1,同时设置ADC分频因子
3)初始化ADC1参数,设置ADC1的工作模式以及规则序列的相关信息
4)使能ADC并校准
5)配置规则通道参数
6)开启软件转换
//7)使能ADC1的DMA传送
DMA设置步骤
1)使能DMA时钟
2)初始化DMA通道参数
3)使能DMA函数
常用的外设DMA使能函数
USART_DMACmd();
ADC_DMACmd();
DAC_DMACmd();
I2C_DMACmd();
SPIO_DMACmd();
SPI_I2S_DMACmd();
TIM_DMACmd();
4)使能DMA通道,启动传输
5)查询DMA传输状态
代码块(STM32F1)
adc.c
//初始化ADC
//ADC1规则通道4、5、6
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1, ENABLE ); //使能ADC1通道时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6,ADC最大时间不能超过14M
//PA4,5,6 作为模拟通道输入引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4| GPIO_Pin_5|GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_DeInit(ADC1); //复位ADC1
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式
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数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 3; //顺序进行规则转换的ADC通道的数目
ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1
ADC_ResetCalibration(ADC1); //使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
ADC_StartCalibration(ADC1); //开启AD校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1,ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2,ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 3,ADC_SampleTime_239Cycles5);
ADC_DMACmd(ADC1,ENABLE); //使能ADC1的DMA发送
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
}
dam.c
//配置DMA1
//从存储器->外设模式/16位数据宽度/存储器增量模式
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
void MYDMA_Config(u32 cpar,u32 cmar,u16 cndtr)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输时钟
DMA_DeInit(DMA1_Channel1); //将DMA的通道1寄存器重设为缺省值
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,从外设发送到内存
DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小
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_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道 x拥有高优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE);
}
//得到转换值
if(DMA_GetFlagStatus(DMA1_FLAG_TC1)!=RESET)
{
temp1=(float)RecBuff[0]*(3.3/4096);
temp2=(float)RecBuff[1]*(3.3/4096);
temp3=(float)RecBuff[2]*(3.3/4096);
DMA_ClearFlag(DMA1_FLAG_TC1); //清除通道1传输完成标志
}