大号在练葵花宝典 发表于 2024-12-28 06:09:22

STM32——ADC篇(ADC的利用)

一、ADC的先容 

1.1什么是ADC
        ADC(Analogto-Digital Converter)模拟数字转换器,是将模拟信号转换成数字信号的一种外设。比如某一个电阻两端的是一个模拟信号,单片机无法直接采集,此时需要ADC先将短租两端的电压这个模拟信号转化成数字信号,单片机才气够进行处理。
1.2 ADC的用途

        ADC具有将模拟信号转换成数字信号的能力,比如将模拟的电压转换成数字信号,单片机进行处理。可以用作温度监测或者电流监测等方面,用途极广。
1.3 STM32F1系列的ADC先容 

        STM32F1的ADC为12位ADC,是一种逐次迫近型模拟数字转换器。它有多达18个通道,可丈量16个外部和2个内部 信号源。各通道的A/D转换可以单次、连续、扫描或中断模式执行。ADC的结果可以左对齐或右 对齐方式存储在16位数据寄存器中。 模拟看门狗特性答应应用程序检测输入电压是否超出用户定义的高/低阀值。 ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。
https://i-blog.csdnimg.cn/blog_migrate/9115f34a674ffe6e7c9246d5e4c95542.png
        STM32的ADC其转换时间为1us。 
二、STM32的ADC时钟先容

        下图是截取的时钟树关于ADC部分,至于时钟树可以在编程参考手册的56页找到或者直接搜索时钟树就可以找到了。 
        https://i-blog.csdnimg.cn/blog_migrate/d23228b44cebf415cf9c14bc0aae8962.png

       可以看见当时钟来源于APB2总线,其频率最大可以到达72MHz,而ADC的时钟最大只能为14MHz,故先颠末ADC预分频器经行6分频得到12MHz的时钟。
 三、ADC框图先容:

        对于ADC的框图,下图以经把各个功能模块以及分好了,见下图:
 https://i-blog.csdnimg.cn/blog_migrate/09431672ad3bc88416d35bf1a23b0928.png
3.1  ADC的18个通道先容        

        首先其16个外部通道接口对应着某些GPIO口,至于哪些就不先容了,可以检察引脚定义。
        而内部通道一个为内部温度传感器,可以用于检察CPU温度,另一个则是内部参考电压了,为一个1.2V左右的基准电压(不会随外部供电电压变化而变化)。有没有想过为什么ADC初始化需要校准呢?假如你芯片的供电电压不是标准的3.3V,那丈量外部引脚的电压就可能不对,这时就可以读取这个基准电压经行校准,就能得到正确的电压值了,这就是校准的作用。
3.2  ADC转换单位的先容

        规则组和注入组两个转换单位,在图中可以看见注入组最多四个通道,而规则组最多16个通道。如何选择这两种转换单位呢?下面我来阐明这两种的区别:
           
        首先是通道数:规则组可以包含最多16个转换,而注入组最多只能有4个转换。这意味着规则组适用于更多的通道同时进行转换,而注入组则更适合于次序执行的单次转换。注:注入通道虽然只有4个通道,但是每一个通道都有自己的数据寄存器,即注入组有四个数据寄存器。而规则组虽然有16个转换通道,但只有一个数据寄存器。
        利用场景:规则组通常用于大规模的连续转换条件下,而注入组则多用于执行单次的转换,仅在需要时进行转换。
        触发方式:注入组可以打断规则组的转换,具有更高的优先级。具体来说,假如注入组在规则组转换期间被触发,当前规则组的转换会被制止,并开始执行注入组的转换。注入组转换完成后,规则组的转换会继续。此外,注入组可以在规则通道之后自动进行转换,这种模式答应最多20个转换序列的组合,此中规则通道在前,注入通道在后。
        综上所述,规则组和注入组的选择取决于具体的应用需求和场景。规则组适合于需要连续、大规模数据采集的场景,而注入组则适用于需要快速响应、单次数据采集的情况。
