关于AD转换,数模转换如何配置—代码开源—简单易懂超详细
时间:2023-01-17 18:30:00
首先,关于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三是寄存器AD转换的启动位(ADC_START),手动放置时"1"后,AD转换开始,当AD转换后,这个位置将自动位置"0",还是比较方便的。
三、转换标志位
ADC_CONTR第四个寄存器是AD转换标志位(ADC_FLAG),每次当AD转换完成后,这个位置将自动放置"1",需要手动重置这个位置"0"。
四、转换速度
ADC_CONTR寄存器的第5、6位就是AD转换速度选择(SPEED1、SPEED0)转换速度取决于系统时钟周期,具体配置如下
对于两位速度的选择,总共有以上四种速度方法。
五、转换主开关
ADC_CONTR第七个寄存器是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 但是,如果标志位于"1",进行与运算后的值就是0x10(0001 0000),而在while中非"0"则"1",所以加一个!标志反向结果,从而知道标志位是"0"还是"1"了,从然让while正确拦截,等待转换完成。
ADC_CONTR &= ~ADC_FLAG; 这句话就是重新开始AD重置转换标志位置"0",等待下次AD转换。
最后两句话是返回转换结果。
最后,如果用电位器转换后,值总是255,无论如何都是255。
别担心,电位器有三个引脚,需要分别解决两段VCC和GND,然后中间接AD转换输入引脚,然后滑动电位器,值开始变化。我以前被这个坑坑坑过。