STM32笔记(1)———ADC模数转换器原理及单、双通道转换

这篇具有很好参考价值的文章主要介绍了STM32笔记(1)———ADC模数转换器原理及单、双通道转换。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一.ADC 模数转换器

1.1 ADC、DAC、PWM

ADC(Analog-Digital Converter),意即模拟-数字转换器,简称模数转换器。ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。

DAC:数字到模拟的桥梁(PWM控制灯的亮度和电机旋转的速度,DAC的使用只要是在信号发生器、音频解码芯片等
PWM:数字到模拟的桥梁,例如PWM控制灯的亮度和电机旋转的速度,PWM只有完全导通和完全断开两种状态,在这两种状态都没有功率损耗,故直流电机调速这种大功率的应用场景,使用PWM来等效模拟量,是比DAC更好的选择,PWM电路更简单,更常用。

1.2 12位逐次逼近型ADC,1us转换时间

  • STM32中的ADC是一个12位的逐次逼近型的ADC,最快转换时间1us。“逐次逼近”是ADC的一种工作模式;“12位”指ADC的分辨率,12位AD值的表示范围即0 ∼ 212− 1 ,量化值为0 ∼ 4095 ,位数越高,量化结果越精细,对应ADC的分辨率就越高;转换时间1us对应的频率就是1MHz,这就是STM32中ADC的最快转换频率。
  • STM32中的ADC的输入电压范围为0 ∼ 3.3V,对应的转换结果就是0 ∼ 4095。ADC的输入电压一般要求都是要在芯片供电的正负极之间变化且电压和转换结果都是一一对应的线性关系。

1.3 ADC有18个输入通道

  • 可以测量16个外部信号和2个内部信号源。外部的16个信号源即16个GPIO口(可能来自不同的GPIOx,具体要参考引脚定义),在引脚上直接输入模拟信号即可,不需要额外的测量电路;
  • 2个内部信号源分别是内部温度传感器和内部参考电压,温度传感器可以测量CPU的温度,内部参考电压是一个1.2V左右的内部基准电压,且这个内部基准电压是不随外部供电电压变化的。当芯片的供电电压不是准确的3.3V时,就可以通过这个内部的基准电压进行校准来得到正确的电压值。
  • 采用STM32C8T6只有 ADC1、ADC2,10个外部输入通道,即最多只能测量10个外部引脚的模拟信号。

1.4 规则组和注入组两个转换单元

普通的AD转换流程为:先启动一次转换,之后读值,依次循环。
STM32的ADC可以将要转换的通道列为一组,每一次连续转换多个值。

  • 规则组用于常规使用,注入组一般用于突发事件。

  • 一般可以用于测量光线强度、温度这些值
    如果光线高于某个预值、低于某个预值,或者温度高于某个预值、低于某个预值时,就会执行一些操作

  • 模拟开门狗可以监测指定的某些通道,当AD值高于他设定的上域值,或者低于下域值时。就会申请中断,然后就可以在中断函数里,执行相应的操作。

1.5 逐次逼近型ADC

下图所示的即为逐次逼近型ADC的工作原理图(ADC0809)。STM32中的ADC的结构与此类似
adc模数转换电路原理图,STM32学习,stm32,笔记,嵌入式硬件,单片机

  • IN0~IN7是八个输入通道
    通过配置ADDA~ADDC可以选择一个通道作为信号输入
    通过比较器, DAC逐渐逼近输入信号, DAC的值最终与输入信号十分接近
  • 结构图上方的EOC(End Of Convert)是转换结束信号。该芯片通过START端口控制转换开始,CLOCK控制ADC内部的转换工作频率。VREF(+) 和VREF(-)是DAC的参考电压,定义数据对应的电压范围(255对应3.3V或5V)。通常芯片的工作电压正极VCC 和VREF 相同,接在一起;通常芯片的工作电压负极GND和VREF(-) 相同,接在一起。

1.6 STM32中的ADC框图

adc模数转换电路原理图,STM32学习,stm32,笔记,嵌入式硬件,单片机

  1. 普通的ADC多路开关一般只选中一个,STM32的ADC可以同时选中多个通道进行转换,规则组最多同时选中16个通道,注入组一次最多可以选中4个通道。(以餐厅点菜模型为例,普通模式为每次点一个菜,做好菜后上菜;STM32可以做到每次列出一个菜单,规则组一次最多可以列16个菜,注入组一次最多可以列4个菜,做好后依次上菜)
  2. STM32中的ADC的转换结果会被存储在对应的数据寄存器中。对于规则组通道,其只有一个数据寄存器(餐桌上只能摆一个菜),后转换的数据会将之前转换的数据覆盖,之前转换的数据就会丢失。对于规则组通道,要想实现同时转换的功能,最好配合DMA来将转换后的数据及时转运,就可以保证转换的数据不会丢失了。对于注入组通道,它拥有4个数据寄存器(餐厅的VIP坐席,餐桌上一次可以摆四个菜)。对于注入组而言,就不用担心数据覆盖的问题了。一般情况下,使用规则组和DMA就可以满足大部分的使用需求。(这里只讲解规则组使用,注入组自行了解即可)
  3. 框图的左下角为触发转换信号,对应ADC0809的START信号。STM32的触发转换信号来源有两种:软件触发和硬件触发。硬件触发信号可以来自于定时器的各个通道、定时器TRGO主模式的输出,外部中断EXTI。下表列出了ADC1和ADC2的触发源。(其中EXTI线11/TIM8_YRGO事件的选择需要使用AFIO端口重映射来配置)
  4. 这里ADC的时钟ADCCLK是来自于RCC的APB2时钟。由原理图可得,ADCCLK最大为14MHz,所以ADC预分频器只能选择6分频(得到12MHz)和8分频(得到9MHz)两个值
  5. ADC可以通过DMA请求信号触发DMA转运数据
  6. 模拟看门狗的功能是监测指定的通道。可以设置模拟看门狗的阈值高限(12位)、阈值底限(12位)和指定“看门”的通道。只要通道的电压值超过阈值范围,模拟看门狗就会“乱叫”,申请一个模拟看门狗的中断,之后通向NVIC。
  7. 规则组和注入组在转换完成后会生成一个转换完成的信号。EOC为规则组转换完成的信号,JEOC为注入组转换完成的信号。这两个信号会在状态寄存器中置一个标志位,我们通过读取状态寄存器,就可以知道转换是否完成了。同时这两个标志位也可以通过配置通向NVIC申请中断。

1.7 ADC基本结构

adc模数转换电路原理图,STM32学习,stm32,笔记,嵌入式硬件,单片机

  • 左边是输入通道16个GPIO口外加2个内部的通道
  • AD数据寄存器:规则组只有1个数据计算器,注入组有4个
  • 触发控制:提供开始转换START信号,触发控制可以选择软件触发和硬件触发,硬件触发主要是来自于定时器,也可以选择外部中断的硬件
  • RCC的ADC时钟CLOCK:推动ADC逐次比较的过程
  • 模拟看门狗:监测转换结果的范围,如果超出设定的预值就通过中断输出控制,向NVIC申请中断

1.8 输入通道

通道 AD1 AD2 AD3
通道0 PA0 PA0 PA0
通道1 PA1 PA1 PA1
通道2 PA2 PA2 PA2
通道3 PA3 PA3 PA3
通道4 PA4 PA4 PF6
通道5 PA5 PA5 PF7
通道6 PA6 PA6 PF8
通道7 PA7 PA7 PF9
通道8 PB0 PB0 PF10
通道9 PB1 PB1
通道10 PC0 PC0 PC0
通道11 PC1 PC1 PC1
通道12 PC2 PC2 PC2
通道13 PC3 PC3 PC3
通道14 PC4 PC4
通道15 PC5 PC5
通道16 温度传感器
通道17 内部参考电压

本节课程使用的STM32F103C8T6没有PC0到PC5的引脚,故也就不存在通道10到通道15。

1.9 ADC的四种转换模式

单次转换非扫描模式、连续转换非扫描模式、单次转换扫描模式、连续转换扫描模式

1.9.1单次转换非扫描模式

adc模数转换电路原理图,STM32学习,stm32,笔记,嵌入式硬件,单片机

  • 非扫描的模式下,只有第一个序列1的位置有效
  • 在序列1的位置,我们可以指定想转换的通道,比如通道2,写到序列1的位置然后触发转换,ADC就会对这个通道2进行模数转换,转换完成后,转换结果放在数据计算器里,同时给EOC标志位置1,转换结束
  • 通过判断这个EOC标志位是否转换完成,若完成,就可以在数据寄存器里读结果
  • 若想再启动一次转换,需要再触发一次,转换结束至EOC标志位读结果
  • 若想换一个通道转换,在转换之前,把第一个位置的通道2改成其他通道,然后再启动转换就行了

1.9.2 连续转换非扫描模式

adc模数转换电路原理图,STM32学习,stm32,笔记,嵌入式硬件,单片机

  • 非扫描模式:菜单列表就只用第一个
  • 连续转换:在一次转换结束后不会停止,而是立刻开始下一轮的转换,然后一直持续下去,只需要最开始触发一次,就可以一直转换
  • 读取的时候不用判断是否结束,直接从数据寄存器读即可

1.9.3 单次转换扫描模式

adc模数转换电路原理图,STM32学习,stm32,笔记,嵌入式硬件,单片机

  • 单次转换:每触发一次,转换结束后就会停下来,下次转换需要再触发
  • 扫描模式:会用到这个菜单列表了,通道几(相当于菜)可以任意指定,且可以重复,初始化结构体有个参数表示通道数目(比如7个),说明只需要用多少序列
  • 为了防止数据被覆盖,用DMA及时将数据挪走,7个通道转换完成之后产生EOC信号,转换结束
  • 然后再触发,重新开始

1.9.4 连续转换扫描模式

adc模数转换电路原理图,STM32学习,stm32,笔记,嵌入式硬件,单片机
一次转换完成后,立刻开始下一次的转换
在扫描模式下还可有一种模式——间断模式,作用是在扫描过程中每隔几个转换,就暂停一次,需要再次触发才能继续

1.10 细节之处

1.10.1 触发控制 adc模数转换电路原理图,STM32学习,stm32,笔记,嵌入式硬件,单片机

adc模数转换电路原理图,STM32学习,stm32,笔记,嵌入式硬件,单片机

此表为规则组的触发源,也就是上图第2部分,有来自定时器的信号、引脚或定时器的信号(具体是引脚和定时器,需要用AFIO重映射来确定)最后的软件控制位就是软件触发。这些触发信号的选择,可以通过上图1设置表右边的寄存器完成,使用库函数的话只需一个函数给个参数即可。

1.10.2 数据对齐

adc模数转换电路原理图,STM32学习,stm32,笔记,嵌入式硬件,单片机

数据右对齐,即作为转换结果的12位数据向右靠,高位补0;
数据左对齐,即作为转换结果的12位数据向左靠,低位补0。
在使用时通常使用数据右对齐,这样在读取时直接读取寄存器即可。
如果选择左对齐直接读取,得到的数据会比实际的数据大16倍。
当对分辨率的要求不高时(对电压仅作大概的判断即可)可以采用左对齐,将数据寄存器的高8位取出,就相当于舍弃了转换结果的4位的精度,12位的ADC退化位为8位的ADC

1.10.3 转换时间(AD转换很快,一般忽略)

  • AD转换的步骤: 采样, 保持, 量化, 编码
  • STM32 ADC的总转换时间为:
    Tconv = 采样时间 + 12.5个ADC周期
    (花费12个ADC周期进行量化和编码,多余的0.5个周期完成了其他的工作)
  • 最短的转换时间:
    例如:当ADCCLK = 14MHz, 采样时间为1.5个ADC周期
    ​ Tconv = 1.5 + 12.5 = 14个ADC周期 = 1us
  • 采样时间越大,越能避免一些毛刺信号的干扰,不过转换时间也会相应延长

1.10.4 校准

ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的精准度误差。校准期间, 在每个电容器上都会计算出一个修正码(数字值), 这个码用于消除在随后的转换中每个电容器上产生的误差
建议在每次上电后执行一次校准启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期由于校准过程是固定的,对于使用者而言只需要在初始化后加上几条代码即可!

二. 硬件电路

ADC外围电路的设计给出以下三个电路图:
adc模数转换电路原理图,STM32学习,stm32,笔记,嵌入式硬件,单片机

图1:电位器产生一个可调的电压的电路

中间的滑动端可以输出一个0~3.3伏可调的电压输出来,上滑时电压增大,下滑时电压减小,若阻值太小,电阻就会比较费电

图2:分压方法输出传感器组织的电路

  • 传感器输出电压的电路,例如光敏电阻、热敏电阻、红外接头管、麦克风等都可以等效为一个可变电阻
  • 那电阻阻值得通过和一个固定电阻串联分压,当传感器阻值变大时,下拉作用变弱,输出端受上拉电阻的作用,电压就会升高
  • 固定电阻建议选择和传感器阻值相近的电阻,才可以得到一个位于中间电压区域比较好的输出
  • 此处传感器和固定电阻的位置也调换,输出电压的极性就反过来了

图3:简单的电压转换电路

想测一个0-5V的VIN电压,到那时ADC只能接收0~3.3V的电压,就可以搭建此类电路。使用电阻分压,上面阻值17K,下面阻值33K,加一起50K,中间的电压就是VIN/50K*33K,得到的电压范围就是0-3.3伏,就可以进入ADC转换了。想要其他范围(如5V、10V)的VIN电压可类似操作,如果电压过高就不建议使用这种电路了,可能比较危险,高电压采集最好使用专用芯片,比如隔离放大器等,做到高低电压隔离保证电路安全。

三. ADC 常用库函数

3.1 ADC的RCC时钟配置函数

该配置函数定义存放在stm32f10x_rcc.h文件中,用来配置ADCCLK分频器。它可以对APB2的72MHz时钟选择2、4、6、8分频,输出到ADCCLK。

1.void RCC_ADCCLKConfig(uint32_t RCC_PCLK2)

3.2 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);

