首先,关于AD转换有两个比较重要的寄存器
P1ADF寄存器
ADC_CONTR寄存器
这两个寄存器均为不可位寻址寄存器,所以配置起来会比较困难一些
Q:不可位寻址是什么意思呢?
A:平时我们配置IO口的时候经常会用到sbit语句,假如我想让P00定位到P0端口的第0个引脚,那就会这样写
sbit P00 = P0^0;
但上面提到的两个寄存器却不能这么方便的进行配置,正是因为它们是不可寻址寄存器
除此之外还有两个寄存器是拿来保存转换结果的分别是ADC_RES和ADCRESL,但这储存方法还有两种,切换方法是CLK_DIV寄存器中的第五位(ADRJ)的值来的
至于为什么要这样搞我也就不太清楚了
一、端口选择
关于端口选择,上面两个寄存器中,P1ADF是专门选择AD转换的引脚的,而ADC_CONTR的后三位(CSH0、CSH1、CSH2)也是选择AD转换引脚的,所以在配置的时候这两个寄存器得相互对应起来才行
关于P1ADF选择就很简单,用哪个就让哪个置"1"就行,而另一个寄存器ADC_CONTR就得用3位代替8位来选择
但同时这三位又正好在后三位,所以通常我们用10进制赋值的之后就正好对应上去了,假如我想配置P17为AD输入,那就让ADC_CONTR = 7;就行了,因为十进制的7正好对应二进制的0111;而P1ADF寄存器就简单的用P1ADF = (0x01 << 7);这样就行了。
二、转换启动位
ADC_CONTR寄存器的第3位就是AD转换的启动位(ADC_START),当手动将其置"1"后,AD转换开始,当AD转换结束后这个位就会自动置"0",还是比较方便的。
三、转换标志位
ADC_CONTR寄存器的第4位就是AD转换的转换标志位(ADC_FLAG),每次当AD转换结束完成后,这个位就会自动置"1",需要手动将这一位重新置"0"。
四、转换速度
ADC_CONTR寄存器的第5、6位就是AD转换的速度选择(SPEED1、SPEED0),这个转换速度取决于系统时钟周期,具体配置如下
对于两位速度选择,一共就上面4种速度方式。
五、转换总开关
ADC_CONTR寄存器的第7位就是AD转换的总开关(ADC_POWER),这个不用过多解释,就是总开关,想用AD转换就必须把这个位置"1"
知道上面这些东西之后就可以愉快的进行AD转换了,这个代码是之前翻阅资料的时候找到的,同时我也是对这个函数进行了一些修改,让它变得可能好用一点
#include "STC15F2K60S2.h"
//将各个设置的标准提前宏定义好
#define ADC_POWER 0x80 //ADC 模数转换总电源 1000 0000
#define ADC_FLAG 0x10 //ADC 模数转换结束标志位 0001 0000
#define ADC_START 0x08 //ADC 模数转换启动控制位 0000 1000
//对于转换速度的宏定义,只用其中一个
#define ADC_SPEEDLL 0x00 //540 clocks 0000 0000
#define ADC_SPEEDL 0x20 //360 clocks 0010 0000
#define ADC_SPEEDH 0x40 //180 clocks 0100 0000
#define ADC_SPEEDHH 0x60 //90 clocks 0110 0000
/*========================================================
*功能描述: 获取P1指定引脚的AD转换值
*参数说明: H -> P1上某个IO值
* (假如我想获取P1.0上的AD转换值
* 那么直接GetADCResult(0)即可)
*附加说明: 无
*========================================================*/
unsigned int GetADCResult(unsigned char H)
{
unsigned int Up; //定义返回值
ADC_RES = 0;
ADC_RESL = 0;
P1ASF = (0x01 << H);
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | H | ADC_START;
_nop_();
_nop_();
_nop_();
_nop_();
while(!(ADC_CONTR & ADC_FLAG));
ADC_CONTR &= ~ADC_FLAG;
Up = ADC_RES;
return Up;
}
接下来我们逐行解释这个函数,这里使用的芯片是自带AD转换的STC15F2K60S2,大部分STC芯片都能用
首先开始就是一堆的宏定义哈,因为之前也说了,涉及AD转换的两个寄存器不能进行位寻址,所以只能直接通过计算赋值来实现功能,代码中对于每个宏定义的16进制对应的2进制都有标注,可以对照上面的解释来看
函数内部,参数定义了个ch,用来选择P1端口上的哪个口进行AD转换;
开始先把两个用来储存AD转换的值进行清零操作,这样转换的值不会收到上次转换的影响;
之后P1ASF = (0x01 << H); 用来进行端口选择之一;
ADC_CONTR = ADC_POWER | ADC_SPEEDLL | H | ADC_START; 这一行是直接把总电源,速度,端口选择,启动位置"1"全部进行或运算后赋值给了寄存器里,可以说是一步到位;
4个nop延迟是为了等待AD转换的启动(其实只需要在AD总电源打开的时候需要延迟,之后就不需要延迟了)
while(!(ADC_CONTR & ADC_FLAG));这一句用当前寄存器和转换结束标志位进行与运算,如果寄存器中标志位为"0",那么与运算后的值就是0x00(0000 0000),但是如果标志位为"1",进行与运算后的值就是0x10(0001 0000),而在while中非"0"则"1",所以加一个!的标志对结果进行取反,这样就能知道这个标志位是"0"还是"1"了,从然让while正确的进行拦截,等待转换完毕。
ADC_CONTR &= ~ADC_FLAG; 这句就是重新把AD转换标志位重新置"0",等待下次AD转换。
最后两句就是把转换的结果返回出去。
最后,如果你用电位器转换后值一直都是255,而且无论怎么转都是255。
别着急,电位器有三个引脚,需要的是把两段分别解VCC和GND,然后中间接AD转换输入引脚,这样接着滑动电位器,数值才会开始变化。之前我就是被这个坑给坑到了。