ADC (Analog Digital converter)
模拟 数字转换器 ,ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁
(当然,有ADC模数转换就有DAC数模转换,但是STM32只有ADC模数转换,不过我个人认为STM32的PWM输出比较也算DAC)
STM32的ADC是 12位逐次逼近型的ADC(12位表示范围0~2的十二次方,再减一,也就是0~4095),1us的转换时间(1us表示,从AD转换开始,到产生结果,需要1us的时间,对应AD转换频率就是1MHZ),输入电压范围 0~3.3V,转换结果范围 0~4095,这两个成一一对应的线性关系,0~4095有4096个数,每个数都对应一个电压值,所以只要输入的电压信号在0~3.3V之间变化,对应的转换结果也跟着相应变化
逐次逼近型ADC的原理
ADC0809是一个外接的模数转换器,它就是逐次逼近型,STM32的ADC逐次逼近和这个差不多,我就用这个外接的模数转换器来做参考
左边是输入通道,引脚输入模拟型号,到达比较器,同时内部的DAC也输入一个可变的模拟电压到比较器(这个内部DAC是数模拟转换器,写入数字信号,它就会转换为模拟信号),输入的模拟信号和内部DAC产生的模拟信号做比较,因为内部的DAC模拟信号是随着(逐次逼近寄存器SAR)写入的数字信号不断变化,当DAC模拟信号变化到和外部引脚的模拟信号近似相等的时候,就将内部DAC逐次逼近寄存器SAR的数字信号锁存到缓冲器,写入的数字信号也就相当于外部引脚模拟信号转换成的数字信号
模拟信号的输入通道,ADC输入通道有18个输入通道,可测量16个外部信号源和2个内部信号源,但是我用的STM32F103C8T6的型号只有10个外部型号源,不同的型号的通道个数需要查看手册,其中刚刚说的16个外部型号源,是指不需要任何额外的电路,直接测量的引脚上的模拟电压,2个内部信号源,是内部温度传感器和内部参考电压,内部温度传感器可以测量CPU的温度,内部参考电压是一个1.2V的基准电压,它不随外部供电变化而变化,,如果芯片不是标准的3.3V,测量的外部引脚就有可能不准确,那么就可以用这个基准电压进行校准,就能得到正确的电压值
其中,还可以用模拟看门狗来检测电压的范围,可以设置超出阈值中断触发
STM32的ADC基本框图
左边GPIO口通过选择通道,选择注入组还是规则组转换,模拟至数字转换器也就是上面讲到的ADC0809那个类似的流程,最后转换的结果写入上面的寄存器,细心的话就能注意,注入通道最多可以有4个输入通道,规则组最多可以有16个输入通道,也就是把这些通道放到一个组里面,一次性转换,但是!!规则组只有一个寄存器,如果有多个通道到规则组,那么寄存器里面只会保留一个组里面最后那个通道的转换数据,前面的会被覆盖,如果想组里面每个通道的数据都转换,那么就要使用DMA进行数据转运存储起来,注入组输入的4个通道都能转换并写到到存储器里,注入组有4个数据寄存器,所以不用担心数据覆盖的问题
置标志位部分
规则组通道寄存器转换完成会置标志位,———EOC,注入组通道完成转换也会置标志位,————JEOC,还有一个模拟看门狗,可以设置注入组或者规则组寄存器数据的阈值,超过设置的阈值或者低于设置的阈值,看门狗就会置标志位产生中断,最后通道NVIC,最后,这三个置标志位后,可以通过函数检测有没有置标志位,判断标志位状态,可以产生中断到NVIC,如果开启了NVIC对应的通道,就能实行相应的中断程序
最后给一个总结的ADC基本结构图,上面的图简化的
写程序的时候,按照个这个流程配置就好了
流程就是 :左边是16个外部通道GPIO口,外加两个内部通道,然后进入AD转换器,可以根据需求选择规则组和注入组,转换完成的数据存入AD数据寄存器,规则组只能存一个数据,注入组可以存4个数据,数据转换完成后会置一个标志位EOC,也可以经过中断输出控制通向NVIC,还能配置一个模拟看门狗,检测转换结果的范围,如果超出设定的阈值,就能通过中断输出控制,到NVIC申请中断,调用函数触发,硬件触发主要是来自定时器,也可以选择外部中断的引脚。右边是RCC的ADC时钟CLOCK,ADC逐次比较的过程就是由这个时钟推动的。最后还有一个开关控制,在库函数中,是调用ADC_Cmd函数来给ADC上电的
STM32增强功能 规则组和注入组
普通的ADC转换是,启动一次转换,读一次值,再启动,再读值,STM32的ADC转换可以列一个组,一次性启动一个组,连续转换多个值,这个组分为规则组和注入组
规则组
规则组最多可以同时进入16个通道,但是寄存器只能存一个通道的转换值,所以如果有多个通道同时接入规则组,寄存器只存最后一个通道转换的值,前面的会被覆盖,但是有解决办法,就是每个通道转换完之后,立马用DMA把寄存器的数据给转移走,到别的地方存储起来就行了
分为四种模式。1:单次转换,扫描模式 2:单次转换,非扫描模式
3:连续转换,扫描模式 4:连续转换,非扫描模式
1:单次转换扫描模式
扫描的意思是,假如接入了一个以上的通道,挨着顺序,从序列一的通道挨个转换,直到转换到最后一个通道为止。单次转换的意思是,通道扫描转换完之后,转换结束,停止转换。
2:单次转换,非扫描模式
非扫描意思是,只扫描转换序列1的通道,转换结束置标志位EOC。 单次转换的意思是,通道扫描转换完之后,转换结束,停止转换。
3:连续转换,扫描模式
扫描模式,就是从序列1的通道,挨个扫描转换,直到扫描完所有通道,置标志位EOC。连续转换,最后一个通道扫描完成之后,又重新从序列1的通道挨个扫描转换,一直持续下去
4:连续转换,非扫描模式
非扫描模式,只扫描转换序列1的通道,扫描完成后置标志位EOC并把数据传到寄存器 ,连续转换,所有通道扫描完成后,又重新从第一个通道开始扫描,一直持续下去.当然这里是非扫描模式,只扫描了序列1的通道,序列1的扫描转换完后,因为是连续转换,又继续扫描序列1的通道,一直不停转换下去
这个模式很重要,写程序配置参数的时候会选模式
最后还有一个小知识点,一开始我们提到了STM32的ADC是12位的逐次逼近型ADC,所以,转换出来的结果,也是12位的,但是!!STM32的寄存器是16位的,那应该怎么放,我们有两种规定的对齐方式,数据左对齐,数据右对齐
数据右对齐,12位的数据向右靠,左边多出来的空位补0
数据左对齐,12位的数据向左靠,右边多出来的空位补0
一般使用数据右对齐,这样读取的16位寄存器,直接就是转换结果,如果选择数据左对齐,直接读寄存器的话,得到的数据会比实际的大,数据左对齐,相当于把数据左移了4次,二进制的特点就是,左移一次,就等效于把这个数据乘2,这里左移4次,相当于结果乘了16,直接读的话,结果会比实际大16倍,数据左对齐的用途我暂时还不了解,一般用右对齐
最后大致了解一下转换时间的公式
好了,老样子,过一遍ADC的代码部分
按照结构图打通
1:开启RCC时钟,包括ADC和GPIO的时钟,另外ADCCLK的分频器,也需要配置
2:配置GPIO,把要用的GPIO配置成模拟输入模式
3:配置多路开关,把左边的通道接入到右边的规则组列表里
4:配置ADC转换器,调用库函数,用结构体配置
5:调用ADC_Cmd函数,给ADC上电
6:根据手册的建议,开始ADC后,还要对ADC进行校准,减小误差
void AD_Init(void)
{
选择通道0,放入序列1,最后通道采样时间我们随便同一个,要求高的话可以根据需求填其他值
第一个Mode是ADC的工作模式,是ADC独立模式还是双ADC模式,根据需求选择
第二个数据对齐,左对齐还是右对齐
第三,外部触发转换选择,也就是触发源选择
第四,选择连续还是单次
第五,选择扫描模式
第六,通道数目,用了几个通道就写几
ADC校准
ADC大致初始化代码就这样,谢谢观看