双ADC同步规则模式-必会要点



简介:   

AD转换包括采样阶段和转换阶段。在采样阶段对通道数据进行采集,在转换阶段只是将采到的数据转换为数字量输出。ADC为12位,故转换的数字量范围为0-65535。

 我们为什么要使用双ADC呢?

相较于单ADC模式他有什么好处呢?下面就让我来浅浅解答一下:

        首先ADC独立模式是指单个ADC模块独立地进行模数转换,即每个ADC模块都有自己的采样和转换控制器,可以独立地进行模数转换。这种模式适用于需要单独处理每个模拟信号的应用场景。

        而双ADC同步模式是指两个ADC模块同时进行模数转换,即两个ADC模块共享同一个采样和转换控制器,可以同时对两个模拟信号进行采样和转换。这种模式适用于需要同时处理两个模拟信号的应用场景,例如音频信号的采集和处理。

        现在假设我们要采集两路马达的电流值,对电流值的稳定性有一定要求。最初使用DMA+一个ADC的两个通道,采集的数据老是错位且数据变化波动大。而当我转换成双ADC+DMA模式时,使用两个ADC采集,就基本解决了以上问题。

        当然双重 ADC 模式 较独立模式一个最大的优势就是提高了采样率,弥补了单个 ADC 采样不够快的缺点。

下面我会列举一点双ADC同步规则模式配置中容易混淆的知识点

注意只有ADC1、ADC3可以使能DMA位,而ADC2没有。这里我们使用ADC1作为主ADC,ADC2作为从ADC。我们只需要使能ADC1的DMA即可。

在双ADC模式里,为了在主数据寄存器上读取从转换数据,必须使能DMA位,即使不使用DMA。

在ADCx配置中应注意:

  1、 数据格式右对齐、选择ADC规则同步模式(ADC_Mode_RegSimult)、开启连续转换扫描模式、使用软件触发ADC转换。

  2、不要忘记配置ADC规则组通道,注意对应的ADC的通道选择。

  3、在ADCx的初始化函数中我们应配置: 不用外部触发转换,而是软件开启。


	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;

但由于两个ADC为同步规则触发,要想达到同步,我们可以将从ADC开启通道的外部触发模式,

//使能外部触发转换ADC2
	ADC_ExternalTrigConvCmd(ADC2,ENABLE);

这样当主ADC的被触发时,从ADC也会被同时开启。
  4、ADC1为主,占ADC1->DR的低十六位,ADC2为从,占ADC1->DR的高16位
  5、这里只开启ADC1的DMA即可。
  6、必须先使能ADC,再进行ADC的校准。

  7、两个ADC的通道的采样时间需要一致。

在DMA配置中应注意:

  1、外设基地址为ADC1数据寄存器的地址即  (uint32_t)(&(ADC1->DR))  这里我们设置 外设为源地址。ADC1数据寄存器只有一个 故地址不自增。

    2、存储器基地址为我们定义的存放数据的变量的地址 。若要接受的数据有多个,则可以设置存储器地址自增。

    3、每个ADC是12位转换结果,但是我们采用的是双ADC。而在双ADC模式中,ADC1和ADC2转换的数据都是存在ADC1中(也就是主ADC中),他们分别占主ADC1->DR的低十六位、高十六位。

    4、最后软件触发ADC1开启转换,则相当于开启了双ADC同步规则模式。

基本流程分析:

    1、ADC模拟输入管脚初始化  (模拟输入模式)
    2、ADC1工作参数初始化、ADC2工作参数初始化(注意开启时钟)
    3、DMA配置、ADC1校准、ADC2校准x
    4、使能ADCx,开软件触发ADC1转换。


部分代码分享:

void ADC_DMA_Init(void)
{
	ADC_InitTypeDef ADC_InitStruct;
	DMA_InitTypeDef DMA_InitStruct;
	//开启外设时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2,ENABLE);

	//配置ADCCLK
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//将输入时钟(72MHz)6分频
	/************************ADC1配置************************************/
	ADC_InitStruct.ADC_ContinuousConvMode=ENABLE; //连续转换
	ADC_InitStruct.ADC_ScanConvMode=ENABLE; //扫描
	ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;     
	ADC_InitStruct.ADC_Mode=ADC_Mode_RegSimult;                    //同步规则
	ADC_InitStruct.ADC_NbrOfChannel=NOFCHANEL;     //AD通道
	ADC_Init(ADC1,&ADC_InitStruct);
	//AD规则组通道配置
	ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_55Cycles5);
	//AD到DMA使能
	ADC_DMACmd(ADC1,ENABLE);
	/************************ADC2配置************************************/
	ADC_InitStruct.ADC_ContinuousConvMode=ENABLE; //连续转换
	ADC_InitStruct.ADC_ScanConvMode=ENABLE; //扫描
	ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;     
	ADC_InitStruct.ADC_Mode=ADC_Mode_RegSimult;                    //同步规则
	ADC_InitStruct.ADC_NbrOfChannel=NOFCHANEL;     //AD通道
	ADC_Init(ADC2,&ADC_InitStruct);
	//AD规则组通道配置
	ADC_RegularChannelConfig(ADC2,ADC_Channel_4,1,ADC_SampleTime_55Cycles5);
	//使能外部触发转换ADC2
	ADC_ExternalTrigConvCmd(ADC2,ENABLE);
	/************************DMA配置************************************/
	DMA_InitStruct.DMA_BufferSize=1;                  //缓冲区大小,应等于数据目的地大小
	DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;          //外设为源地址
	DMA_InitStruct.DMA_M2M=DMA_M2M_Disable;  
	DMA_InitStruct.DMA_Mode=DMA_Mode_Circular;   //连续转运
	DMA_InitStruct.DMA_Priority=DMA_Priority_Medium;
	
	DMA_InitStruct.DMA_MemoryBaseAddr=(uint32_t)ADC_ConvertedValue;   //一个32位变量接收数据
	DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_Word;  //DMA转运的是32位
	DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;     //存储器地址自增
	
	DMA_InitStruct.DMA_PeripheralBaseAddr=(uint32_t)(&(ADC1->DR));    //主ADC的数据寄存器 
	DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Word;
	DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
	DMA_Init(DMA1_Channel1,&DMA_InitStruct);  //ADC的DMA请求映像通道为DMA1的通道1
	
	
	DMA_Cmd(DMA1_Channel1,ENABLE);
	/************************必须先使能ADC,再进行ADC的校准************************************/
	ADC_Cmd(ADC1,ENABLE);
	ADC_Cmd(ADC2,ENABLE);
	/************************ADC1校准************************************/
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1)==SET);
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1)==SET);
	/************************ADC2校准************************************/
	ADC_ResetCalibration(ADC2);
	while(ADC_GetResetCalibrationStatus(ADC2)==SET);
	ADC_StartCalibration(ADC2);
	while(ADC_GetCalibrationStatus(ADC2)==SET);
	/************************************************************/
	//软件先不开启ADC
	ADC_SoftwareStartConvCmd(ADC1,DISABLE);
}

有问题欢迎指正哦~

  • 42
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值