硬件驱动——I.MX6ULL裸机启动(7)(ADC相关设置)
※重点
1.
ADC是模拟到数字转换器(Analog-to-Digital Conberter)的缩写,他是一种电子设备或模块,2440内部拥有一个ADC外设。用于将连续变化的模拟信号转换为离散的数字信号,以便数字系统(如微处理器,微控制器等)能够对其处理和分析。
2.
ADC的分辨率是ADC当中比较器的个数
常见的分辨率有8位,10位,12位,16位
3.
ADC的参考电压的作用:
(1)定义量程范围(2)决定转换精度与分辨率(3)影响动态性能
4.
逐次逼近法的工作原理:将基准电压的1/2与待测电压放入比较器的b和a进行比较,如果待测电压大于基准电压的1/2则比较器输出1,如果待测电压小于基准电压的1/2则比较器输出0,若比较器输出1,则将b变为基准电压1/2减去基准电压1/2的1/2,若比较器输出0,则将b变为基准电压1/2加基准电压1/2的1/2,以此类退,以这种方式来减小误差,分辨率多少位就有多少个比较器,位数越多基准电压值越精准
一.ADC相关定义和原理
1.模拟信号一般是指连续变化的电压信号,其数值在一定范围内变化。而数字信号是由一系列练得数字表示,只能取有限的值,通常以二进制形式表示
2.ADC的工作原理是将模拟信号分割成一系列离散的取样,并将每个取样值转换为相应的数字表示。这个过程涉及到两个主要步骤:采样和量化
3.采样:ADC将连续变化的模拟信号在一定时间间隔内进行取样。取样频率决定了每秒采集的样本数,通常以赫兹表示,采样过程通过保持并测量模拟信号在每个采样时间点的电压值来实现。
4.量化:采样得到的连续模拟信号经过量化转换为数字形式。量化是将每个采样值映射到一个离散的数字值的过程。这通常通过比较采样值与参考电压之间的差异,并将其转换为数字表示。
5.ADC量化的过程是相对于一个基准值得,这个基准值称之为基准电压。一般采用逐次逼近法的ADC会先拿采样电压Vabc和基准电压Vref的1/2进行比较,如果Vabc>Vref,则结果为1,否则结果为0。之后继续拿Vabc和Vref的1/4或Vref的3/4继续比较。这个过程有点像二分法,每次比较都会使量化的结果逼近真实值。很明显,比较的次数决定了测量的精度,这个精度被称之为ADC的分辨率。比如一个比较了8次的ADC外设,他就称之为8位ADC,其结果是0~255之间的一个数值,设该数值为n,那么实际电压就是Vref * (n / 255)。如果把比较次数增加到10次,结果就是0~1023之间的一个数。常见的分辨率包括8位,10位,12位,16位
二.IMX6ULL中的ADC
1.IMX6ULL内部具有两个ADC控制器。都是采用逐次逼近法设计的。每路ADC的分辨率可选,分别为8/10/12位。IMX6ULL内部ADC具有自动校准功能,因此能够保证更高的测量精度;最大转换速率为1MHz,即完成一次转换所需的时间最快只需要1us。IMX6ULL的ADC还具有硬件平均功能和比较功能,大大方便了软件设计。
2.每个ADC拥有10个通道,这里的通道就是指输入的电压信号是从那个引脚输入进来的意思。10个引脚其实就是GPIO1_IO00~GPIO1_IO09这10个引脚,我们在配置引脚功能时只需要将引脚配置为GPIO就行,电气配置时可以保持默认配置下使能Keeper即可。
3.IMX6ULL的时钟源可以是igpclk,igpclk/2和ADACK,其中ADACK是IMX6ULL内部提供的时钟源,只能提供给ADC外设使用,这样做的目的是保证系统处于低功耗状态时,ADC依旧能够运行。ADACK的时钟默认为20MHz。
4.IMX6ULL的ADC使用,首先在初始化的时候配置好引脚,之后配置ADCx_CFG和ADCx_GC寄存器。然后启动一次自动校准,系统校准完成后每次向ADCx_HC0寄存器中写入一次数据(本质是切换到别的通道之后再切换回来)就会启动一次ADC转换。转换结束之后的数据就保存在ADCx_R0寄存器当中。
三.相关代码
#include "adc.h"
#include "MCIMX6Y2.h"
#include "fsl_iomuxc.h"
#include "stdio.h"void init_adc1_channle1(void)
{IOMUXC_SetPinMux(IOMUXC_GPIO1_IO01_GPIO1_IO01, 0); //配置引脚的IO复用功能IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO01_GPIO1_IO01, IOMUXC_SW_PAD_CTL_PAD_PKE(1)); //配置IO01的电气属性,打开使能KeeperIOMUXC_SetPinConfig(IOMUXC_GPIO1_IO01_GPIO1_IO01, IOMUXC_SW_PAD_CTL_PAD_PUE(0)); //将使能keeper设置为保持状态ADC1->HC[0] &= ~(1 << 7); //将转换完成中断关闭ADC1->CFG = 0; //将CFG寄存器的所有位清零ADC1->CFG |= (2 << 2) | (3 << 0); //将ADC寄存器设置为12位的分辨率,选择ADACK时钟ADC1->GC = 0; //将GC寄存器的所有位清零ADC1->GC |= (1 << 0); //由于时钟选择的是ADACK时钟,所以在此处将该时钟使能printf(adc1_clibration() ? "Calibration completed normally" : "Calibration failed");
}int adc1_clibration(void)
{ADC1->GC |= (1 << 7); //校准时应该将此位置1while((ADC1->GC & (1 << 7)) != 0); //判断此位是否为0,校准完成后此位会自动清零if((ADC1->GS & (1 << 1)) == 0) //判断是否校准失败标记{return 1;}else{return 0;}
}unsigned short adc_get_origin_value(void)
{ADC1->HC[0] = 0; //配置转换通道为通道1,禁用中断ADC1->HC[0] |= (1 << 0);while((ADC1->HS & (1 << 0)) == 0); //等待转换完成return ADC1->R[0] & 0xFFF; //1111 1111 1111 返回12位ADC转换结果
}
#include "beep.h"
#include "led.h"
#include "key.h"
#include "core_ca7.h"
#include "interrupt.h"
#include "clock.h"
#include "epit.h"
#include "gpt.h"
#include "delay.h"
#include "uart.h"
#include "stdio.h"
#include "i2c.h"
#include "string.h"
#include "lm75.h"
#include "adc.h"int main(void)
{init_clock();system_interrupt_init();init_beep();init_led();
// init_key();
// init_epit1();init_gpt1();init_uart1();init_i2c1();init_adc1_channle1();while(1){unsigned short t;t = adc_get_origin_value();printf("%d\n",t);}return 0;
}