深入理解STM32中级篇4-ADC和DAC并实践

本篇博文目录:

  • 一.ADC的基础概念
  • 1.什么是ADC
  • 2.在单片机中我们一般使用ADC技术来做什么?
  • 3.怎么查看单片机的某一个引脚是否具有ADC功能
  • 4.ADC采集和引脚数据的读取有什么区别
  • 5.单片机内部采用的是数字信号,为什么还要采用ADC进行转换
  • 6.ADC的分类
  • 7.ADC的工作原理
  • 8.ADC的参数
  • 二.DAC的基础知识
  • 1.什么是DAC
  • 2.在单片机中我们一般使用DAC技术来做什么?
  • 3.怎么看单片机的某一个引脚是否具有ADC功能
  • 4.PWM和DAC的区别
  • 5.DAC的工作原理
  • 6.DAC的参数
  • 三.代码实例
  • 一.ADC的基础概念

    1.什么是ADC

    ① ADC全称为Analog-to-Digital Converter,中文名称为模数转换器。ADC是一种将模拟信号转换为数字信号的电路设备,它在电子系统中扮演着非常重要的角色。
    ② 模拟信号是以连续的方式变化的信号,例如声音、温度等,而数字信号是以离散的方式表示的信号,它是由“0”和“1”两种状态组成。ADC将模拟信号的大小和时间上的连续性转化为数字信号来进行处理,因此在很多电子系统中都需要使用ADC。
    ③ ADC通常由四个主要部分组成:采样、量化、编码和输出缓冲。采样部分将连续的模拟信号转换成离散的信号,量化部分将离散的信号转换成具有固定间隔的数字化电信号,编码部分将固定间隔的数字化电信号转化为可存储、传输和处理的二进制形式,输出缓冲区将数字信号放大并存储在输出端口,便于外部电路读取。
    ④ ADC的精度通常通过量化位数来表示。量化位数越高,ADC的精度和分辨率会越好,但相应的芯片价格和功耗也会越高。不同的电子系统需要使用不同精度的ADC来满足需要。
    ⑤ 总之,ADC是电子系统中重要的基础组成部分,它将模拟信号转化为对数字信号,实现了从现实世界到数字世界的转换,为数字电路的应用提供了可能。

    作用:将模拟信号转换为数字信息
    转换过程:采样–>量化–>编码–>输出缓冲

    2.在单片机中我们一般使用ADC技术来做什么?

    ① 在单片机中,我们使用ADC技术来实现模拟量的数字化采集。
    ② 单片机内部集成有ADC模块,我们可以通过配置单片机的寄存器操作,将外部的模拟信号输入到ADC输入端口,ADC会将其转换成数字信号,并将结果保存在特定的寄存器中。通过读取这些寄存器的值,我们就可以得到正在测量的模拟量的数字化值。
    ③ 单片机中常使用ADC技术的应用包括温度和湿度测量、光强度检测、电压和电流测量、电池电量测量等。在这些应用中,ADC会将模拟量信号转换为数字信号,然后通过单片机内部的处理器进行处理、分析、存储等操作,实现各种不同的智能化应用。

    3.怎么查看单片机的某一个引脚是否具有ADC功能

    单片机的某一个引脚是否具有该ADC功能,需要结合数据手册进行查询,一般查询芯片数据手册中的Table 5. Medium-density STM32F103xx pin definitions 表格,下图是STM32F103xx芯片的引脚信息表截图。

    4.ADC采集和引脚数据的读取有什么区别

    ADC采集和引脚数据的读取有以下几个不同之处:
    ① 采集方式不同:ADC采集是通过ADC模块对模拟信号的采样和转换,而引脚数据的读取是通过直接读取引脚的电平状态来获取数字信号。
    ② 数据类型不同:ADC采集的结果是模拟信号的数字化结果,通常是一个整型数值(例如10位的ADC采集结果就是一个0-1023的整数),而引脚数据的读取是数字信号(高电平和低电平)。
    ③ 精度不同:ADC采集的精度和分辨率通常比引脚数据的读取要高。ADC的精度和分辨率通常是通过芯片的参数来限定的,在一定的参考电压下,可以实现更高的精度和分辨率。而引脚数据的读取通常只能读取到高电平和低电平两种状态,精度比ADC低。
    ④ 用途不同:ADC主要用于模拟信号的数字化处理,通常用于传感器采集、电压测量等场景。而引脚数据的读取通常用于控制IO设备、读取开关状态、读取数字信号等场景。
    ⑤ 需要注意的是,在某些场景下,ADC采集和引脚数据的读取是有联系的。例如,通过ADC采集对某个传感器的模拟信号进行数字转换后,将数字量作为引脚输出,用于控制其他设备的开关状态。在这种情况下,ADC采集和引脚数据的读取就是相互关联的。

    5.单片机内部采用的是数字信号,为什么还要采用ADC进行转换

  • 比如采集内部的电源电压
  • ① 如果是单片机内部信号,一般情况下是不需要通过ADC进行转换的。对于CPU内部的数字信号,我们可以直接使用单片机提供的IO口进行读取,这些IO口所输入的数字信号是可以直接被单片机内部电路所处理的。
    ② 例如,单片机内部包含一个计时器,可以通过IO口读取计时器内部的计数值,这个计数值就是单片机内部的数字信号,我们可以直接使用IO口进行读取。
    ③ 至于电源电压,它虽然也在单片机内部,但由于它是一个模拟信号,需要通过ADC模块进行转换后才能被单片机识别和处理。注意,这里需要测量的是单片机内部电源电压,而不是单片机外部电源电压。对于单片机外部电源电压,需要借助外部的模拟信号采集电路,通过ADC模块进行转换。
    ④ 对于单片机内部的电源电压,可以通过单片机内部的ADC模块进行采集,但是采集到的数据也需要进行转换才能得到实际电压值。因为单片机内部的ADC模块采集到的是数值结果,而不是电压值。
    ⑤ 一般来说,需要通过额外的硬件电路,如光电耦合器或电压传感器等,将电源电压转换成模拟信号进行采集,然后再经过ADC模块进行数字化处理。这样可以得到实际的电压值,以便进行后续的计算和控制。

  • 电压采集采样电路设计
  • 你可以通过这篇博文(https://blog.csdn.net/weixin_42090940/article/details/102615898) 进行学习。

    6.ADC的分类

  • ADC的分类
  • ADC根据不同的工作原理和使用场景,可以分为以下几类:

    1.逐次逼近型ADC:

    逐次逼近型ADC是一种常见的、精度较高的ADC。它从最高位开始逼近,逐一比较,并根据比较结果不断逼近所测量的数字量。这种ADC常用于需要高精度的应用,如仪器、传感器和电路控制等领域。

    2.积分型ADC:

    积分型ADC利用了信号积分的特性,将模拟信号分别积分和放电,并根据放电时间和模拟电压之间的关系,计算出模拟信号的值。这种ADC通常用于需要高速且精确的应用领域,如高速数据采集和声音处理等。

    3.单比较器型ADC:

    单比较器型ADC具有简单设计和低功耗的优点。它通过对参考电压和输入信号的比较,确定比较器的输出来得到模拟信号的值。它通常应用于低精度的电路,如电池电压检测等。

    4.脉冲编码型ADC:

    脉冲编码型ADC将模拟信号编码成脉冲信号,并通过对脉冲信号的计数得到数字信号的值。这种ADC通常用于高速和低功耗的应用领域,如视频和图像处理,还可以用于移动设备和智能手表等小型电子产品的应用。

    以上是ADC的一些常见分类,不同类型的ADC适用于不同的应用场景,同时,不同类型的ADC在精度、功耗、速度和价格等方面也有差异。

  • 在单片机中ADC一般采用哪一种类型
  • ① 在单片机中,ADC一般采用逐次逼近型ADC或单比较器型ADC。逐次逼近型ADC可以提供较高的精度,而单比较器型ADC则具有简单和低功耗的优点。
    ② 其中,逐次逼近型ADC通常比较精确,通过比较ADC的输出和参考电压大小,确定位值输出。由于逐次逼近算法每次只确定一位比特,所以需要多次多次逼进,速度较慢。但由于现有的MCU一般都有硬件支持,因此程序也比较容易实现。
    ③ 单比较器型ADC是一种常见的低精度ADC,它采用单个比较器对参考电压和输入信号进行比较。它通常具有低功耗、体积小、成本低等优点,能够满足一些功耗要求较低、精度要求不高的应用场景。然而,由于单比较器型ADC的输出是一个开关量,其精度不如逐次逼近型ADC,不过它在一些应用中也显得更加实用,如电池电压检测等。
    ④ 综上所述,单片机的ADC根据不同的应用场景而选择逐次逼近型ADC或单比较器型ADC,以满足不同的精度、速度、功耗和成本要求。

  • STM32F103系列的单片机的ADC采用什么类型的ADC
  • STM32F103系列的单片机内置了12位逐次逼近型模数转换器(ADC),可采用单独或多路扩展模式进行采样转换。该ADC采用的是逐次逼近型ADC。该型号的ADC最大采样速率为1Msps,具有多通道采样功能和多种触发方式,可满足不同的应用要求。此外,STM32F103系列单片机的ADC支持内部参考电压和外部参考电压,以及DMA和中断方式进行数据传输。因此在使用STM32F103系列单片机进行模拟量采集时,可以采用其内置的逐次逼近型ADC来实现对模拟信号的高精度采样。

  • 怎么查询ADC的类型
  • 在STM32参考手册中,模拟、数字转换(ADC)章节中有介绍,如下:

    7.ADC的工作原理

    ADC(Analog-to-Digital Converter)是模拟信号转换为数字信号的电子元件,其工作原理可简单概括为:将模拟信号经过采样、量化和编码等步骤转换成数字信号。

  • 采样
  • 将模拟信号按照一定的时间间隔进行采样,根据采样定理,采样频率要大于2倍的信号最大频率。

  • 量化
  • 采样得到的模拟信号数值是连续的,为了转换成数字信号,需要将其离散化。量化过程会将连续的模拟信号转换成离散的数字信号,通常使用ADC内部的比较器,将输入的模拟信号与一些固定电压进行比较,并据此确定该信号在固定时刻内的大小区间。上图和这部分的知识可以参照这篇知乎文章:https://www.zhihu.com/tardis/zm/art/462841831?source_id=1005

  • 编码
  • 编码是将量化后的数字信号转换成二进制数。通常使用的是逐次逼近法,即将每个定时段后,两个可能的数字中选其中的一个,将数字信号由连续变量转化为离散变量。 ADC根据输入模拟量信号的量化值大小,通过电路控制二进制加法器的级数来实现逐次逼近法。

    你可以通过B站上的https://www.bilibili.com/video/BV1LN4y1g7yt/ 这个视频了解什么是逐次逼近法:

  • 输出
  • 经过采样、量化和编码后,ADC输出的是一串二进制代码,该代码代表着输入模拟信号的数字化结果。这些数字化结果可以通过接口(如SPI、I2C、USART等)输出到其他外设进行进一步处理和存储。

    需要注意的是,ADC的转换精度与采样率有关,通常转换精度越高(比如12位、16位),采样率越高,ADC的精度和灵敏度也就越高,但相应的功耗和转换时间也会增加。

    8.ADC的参数

    ADC是一个重要的电子元器件,通常需要考虑以下几个参数:

    分辨率:ADC转换的数字值的位数,常用的有8位、10位、12位、16位等,分辨率越高,精度越高,但转换速度会受到影响。
    采样率:ADC采样的频率,指ADC每秒可以对输入信号进行多少次采样,采样率越高,转换出来的信息将更接近原始信号,但转换时间也会增加。
    灵敏度:指在不同电平的输入下,ADC在输出端所能够分辨的最小量化单位,也称为LSB(最小可测量值),其值取决于ADC的分辨率。
    输入电压范围:ADC能够转换的模拟信号的电压范围,超出输入电压范围的模拟信号将导致ADC失真。
    信噪比(SNR)和总谐波失真(THD):反映ADC在转换过程中的精度和噪声抗干扰能力,SNR越高,转换精度越高,THD越低,输出信号越干净。
    功耗:ADC在工作时所消耗的电功率,功耗越低,对于需要长时间运行的应用更为适用。
    模式:有单次采样模式、均值模式、峰值模式等,不同模式适用于不同的应用场景。
    综上所述,选择ADC时需要根据不同的应用场景和要求选取适当的分辨率、采样率、输入电压范围、信噪比等参数。

    二.DAC的基础知识

    1.什么是DAC

    ① DAC是数字模拟转换器(Digital-to-Analog Converter)的缩写,是一种电子元件或集成电路,用于将数字信号转换为对应的模拟电压或电流输出。它将数字信号中每一个离散的数值转换为对应的连续的模拟信号,以便于驱动模拟电路或外设等。
    ② 通常情况下,数字信号是由微处理器、单片机、DSP等数字电路产生的,其信号取值范围是固定的、离散的、量化的,在某些应用中需要将这些数字信号转换为模拟信号,如音频信号处理、温度控制等领域。因此,DAC作为一种重要的数字与模拟接口,广泛应用于各种电子产品中,包括音频设备、仪表、通信设备、工业控制系统和汽车电子等。

    2.在单片机中我们一般使用DAC技术来做什么?

    在单片机中,DAC技术主要用于将数字信号转换成模拟信号,以驱动各种需要模拟输入信号的电路或设备。常见的应用包括:
    1.音频处理:DAC被广泛应用于音频领域,如音效处理、音量控制、音频合成等。单片机通过DAC输出模拟信号,驱动扬声器或耳机等音频输出设备。
    2.电压输出:DAC也可以被用来控制电源以及其它需要模拟输入电压的设备,如电机驱动、热敏电阻温度采集、LED亮度调节控制等。
    3.模拟信号控制:例如模拟表盘、电流表、电压表等。单片机通过DAC输出模拟信号,驱动模拟表头指针。
    总之,DAC是单片机中重要的模拟输出方式之一,可以提供准确、稳定的模拟输出信号,使单片机能够与模拟电路或外设连贯无缝地进行数据交互。

    3.怎么看单片机的某一个引脚是否具有ADC功能

    下图以STM32F103的数据手册为例,在Full compatibility throughout the family中就列出了相关DAC情况。其中STM32F103xx系列中,低密度型号设备和中低密度型号设备都不具备DAC功能。

    4.PWM和DAC的区别

    ① PWM代表脉冲宽度调制,DAC代表数字到模拟转换。这两种技术在控制电路中常被用于产生模拟信号。
    ② PWM是一种数字信号,它通过不同占空比的脉冲信号来模拟产生一个模拟信号。PWM的输出信号包含一个高电平时间和一个低电平时间,通过这两个时间的比例来控制输出电压的大小。由于PWM信号是数字信号,所以它通常需要通过低通滤波器来去除高频噪声,生成一个平滑的模拟信号。
    ③ DAC是将数字信号转换为模拟信号的过程。它将数字信号的离散取值转化为连续的模拟信号。DAC通常具有比较高的精度和分辨率,可以产生高质量的模拟信号。
    ④ 因此,PWM和DAC都可以产生模拟信号,但它们的原理和应用场景略有不同。PWM通常用于控制设备,例如马达或LED灯的亮度调节。而DAC通常用于音频、视频和其他需要高质量模拟信号的应用中。

    5.DAC的工作原理

    DAC(数字模拟转换器)的作用是将数字信号转换成相应的模拟信号,它是数字信号处理中最常用的模拟输出设备之一。DAC的工作原理可以简单地描述为以下几个步骤:

    1. 输入数字信号:首先,将一个数字信号(如二进制代码)输入到DAC芯片中。
    2. 数字到模拟转换:通过DAC芯片内部的电路,在数字信号和模拟信号之间建立了一个映射关系,将数字信号转换成相应的模拟信号。这个过程主要涉及到DAC芯片内部的参考电压、比较器和开关电路等模块,以实现模拟信号输出的稳定性和准确性。
    3. 输出模拟信号:最后,DAC芯片将模拟信号输出到DAC的输出端口上,供外部电路使用。

    需要注意的是,DAC的转换速度和精度取决于DAC芯片的设计和工作电路的特性。因此,在实际应用中,需要根据具体需求选择合适的DAC芯片,并正确设计和使用电路,以保证模拟信号输出的准确性和可靠性。

    6.DAC的参数

    DAC(数字模拟转换器)的参数包括以下几个方面:

    1. 分辨率(Resolution):分辨率是指DAC可以输出的模拟电压值的细节程度,通常用比特数(bits)表示,也就是能够将数字信号精确转换为多少级的模拟电压。例如,一个12位的DAC可以将数字信号精确转换为2^12=4096个模拟电压级别。

    2. 采样速率(Sampling Rate):采样速率是指DAC每秒钟可以进行多少次数字到模拟的转换,通常用赫兹(Hz)表示。采样速率越高,输出的模拟信号就越精确。

    3. 转换精度(Accuracy):转换精度是指DAC将数字信号转换为模拟信号时的精确度。通常用百分比的形式来表示,例如0.1%。转换精度越高,输出的模拟信号就越准确。

    4. DNL(差分非线性度):DNL是描述DAC输出非线性误差的指标,它反映了DAC相邻码之间的偏差是否均匀。如果DNL小于1 LSB(最低有效位),则认为DAC的性能较好。

    5. INL(积分非线性度):INL是一种衡量DAC非线性误差的指标,它反映了所有码之间的偏差是否均匀。如果INL小于1 LSB,也认为DAC的性能较好。

    6. 输出电压范围(Output Voltage Range):输出电压范围是指DAC可以输出的模拟电压的最大值和最小值之间的差值。通常用伏特(V)表示。

    7. 供电电源(Power Supply):DAC需要一个合适的供电电源来工作,需要在应用中选择合适的供电电源。

    8. 功耗(Power Consumption):DAC的功耗越低,对于应用来说就越省电。

    9. 封装类型(Package Type):DAC的封装类型有多种,选择合适的封装类型可以方便应用的设计和安装。

    以上几个参数可以帮助用户选择合适的DAC芯片,并满足应用需求。

    三.代码实例

    下面的实例代码是我写的某个项目中ADC部分的代码,该项目使用了DMA来实现同步数据采集,至于怎么通过STM32来编写ADC采集代码就不做讲解了,你可以通过这篇博文进行了解https://blog.csdn.net/weixin_44636409/article/details/118678500。

  • 原理图
  • adc.h
  • #ifndef __ADC_H
    #define __ADC_H	
    #include "sys.h"
    
    
    void Adc_Init(void);
    u16 Get_Adc_SoilMoisture();
    u16 Get_Adc_WaterDepth();
    #endif 
    
    
  • adc.c
  • #include "adc.h"
    #include "delay.h"
    #include "usart.h"
    #include "math.h"
    __IO uint32_t ADC_convered[1]={0}; // ADC2不存在DMA,所以只需要一个1空间即可;ADC2采用高16位,土壤湿度;ADC1采用低16位,水位深度
    
    
    static void ADC_GPIO_CONFIG(void)// IO口的初始化
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE );	  //使能GPIOB通道时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE );	  //使能GPIOA通道时钟
    	// PA0的GPIO配置
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	// PB1的GPIO配置
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    	GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    }
    
    
    static void ADC_MODE_CONFIG(void)// 配置ADC的模式
    { 	
    	// 开启时钟
    	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);// DMA1时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);// ADC1和ADC2时钟
    	
    	
    	// ADC和DMA的结构体
    	ADC_InitTypeDef ADC_InitStruct;	
    	DMA_InitTypeDef DMA_InitStructure;
    
    	
    	// 配置DMA
    	DMA_DeInit(DMA1_Channel1);// 重置DMA1(复位)
    	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC1->DR));// 外设地址(数据源地址)
    	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_convered;// 存储器地址
    	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;// 外设到存储器
    	DMA_InitStructure.DMA_BufferSize = 1;// 缓存区大小
    	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;// 外设地址是否递增(否)
    	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;// 存储器地址是否递增(否)
    	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;    // 外设大小(1字=32位)
    	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;            // 存储器大小(1字=32位)
    	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;	// 循环传输模式
    	DMA_InitStructure.DMA_Priority = DMA_Priority_High;// DMA传输优先级(高)
    	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;// 禁止存储器到存储器
    	DMA_Init(DMA1_Channel1, &DMA_InitStructure);// 初始化DMA
    	DMA_Cmd(DMA1_Channel1, ENABLE);// 使能DMA通道
    
      // 配置ADC1
    	ADC_InitStruct.ADC_Mode = ADC_Mode_RegSimult;           // 采用规则同步模式
    	ADC_InitStruct.ADC_ScanConvMode = DISABLE;       // 不启用扫描模式(只有一个不需要扫描)
    	ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;	// 启用连续转换
    	ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 启动方式不采用中断方式
    	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;// 数据对齐方式采用右对齐
    	ADC_InitStruct.ADC_NbrOfChannel = 1;	// 转换通道数量:1
    	ADC_Init(ADC1,&ADC_InitStruct);// 初始化ADC
    	
    	// 配置ADC时钟N狿CLK2的8分频,即9MHz
    	RCC_ADCCLKConfig(RCC_PCLK2_Div8);	
    	// 配置ADC 通道的转换顺序和采样时间
    	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);
      // 使能ADC DMA请求
    	ADC_DMACmd(ADC1, ENABLE);
    
    
      // 配置ADC2
    	ADC_InitStruct.ADC_Mode = ADC_Mode_RegSimult;           // 采用规则同步模式
    	ADC_InitStruct.ADC_ScanConvMode = DISABLE;       // 不启用扫描模式(只有一个不需要扫描)
    	ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;	// 启用连续转换
    	ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 启动方式不采用中断方式
    	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;// 数据对齐方式采用右对齐
    	ADC_InitStruct.ADC_NbrOfChannel = 1;	// 转换通道数量:1
    	ADC_Init(ADC2,&ADC_InitStruct);// 初始化ADC
    	
    	// 配置ADC时钟N狿CLK2的8分频,即9MHz
    	RCC_ADCCLKConfig(RCC_PCLK2_Div8);	
    	// 配置ADC 通道的转换顺序和采样时间
    	ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 1, ADC_SampleTime_239Cycles5);
      /* 使能ADCx_2的外部触发转换 */
      ADC_ExternalTrigConvCmd(ADC2, ENABLE);
    
    
    	/**** ADC1校验 ****/
    	// 开启ADC ,并开始转换
    	ADC_Cmd(ADC1, ENABLE);	
    	// 初始化ADC 校准寄存器  
    	ADC_ResetCalibration(ADC1);
    	// 等待校准寄存器初始化完成
    	while(ADC_GetResetCalibrationStatus(ADC1));	
    	// ADC开始校准
    	ADC_StartCalibration(ADC1);
    	// 等待校准完成
    	while(ADC_GetCalibrationStatus(ADC1));
    
    	/**** ADC2校验 ****/
    	// 开启ADC ,并开始转换
    	ADC_Cmd(ADC2, ENABLE);	
    	// 初始化ADC 校准寄存器  
    	ADC_ResetCalibration(ADC2);
    	// 等待校准寄存器初始化完成
    	while(ADC_GetResetCalibrationStatus(ADC2));	
    	// ADC开始校准
    	ADC_StartCalibration(ADC2);
    	// 等待校准完成
    	while(ADC_GetCalibrationStatus(ADC2));
    
    	// 由于没有采用外部触发,所以使用软件触发ADC转换 (ADC2采用的外部触发)
    	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    }				  
    
    
    void Adc_Init()// 初始化Adc
    {
       ADC_GPIO_CONFIG();
       ADC_MODE_CONFIG();
    }
    
    
    
    
    u16 Get_Adc_SoilMoisture()  //获取土壤湿度的数据并返回给主函数
    {
    	
    	  uint16_t temp = (ADC_convered[0] & 0xFFFF0000) >> 16;     // 高16位数据,这是ADC2的转换数据
        UsartPrintf(USART1,"adc1=%d",((ADC_convered[0] & 0xFFFF0000) >> 16)); 
    	  float result = (4095-(float)temp)/(4095-1948)*100;
    	
    	return result >=100? 100:result;//(M_max-adcx)/(M_max-M_min)*100
    }
    
    
    u16 Get_Adc_WaterDepth(){   //获取水位传感器的数据并返回给主函数
      uint16_t temp = (ADC_convered[0] & 0xFFFF);   
    	if(temp<= 3){
    		return 0;
    	}else{
    			// 说明有值
    	float tempValue = (float)temp/3.5;//GetAdc=2300/x = 250 ;250x=2300;x=2300/661
    	u16 temp2 = (exp(0.0056*tempValue));//0.0056*tempValue = 3.7;tempValue=3.7/0.0056=661
    	  UsartPrintf(USART1,"waterdepth=%d;GetAdc(0)=%d;tempValue=%.1f",temp2,temp,tempValue);
    		return temp2;
    	}
    }
    
    
  • main.c
  • #include "adc.h"
    int waterDepth = 0; //光照度
    int soilMoisture = 0;// 土壤湿度
    
    int main(){
    // 初始化ADC
    Adc_Init();
    
    while(1){
    	 // 获取土壤湿度
    	 soilMoisture = Get_Adc_SoilMoisture();
    		
    	 // 获取水位
    	 waterDepth = Get_Adc_WaterDepth(); 
    	 // 延时...
    }
    return 0;
    }
    
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » 深入理解STM32中级篇4-ADC和DAC并实践

    发表评论