3.3  模拟看门狗的先容

        模拟看门狗检测输入电压范围:用于检测ADC值,当检测值低于或高于某个阈值时,用来执行某些操纵(也就相称于报警,而监测不需要人为去看管,不需要自己手动读值再用if判定,相称于家里养了狗,有陌生人来了狗就会叫,而这个陌生人代指超阈值)。
3.4  ADC触发源的先容

        其触发源可以来自定时器、外部引脚以及软件控制位来触发。即两种触发源:软件触发以及外部触发(内部定时器、外部制止)。
        3.4.1  定时器触发:

        ADC在寻常利用过程中经常需要过一个固定时间转换一次,比如每个1ms转换一次,正常思路是在定时器制止中用软件控制位来控制触发。但是这样频仍进入制止对主程序是有一定影响的,当你有很多制止时由于优先级差别也会导致某些制止不能及时得到响应,还是有很大影响,以是对于这种需要频仍进入制止且在制止只完成简朴工作的情况的一般都有硬件的支持。在这里便可以这样利用:先给定时器设置定时时间,并把定时器更新变乱选择为TRGO输出,然后在ADC这里选择开始触发信号为定时器的TRGO,这样定时器的更新变乱就能自动触发ADC转换了且无需进入制止,节省了制止资源。
        3.4.2  外部制止触发

        外部制止可以产生一个触发脉冲,触发Adc转换。先设置EXTTRIG控制位,则外部变乱就能够触发转换。
        3.4.3  软件自动触发

        软件控制位触发
3.5  ADC时钟先容

        上文有先容到当时钟最大不超过14MHz,那么为什么有这个规定呢?
我们可以看到其ADC的转换时间为1us,假如其频率超过了14MHz,会导致转换时间少于1us,也就导致其采样不准确。ADC的总转换时间如下:
                                Tconv = 采样时间 + 12.5个周期;
例如:当其频率ADCCLK = 14MHz,采样时间为1.5个周期(最小为1.5个周期)见下图:
https://i-blog.csdnimg.cn/blog_migrate/be43758d0858c61a6c35b4bf7c3861b0.png
 那么此时转换时间为 :Tconv = 1.5 + 12.5 = 14个周期,而频率为14MHz,则时间T = 14 * (单个周期时间)1/14MHz = 1MHz,也就是1us。这下你应该明白了吧?
四、ADC转换模式的先容

        在ADC的配置过程中会遇到配置两个参数,即是否利用连续转换(ADC_ContinuousConvMode)以及是否启用扫描模式(ADC_ScanConvMode),而这两个配置也就产生了四种结果:单次转换非扫描、连续转换非扫描、单次转换扫描、连续转换扫描模式。
           单次转换:     只执行转换一次
        连续转换:      转换一次后立马进行下一次转换。
        非扫描模式:   只转换ADC_SQRx或ADC_JSQR选中的第一个通道。
        扫描模式:       一次性转换全部被选中的通道
下面先容ADC的几种转换模式:
4.1   单次转换非扫描模式

        即一次只转换选中的某一个通道,且只转换一次。其转换结果放在数据寄存器里面,给EOC标志位置1表现转换完成。想获取转换结果只需要判定EOC标志位,为1时便可以读取数据了。假如还想继续转换,就得重新再触发一次。
        假如想换一个通道转换就在转换之前将第一个位置的通道改成其他通再启动转换。
4.2  连续转换非扫描模式

        一次只转换选中的某一个通道,开始时只需要触发一次便可以不停转换。与上面的区别就是不需要你再次触发了,且读取AD值直接去数据寄存器里面取,无需判定转换是否结束。
4.3  单次转换、扫描模式

        即触发转换后只转换一次,每触发一次转换结束后就会停下来,再次转换得重新触发一次。单和单次转换非扫描模式的区别就是一次可以转换多个指定的通道,即按你指定的次序依次转换并放入到数据寄存器中。但数据寄存器只有一个,以是为了防止覆盖需要及时将数据挪走(不及时木挪走读取到的便是被后面通道所覆盖的数据)。当转换完成也会产生一个EOC信号,即转换结束。