3.3 配置的参数

(1)双ADC工作模式选择,ADC_Mode,其中分别为:

#define ADC_Mode_Independent                       ((uint32_t)0x00000000)//独立模式
#define ADC_Mode_RegInjecSimult                    ((uint32_t)0x00010000)//同步规则和同步注入模式
#define ADC_Mode_RegSimult_AlterTrig               ((uint32_t)0x00020000)//同步规则和交替触发模式
#define ADC_Mode_InjecSimult_FastInterl            ((uint32_t)0x00030000)//同步注入和快速交叉模式
#define ADC_Mode_InjecSimult_SlowInterl            ((uint32_t)0x00040000)//同步注入和慢速交叉模式
#define ADC_Mode_InjecSimult                       ((uint32_t)0x00050000)//同步注入模式
#define ADC_Mode_RegSimult                         ((uint32_t)0x00060000)//同步规则模式
#define ADC_Mode_FastInterl                        ((uint32_t)0x00070000)//快速交叉模式
#define ADC_Mode_SlowInterl                        ((uint32_t)0x00080000)//慢速交叉模式
#define ADC_Mode_AlterTrig                         ((uint32_t)0x00090000)//交替触发模式

(2)扫描模式选择,ADC_ScanConvMode,ENABLE表示多通道扫描模式,否则为单通道。
(3)连续转换模式选择,ADC_ContinuousConvMode,ENABLE表示连续转换模式,否则为单次转换模式。
(4)ADC转换触发方式选择,ADC_ContinuousConvMode,其中ADC_ExternalTrigConv_None为不使用外部触发,即使用软件触发方式。
(5)ADC转换数据对齐方式选择,ADC_DataAlign,可以左对齐或右对齐
(6) 顺序进行规则转换的ADC通道的数目设置,ADC_NbrOfChannel,可以设置1~16个通道

