为什么进不了中国建设银行网站icp备案添加网站
为什么进不了中国建设银行网站,icp备案添加网站,合肥网站建设q.479185700惠,百度可以做网站吗0. 江协科技/江科大-STM32标准库开发-各章节详细笔记-查阅传送门_江协科技stm32笔记-CSDN博客文章浏览阅读2.9k次#xff0c;点赞44次#xff0c;收藏128次。江协科技/江科大-STM32标准库开发-各章节详细笔记-传送门至各个章节笔记。基本上课程讲的每句都详细记录#xff0c…0. 江协科技/江科大-STM32标准库开发-各章节详细笔记-查阅传送门_江协科技stm32笔记-CSDN博客文章浏览阅读2.9k次点赞44次收藏128次。江协科技/江科大-STM32标准库开发-各章节详细笔记-传送门至各个章节笔记。基本上课程讲的每句都详细记录方便回顾。_江协科技stm32笔记https://blog.csdn.net/m0_61712829/article/details/132434192?spm1001.2014.3001.5501
目录
一、ADC模数转换器知识点
ADC简介
逐次逼近型ADC芯片ADC0809
STM32的逐次逼近型ADC
STM32的ADC框图
STM32的ADC基本结构总结
STM32的ADC输入通道和引脚的关系
STM32的ADC规则组的四种转换模式
STM32的ADC规则组的触发源
数据对齐
AD转换时间
ADC校准
ADC的外围电路
二、 AD单通道AD多通道应用程序示例
ADC 常用库函数
ADC 单通道转换
ADC 多通道转换 一、ADC模数转换器知识点
精华ADC其实就像是一个电压表把引脚的电压测出来放在一个变量里这就是ADC的作用。
ADC简介
ADCAnalog-Digital Converter模拟-数字转换器简称模数转换器或AD转换器ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量建立模拟电路到数字电路的桥梁。1.STM32主要是数字电路数字电路只有高低电平没有几v电压的概念所以想读取电压值就需要借助adc模数转换器来实现adc读取引脚上的模拟电压转换为一个数据存在寄存器里我们再把这个数据读取到变量里来就可以进行显示、判断、记录等操作了2.数字到模拟的桥梁是DAC数字模拟转换器使用DAC就可以将数字变量转换为模拟电压PWM也是数字到模拟的桥梁PWM实现的就是DAC的功能同时PWM只有完全导通和完全断开两种状态在这两种状态上都没有功率损耗所以在直流电机调速这种大功率的应用场景使用pwm来等效模拟量是比DAC更好的选择并且pwm电路更加简单更加常用所以pwm还是挤占了dac很多的应用空间目前dac的应用主要是在波形生成领域比如信号发生器、音频解码芯片等这些领域pwm还是不好代替的
12位逐次逼近型ADC1us转换时间。逐次逼近型是ADC的工作模式12位和1us涉及到adc的俩个关键参数第一个是分辨率一般用多少位来表示12位ad值表示范围就是0~2^12-1就是量化结果的范围0~4095位数越高量化结果就越精细对应分辨率就越高第二个是转换时间就是转换频率ad转换是需要花一小段时间的这里1us就是表示从ad转换开始到产生结果需要花1us的时间对应ad转换的频率就是1MHz1MHz的周期是1微秒是stm32的adc最快转换频率如果你需要转换一个频率非常高的信号那就需要考虑一下这个转换频率是不是够用如果你的信号频率比较低那这个最大1MHz的转换频率也完全够用输入电压范围0~3.3V转换结果范围0~4095。adc的输入电压一般要求是在芯片供电的负极和正极之间变化的0v对应03.3v对应4095中间都是一一对应的线性关系18个输入通道可测量16个外部和2个内部信号源。外部信号源就是16个gpio口在引脚上直接接模拟信号就行了不需任何额外的电路引脚就直接能测电压2个内部信号源是内部温度传感器和内部参考电压温度传感器可以测量cpu的温度比如你电脑可以显示一个cpu的温度就可以用adc读取这个温度传感器来测量内部参考电压是一个1.2v左右的基准电压这个基准电压是不随外部供电电压变化而变化的所以如果你芯片的供电不是标准的3.3v那测量外部引脚的电压可能就不对这时就可以读取这个基准电压进行校准这样就能得到正确的电压值了规则组和注入组两个转换单元。是stm32 adc的增强功能普通的ad转换流程是启动一次转换读一次值然后再启动再读值这样的流程stm32的adc可以列一个组一次启动一个组连续转换多个值并且有两个组一个是用于常规使用的规则组一个是用于突发事件的注入组模拟看门狗自动监测输入电压范围。一般可以用于测量光线强度温度这些值并且经常会有个需求就是如果光线高于某个阈值/低于某个阈值或者温度高于某个阈值/低于某个阈值执行一些操作这个高于某个阈值/低于某个阈值的判断就可以用模拟看门狗来自动执行模拟看门狗可以监测指定的某些通道当ad值高于设定的上阈值或低于下阈值时它就会申请中断就可以在中断函数里执行相应的操作这样就不用不断地手动读值再用if进行判断了STM32F103C8T6 的ADC资源ADC1、ADC210个外部输入通道。最多支持16个外部信号源若想用更多的外部通道可以选择引脚更多的型号具体有多少个通道可以参考数据手册 补充get # 电位器滑动变阻器用电位器可产生一个0-3.3v连续变化的模拟电压信号用stm32内部的ADC读取电压数据显示在屏幕上可以读取AD转换后的原始数据和经过处理后实际的电压值 # stm32的ADC是12位的所以AD结果最大值是4095也就是2^12-1对应的电压是3.3v 对于单片机的普通GPIO来说只能读取引脚的高低电平要么是高电平要么是低电平只有两个值而使用了ADC之后我们就可以对高电平和低电平之间的任意电压进行量化最终用一个变量来表示读取这个变量就可以知道这个引脚的具体电压到底是多少了所以ADC其实就是一个电压表把引脚的电压测出来放在一个变量里这就是ADC的作用。
逐次逼近型ADC芯片ADC0809
下图为逐次逼近型adc的内部结构了解这个结构对你学习stm32的adc有很大帮助因为stm32的adc原理和这个是一样的但是是他们32只画了一个框表示adc并没有描述内部结构所以先介绍一下这个结构这样再理解stm32的adc就会简单一些下图为adc0809的内部结构图。 ADC0809是一个独立的8位逐次逼近型ADC芯片。它拥有IN0~IN78个输入通道通过地址锁存器和译码器电路实现对通道的选择且每一次转换通道选择开关只能转换一个通道的信号输入通道选择这部分相当于一个可以通过模拟信号的数据选择器。ADC转换的速度非常快从信号转换开始到结束只需要几个us的时间如果想转换多路信号不必设计多个ADC只需要在每一次转换前通过多路选择开关选择要转换的通路即可。 STM32的ADC拥有18个输入通道与这里的输入通道选择部分8个输入通道的结构相对应。 接下来如何知道这个电压对应的编码数据是多少呢就需要用逐次逼近的方法一一比较了。 电压比较器可以判断两个输入信号电压的大小关系输出一个高低电平指示谁大谁小两个输入端一个是待测电压另一个是DAC的电压输出端给dac一个数据它就可以输出数据对应的电压若dac输出的电压比较大就调小dac数据若dac输出电压比较小就增大dac数据直到dac输出电压和外部通道输入的电压近似相等这样dac输入的数据就是外部电压的编码数据了这就是dac的实现原理这个电压调节的过程就是逐次逼近SAR来完成的。 ADC内部拥有一个DAC模块其内部是通过加权电阻网络实现模数转换可以将逐次逼近寄存器SAR的值转换为对应的模拟电压值将其电压值再与待测电压相比较比较结果控制SAR中存储的值直到DAC输出的电压与外部通道输入的电压近似相等DAC输入的数据就是外部电压的编码数据了。为了最快找到未知编码的电压通常使用二分法进行查找。且使用二分法查找未知电压的编码的好处在于每次选择比较的值2^n恰好为对应二进制数字的每一位的权数判断过程相当于从高位到底位依次判断为1还是为0的过程这就是逐次逼近型名字的来源。要找到未知编码的电压8位ADC需要判断8次12位ADC需要判断12次这就是逐次逼近的过程。转换结束后dac的输入数据就是未知电压的编码通过8位数字输出端口D0~D7进行输出。 结构图上方的EOCEnd Of Convert是转换结束信号。该芯片通过START端口控制转换开始给一个输入脉冲开始转换CLOCK是adc时钟因为adc内部是一步一步进行判断的所以需要时钟来推进这个过程控制ADC内部的转换工作频率。V ref ( ) 和V ref ( − ) 是DAC的参考电压定义数据对应的电压范围比如255对应3.3V还是5V这个dac的参考电压也决定了adc的输入范围所以它也是adc参考电压。最后左边vcc和gnd是整个芯片的供电通常参考电压的正极和VCC是一样的会接在一起参考电压的负极和gnd是一样的也接在一起所以一般情况下adc输入电压的范围和adc的供电是一样的。
STM32的逐次逼近型ADC
STM32的ADC框图 一般在手册里每个外设的最前面都有一个整体的结构图这个结构图还是非常重要的需要多花时间看看。 STM32中ADC的结构框图如上图所示。总共有18个输入通道包括16个gpio口和2个内部通道内部温度传感器和内部参考电压。模拟多路开关可以指定我们想要的通道右边是多路开关的输出进入到模数转换器这里模数转换器就是执行刚讲的逐次比较的过程转换结果会直接放在数据寄存器里读取寄存器就能知道adc转换的结构了。
对于普通的adc多路开关一般都是只选中一个就是选中一个通道、开始转换、等待转换完成、读取结果这是普通的流程。而stm32的多路开关就比较高级可以同时选中多个而且在转换的时候还分成了两个组规则组和注入组其中规则组可以一次性最多选中16个通道注入组最多可以选中4个通道。
其“模拟至数字转换器”模块的工作模式与ADC0809在原理上完全相同。不同点有以下几点
普通的ADC多路开关一般只选中一个STM32的ADC可以同时选中多个通道进行转换规则组最多同时选中16个通道注入组一次最多可以选中4个通道。以餐厅点菜模型为例普通模式为每次点一个菜做好菜后上菜STM32可以做到每次列出一个菜单规则组一次最多可以列16个菜注入组一次最多可以列4个菜做好后依次上菜STM32中的ADC的转换结果会被存储在对应的数据寄存器中。对于规则组通道其只有一个数据寄存器餐桌上只能摆一个菜后转换的数据会将之前转换的数据覆盖之前转换的数据就会丢失。对于规则组通道要想实现同时转换的功能最好配合DMA来将转换后的数据及时转运DMA可以在每上一个菜之后把这个菜挪到其它地方去防止被覆盖就可以保证转换的数据不会丢失了。对于注入组通道它拥有4个数据寄存器餐厅的VIP坐席餐桌上一次可以摆四个菜。对于注入组而言就不用担心数据覆盖的问题了。一般情况下使用规则组和DMA就可以满足大部分的使用需求。所以接下来主要讲规则组注入组涉及的不多可以看手册自行了解结构图的左下角为触发转换信号对应ADC0809的START信号。STM32的触发转换信号来源有两种软件触发和硬件触发。软件触发就是在程序中手动调用一条代码就可以启动转换了。硬件触发信号可以来自于定时器的各个通道、定时器TRGO定时器主模式的输出外部中断EXTI。在STM32中V R E F ( ) 一般和V DDA ADC模块的正极供电引脚接在一起V R E F ( − ) 一般和V SSA ADC模块的负极供电引脚接在一起。本课程使用的芯片没有单独的V REF() 和V REF(−) 的引脚它在芯片内部就已经和对应引脚连接在一起了。V DDA 和V SSA 是STM32模拟部分的电源例如ADC、RC振荡器、锁相环等在套件中的最小系统板中已经将V DDA 与3.3V、V S S A 与GND相连接了。 这里ADC的时钟ADCCLK是来自于RCC的APB2时钟。由原理图可得ADCCLK最大为14MHz所以ADC预分频器只能选择6分频得到12MHz和8分频得到9MHz两个值。 ADC可以通过DMA请求信号触发DMA转运数据。 模拟看门狗的功能是监测指定的通道。可以设置模拟看门狗的阈值高限12位、阈值底限12位和指定“看门”的通道。只要通道的电压值超过阈值范围模拟看门狗就会“乱叫”申请一个模拟看门狗的中断之后通向NVIC。 ECC是规则组的完成信号JEOC是注入组完成信号这两个信号会在状态寄存器里置一个标志位读取这个标志位就能知道是不是转换结束了同时这两个标志位也可以去到NVIC申请中断如果开启了NVIC对应的通道就会触发中断
定时器可以通向DAC、ADC这些外设用于触发转换因为ADC经常需要过一个固定时间段转换一次比如每隔1ms转换一次正常思路就是用定时器每隔1ms申请一次中断在中断里手动开始一次转换但是频繁进中断对我们的程序是由一定影响的比如你有很多中断都需要频繁进入那肯定会影响主程序的执行并且不同中断之间由于优先级的不同也会导致某些中断不能及时得到响应如果触发ADC的中断不能及时响应那adc的转换频率就肯定会产生影响所以对于这种需要频繁进中断并且在中断里只完成了简单工作的情况一般都会有硬件支持比如可以给tim3定个1ms的时间并且把tim3的更新事件选择为TRGO输出然后在ADC选择开始触发信号为tim3的TRGO这样tim3的更新事件就能通过硬件自动触发adc转换了整个过程不需进中断节省了中断资源这就是定时器触发的作用
STM32的ADC基本结构总结
如下图左边是输入通道16个gpio口外加两个内部通道然后进行AD转换器ad转换器里有两个组一个是规则组、一个是注入组规则组最多可以选中16个通道。注入组最多可以选择4个通道然后转换的结果可以存放在AD数据寄存器里其中规则组有1个数据寄存器注入组有4个然后有触发控制提供了开始转换的START信号触发控制可以选择软件触发和硬件触发硬件触发主要来自定时器也可以选择外部中断引脚然后还有ADC时钟CLOCK来自RCCadc逐次比较的过程就是由这个时钟推动的然后可以布置一个模拟看门狗用于检测转换结果的范围如果超出设定的阈值就通过中断输出控制向NVIC申请中断另外规则组和注入组转换完成后会有个EOC信号会置一个标志位当然也可以通向NVIC最后还有个右下角有个开关控制在库函数中就是ADC_Cmd函数用于给ADC上电以上就是STM32 ADC的内部结构了 STM32的ADC输入通道和引脚的关系
由ADC的内部结构可知STM32的ADC对应16个输入通道。这16个输入通道对应的GPIO端口如下表所示 上表展示了ADC通道和引脚复用之间的连接关系这个对应关系也可以参考引脚定义表。可以看到只有ADC1拥有温度传感器和内部参考电压的采样通道。ADC1和ADC2的引脚完全相同ADC3有些是存在变化的。本节课程使用的STM32F103C8T6没有PC0到PC5的引脚故也就不存在通道10到通道15。
参考下面引脚定义表可以看到STM32的ADC1和ADC2的引脚是相同的。这样的设计是为双ADC模式服务的。关于双ADC模式的内容比较复杂这里仅作简单了解即可。双ADC模式即ADC1和ADC2同时工作二者可以配合为同步模式、交叉模式等多种不同的工作模式。以交叉模式为例ADC1和ADC2交叉对同一个通道进行采样这样就可以进一步提高采样率交叉模式就像你打拳一样左手打一圈、右手打一圈快速交叉地打拳那打击的频率肯定比一个拳头打得快。当然ADC1和ADC2也是可以分开使用的可以分别对不同的引脚进行采样这样也是可以的
注引脚定义表中例如ADC12_IN0的意思是ADC1和ADC2的IN0都是在PA0上。 STM32的ADC规则组的四种转换模式
STM32中的ADC规则组的转换模式有以下四种 单次转换 非扫描模式 单次转换 扫描模式 连续转换 非扫描模式 连续转换 扫描模式 精华提取
单次转换每触发一次转换结束就会停下来下次转换就得再触发才能开始。
连续转换 一次转换完成后不会停止而是立刻开始下一轮的转换并持续下去。
非扫描模式只对存放在序列1的通道起作用。
扫描模式用到“菜单”列表可以在菜单里点菜每个菜单列表位置是通道几是可以任意指定的并且可以重复然后初始化结构体有个通道数目的参数表明用了几个通道
扫描模式下转换到数据寄存器的过程中用DMA防止数据被覆盖DMA进行数据及时转移
在扫描模式的情况下还可以使用间断模式。它的作用是在扫描的过程中每隔几次转换就暂停需要再次触发才能继续。该模式仅作了解即可。
单次转换非扫描模式 如下列表就是规则组的菜单有16个空位分别是序列1~16你可以在列表点菜就是写入你要转换的通道在非扫描的模式下这个菜单就只有一个序列1的位置有效这时菜单同时选中一组的方式就退化为简单地选中一个的方式了可以在序列1的位置指定我们想转换的通道比如通道2写到这个位置然后就可以触发转换adc就会对通道2进行模数转换过一小段时间后转换完成转换结果放在数据寄存器里同时给EOC标志位置1整个转换过程就结束了然后判断EOC标志位如果转换完了就可以在数据寄存器里读取结果了若想再启动一次转换就需要再触发一次转换结束置EOC标志位读结果若想换一个通道转换那就在转换之前把第一个位置的通道2改成其它通道然后再启动转换就行了以上就是单次转换非扫描模式 没有用到菜单列表是比较简单地一种模式 连续转换非扫描模式
首先连续转换非扫描模式是非扫描模式所以菜单列表只用第一个与上一种单次转换非扫描模式不同的是它在一次转换结束后不会停止而是立刻开始下一轮的转换然后一直持续下去这样就只需要最开始触发一次之后就可以一直转换了这个模式的好处是开始转换之后就不需等待一段时间因为它一直都在转换所以不需手动开始转换了也不用判断是否结束想读ad值的时候直接从数据寄存器读取以上就是连续转换非扫描模式 单次转换扫描模式
每触发一次转换结束就会停下来下次转换就得再触发才能开始。扫描模式用到“菜单”列表可以在菜单里点菜每个菜单列表位置是通道几是可以任意指定的并且可以重复然后初始化结构体有个通道数目的参数表明用了几个通道
每次触发之后就会依次对前7通道数目个位置进行AD转换转换结果都放在数据寄存器里为了防止数据被覆盖就需要用DMA及时将数据挪走7个通道转换完成后产生EOC信号转换结束然后再触发下一次就又开始新一轮的转换以上就是单次转换扫描模式 连续转换扫描模式
连续转换扫描模式与单次转换扫描模式不同之处就是一次转换完成后立刻进行下一次的转换 STM32的ADC规则组的触发源
规则组的触发源如下表所示
有来自定时器的信号、来自引脚或定时器的信号具体是引脚还是定时器需要用AFIO重映射来确定、软件控制位就是软件触发
触发信号的选择可以通过设置寄存器来完成EXTSEL[2:0]当然使用库函数的话直接给一个参数就行了 数据对齐
STM32中的ADC是12位的但是数据寄存器拥有16位故存在数据对齐的问题。数据右对齐即作为转换结果的12位数据向右靠高位补0数据左对齐即作为转换结果的12位数据向左靠低位补0。在使用时通常使用数据右对齐这样在读取时直接读取寄存器即可。如果选择左对齐直接读取得到的数据会比实际的数据大16倍。当对分辨率的要求不高时对电压仅作大概的判断即可可以采用左对齐将数据寄存器的高8位取出就相当于舍弃了转换结果的4位的精度12位的ADC退化位为8位的ADC。
注二进制中数据左移一次就等效于把这个数据乘2左移4次就相当于把结果乘16 AD转换时间 AD的转换时间是一个很短的时间如果不需要极高的转换频率那么转换时间是可以忽略的。那么转换时间具体是多少呢 AD转换的步骤分别是采样、保持、量化、编码。其中采样和保持可以看作一个过程量化和编码可以看作一个过程。量化和编码实际上就是ADC逐次比较的过程一般ADC的位数越多所花费的时间就越长。采样和保持是为了保证在量化和编码的过程中输入电压的变化不会过大。在量化和编码之前需要添加采样-保持电路即需要设置一个采样开关打开开关一段时间来收集电压可以用一个小容量的电容来存储这个电压存储完成之后断开开关再进行之后的AD转换。这样就可以保证在量化和编码器件始终保持电压基本不变。这个采样时间是比较长的。ADC的采样时间可以在程序中进行配置。之后花费12个ADC周期进行量化和编码多余的0.5个周期完成了其他的工作。 所以AD转换所花费时间为采样-保持电路的采样时间 量化和编码花费的时间12.5个ADC周期。即STM32 ADC总转换时间 采样时间 12.5个ADC周期 ADC周期就是从RCC分频过来的ADCCLKADCCLK最大是14MHz 最短的转换时间当ADCCLK 14MHz采样时间为1.5个ADC周期时ADC总转换时间为1us 这就是最快1us时间的来源如果采样周期再长些就达不到1us了。当然可以通过设置将ADC的转换频率超过14MHz这样ADC就会工作在超频状态下。超频时转换时间可能会更短不过电路的稳定性将无法保证。 ADC校准 ADC有一个固定的内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间在每个电容器上都会计算出一个误差修正码(数字值)这个码用于消除在随后的转换中每个电容器上产生的误差。建议在每次上电后执行依次校准且启动校准前ADC必须处于关电状态超过至少两个ADC周期。不需要理解这个校准过程是固定的只需要在ADC初始化的最后加几条代码就行了至于如何计算如何校准不需管 ADC的外围电路
第一个是电位器产生可调电压的电路。电位器产生一个可调电压这里电位器的两个固定端一端接3.3v一端接gnd这样中间的滑动就可以输出一个0~3.3v可调的电压输出可以接adc的输入通道比如PA0口当滑动端往上滑时电压增大往下滑时电压减小注意电阻的阻值不能给太小因为电阻两端也是直接跨接在电源正负极的如果阻值太小电阻就会比较费电再小就有可能发热冒烟 一般至少接kΩ级的电阻比如这里接的是10k电阻
第二个是分压方法来输出传感器阻值的电路。一般来说像光敏电阻、热敏电阻、红外接收管、麦克风等都可以等效为可变电阻N1电阻值无法直接测量所以就可以通过和一个固定电阻串联分压来得到一个反应电阻值的电压的电路。传感器N1阻值变小时下拉作用变强输出端PA1电压就下降传感器N1阻值变大时下拉作用变弱输出端PA1受上拉电阻的作用电压就会升高。固定电阻R1一般可以选择和传感器N1阻值相近的电阻这样可以得到一个位于中间电压区域比较好的输出当然这里的固定电阻R1和传感器N1的位置也可以缓过来这样输出电压的极性就反过来了。
第三个是简单的电压转换电路。比如你想测一个0-5v的VIN电压但是ADC只能接受0-3.3v的电压那就可以使用这样的简易转换电路还是使用电阻进行分压上面电阻r1阻值17k下面阻值r2是33k一共是50k根据分压公式中间的电压就是VIN/50K * 33k最后得到的电压范围就是0-3.3v就可以进入adc转换了若想采集5v、10v这些电压的话就可以使用这个电路但是若电压再高些就不建议使用这个电路了可能会比较危险高电压采集最好使用一些专用的采集芯片比如隔离放大器等做好高低电压的隔离保证电路的安全 二、 AD单通道AD多通道应用程序示例
ADC 常用库函数
ADC的RCC时钟配置函数
该配置函数定义存放在stm32f10x_rcc.h文件中用来配置ADCCLK分频器。它可以对APB2的72MHz时钟选择2、4、6、8分频输出到ADCCLK。
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2)ADC设置
// 恢复ADC缺省配置
void ADC_DeInit(ADC_TypeDef* ADCx);
// ADC初始化
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
// ADC配置结构体初始化
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);// ADC上电工作函数即开关控制函数
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);// ADC开启DMA输出信号
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);// ADC中断输出控制函数
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);// 下面4个函数用于ADC工作前的校准操作在ADC初始化完成后依次调用即可
// ADC复位校准
void ADC_ResetCalibration(ADC_TypeDef* ADCx);
// ADC获取复位校准状态
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
// ADC开始校准
void ADC_StartCalibration(ADC_TypeDef* ADCx);
// ADC获取开始校准状态
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);// ADC软件触发转换给CR2的SWSTART置1开始转换后立即自动清0
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
// ADC获取软件触发状态获取CR2的SWSTART开始转换规则通道位
// 不能用它判断转换是否结束一般不用了解即可
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);// ADC规则组通道配置给转换序列的每个位置填写指定的通道
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);// ADC外部触发转换控制是否允许外部触发转换
void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);// ADC获取转换值获取AD转换的数据寄存器
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);// ADC获取双模式转换值读取双ADC模式下ADC的转换结果
uint32_t ADC_GetDualModeConversionValue(void);// ADC温度传感器、内部参考电压控制开启内部的两个转换通道
void ADC_TempSensorVrefintCmd(FunctionalState NewState);// 下面的函数与操作标志位寄存器状态有关
// ADC获取标志位状态可通过获取EOC标志位判断转换是否结束
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
// 清除标志位
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
// 获取中断标志位
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);
// 清除中断挂起位
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);模拟看门狗配置本节暂不涉及需要可以了解
// 对模拟看门狗进行配置
// 是否启动模拟看门狗
void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog);
// 配置模拟看门狗高低阈值
void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold);
// 配置看门通道
void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel);注入组相关配置函数本节暂不涉及需要可以了解
void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv);
void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_SoftwareStartInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx);
void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length);
void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset);
uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel);ADC间断模式配置
// 下面两个函数用来配置STM32中ADC的间断模式
// 配置每隔几个通道间断依次
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
// 开启间断模式
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);ADC 单通道转换 AD.c
#include stm32f10x.h // Device header/*** brief ADC初始化函数软件触发且这里不使用模拟看门狗和中断* param 无* retval 无*/
void AD_Init(void)
{// 1. RCC开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6); // ADCCLK 72MHz / 6 12MHz// 2. 配置GPIOGPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA, GPIO_InitStructure);// 3. 将指定的GPIO端口接入规则组列表中ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // 把通道0填入序列1中通道的采样周期是55.5个ADCCLK的周期// 4. 配置ADCADC_InitTypeDef ADC_InitStruct;ADC_InitStruct.ADC_Mode ADC_Mode_Independent; // ADC模式独立模式或双ADC模式独立模式 ADC_InitStruct.ADC_DataAlign ADC_DataAlign_Right; // ADC数据对齐右对齐ADC_InitStruct.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; // ADC外部触发源选择不使用外部源触发这里使用软件触发ADC_InitStruct.ADC_ContinuousConvMode DISABLE; // ADC连续转换模式单次转换ADC_InitStruct.ADC_ScanConvMode DISABLE; // ADC扫描模式非扫描ADC_InitStruct.ADC_NbrOfChannel 1; // 扫描模式下通道的数量ADC_Init(ADC1, ADC_InitStruct);/* 中断和模拟看门狗在此配置 */// 5. 开关控制ADC_Cmd(ADC1, ENABLE);// 6. 对ADC进行校准ADC_ResetCalibration(ADC1); // 复位校准while (ADC_GetResetCalibrationStatus(ADC1) SET); // 等待复位校准完成ADC_StartCalibration(ADC1); // 开始校准while (ADC_GetCalibrationStatus(ADC1) SET); // 等待校准完成
}/*** brief ADC结果读取函数软件触发* param 无* retval 转换之后的结果*/
uint16_t AD_GetValue(void)
{// 1. 软件触发开启转换ADC_SoftwareStartConvCmd(ADC1, ENABLE);// 2. 等待转换完成获取标志位状态等待EOC标志位置1while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) RESET); // 转换未完成则等待55.5T 12.5T 68T结果大概为5.6us// 3. 读取ADC数据寄存器并返回return ADC_GetConversionValue(ADC1); // 读取之后会自动清除EOC标志位
}
main.c
#include stm32f10x.h // Device header
#include Delay.h
#include OLED.h
#include AD.huint16_t AD_Value;
float Voltage;int main()
{OLED_Init();AD_Init();OLED_ShowString(1, 1, AD_Value:);OLED_ShowString(2, 1, Voltage:0.00V);while(1){AD_Value AD_GetValue();Voltage (float)AD_Value / 4095 * 3.3; // 整数除以小数会舍弃小数部分OLED_ShowNum(1, 10, AD_Value, 4);OLED_ShowNum(2, 9, Voltage, 1); // 显示整数部分OLED_ShowNum(2, 11, (uint16_t)(Voltage * 100) % 100, 2); // 显示小数部分Delay_ms(100);}
}
ADC 多通道转换 AD.c
#include stm32f10x.h // Device header/*** brief ADC初始化函数单次转换非扫描实现多通道转换软件触发且这里不使用模拟看门狗和中断* param 无* retval 无*/
void AD_Init(void)
{// 1. RCC开启时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6); // ADCCLK 72MHz / 6 12MHz// 2. 配置GPIOGPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA, GPIO_InitStructure);// 3. 将指定的GPIO端口接入规则组列表中/* 这里要在每一次转换前都更改转换列表中要转换的GPIO端口 */// 4. 配置ADCADC_InitTypeDef ADC_InitStruct;ADC_InitStruct.ADC_Mode ADC_Mode_Independent; // ADC模式独立模式或双ADC模式独立模式 ADC_InitStruct.ADC_DataAlign ADC_DataAlign_Right; // ADC数据对齐右对齐ADC_InitStruct.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; // ADC外部触发源选择不使用外部源触发这里使用软件触发ADC_InitStruct.ADC_ContinuousConvMode DISABLE; // ADC连续转换模式单次转换ADC_InitStruct.ADC_ScanConvMode DISABLE; // ADC扫描模式非扫描ADC_InitStruct.ADC_NbrOfChannel 1; // 扫描模式下通道的数量ADC_Init(ADC1, ADC_InitStruct);/* 中断和模拟看门狗在此配置 */// 5. 开关控制ADC_Cmd(ADC1, ENABLE);// 6. 对ADC进行校准ADC_ResetCalibration(ADC1); // 复位校准while (ADC_GetResetCalibrationStatus(ADC1) SET); // 等待复位校准完成ADC_StartCalibration(ADC1); // 开始校准while (ADC_GetCalibrationStatus(ADC1) SET); // 等待校准完成
}/*** brief ADC结果读取函数单次转换非扫描实现多通道转换软件触发* param 无* retval 转换之后的结果*/
uint16_t AD_GetValue(uint8_t ADC_Channel)
{ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5); // 把通道作为参数填入序列1中通道的采样周期是55.5个ADCCLK的周期// 1. 软件触发开启转换ADC_SoftwareStartConvCmd(ADC1, ENABLE);// 2. 等待转换完成获取标志位状态等待EOC标志位置1while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) RESET); // 转换未完成则等待55.5T 12.5T 68T结果大概为5.6us// 3. 读取ADC数据寄存器并返回return ADC_GetConversionValue(ADC1); // 读取之后会自动清除EOC标志位
}
main.c
#include stm32f10x.h // Device header
#include Delay.h
#include OLED.h
#include AD.huint16_t AD0, AD1, AD2, AD3;int main()
{OLED_Init();AD_Init();OLED_ShowString(1, 1, AD0:);OLED_ShowString(2, 1, AD1:);OLED_ShowString(3, 1, AD2:);OLED_ShowString(4, 1, AD3:);while(1){AD0 AD_GetValue(ADC_Channel_0);AD1 AD_GetValue(ADC_Channel_1);AD2 AD_GetValue(ADC_Channel_2);AD3 AD_GetValue(ADC_Channel_3);OLED_ShowNum(1, 5, AD0, 4);OLED_ShowNum(2, 5, AD1, 4);OLED_ShowNum(3, 5, AD2, 4);OLED_ShowNum(4, 5, AD3, 4);Delay_ms(100);}
}
传送门https://archie.blog.csdn.net/article/details/132434192
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/87140.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!