4.4   连续转换扫描模式

        讲到这里你应该已经明白了,无非是单次转换扫描模式换成连续扫描而已。即一次转换完成继续下一次转换且可以转换多个通道而已。
五、ADC的对齐模式:

        由于此芯片的ADC为12位的,而数据寄存器为16位的,假如选择左对齐也就是相称于往左位移了4位,也就是扩大了AD采集结果。二进制特点就是数据左移一次就等效于把这个数据乘2,而左移4次也就是扩大了16倍了。
        而数据右对齐则没有这种情况,且寻常都是利用右对齐。
六、ADC配置流程

           1. GPIO的初始化(开启时钟包括ADC的时钟,配置为模拟输入)
        2. 选择ADC的预分频系数(很紧张!)
        3. ADC的初始化:ADC的模式(ADC_Mode:选择是否独立模式)、
                                     数据对齐(ADC_DataAlign:左对齐或右对齐)、
                                     外部触发转换选择(ADC_ExternalTrigConv:三种触发源)、
                                     是否为连续转换模式(ADC_ContinuousConvMode)、
                                     是否为扫描模式(ADC_ScanConvMode)、
                                     通道数量(ADC_NbrOfChannel)。最后初始化ADC_Init();
        4.  ADC通道配置: 选择通道以及采样时间
        5.  ADC使能以及校准:ADC_Cmd(ADCx,ENABLE);
        6.  使能或者失能指定的ADC的软件转换启动功能
七、ADC的代码例程展示

/*
*==============================================================================
*函数名称:ADC1_Init
*函数功能:初始化ADCx
*输入参数:无
*返回值:无
*备注:无
*==============================================================================
*/
void ADC1_Init(void)
{
        // 结构体定义
        GPIO_InitTypeDef GPIO_InitStructure;
        ADC_InitTypeDef ADC_InitStructure;
       
        // 开启时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1,ENABLE);
       
        // 设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);
       
        // GPIO配置
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;   //ADC1通道1
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;   // 模拟输入
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStructure);
       
        // ADC参数配置
        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;   // 独立模式
        ADC_InitStructure.ADC_ScanConvMode = DISABLE;   // 非扫描模式       
        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;   // 关闭连续转换
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;   // 禁止触发检测,使用软件触发
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;   // 右对齐       
        ADC_InitStructure.ADC_NbrOfChannel = 1;   // 1个转换在规则序列中 也就是只转换规则序列1
        ADC_Init(ADC1, &ADC_InitStructure);   // ADC初始化
       
    ADC_RegularChannelConfig(ADC1,ADC_Channel_1, 1, ADC_SampleTime_239Cycles5 );

        ADC_Cmd(ADC1, ENABLE);   // 开启AD转换器
       
        // ADC校准
        ADC_ResetCalibration(ADC1);   // 重置指定的ADC的校准寄存器
        while(ADC_GetResetCalibrationStatus(ADC1));   // 获取ADC重置校准寄存器的状态
       
        ADC_StartCalibration(ADC1);   // 开始指定ADC的校准状态
        while(ADC_GetCalibrationStatus(ADC1));   // 获取指定ADC的校准程序

        ADC_SoftwareStartConvCmd(ADC1, ENABLE);   // 使能或者失能指定的ADC的软件转换启动功能
}

uint16_t AD_GetValue(void)
{
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);//开启转换
        while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//等待转换完成标志位
        return ADC_GetConversionValue(ADC1);// 返回获取转换结果
}
这里附上一张ADC库函数图:
https://i-blog.csdnimg.cn/blog_migrate/b0db0cd5ecd72f12d7d21fa5a7a22e2c.jpeg
 由于扫描模式得配合DMA利用,否则数据来不及移走导致清空,以是这里先不先容,在下篇DMA的文章中将会先容。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: STM32——ADC篇(ADC的利用)