0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

STM32双ADC采集基本知识介绍

冬至子 来源:小李的创客实验室 作者:初出茅庐的小李 2023-07-08 15:55 次阅读

ADC基本介绍

ADC 的机制就是使用两个 ADC 同时采样一个或者多个通道。双重ADC 模式较独立模式一个最大的优势就是提高了采样率,弥补了单个 ADC 采样不够快的缺点。

双ADC工作框图

图片

双ADC模式

在双ADC模式里,根据ADC1_CR1寄存器DUALMOD[2:0]位所选的模式,转换的启动可以是ADC1主和ADC2从的交替触发或同步触发。

注意:在双ADC模式里,当转换配置成由外部事件触发时,用户必须将其设置成仅触发主ADC,从ADC设置成软件触发,这样可以防止意外的触发从转换。但是,主和从ADC的外部触发必须同时被激活。

注意:在双ADC模式里,为了在主数据寄存器上读取从转换数据,必须使能DMA位,即使不使用DMA传输规则通道数据。

图片

图片

1.jpg

同步规则模式

此模式在规则通道组上执行。外部触发来自ADC1的规则组多路开关(由ADC1_CR2寄存器的EXTSEL[2:0]选择), 它同时给ADC2提供同步触发。

注意: 不要在2个ADC上转换相同的通道 ((两个ADC在同一个通道上的采样时间不能重叠)。

在ADC1或ADC2的转换结束时:

● 产生一个32位DMA传输请求(如果设置了DMA位), 32位的ADC1_DR寄存器内容传输到SRAM中,它上半个字包含ADC2的转换数据,低半个字包含ADC1的转换数据。

● 当所有ADC1/ADC2规则通道都被转换完时,产生EOC中断(若任一ADC接口开放了中断)。

注:在同步规则模式中,必须转换具有相同时间长度的序列,或保证触发的间隔比2个序列中较长的序列长,否则当较长序列的转换还未完成时,具有较短序列的ADC转换可能会被重启。

图片

图片

图片

扫描模式

此模式用来扫描一组模拟通道。 扫描模式可通过设置ADC_CR1寄存器的SCAN位来选择。一旦这个位被设置, ADC扫描所有被ADC_SQRX寄存器(对规则通道)或ADC_JSQR(对注入通道)选中的所有通道。在每个组的每个通道上执行单次转换。在每个转换结束时,同一组的下一个通道被自动转换。如果设置了CONT位,转换不会在选择组的最后一个通道上停止,而是再次从选择组的第一个通道继续转换。

如果设置了DMA位,在每次EOC后, DMA控制器把规则组通道的转换数据传输到SRAM中。而 注入通道转换的数据总是存储在ADC_JDRx寄存器中。

图片

图片

连续转换模式

图片

*单次转换

*图片

外部触发转换

转换可以由外部事件触发(例如定时器捕获,EXTI线)。如果设置了EXTTRIG控制位,则外部事件就能够触发转换。EXTSEL[2:0]和JEXTSEL2:0]控制位允许应用程序选择8个可能的事件中的某一个,可以触发规则和注入组的采样。

注意:当外部触发信号被选为ADC规则或注入转换时,只有它的上升沿可以启动转换

图片

数据对齐

ADC_CR2寄存器中的ALIGN位选择转换后数据储存的对齐方式。数据可以左对齐或右对齐,如图29和图30所示。注入组通道转换的数据值已经减去了在ADC_JOFRx寄存器中定义的偏移量,因此结果可以是一个负值。SEXT位是扩展的符号值。对于规则组通道,不需减去偏移值,因此只有12个位有效。

图片

通道选择

有16个多路通道。可以把转换组织成两组: 规则组和注入组 。在任意多个通道上以任意顺序进行的一系列转换构成成组转换。例如,可以如下顺序完成转换:通道3、通道8、通道2、通道 2、通道0、通道2、通道2、通道15。

● 规则组由多达16个转换组成。规则通道和它们的转换顺序在ADC_SQRx寄存器中选择。规则组中转换的总数应写入ADC_SQR1寄存器的L[3:0]位中。

● 注入组由多达4个转换组成。注入通道和它们的转换顺序在ADC_JSQR寄存器中选择。注入组里的转换总数目应写入ADC_JSQR寄存器的L[1:0]位中。

