STM32双ADC采集基本知识介绍

发布者:快乐旅途最新更新时间:2024-04-15 来源: elecfans关键字:STM32  多个通道 手机看文章 扫描二维码
随时随地手机看文章

双ADC基本介绍

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


双ADC工作框图

图片

双ADC模式

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

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

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

图片

图片

1.jpg?imageView2/2/w/1000

同步规则模式

此模式在规则通道组上执行。外部触发来自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  多个通道 引用地址:STM32双ADC采集基本知识介绍

上一篇:STM32CubeMx入门教程(2):USART的使用
下一篇:STM32单片机看门狗的配置方法

推荐阅读最新更新时间:2026-03-25 09:37

STM32CUBEMX开发GD32F303(10)----ADC轮询模式扫描多个通道
概述 本章STM32CUBEMX配置STM32F103,并且在GD32F303中进行开发,同时通过GD32303C_START开发板内进行验证。需要GD样片的可以加Q_QUN申请:615061293。 本章主要配置,双ADC轮询模式扫描多个通道,通过串口进行打印。 查阅手册可以得知,PA9、PA10为串口0的输出和输入口。 ADC通道配置 ADC1 IN0(PA0) IN3(PA3) IN4(PA4) ADC2 IN7(PA7) IN8(PB0) IN9(PB1) 生成例程 这里准备了GD32303C_START开发板进行验证。 STM32CUBEMX配置 勾选中断。 ADC1配置。 ADCs_Co
[单片机]
STM32CUBEMX开发GD32F303(10)----<font color='red'>双</font><font color='red'>ADC</font>轮询模式扫描<font color='red'>多个</font><font color='red'>通道</font>
STM32CUBEMX开发GD32F303(11)----ADC在DMA模式下扫描多个通道
概述 本章STM32CUBEMX配置STM32F103,并且在GD32F303中进行开发,同时通过GD32303C_START开发板内进行验证。 需要GD样片的可以加Q_QUN申请:6_15061293。 本章主要配置,双ADC轮询模式扫描多个通道,通过串口进行打印。 查阅手册可以得知,PA9、PA10为串口0的输出和输入口。 ADC通道配置 生成例程 这里准备了GD32303C_START开发板进行验证。 视频教学 https://www.bilibili.com/video/BV1hG41187Ah/ STM32CUBEMX配置 勾选中断。 ADC1配置。 ADCs_Common_Setti
[单片机]
STM32CUBEMX开发GD32F303(11)----<font color='red'>ADC</font>在DMA模式下扫描<font color='red'>多个</font><font color='red'>通道</font>
实战解析:通过一个小项目掌握STM32所有外设
一、项目目标:实现外设间的无缝协同 本项目旨在实现一个清晰的核心功能: 读取数据() 显示温度在 上() 温度超限时蜂鸣器报警(PWM/) 通过按键调整报警阈值(GPIO 输入) 通过串口输出调试信息() 后台定时刷新显示(定时中断 + ) 这一个项目,几乎覆盖了 的全部核心外设模块,是最适合系统学习的实践框架。 二、外设初始化思路 1. RCC 系统 所有外设都依赖时钟。先开启 GPIO、USART、C、M、I2C 等模块的时钟。 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE); RC
[嵌入式]
使用 Keil Studio for Visual Studio Code开发 STM32 设备
Keil Studio是 Arm 最新一代的集成开发环境(IDE),将嵌入式开发工具直接集成到了 Visual Studio Code 中。作为 µVision 的后继者,它提供了现代化的特性,包括与业界工具的无缝集成、版本控制支持,以及用于 CI 工作流的命令行接口(CLI)。 Keil Studio 作为 Arm Keil MDK 6的一部分,为基于 Cortex M 的微控制器提供了全面支持,其中包括 STMicroelectronics 广泛的 STM32 产品系列。它将 Arm 编译器的可靠性与成熟度、广泛的器件支持,与 Visual Studio Code 的灵活性和可扩展性有机结合在一起。 快速上手 借
[单片机]
使用 Keil Studio for Visual Studio Code开发 <font color='red'>STM32</font> 设备
STM32单片机学习】第12章 GPIO—按键轮询
12.1 关于按键 前面控制LED灯是让GPIO输出高低电平,而获取按键则是读取GPIO电平,从而获知用户是否按下按键。 按键监测一般有两种:按键扫描和按键中断。按键扫描是间隔很短时间反复查询GPIO状态,从而得知是否有按键动作,这种方式代码简单,但比较耗资源。按键中断而是通过按键产生中断信号,从而实现按键的检测,这种方式需要使用到中断机制,需要对MCU了解深入一点,效果是最好的。 本节先介绍按键扫描,理解按键的基本原理,下一章再介绍按键中断,同时了解STM32F103的中断使用方法。 按键一般占用一个GPIO口,通过监测该GPIO的电平变化得知按键操作,典型的电路如图 12.1.1 所示。当所需按键比较多时,则可以采用矩阵按键减
[单片机]
STM32单片机AD4630-24驱动程序
AD4630-24是亚德诺推出的一款24位双通道支持同步采样的ADC,高昂的售价注定了这不会是一款常用芯片,我在做驱动开发期间在中文互联网基本没有找到可以参考的资料或例程。但这次毕竟做的是一款高精度同步电压电流表,这款芯片是领导亲自选的,要求很明确,就是分辨率拉满,咱也只能硬着头皮开干。 这次也是分享以下驱动开发的思路和例程,希望能够帮助到相关人士,顺便,这款芯片要求5V和1.8V双电源供电也是让硬件同事疯狂吐槽。 1.通讯接口 AD4630-24支持串行通讯,为了提高采样结果的读取速率,SDO最高支持8通道同步输出,但很可惜这次使用的单片机是STM32F407,意法连QSPI都不给,只能使用标准的SPI接口通讯,例程也
[单片机]
STM32:GPIO使用总结
1、GPIO一图概述: (1)各种接口的措施 1.1 对于串口,假如最大波特率只需115.2k,那么用2M的GPIO的引脚速度就够了,既省电也噪声小。 1.2 对于I2C接口,假如使用400k波特率,若想把余量留大些,那么用2M的GPIO的引脚速度或许不够,这时可以选用10M的GPIO引脚速度。 1.3 对于SPI接口,假如使用18M或9M波特率,用10M的GPIO的引脚速度显然不够了,需要选用50M的GPIO的引脚速度。 1.4 GPIO口设为输入时,输出驱动电路与端口是断开,所以输出速度配置无意义。 1.5 在复位期间和刚复位后,复用功能未开启,I/O端口被配置成浮空输入模式。 1.6 所有端口都有外部
[单片机]
什么是stm32单片机
stm32f103c8t6单片机是高校学生使用的最频繁的单片机了,被广泛的应用在课程设计,电子设计大赛,毕业设计中。其拥有非常优异的性能,同时价格低廉,参考资料多,是广大学生非ban必选的mcu。 单片微型计算机简称单片机,简单来说就是集CPU(运算、控制)、RAM(数据存储-内存)、ROM(程序存储)、输入输出设备(串口、并口等)和中断系统处于同一芯片的器件,在我们自己的个人电脑中,CPU、RAM、ROM、I/O这些都是单独的芯片,然后这些芯片被安装在一个主板上,这样就构成了我们的PC主板,进而组装成电脑,而单片机只是将这所有的集中在了一个芯片上而已 。 或许大家有经常听起过最小系统板这个词儿,那么什么是最小系统板呢?其实最小系
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved