1. 了解ADC的基本概念:分辨率、精度等。
2. 掌握STC8A8K64D4单片机ADC的配置、采样数据计算为实际电压值的方法。
3. 掌握ADC多通道采样。
实际应用中,我们经常需要将模拟量转换为数字量供CPU处理,如电池电压检测、温度检测等等。对于CPU来说,他能处理的是数字量,所以,需要通过A/D转换(模数转换)将时间连续、幅值也连续的模拟量转换为时间离散、幅值也离散的数字信号,从而实现CPU对模拟信号的处理,这种能够实现A/D转换功能的电路称之为模数转换器(ADC:Analog-to-digital converter)。
ADC的结构和实现原理有多种方式,常见的ADC的类型有积分型、逐次逼近型、并行比较型/串并行型、Σ-Δ调制型等。STC8A8K64D4集成的是逐次逼近型ADC,他由一个比较器和 D/A 转换器通过逐次比较逻辑构成,从 MSB 开始,顺序地对每一位将输入电压与内置 D/A 转换器输出进行比较,经 n 次比较而输出数字值。其优点是速度较高、功耗低。
ADC常用的技术参数有以下几点,这是学习ADC必须要掌握的。
ADC分辨率是指输出数字量变化一个最低有效位(LSB)所需的输入模拟电压的变化量。ADC的分辨率用位数表示,如10位的ADC,分辨率为210=1024。如果ADC的量程为(0~5)V,那么ADC即可“分辨”出(5/1024)V的电压变化。
ADC 的精度取决于量化误差及系统内其他误差的总和。这里要特别注意ADC分辨率和ADC精度的区别,“精度”是用来描述物理量的准确程度的,而“分辨率”是用来描述刻度划分的。对于一个给定的器件,他的分辨率是固定的,如STC8A8K64D4,他的分辨率固定为12位的,但是他的精度不仅仅受器件本身的影响,还可能会受PCB布线、外界环境(温度、湿度、干扰等)的影响而变化。
转换速度是指完成一次从模拟转换到数字的AD转换所需的时间的倒数,STC8A8K64D4单片机最快的速度可以达到800K(每秒转换80万次)。
STC8A8K64D4单片机内部集成了一个12位高速A/D转换器,共有16个通道,ADC最快的转换速度可以达到800K,并且ADC 转换结果的数据格式可以配置为左对齐或右对齐格式,以方便用户程序进行读取和引用。ADC应用步骤如下图所示。
图1:ADC应用步骤
使用STC8A8K64D4单片机ADC时,需要选择使用的ADC通道,STC8A8K64D4单片机ADC的16个通道如下表所示。这里要注意一下,ADC的通道15是没有输入引脚的,他只能用于检测内部参考信号源。
表1:STC8A8K64D4单片机ADC引脚分配
ADC通道 |
对应IO口 |
功能描述 |
ADC0 |
P1.0 |
ADC模拟通道输入0 |
ADC1 |
P1.1 |
ADC模拟通道输入1 |
ADC2 |
P1.2 |
ADC模拟通道输入2 |
ADC3 |
P1.3 |
ADC模拟通道输入3 |
ADC4 |
P1.4 |
ADC模拟通道输入4 |
ADC5 |
P1.5 |
ADC模拟通道输入5 |
ADC6 |
P1.6 |
ADC模拟通道输入6 |
ADC7 |
P1.7 |
ADC模拟通道输入7 |
ADC8 |
P0.0 |
ADC模拟通道输入8 |
ADC9 |
P0.1 |
ADC模拟通道输入9 |
ADC10 |
P0.2 |
ADC模拟通道输入10 |
ADC11 |
P0.3 |
ADC模拟通道输入11 |
ADC12 |
P0.4 |
ADC模拟通道输入12 |
ADC13 |
P0.5 |
ADC模拟通道输入13 |
ADC14 |
P0.6 |
ADC模拟通道输入14 |
ADC15 |
ADC 的第 15 通道只能用于检测内部参考信号源, 参考信号源值出厂时校准为 1.19V,由于制造误差以及测量误差,导致实际的内部参考信号源相比 1.19V,大约有± 1%的误差。如果用户需要知道每一颗芯片的准确内部参考信号源值,可外接精准参考信号源,然后利用 ADC 的第 15 通道进行测量标定。 |
ADC输入通道由“ADC 控制寄存器(ADC_CONTR)”中的ADC_CHS[3:0]位确定,如下所示。另外需要注意,当有I/O口被选择为ADC输入通道时,需要通过PxM0/PxM1寄存器将I/O口模式设置为高阻输入模式。
ADC 控制寄存器(ADC_CONTR):
ADC时钟频率和内部时序决定了ADC的转换速度,STC8A8K64D4的ADC转换速度计算公式如下。可以看到ADC转换速度和时钟频率“SPEED”以及ADC内部时序控制寄存器中的“CSSETUP”、“CSHOLD”和“SMPDUTY”相关。
对于ADC转换速度,要注意以下几点:
ADC时钟频率由“ADC 配置寄存器(ADCCFG)”中的SPEED[3:0]位确定,如下所示。
ADC 配置寄存器(ADCCFG):
ADC时序由“ADC时序控制寄存器(ADCTIM)”中的“CSSETUP”、“CSHOLD”和“SMPDUTY”确定,如下所示。
ADC 时序控制寄存器(ADCTIM):
为了方便用户在程序里面处理ADC采样数据,STC8A8K64D4的ADC提供了两种数据格式:左对齐和右对齐,数据格式由“ADC 配置寄存器(ADCCFG)”中的“RESFMT”位设置,如下所示。
ADC 配置寄存器(ADCCFG):
ADC中断的开启和关闭由中断使能寄存器IE的位5(EADC)控制,如下图所示。另外注意:开启ADC中断的情况下,还需要开启总中断“EA=1”,ADC中断才能起作用。
ADC上电和启动由“ADC 控制寄存器(ADC_CONTR)”中“ADC_POWER”和“ADC_START”位控制,如下图所示。
ADC 控制寄存器(ADC_CONTR):
注意事项:
当A/D 转换完成后,转换结果会自动保存到ADC 转换结果寄存器ADC_RES 和 ADC_RESL中。保存时会按照“ADC 配置寄存器(ADCCFG)”中的“RESFMT”位设置的数据格式保存,因此,我们在读取数据时,也要按照设置的格式获取数据。下面的代码是ADC数据格式为右对齐时的读取示例。
代码清单:读取ADC采样结果
读取ADC采样值后,即可计算电压值。开发板使用的是外部2.5V参考电压,采样值转换为电压的公式如下。
使用ADC模拟通道输入14(即引脚P0.6)采样电位器抽头电压,程序中每500毫秒执行一次电压采样,采样结果计算为电压值后通过串口输出。
本例使用查询方式执行ADC采样,所谓查询方式即不开启中断,当ADC启动采样后,程序中反复查询ADC采样完成标志位,若该位置位,表示当前ADC采样完成,此时,可以读取ADC采样结果。
因为在“main.c”文件中使用了“adc.c”文件中的函数,所以需要引用下面的头文件“adc.h”。
代码清单:引用头文件
ADC初始化通常包含以下部分内容:
为了方便程序调用,我们将ADC初始化封装为名称为“adc_config()”的函数,该函数代码如下:
代码清单:ADC初始化函数
ADC初始化并上电完成后,即可启动ADC转换。ADC每次转换都需要启动一次,也就是每启动一次ADC转换,ADC就会执行一次转换,下次转换前需要再次启动。我们编写的启动ADC转换的函数代码如下。
代码清单:ADC启动函数
本例中,我们使用的查询的方式,因此在启动ADC采样之后,需要查询ADC_CONTR寄存器中的ADC_FLAG位(ADC 转换结束标志位),以此判断ADC是否转换完成,代码清单如下。
代码清单:查询ADC转换是否完成
查询到ADC转换完成后,即可读取ADC转换结果,这里需要注意读取结果时需要结合ADC初始化时配置的采样结果数据格式(左对齐或右对齐),从采样结果中读出正确的采样数据。
代码清单:读取ADC采样值
主函数中调用ADC初始化完成ADC的初始化,之后在主循环中每500ms启动一次ADC转换,启动后一直查询ADC 转换结束标志位ADC_FLAG的值,直到ADC_FLAG置位,即ADC转换完成。此后,读取ADC采样值并将其计算为电压值通过串口输出。
代码清单:主函数
本实验需要使用ADC模拟通道输入14(即引脚P0.6)采样电位器抽头电压,因此需要将P06引脚和电位器电路通过跳线帽连接,如下图所示。
图2:跳线帽短接
图3:串口调试助手收发数据
本实验所实现的功能和“实验13-1”完全一样,不同的地方在于本例中ADC采样使用了中断的方式。即程序中开启ADC中断,当启动ADC采样后,无需查询ADC转换完成标志位,ADC转换完成后会进入ADC中断服务函数,此时,我们即可读取ADC采样结果。
由此可见,中断方式的效率要高于查询方式,因为CPU在启动ADC采样后,可以继续去做其他事情,而无需像查询方式一样去反复查询ADC采样是否完成。当ADC采样完成后,会触发中断,以此通知CPU,ADC采样已经完成。
本例中使用了ADC中断,因此,ADC初始化函数中需要开启ADC中断,代码清单如下所示。
代码清单:ADC初始化函数
当ADC采样完成后,会进入中断服务函数,我们在ADC中断服务函数中读取ADC采样值即可。读出的采样值计算为电压值后,同样使用串口输出,代码清单如下。
代码清单:ADC中断服务函数
主函数中开启总中断,之后,在主循环中每500ms启动一次ADC采样,即每500ms采样一次电位器抽头电压,代码清单如下。
代码清单:主函数
同“实验2-11-1:ADC采样电位器电压(查询方式)”。
同“实验2-11-1:ADC采样电位器电压(查询方式)”。
STC8A8K64D4单片机的ADC有16个通道,但是ADC转换器只有一个,因此,ADC模块每次只能对一个通道进行转换,而不能同时对多个通道进行转换。但是在实际应用时,我们经常会用到多个ADC通道采样电压值,这时,我们可以使用轮询的方式对各个ADC通道进行采样,具体的实现流程如下图所示,即对当前ADC通道采样完成后,切换到下一个ADC通道,之后启动ADC转换并在转换完成后读取采样结果,如此轮询对使用的各个ADC通道采样,从而实现ADC多通道采样。
图4:ADC多通道采样流程
本实验对2个ADC通道进行采样:ADC模拟通道输入2(P1.2)和ADC模拟通道输入14(P0.6)。由于开发板上只有一个电位器,为了实验方便,两个通道做如下处理。
程序中使用轮询的方式对2个ADC通道进行采样,采样的结果计算为电压值后通过串口输出,在串口调试助手里面即可观察到ADC采样的电压值。
本例中使用了2个ADC通道,因此需要修改ADC初始化函数,将两个ADC通道的I/O设置为高阻输入模式。另外,为了方便轮询ADC通道,在ADC初始化函数中不设置ADC通道,而是编写了一个专门用于设置ADC通道的函数“adc_set_channel()”用于设置ADC通道。修改后的ADC初始化函数代码清单如下。
代码清单:ADC初始化函数
用于设置ADC通道的函数“adc_set_channel()”的代码清单如下。
代码清单:ADC通道设置函数
使用函数“adc_set_channel()”选择ADC通道后,即可执行ADC采样。这里,我们编写了一个阻塞式的ADC采样函数,将通道切换、启动ADC采样和数据读取封装在该函数中。代码清单如下,首先设置ADC通道,接着启动ADC采样并一直查询ADC转换完成标志直到ADC转换完成标志置位,之后读出采样结果将之计算为电压并通过串口输出,
代码清单:ADC采样函数
主函数中,先调用ADC初始化函数“adc_config()”初始化ADC,之后在主循环里面轮询对两个ADC通道进行采样,每次采样后演示500ms,这样做是为了方便观察实验数据。
对于多通道采样,需要特别注意的是:如果采样的频率比较快,则需要对ADC内部进行放电,即启动采样时先将ADC通道对应的I/O设置为开漏模式进行放电,接着再将其配置为高阻输入执行ADC采样。
代码清单:主函数
本实验需要使用ADC模拟输入通道14(即引脚P0.6)采样电位器抽头电压和ADC模拟输入通道2(P1.2)采样GND电压,因此需要将J27端子的P06和电位器电路(ADC)通过跳线帽连接,并用杜邦线将J9端子的P12连接到J18端子的GND,如下图所示
图5:硬件连接
图6:串口调试助手收发数据