3.4 ADC间断模式配置

// 下面两个函数用来配置STM32中ADC的间断模式
// 配置每隔几个通道间断依次
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
// 开启间断模式
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

四. 程序示例

4.1 ADC单通道转换

1.AD.c(单次转换非扫描)

#include "stm32f10x.h"                  // Device header
void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	//配置ADCCLK分频器,对APB2的72MHz时钟选择2、4、6、8分频,输入到ADCCLK
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//分频后等于72MHz/6=12MHz
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入(ADC的专属模式)在AIN,GPIO口无效,断开GPIO口,防止GPIO口的输入输出对模拟电压造成干扰
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//ADC规则组通道配置,给序列的每个位置填写指定的通道,就是填写点菜菜单的过程
	//第一个参数是ADCx,第二个是ADC指定的通道(通道0-17)
	//第三个是写在序列几的位置,然后第四个指定通道的采样时间
	//ADC_SampleTime_55Cycles5表示55.5个ADCCLK的周期
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
	//ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_55Cycles5);
	//ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_55Cycles5);
	//通道可以重复,序列不要重复,需要的话可以多写几个,这是填充菜单的方法
	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//工作模式,独立模式:ADC1和ADC2各转各的
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不使用外部触发转换,即软件触发
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//单次  //ENABLE:连续转换
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描
	ADC_InitStructure.ADC_NbrOfChannel = 1;//总共需要扫描多少个通道
 
	ADC_Init(ADC1, &ADC_InitStructure);
	
	//中断和看门狗如果需要可以在此处定义
	
	//ADC上电
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);//复位校准
	//为1时,开始复位校准,复位校准完后,该位就会由硬件自动清0
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);//等待复位校准完成
	ADC_StartCalibration(ADC1);//开始校准
	while (ADC_GetCalibrationStatus(ADC1) == SET);//等待校准完成
	/*ADC_SoftwareStartConvCmd(ADC1, ENABLE);	//软件触发(连续转换只需要初始化一次即可,所以软件触发的函数可以挪到初始化函数) */
}
 