如果ADC_SQRx或ADC_JSQR寄存器在转换期间被更改,当前的转换被清除,一个新的启动脉冲将发送到ADC以转换新选择的组。

ADC时钟

ADC预分频器的ADCCLK是ADC模块的时钟来源。通常,由时钟控制器提供的ADCCLK时钟和PCLK2(APB2时钟)同步。RCC控制器为ADC时钟提供一个专用的可编程预分频器。

图片

一般情况下:不要让ADC时钟超过14MHz,否则可能不准。

也就是说,如果按照默认设置PCLK2为72MHz,此时应为6分频或者8分频。

可编程的通道采样时间

ADC使用若干个ADC_CLK周期对输入电压采样,采样周期数目可以通过ADC_SMPR1和ADC_SMPR2寄存器中的SMP[2:0]位更改。每个通道可以分别用不同的时间采样。

总转换时间如下计算:

TCONV = 采样时间+ 12.5个周期

例如:当ADCCLK=14MHz,采样时间为1.5周期,TCONV = 1.5 + 12.5 = 14周期 = 1μs

校准

ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。在校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差。

通过设置 ADC_CR2 寄存器的CAL位启动校准。一旦校准结束, CAL位被硬件复位,可以开始正常转换。建议在上电时执行一次ADC校准。校准阶段结束后,校准码储存在ADC_DR中。

注意:1 建议在每次上电后执行一次校准。2 启动校准前, ADC必须处于关电状态(ADON=’0’)超过至少两个ADC时钟周期

图片

ADC中断

规则和注入组转换结束时能产生中断,当模拟看门狗状态位被设置时也能产生中断。它们都有独立的中断使能位。

注:ADC1和ADC2的中断映射在同一个中断向量上,而ADC3的中断有自己的中断向量。

图片

ADC_SR寄存器中有2个其他标志,但是它们没有相关联的中断:

● JSTRT(注入组通道转换的启动)

● STRT(规则组通道转换的启动)

图片

ADC寄存器

ADC状态寄存器(ADC_SR)

图片

ADC控制寄存器(ADC_CR1)

图片

图片

ADC控制寄存器(ADC_CR2)

图片

图片

图片

图片

ADC采样时间寄存器(ADC_SMPRx)

图片

ADC规则序列寄存器(ADC_SQRx)

图片

ADC规则数据寄存器(ADC_DR)

图片

ADC库函数配置

volatileuint32_t ADC_ConvertedValue[5] = {0};

void ADC_Config(void)
{ 	
	DMA_InitTypeDef DMA_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//开DMA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);//开ADC1,ADC2时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOB, ENABLE);
	
	//GPIO口配置-----------------------------------------------------------------------------											
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 ;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;	
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOB, &GPIO_InitStructure);	

	//DMA1配置-----------------------------------------------------------------------------
	DMA_DeInit(DMA1_Channel1);//复位DMA控制器
	DMA_InitStructure.DMA_PeripheralBaseAddr = ( uint32_t ) ( & ( ADC1- >DR ) );//外设基址为:ADC数据寄存器地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue;//存储器地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//数据源来自外设
	DMA_InitStructure.DMA_BufferSize = 5;//缓冲区大小,应该等于数据目的地的大小
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设寄存器只有一个,地址不用递增
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器地址递增
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//全字(32位)
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;//全字(32位)
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;	//循环传输模式
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA 传输通道优先级为高
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//禁止存储器到存储器模式,因为是从外设到存储器
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);//初始化DMA
		
	//ADC1配置-----------------------------------------------------------------------------
	ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;//同步规则
	ADC_InitStructure.ADC_ScanConvMode = DISABLE ; //关闭扫描模式
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//连续转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不用外部触发转换,软件开启即可
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 1;	//转换通道数
	ADC_Init(ADC1, &ADC_InitStructure);//初始化ADC
	RCC_ADCCLKConfig(RCC_PCLK2_Div8); //配置ADC时钟,CLK2的8分频,即9MHz
	
	ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_239Cycles5);//配置ADC通道的转换顺序和采样时间
	
	ADC_DMACmd(ADC1, ENABLE);	//使能DMA请求

	//ADC2配置-----------------------------------------------------------------------------
	ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;//同步规则
	ADC_InitStructure.ADC_ScanConvMode = DISABLE; //关闭扫描模式
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//连续转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不用外部触发转换,软件开启即可
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 1;	//转换通道数
	ADC_Init(ADC2, &ADC_InitStructure);//初始化ADC
	RCC_ADCCLKConfig(RCC_PCLK2_Div8); //配置ADC时钟,CLK2的8分频,即9MHz
	
	ADC_RegularChannelConfig(ADC2, ADC_Channel_8, 1, ADC_SampleTime_239Cycles5);//配置ADC通道的转换顺序和采样时间

	//ADC1校准-----------------------------------------------------------------------------
	ADC_Cmd(ADC1, ENABLE);//使能ADC1
	ADC_ResetCalibration(ADC1);//使能复位校准 
	while(ADC_GetResetCalibrationStatus(ADC1));//等待复位校准结束	
	ADC_StartCalibration(ADC1);//开启AD校准 
	while(ADC_GetCalibrationStatus(ADC1));//等待校准结束 
		
	//ADC2校准-----------------------------------------------------------------------------
	ADC_Cmd(ADC2, ENABLE);//使能ADC2
	ADC_ResetCalibration(ADC2);//使能复位校准 
	while(ADC_GetResetCalibrationStatus(ADC2));//等待复位校准结束	
	ADC_StartCalibration(ADC2);	//开启AD校准 
	while(ADC_GetCalibrationStatus(ADC2));//等待校准结束 
	
	DMA_Cmd(DMA1_Channel1 , ENABLE);//使能DMA1通道
	ADC_ExternalTrigConvCmd(ADC2, ENABLE);//使能ADC2的外部触发转换
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能软件触发转换
}

