• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

零死角玩转stm32级篇4-ADC和DAC

武飞扬头像
嘟嘟的程序员铲屎官
帮助1

一.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;
}

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgeffkf
系列文章
更多 icon
同类精品
更多 icon
继续加载