uint16_t AD_GetValue(void)
{
	// 1. 软件触发开启转换
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);	//软件触发
	// 2. 等待转换完成(获取标志位状态,等待EOC标志位置1)/*连续转换非扫描:不需要判断标志位while这句可删掉
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//转换结束,EOC置1// 转换未完成则等待(55.5T + 12.5T = 68T,结果大概为5.6us)
	// 3. 读取ADC数据寄存器并返回
	return ADC_GetConversionValue(ADC1);// 读取之后会自动清除EOC标志位
}

2、改为连续转换非扫描

好处:无需不断触发,不需要等待转换完成

  • ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//连续
  • 连续转换只需要初始化一次即可,所以软件触发的函数可以挪到初始化函数最后ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发 在初始化完成后触发一次即可
  • 且在AD_GetValue函数中,不需要判断标志位
    while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//转换结束,EOC置1 这一句可以删除
    程序如上图所示

3、main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"

/*
电位器即滑动变阻器,用电位器产生0~3.3V连续变化的模拟电压信号,然后接到STM32的PA0口上,
之后用STM32内部的ADC读取电压数据,显示在屏幕上                           
屏幕第一行:模拟数据                                                                                                       
屏幕第二行:处理过后显示的电压值
往左拧电位器,AD值减小,对应的电压减小,反之则反
ADC是12位的,AD结果最大值是4095,也就是2^12-1,对应的电压是3.3V
GPIO只能读取高低电平 ,而ADC可以对高低电平之间的任意电压进行量化,最终用一个变量表示
*/
uint16_t ADValue;
float Voltage;
int main(void)
{
	OLED_Init();
	AD_Init();
	OLED_ShowString(1, 1, "ADValue:");
	OLED_ShowString(2, 1, "Volatge:0.00V");

	while(1)
	{
		ADValue = AD_GetValue();
		Voltage = (float)ADValue/4095*3.3;
		//数字与电压映射关系,ADValue为uint16类型除以4095会舍弃小数部分,先强转为float
		OLED_ShowNum(1,9,ADValue,4);
		//目前的OLED没有显示浮点数的功能,但可用显示整数的借用
		OLED_ShowNum(2,9,Voltage,1);//显示整数部分
		OLED_ShowNum(2,11,(uint16_t)(Voltage*100)%100,2);//显示小数部分,浮点数不可%取余所以先强转为整型
		Delay_ms(100);//限制OLED刷新速度

	}
	
}

