• 个人笔记-ADC


    笔记来源于STM32F103VET6,野火指南者,中文参考手册,HAL库开发手册和b站的野火指南者中级篇视频。观看过好多次中级篇了,但往往理解得不够全面,现记下小笔记,用来回顾。属于个人笔记,不用于商业。​​​​​

    ADC,模数转换。在STM32F103VET6中,有3个ADC,精度为12位,每个ADC最多有16个通道。其中ADC1和ADC2都有16个外部通道,ADC13根据CPU引脚的不同通道数也不同,一般都有8个外部通道。

    ADC框图

    对于框图第一点, ADC的输入范围:VREF-<VIN<VREF+。

    在设计原理图时一般把VREF-和VSSA接地,VREF+和VDDA接3.3V,使得ADC的输入范围在0~3.3V。

    如果想让输入范围变宽,使得可以测试负电压或更高的正电压,我们可以在外部加一个电压调理电路,把需要转换的电压抬升或者降低到0~3.3V。

    对于框图第二点,ADC的输入通道。

    对于框图第三点,ADC的通道细分。

    外部的16个通道在转换的时候又分为规则通道和注入通道,其中规则通道最多有16路,注入通道最多有4路。

    如果在规则通道转换过程中,有注入通道插队,那么就要先转换完注入通道,等注入通道转换完成后,再回到规则通道的转换流程。所以,注入通道只有在规则通道存在时才会出现。

    对于框图的第四点,ADC的转换顺序。

    如果 JL 的值小于 4 的话,则 JSQR SQR 决定转换顺序的设置不一样,第一次转换的不是 JSQR1[4:0], 而是 JCQRx[4:0] x = 4-JL),跟 SQR 刚好相反。

    如果 JL=00(1 个转换),那么转换的顺序是从 JSQR4[4:0] 开始,而不是从 JSQR1[4:0] 开始,这个要注意,编程的时候不要搞错。当 JL 等于 4 时,跟 SQR 一样。

    对于框图的第五点,ADC的触发源。

    ADC的转换控制可以是ADC_CR2:ADON位控制。

    0表示关闭ADC转换/校准,并进入断电模式。

    1表示开启ADC并启动转换。

    ADC的转换控制还可以是触发转换。包括了内部定时器触发和外部IO触发。由ADC_CR2:EXTSEL[2:0]和JEXTSEL[2:0]位控制。

    ADC_CR2:EXTSEL[2:0]用于选择规则通道的触发源。

    ADC_CR2:JEXTSEL[2:0]用于选择注入通道的触发源。

    激活触发源由ADC_CR2:EXTTRIG和JEXTTRIG位控制。

    其中ADC3的规则转换和注入转换的触发源与ADC1和ADC2有所不同。

    对于框图的第六点,ADC的转换时间。

    ADC输入时钟ADC_CLK由PCLK2 经过分频产生,最大是 14M,分频因子由RCC_CFGR:ADCPRE[1:0] 设置,可以是 2/4/6/8 分频,注意这里没有 1 分频。一般我们设置 PCLK2=HCLK

    =72M。

    ADC 使用若干个 ADC_CLK 周期对输入的电压进行采样,采样的周期数可通过ADC_SMPR1、ADC_SMPR2 中的 SMP[2:0] 位设置,ADC_SMPR2 控制的是通道 0~9, ADC_SMPR1 控制的是通道 10~17。每个通道可以分别用不同的时间采样。其中采样周期最小是 1.5 个,即如果我们要达到最快的采样,那么应该设置采样周期为 1.5 个周期,周期就是 1/ADC_CLK

    ADC 的转换时间跟 ADC 的输入时钟和采样时间有关,公式为:Tconv = 采样时间 + 12.5 个周期。

    ADCLK = 14MHZ(最高),采样时间设置为 1.5 周期(最快),那么总的转换时间(最短)Tconv = 1.5 周期 + 12.5 周期 = 14 周期 = 1us

    一般我们设置 PCLK2=72M,经过 ADC 预分频器能分频到最大的时钟只能是 12M,采样周期设 置为 1.5 个周期,算出最短的转换时间为 1.17us,这个才是最常用的。

    对于框图的第七点,ADC的数据寄存器。

    规则组的数据放在 ADC_DR 寄存器, 注入组的数据放在 ADC_JDRx寄存器。

    ADC_DR寄存器只有一个,32位。低16位在单ADC时使用,高16位在双ADC模式时保存ADC2转换的规则数据。在单模式下,ADC1、ADC2和ADC3的都不使用高16位。

    因为ADC的精度是12位,所以ADC_DR的高16位和低16位都放不满。所以可以选择对齐方式,由ADC_CR2:ALIGN设置。

    规则通道可以有 16 个这么多,可规则数据寄存器只有一个,如果使用多通道转换,那转换的数据就全部都挤在了 DR 里面,前一个时间点转换的通道数据,就会被下一个时间点的另外一个通道转换的数据覆盖掉,所以当通道转换完成后就应该把数据取走,或者开启 DMA 模式,把数据传输到内存里面,不然就会造成数据的覆盖。最常用的做法就是开启 DMA 传输。

    ADC 注入组最多有 4 个通道,刚好注入数据寄存器也有 4 个,每个通道对应着自己的寄存器,不会跟规则寄存器那样产生数据覆盖的问题。注入组配置的话和规则组一样。

    中断

    规则通道转换结束

    可以产生规则通道转换结束中断,还可以产生DMA请求,把转换好的数据存储在内存里面。要注意的是,只有ADC1和ADC3可以产生DMA请求。一般我们在使用ADC的时候都会开启DMA传输。

    注入通道转换结束

    可以产生注入通道转换结束中断,还可以产生DMA请求,把转换好的数据存储在内存里面。要注意的是,只有ADC1和ADC3可以产生DMA请求。一般我们在使用ADC的时候都会开启DMA传输。

    模拟看门狗

    转换后的模拟电压低于低阈值或者高于高阈值时,就会产生中断。

    前提是我们开启了模拟看门狗中断,其中低阈值和高阈值由 ADC_LTR寄存器和ADC_HTR寄存器设置。

    例如我们设置高阈值是2.5V,那么模拟电压超过 2.5V 的时候,就会产生模拟看门狗中断,反之低阈值也一样。

    数据读取

    可以通过中断读取,通过中断服务函数保存数据。

    可以通过DMA读取,保存数据在内存中。

    使用中断的优点:读取的数据较少或读取速度较慢的,可以用中断。

    使用DMA的优点:速度快。方便,不需要写中断服务函数。

    电压转换

    模拟电压经过ADC转换后,是一个12位的数字值。在设计原理图时一般把VREF-和VSSA接地,VREF+和VDDA接3.3V,使得ADC的输入范围在0~3.3V。

    因此12位满量程(2^12)-3.3V,0-0V。

    如果转换后的数值为X,X对应的模拟电压为Y,那么:Y/X=3.3/4096。Y=3.3X/4096。

    ADC的初始化结构体解析

    1. typedef struct
    2. {
    3. uint32_t ADC_Mode; //工作模式
    4. FunctionalState ADC_ScanConvMode; //扫描(多通道)or 单次(单通道)模式
    5. FunctionalState ADC_ContinuousConvMode; //连续转换 or 单次转换
    6. uint32_t ADC_ExternalTrigConv; //转换触发信号选择
    7. uint32_t ADC_DataAlign; //数据寄存器对齐方式
    8. uint8_t ADC_NbrOfChannel; //采集通道数
    9. }ADC_InitTypeDef;

    对于ADC_Mode

    1. #define ADC_Mode_Independent ((uint32_t)0x00000000) //独立模式,一般单ADC时使用。
    2. #define ADC_Mode_RegInjecSimult ((uint32_t)0x00010000) //混合的同步规则+注入同步模式
    3. #define ADC_Mode_RegSimult_AlterTrig ((uint32_t)0x00020000) //混合的同步规则+交替触发模式
    4. #define ADC_Mode_InjecSimult_FastInterl ((uint32_t)0x00030000) //混合同步注入+快速交叉模式
    5. #define ADC_Mode_InjecSimult_SlowInterl ((uint32_t)0x00040000) //混合同步注入+慢速交叉模式
    6. #define ADC_Mode_InjecSimult ((uint32_t)0x00050000) //注入同步模式
    7. #define ADC_Mode_RegSimult ((uint32_t)0x00060000) //规则同步模式
    8. #define ADC_Mode_FastInterl ((uint32_t)0x00070000) //快速交叉模式
    9. #define ADC_Mode_SlowInterl ((uint32_t)0x00080000) //慢速交叉模式
    10. #define ADC_Mode_AlterTrig ((uint32_t)0x00090000) //交替触发模式

    对于ADC_ScanConvMode:ENABLE or DISABLE。

    对于ADC_ContinuousConvMode:ENABLE or DISABLE。

    对于ADC_ExternalTrigConv

    1. #define ADC_ExternalTrigConv_T1_CC1 ((uint32_t)0x00000000) //对于ADC1和ADC2
    2. #define ADC_ExternalTrigConv_T1_CC2 ((uint32_t)0x00020000) //对于ADC1和ADC2
    3. #define ADC_ExternalTrigConv_T2_CC2 ((uint32_t)0x00060000) //对于ADC1和ADC2
    4. #define ADC_ExternalTrigConv_T3_TRGO ((uint32_t)0x00080000) //对于ADC1和ADC2
    5. #define ADC_ExternalTrigConv_T4_CC4 ((uint32_t)0x000A0000) //对于ADC1和ADC2
    6. #define ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO ((uint32_t)0x000C0000) //对于ADC1和ADC2
    7. #define ADC_ExternalTrigConv_T1_CC3 ((uint32_t)0x00040000) //对于ADC1、ADC2和ADC3
    8. #define ADC_ExternalTrigConv_None ((uint32_t)0x000E0000) //对于ADC1、ADC2和ADC3,不需要外部触发,软件来开启
    9. #define ADC_ExternalTrigConv_T3_CC1 ((uint32_t)0x00000000) //对于ADC3
    10. #define ADC_ExternalTrigConv_T2_CC3 ((uint32_t)0x00020000) //对于ADC3
    11. #define ADC_ExternalTrigConv_T8_CC1 ((uint32_t)0x00060000) //对于ADC3
    12. #define ADC_ExternalTrigConv_T8_TRGO ((uint32_t)0x00080000) //对于ADC3
    13. #define ADC_ExternalTrigConv_T5_CC1 ((uint32_t)0x000A0000) //对于ADC3
    14. #define ADC_ExternalTrigConv_T5_CC3 ((uint32_t)0x000C0000) //对于ADC3

    对于ADC_DataAlign:ADC_DataAlign_Right 、ADC_DataAlign_Left 。

    对于ADC_NbrOfChannel:1~16。

    ADC的一般配置流程:

    初始化ADC的GPIO。

    初始化ADC初始化结构体。

    配置ADC时钟,配置通道的转换顺序和采样时间。

    1. RCC_ADCCLKConfig(RCC_PCLK2_Div8);
    2. ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, ADC_SampleTime_55Cycles5);

    使能ADC转换完成中断,配置中断优先级。

    ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE);

    使能ADC,准备开始转换。

    校准ADC。

    1. // 初始化ADC 校准寄存器
    2. ADC_ResetCalibration(ADCx);
    3. // 等待校准寄存器初始化完成
    4. while(ADC_GetResetCalibrationStatus(ADCx));
    5. // ADC开始校准
    6. ADC_StartCalibration(ADCx);
    7. // 等待校准完成
    8. while(ADC_GetCalibrationStatus(ADCx));

    软件触发ADC,真正开始转换。

    ADC_SoftwareStartConvCmd(ADCx, ENABLE);

    编写中断服务函数,读取ADC转换数据。

    编写main函数,把转换的数据打印出来。 

  • 相关阅读:
    计算机毕设(附源码)JAVA-SSM基于数据可视化的少儿编程
    解决局域网内因为不在同一网段无法ping通的问题
    Spring In Action 5 学习笔记 chapter4 Spring Security部分关键点
    Vue中自定义实现类似el-table的表格效果实现行颜色根据数据去变化展示
    Http实战之编码、分块传输、范围请求
    Flink中的时间和窗口(三)
    (八)、基于 LangChain 实现大模型应用程序开发 | 基于知识库的个性化问答 (检索 Retrieval)
    贪心——122. 买卖股票的最佳时机 II
    java基于微信小程序的知识分享科普管理系统 uniapp小程序
    spider 网页爬虫中的 AWS 实例数据获取问题及解决方案
  • 原文地址:https://blog.csdn.net/weixin_47077788/article/details/125463763