//DMA1中断服务函数
__IO uint16_t ADC_ConvertedValueLocal_R = 0;
__IO uint16_t ADC_ConvertedValueLocal_L = 0;
uint16_t ADC_ConvertedValue_R[5] = {0};
uint16_t ADC_ConvertedValue_L[5] = {0};
void DMA1_Channel1_IRQHandler(void)//电流值读取
{
	if(DMA_GetITStatus(DMA1_IT_TC1) != RESET)
	{
		int i = 0, j = 0, k = 0;
		 
		DMA_ClearITPendingBit(DMA1_IT_TC1);
		DMA_Cmd(DMA1_Channel1, DISABLE); 
		ADC_Cmd(ADC1, DISABLE);
		ADC_Cmd(ADC2, DISABLE);
		
		 for(i = 0; i < 5; i++)
		 {
			 //ADC1- >DR低16位,ADC1的数据
			 ADC_ConvertedValue_R[k++] = (ADC_ConvertedValue[i] & 0xffff);
			 //ADC1- >DR高16位,ADC2的数据
			 ADC_ConvertedValue_L[j++] = (ADC_ConvertedValue[i] & 0xffff0000) > > 16;
		 }
		 QuickSort(ADC_ConvertedValue_R, 0, 4);
		 QuickSort(ADC_ConvertedValue_L, 0, 4);
		 ADC_ConvertedValueLocal_R = ADC_ConvertedValue_R[2];
		 ADC_ConvertedValueLocal_L = ADC_ConvertedValue_L[2];
	 }
	 DMA_SetCurrDataCounter(DMA1_Channel1, 5);
	 DMA_Cmd(DMA1_Channel1, ENABLE);
	 ADC_Cmd(ADC1, ENABLE);
   	 ADC_Cmd(ADC2, ENABLE);
	 ADC_ExternalTrigConvCmd(ADC2, ENABLE);
	 ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	}	 	
}

 //快速排序法
void QuickSort(uint16_t* a, int left, int right)
{
	int i = left;
    int j = right;
    int key = a[left];
	
	/*如果左边索引大于或者等于右边的索引就代表已经整理完成一个组了*/
    if (left >= right) { return; }

	/*控制在当组内寻找一遍*/
    while (i < j)
    {
        while (i < j && key <= a[j]) { 
			j--; 
		}
		
        a[i] = a[j];

        while (i < j && key >= a[i]) {
            i++;
        }

        a[j] = a[i];
    }
    a[i] = key;
	
    QuickSort(a, left, i - 1);
    QuickSort(a, i + 1, right);
}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • STM32
    +关注

    关注

    2270

    文章

    10900

    浏览量

    356092
  • 定时器
    +关注

    关注

    23

    文章

    3248

    浏览量

    114833
  • RCC
    RCC
    +关注

    关注

    0

    文章

    93

    浏览量

    26940
  • 预分频器
    +关注

    关注

    0

    文章

    18

    浏览量

    8138
  • ADC采样
    +关注

    关注

    0

    文章

    134

    浏览量

    12848
收藏 人收藏

    评论

    相关推荐

    电磁继电器基本知识介绍

    本帖最后由 eehome 于 2013-1-5 10:03 编辑 电磁继电器基本知识介绍
    发表于 08-16 17:22

    电磁继电器基本知识介绍

    本帖最后由 eehome 于 2013-1-5 09:55 编辑 电磁继电器基本知识介绍
    发表于 08-20 09:39

    学习STM32,在ADC转换采集这一章,adc采集与单adc采集相同通道速度是一样的吗?

    学习STM32,在ADC转换采集这一章,adc采集与单ad
    发表于 09-23 09:25

    STM32F103外部中断基本知识介绍

    外部中断基本知识介绍EXTI–外部中断/事件控制器STM32的每个IO都可以作为外部中断的中断输入口。STM32的中断控制器支持19个外部中断/事件请求:**线0~15:**对应外部I
    发表于 08-16 06:41

    STM32CubeMX之RTC闹钟唤醒停机模式基本知识介绍

    STM32CubeMX(stm32L151C8T6) 之RTC闹钟唤醒停机模式基本知识介绍低功耗模式STM32F10xxx有三种低功耗模式:
    发表于 08-18 06:01

    STM32的GPIO端口模式基本知识介绍

    STM32基本知识点GPIO端口模式(1)GPIO_Mode_AIN 模拟输入(2)GPIO_Mode_IN_FLOATING 浮空输入(3)GPIO_Mode_IPD 下拉输入(4
    发表于 02-22 06:39

    MIMO 的基本知识介绍

    MIMO 的基本知识介绍 很好的初学者入门书籍
    发表于 06-25 14:47 25次下载

    锂离子电池的基本知识介绍

    锂离子电池的基本知识介绍  锂离子电池(Li-ion Batteries)是锂电池发展
    发表于 10-24 16:13 786次阅读

    图像采集基本知识介绍

    图像采集基本知识介绍 视频采集     即将视频转换成PC机可使用的数字格式。    微视专业图象
    发表于 01-15 14:55 2584次阅读

    LED基本知识

    介绍LED的基本知识以及LED的分类。
    发表于 05-30 14:58 0次下载

    安全用电基本知识

    安全用电基本知识安全用电基本知识安全用电基本知识
    发表于 01-14 15:54 0次下载

    电缆接续基本知识_电缆接续工艺介绍

    下面我将从四个方面介绍电缆接续的基本知识以及电缆接续工艺方面相关知识
    发表于 12-28 10:27 1.8w次阅读

    STM32单片机ADC采集

    STM32单片机ADC采集
    发表于 11-18 20:36 75次下载
    <b class='flag-5'>STM32</b>单片机<b class='flag-5'>ADC</b><b class='flag-5'>采集</b>

    Σ-ADC拓扑背后的基本原理的基本知识

    Σ- ADC是当今信号采集和处理系统设计人员工具包中的主要产品。本文旨在为读者提供有关Σ-ADC拓扑背后的基本原理的基本知识。本文探讨了噪声、带宽、建立时间和与
    的头像 发表于 01-23 09:12 1342次阅读
    Σ-<b class='flag-5'>ADC</b>拓扑背后的基本原理的<b class='flag-5'>基本知识</b>

    第12章-ADC采集电压和显示 基于STM32ADC—电压采集(详细讲解+HAL库)

    第12章-ADC采集电压和显示 基于STM32ADC—电压采集(详细讲解+HAL库)
    的头像 发表于 08-21 16:31 2589次阅读
    第12章-<b class='flag-5'>ADC</b><b class='flag-5'>采集</b>电压和显示 基于<b class='flag-5'>STM32</b>的<b class='flag-5'>ADC</b>—电压<b class='flag-5'>采集</b>(详细讲解+HAL库)