4.2 ADC多通道转换

1、思路

在每次触发转换之前,手动更改一下列表第一个位置的通道
比如第一次转换,在序列1先写入通道0,之后触发、等待、读值
第二次转换,在序列1把通道0改成通道1,之后触发、等待、读值
第三次转换,在序列1改成通道2等等

2、AD.c

#include "stm32f10x.h"                  // Device header

//(单次转换非扫描)

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	//配置ADCCLK分频器,对APB2的72MHz时钟选择2、4、6、8分频,输入到ADCCLK
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//分频后等于72MHz/6=12MHz
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入(ADC的专属模式)在AIN,GPIO口无效,断开GPIO口,防止GPIO口的输入输出对模拟电压造成干扰
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//工作模式,独立模式:ADC1和ADC2各转各的
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不使用外部触发转换,即软件触发
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//单次  //ENABLE:连续转换
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描
	ADC_InitStructure.ADC_NbrOfChannel = 1;//总共需要扫描多少个通道
 
	ADC_Init(ADC1, &ADC_InitStructure);
	
	//中断和看门狗如果需要可以在此处定义
	
	//ADC上电
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);//复位校准
	//为1时,开始复位校准,复位校准完后,该位就会由硬件自动清0
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);//等待复位校准完成
	ADC_StartCalibration(ADC1);//开始校准
	while (ADC_GetCalibrationStatus(ADC1) == SET);//等待校准完成
	/*ADC_SoftwareStartConvCmd(ADC1, ENABLE);	//软件触发(连续转换只需要初始化一次即可,所以软件触发的函数可以挪到初始化函数) */
}
 
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标志位置1)/*连续转换非扫描:不需要判断标志位while这句可删掉
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//转换结束,EOC置1// 转换未完成则等待(55.5T + 12.5T = 68T,结果大概为5.6us)
	// 3. 读取ADC数据寄存器并返回
	return ADC_GetConversionValue(ADC1);// 读取之后会自动清除EOC标志位
}

3、main.c文章来源地址https://www.toymoban.com/news/detail-756942.html

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"

/*
DO是数字输出
AO是模拟量输出
*/
uint16_t AD0,AD1,AD2,AD3;//表示四个ADC输入通道的转换结果的接收变量

