首页 > 嵌入式/内核开发 > 嵌入式/内核开发 > [蓝桥杯嵌入式有手就行]9_ADC
前言
一、内部结构
1、框图
2、ADC采集原理
二、ADC模块分析
1、原理图
2、ADC相关参数说明(stm32G431RB)
1、ADC频率
2、采样深度(分辨率)
3、采样时间
4、过采样
5、触发方式
6、工作方式
三、代码示例
1、cubemx配置
1、ADC配置
2、ADC时钟
3、DMA
4、中断
2、上代码
四、问题
1、通道问题
2、ADC测量不准确
总结
前言
注:本系列基于2023年蓝桥杯实战情况就行编写,所有软件均采用2023年赛点资源包
ADC比较简单,也不会考的很难,使用前记得校准就可以(不做也行,反正在误差范围内)。
一、内部结构
1、框图

这里涉及到我们对主频的选择,一般我采用80M主频,这样16分频后ADC的时钟在5Mhz,相对合适。

这里请注意区分规则通道和注入通道。举个简单的例子
规则通道:在食堂打饭时按照次序排队的人,最多16个通道。只有1个数据寄存器,每个寄存器长度为16bit。要及时取走数据,防止被后面的数据覆盖。
注入通道:校霸拥有特权,直接插队,最多只有4个。注入组有4个数据寄存器,每个寄存器长度为16bit
2、ADC采集 原理
ADC(Analogto-Digital Converter)模拟数字转换器,是将模拟信号转换成数字信号的一种外设。单片机如果要处理这些模拟信号,那就需要通过 ADC 将模拟信号转换成数字信号。
stm32G431内有两个ADC,每个ADC由一个12位逐次逼近型模数转换器组成。每个ADC有多达19个多路复用通道。各种通道的A/D转换可以在单、连续、扫描或不连续模式下执行。ADC的结果存储在左对齐或右对齐的16位数据寄存器中。
二、ADC模块分析
1、原理图

2、ADC相关参数说明(stm32G431RB)
这里只讨论stm32G431RB,其他型号请自行查看手册
1、ADC频率
这里网上有好多说不能超过14Mhz或者16Mhz的,但是又没有给出依据。我在查阅手册后,也没找到相关说明,只能明确一点,ADC可以分为直接、快速、慢速三种通道,不同通道最高速度不一样。

只有1-5通道的INN(Negative analog input channels for each ADC)才是快速通道。由此可知,PB15和PB12均为慢速通道。
数据手册中写到单个ADC的时钟频率可以到60Mhz。然而在参考手册中只能找到官方例子为30Mhz。当然,按目前题目来看,还没这么变态,5Mhz足以。高速采样时间短,波动会更大。

2、采样深度(分辨率)
通过ADC_CFGR的RES[1:0]设置采样深度
RES[1:0] resolution of the conversion
00 12 bit
01 10 bit
10 8 bit
11 6 bit
这里我们可以简单理解为划分成2的多少次份,以12bit为例:
ADC参考电压为3.3V,12bit即4096份,每份0.8mV。
3、采样时间
我们可以通过设置SMP[2:0] bits 来设置采样时间
SMP ADC clock cycles
00 0 2.5
00 1 6.5
01 0 12.5
01 1 24.5
10 0 47.5
10 1 92.5
11 0 247.5
11 1 640.5
转换时间:Tconv=(采样时间+采样深度+0.5)ADC clock cycles
按照我常用的5M采样频率,也就是每个周期200ns,通常我们采用最长时间即640.5个周期的采样时间和12 bit的深度来获得相对准确的数值。这样我们需要653个周期,也就是一次采样耗费130.6us。
一般按照题目,我们显示更新周期也就100ms左右(一般按键响应是100ms以内)。足足相差700多倍,所以我们可以使用较低的速度来获得更高的精度和稳定性。
4、过采样
就目前的精度要求,8位精度足以,但是还是得防一手。
过采样就是一种用速度换性能的技术,G431支持硬件过采样,我们可以通过这个技术将ADC的分辨率提升到16位。这里详细的请看参考手册21.4.29小节。

我们每提高一位分辨率,就需要增加4倍的采样率。还是以上一小节的数据为例,12bit一次采集需要130.6us,我们提升到13bit后就需要130.6* 4=522.4us,提升到16bit,就需要130.6*4^4=33.4336ms。
个人觉得当ADC转换时间超过10ms的时候,我们就需要考虑启用DMA,来节省每次等待ADC转换完成耗费大量的时间。
注意:256倍过采样后结果位20位,寄存器只有16位,我们需要右移4位
5、触发方式
触发方式 说明
软件触发 通过向 ADC-CR2 寄存器的 AD ON 位写1来开启转换
硬件触发 可以是定时器(TIM)触发、外部引脚(EXIT)触发。
6、工作方式
扫描:按照顺序依次对每个开启的通道执行转换
非扫描:不管有多少个,只转换那个优先级最高的
单次转换:一次启动,就只转换一次(不是只转换一个通道),然后停止,直到下一次开始转换的命令
连续转换:转换完成后立即回到开始的位置继续转换
三、代码示例
1、cubemx配置
1、ADC配置


2、ADC时钟

上一节中的ADC时钟设置为异步后,这里才可以调节,但是我建议还是使用SYSCLK分频获得。
3、DMA
这里看情况,到目前为止,就比赛而言好像还用不上。

4、中断

别忘了开就行
2、上代码
HAL_ADC_Start(&hadc2); HAL_ADC_PollForConversion(&hadc2,10);//10表示等待时间,要大于转换时间 v=HAL_ADC_GetValue(&hadc2); HAL_ADC_Stop(&hadc2); HAL_ADC_Start_DMA(&hadc1,(uint32_t *)&adc_buf,16); //最后一位Length:Number of data to be transferred from ADC peripheral to memory
这里ADC1开启了DMA,ADC2没有开启,两种写法都列出来了。
四、问题
1、通道问题
实际上ADC内部有19个通道,但是我们只能使用其中16个,可以看二、2、2的图,我们可能用的上的也就这个了。

2、ADC测量不准确
我们只需要在main函数ADC初始化后添加
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);
然后务必延时一段时间,等待其完成校准。
一个程序只需要做一次
总结
以上就是ADC部分的内容了,使用时务必计算清楚转换耗时,一般情况下预留1ms足以。然后就是要搞清楚优先级。否则可能转换的不是我们需要的。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70050091/viewspace-3117701/ ,如需转载,请注明出处,否则将追究法律责任。