int main(void)
{
	OLED_Init();
	AD_Init();
	OLED_ShowString(1, 1, "AD0:");
	OLED_ShowString(2, 1, "AD1:");
	while(1)
	{
		AD0 = AD_GetValue(ADC_Channel_0); 
		AD1 = AD_GetValue(ADC_Channel_1); 
		//根据需要也可设置映射关系,再进行显示
		
		OLED_ShowNum(1,5,AD0,4);
		OLED_ShowNum(2,5,AD1,4);
		Delay_ms(100);//限制OLED刷新速度

	}
	
}

到了这里,关于STM32笔记(1)———ADC模数转换器原理及单、双通道转换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32之模数转换器(ADC)

    一、模数转换器介绍 1、模数转换器简介 为什么使用模拟转换器?? 因为MCU只能识别01010101的数字信号,而外部物理信号均为模拟信号,如声音、光、电等,所以为了让计算机能够处理外部物理的信息,必须要通过模拟转换器将模拟量转换成数字量。 模数转换器:将模拟信号

    2024年02月20日
    浏览(20)
  • 【STM32学习】模数转换器——ADC

    [STM32固件库(标准外设库)入门学习 第七章 ADC数模转换(一) 刘凯:STM32F103(一):ADC 通过上述的两个链接以及stm32的参考手册,应该可以把ADC理解的差不多了,接下来说一下自己对某些内容的理解。 STM32 ADC转换速度与精度 对于AD转换所需要的时间,我们经常看到:Tconv = S

    2024年02月05日
    浏览(16)
  • STM32之模数转换器ADC

    目录 1、ADC介绍 1.什么是ADC? ADC的全称是Analog-to-Digital Converter,指模拟/数字转换器  2.ADC的性能指标 3.ADC特性 12位分辨率 4.ADC通道 5.ADC转换顺序  6.ADC触发方式  7.ADC转化时间  8.ADC转化模式  9.模拟看门狗 实验:使用ADC读取烟雾传感器的值  CubeMX配置   ​编辑 代码实现  效

    2024年02月04日
    浏览(29)
  • STM32F4_模数转换器(ADC)详解

    目录 1. ADC是什么 2. ADC主要特性 3. ADC框图 3.1 ADC开关控制 3.2 ADC时钟 3.3 通道选择 3.4 单次转换模式和连续转换模式 3.5 时序图 3.6 模拟看门狗 4 温度传感器 5. ADC中断 6. ADC初始化结构体 6.1 ADC相关实验配置 7. 相关寄存器 7.1 ADC控制寄存器:ADC_CR1和ADC_CR2 7.2 ADC通用控制寄存器:A

    2024年02月15日
    浏览(17)
  • STM32f103入门(10)ADC模数转换器

    ADC简介 ADC(Analog-Digital Converter)模拟-数字转换器 ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁 12位逐次逼近型ADC,1us转换时间 输入电压范围:0~ 3.3V,转换结果范围:0~ 4095 18个输入通道,可测量16个外部和2个内部信号源

    2024年02月10日
    浏览(15)
  • STM-32:ADC模数转换器—ADC单通道转换/ADC多通道转换

    ADC(Analog-Digital Converter),意即模拟-数字转换器,简称模数转换器。ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。与ADC相对应,从数字电路到模拟电路的桥梁即DAC(Digital-Analog Convertor),数模转换器。 DAC不是唯一可以

    2024年02月09日
    浏览(27)
  • 超详细!!STM32-ADC模数转换器-驱动内部温度传感器

      在STM32微控制器系列中,ADC(Analog-to-Digital Converter)是一个重要的外设模块,它允许微控制器将模拟信号转换成数字信号以进行处理。模拟信号–数字信号。    MCU只能处理数字量(10011001),如果需要MCU区分模拟输入信号时,MCU直接做不了,需要将模拟信号通过模数转换

    2024年02月19日
    浏览(16)
  • 基于51单片机 + MQ-3酒精传感器 + ADC0832模数转换器 + LCD1602液晶显示器的酒精检测系统

    废话不多说,直接上东西。本文是基于51单片机的酒精检测系统设计,用的元器件有:51单片机、MQ-3酒精传感器、ADC0832模数转换器、 LCD1602液晶显示器、喇叭等元器件。 1、MQ-3 酒精检测传感器,用于检测酒精浓度。当然采集到的数据是模拟的还需要通过ADC0832模数转换器将其转

    2024年02月12日
    浏览(25)
  • 快速了解A/D(模数转换器)

    以下是一个简要的概述: A/D转换器是一种电子设备 ,用于将模拟信号转换为数字信号。它将连续变化的模拟信号离散化为一系列数字值,以便于数字系统的处理和分析。 A/D转换器的原理图 通常包括模拟输入电路、采样保持电路、编码器、数字输出接口等。 了解A/D转换器的

    2024年02月06日
    浏览(18)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包