10.STC15W408AS单片机A/D转换器

STC15系列单片机内部集成了8路10位高速A/D转换器。STC15系列单片机的A/D转换口在P1口(P1.7-P1.0),有8路10位高速A/D转换器,速度到300KHz(30万次/秒)。8路电压输入型A/D,可做温度检测、电池电压检测、按键扫描、频谱检测等。

一.A/D转换器的结构

STC15系列单片机ADC由多路选择开关、比较器、逐次比较寄存器、10位DAC、转换结果寄存器(ADC_RES和ADC_RESL)以及ADC_CONTR构成。

STC15系列单片机的ADC是逐次比较型ADC。逐次比较型ADC由一个比较器和D/A转换器构成,通过逐次比较逻辑,从最高位(MSB)开始,顺序地对每一输入电压与内置D/A转换器输出进行比较,经过多次比较,使转换所得的数字量逐次逼近输入模拟量对应值。逐次比较型A/D转换器具有速度高,功耗低等优点。

从上图可以看出,通过模拟多路开关,将通过ADC0~7的模拟量输入送给比较器。用数/模转换器(DAC)转换的模拟量与输入的模拟量通过比较器进行比较,将比较结果保存到逐次比较寄存器,并通过逐次比较寄存器输出转换结果。A/D转换结束后,最终的转换结果保存到ADC转换结果寄存器ADC_RES和ADC_RESL,同时,置位ADC控制寄存器ADC_CONTR中的A/D转换结束标志位ADC_FLAG,以供程序查询或发出中断申请。模拟通道的选择控制由ADC控制寄存器ADC_CONTR中的CHS2~CHS0确定。ADC的转换速度由ADC控制寄存器中的SPEED1和SPEED0确定。在使用ADC之前,应先给ADC上电,也就是置位ADC控制寄存器中的ADC_POWER位。

当CLK_DIV.5(PCON2.5)/ADRJ = 0时,A/D转换结果寄存器格式如下:

当ADRJ=0时,如果取10位结果,则按下面公式计算:

当ADRJ=0时,如果取8位结果,按下面公式计算:

当CLK_DIV.5(PCON2.5)/ADRJ = 1时,A/D转换结果寄存器格式如下:

当ADRJ=1时,如果取10位结果,则按下面公式计算:

式中,Vin为模拟输入通道输入电压,Vcc为单片机实际工作电压,用单片机工作电压作为

模拟参考电压。

二.与A/D转换相关的寄存器

与STC15系列单片机A/D转换相关的寄存器列于下表所示。

2.1 P1口模拟功能控制寄存器P1ASF

STC15系列单片机的A/D转换口在P1口(P1.7-P1.0),有8路10位高速A/D转换器速度可达到到300KHz(30万次/秒)。8路电压输入型A/D,可做温度检测、电池电压检测、按键扫描、频谱检测等。上电复位后P1口为弱上拉型I/O口,用户可以通过软件设置将8路中的任何一路设置为A/D转换,不需作为A/D使用的P1口可继续作为I/O口使用(建议只作为输入)。需作为A/D使用的口需先将P1ASF特殊功能寄存器中的相应位置为‘1’,将相应的口设置为模拟功能。 P1ASF存器的格式如下:

P1ASF : P1口模拟功能控制寄存器(该寄存器是只写寄存器,读无效)

2.2 ADC控制寄存器ADC_CONTR

ADC_CONTR寄存器的格式如下:

ADC_CONTR : ADC控制寄存器

对ADC_CONTR寄存器进行操作,建议直接用MOV赋值语句,不要用‘与’和‘或’语句。

ADC_POWER: ADC 电源控制位。

0:关闭ADC 电源;

1:打开A/D转换器电源.

建议进入空闲模式和掉电模式前,将ADC电源关闭,即ADC_POWER =0,可降低功耗。

启动A/D转换前一定要确认A/D电源已打开,A/D转换结束后关闭A/D电源可降低功耗,也可

不关闭。初次打开内部A/D转换模拟电源,需适当延时,等内部模拟电源稳定后,再启

动A/D转换。

建议启动A/D转换后,在A/D转换结束之前,不改变任何I/O口的状态,有利于高精度A/D转换,如能将定时器/串行口/中断系统关闭更好。

SPEED1,SPEED0:模数转换器转换速度控制位

ADC_FLAG: 模数转换器转换结束标志位,当A/D转换完成后,ADC_FLAG = 1,要由软件清0。

不管是A/D 转换完成后由该位申请产生中断,还是由软件查询该标志位A/D转换是

否结束,当A/D转换完成后,ADC_FLAG = 1,一定要软件清0。

ADC_START:模数转换器(ADC)转换启动控制位,设置为“1”时,开始转换,转换结束后为0。

CHS2/CHS1/CHS0:模拟输入通道选择,CHS2/CHS1/CHS0

2.3 ADC转换结果调整寄存器位——ADRJ

ADC转换结果调整寄存器位——ADRJ位于寄存器CLK_DIV/PCON中,用于控制ADC转换

结果存放的位置。

ADRJ:ADC转换结果调整

0:ADC_RES[7:0]存放高8位ADC结果,ADC_RESL[1:0]存放低2位ADC结果

1:ADC_RES[1:0]存放高2位ADC结果,ADC_RESL[7:0]存放低8位ADC结果

2.4 A/D转换结果寄存器ADC_RES、ADC_RESL

特殊功能寄存器ADC_RES和ADC_RESL寄存器用于保存A/D转换结果,其格式如下:

CKKO_DIV寄存器的ADRJ位是A/D转换结果寄存器(ADC_RES,ADC_RESL)的数据格式调整控制位。

当ADRJ=0时,10位是A/D转换结果的高8位存放在在ADC_RES中,低2位存放在ADC_RESL的低2位中。

2.5 中断允许寄存器IE

IE : 中断允许寄存器 (可位寻址)

EA : CPU的中断开放标志

EA=1,CPU开放中断,

EA=0,CPU屏蔽所有的中断申请。

EA的作用是使中断允许形成多级控制。即各中断源首先受EA控制;其次还受各中断源自己的

中断允许控制位控制。

EADC : A/D转换中断允许位

EADC=1,允许A/D转换中断,

EADC=0,禁止A/D转换中断。

2.6 A/D转换典型应用线路

3.测试程序

3.1 中断方式

#include "stc15.h"
#include "intrins.h"
#include "delay.h"#define uchar unsigned char
#define uint unsigned int#define FOSC 11059200L          //系统频率
#define BAUD 9600               //串口波特率void UatrInit();
void SendData(uchar dat);
void SendString(char *s);
void AdInit();uchar num[10] = {'0','1','2','3','4','5','6','7','8','9'};
uint adc_result = 0;void main()
{P1M0 = 0x02;P1M1 = 0x00;UatrInit();AdInit();EA = 1;    // CPU开放中断while (1);
}
// 初始化串口
void UatrInit()
{SCON = 0x50;                //8位可变波特率 串口工作模式1T2L = (65536 - (FOSC/4/BAUD));   //设置波特率重装值T2H = (65536 - (FOSC/4/BAUD))>>8;AUXR = 0x14;                //T2为1T模式, 并启动定时器2AUXR |= 0x01;               //选择定时器2为串口1的波特率发生器ES = 1;                     //使能串口1中断
}
// 初始化ADC
void AdInit()
{P1ASF = 0x01;  // P1.0作为模拟功能A/D使用ADC_RES = 0;ADC_RESL = 0;   // 结果寄存器清零ADC_CONTR = 0x88;  // 打开ADC的电源  540个周期转换一次 选择P1.0作为A/D输入来用  delayus(20);EADC = 1;  // 允许A/D转换中断
}
// ADC中断服务函数
void adc_isr() interrupt 5
{ADC_CONTR &= !0x10; // 清除ADC中断标志adc_result = ADC_RES*4 + ADC_RESL;    // 获取ADC结果,高2位在前SendData(num[adc_result/1000]);       // 千SendData(num[adc_result%1000/100]);   // 百SendData(num[adc_result%100/10]);     // 十SendData(num[adc_result%10]);         // 个// SendData(ADC_RES);
//  SendData(ADC_RESL);SendString("\r\n");  // 换行ADC_CONTR = 0x88;    // 开始ADC 转换delayms(2000);
}
// 发送串口数据
void SendData(uchar dat)
{SBUF = dat;while(TI == 0);TI = 0;
}
// 发送字符串
void SendString(char *s)
{while (*s)                  //检测字符串结束标志{SendData(*s++);         //发送当前字符}
}
// 串口中断
void Uart() interrupt 4
{   // 接收中断标志位if (RI){RI = 0;                 //清除RI位//  P0 = SBUF;              //P0显示串口数据SendString("HELLO\r\n");}// 发送中断标志位if (TI){TI = 0;                 //清除TI位SendString("发送完成!\r\n");}
}

3.2 查询方式

#include "stc15.h"
#include "intrins.h"
#include "delay.h"#define uchar unsigned char
#define uint unsigned int#define FOSC 11059200L          //系统频率
#define BAUD 9600               //串口波特率void UatrInit();
void SendData(uchar dat);
void SendString(char *s);
void AdInit();
uint GetADCResult();uchar num[10] = {'0','1','2','3','4','5','6','7','8','9'};
uint adc_result = 0;void main()
{P1M0 = 0x02;P1M1 = 0x00;UatrInit();AdInit();EA = 1;    // CPU开放中断while (1){adc_result = GetADCResult();SendData(num[adc_result/1000]);SendData(num[adc_result%1000/100]);SendData(num[adc_result%100/10]);SendData(num[adc_result%10]);SendString("\r\n");delayms(2000);}
}
// 初始化串口
void UatrInit()
{SCON = 0x50;                //8位可变波特率 串口工作模式1T2L = (65536 - (FOSC/4/BAUD));   //设置波特率重装值T2H = (65536 - (FOSC/4/BAUD))>>8;AUXR = 0x14;                //T2为1T模式, 并启动定时器2AUXR |= 0x01;               //选择定时器2为串口1的波特率发生器ES = 1;                     //使能串口1中断
}
// 初始化ADC
void AdInit()
{P1ASF = 0x01;  // P1.0作为模拟功能A/D使用ADC_RES = 0;ADC_RESL = 0;   // 结果寄存器清零ADC_CONTR = 0x88;  // 打开ADC的电源  540个周期转换一次 选择P1.0作为A/D输入来用  delayus(20);
//  EADC = 1;  // 允许A/D转换中断
}
// 读取ADC结果
uint GetADCResult()
{ADC_CONTR = 0x88;_nop_();                        //等待4个NOP_nop_();_nop_();_nop_();while (!(ADC_CONTR & 0x10));//等待ADC转换完成ADC_CONTR &= ~0x10;         //Close ADCreturn ADC_RES*4 + ADC_RESL;                //返回ADC结果}
// 发送串口数据
void SendData(uchar dat)
{SBUF = dat;while(TI == 0);TI = 0;
}
// 发送字符串
void SendString(char *s)
{while (*s)                  //检测字符串结束标志{SendData(*s++);         //发送当前字符}
}
// 串门中断
void Uart() interrupt 4
{   // 接收中断标志位if (RI){RI = 0;                 //清除RI位}// 发送中断标志位if (TI){TI = 0;                 //清除TI位}
}

四、利用新增的ADC第9通道测量内部参考电压的测试程序

ADC的第9通道是用来测试内部BandGap参考电压的,由于内部BandGap参考电压很稳定,不会随芯片的工作电压的改变而变化,所以可以通过测量内部BandGap参考电压,然后通过ADC的值便可反推出VCC的电压,从而用户可以实现自己的低压检测功能。ADC的第9通道的测量方法:首先将P1ASF初始化为0,即关闭所有P1口的模拟功能然后通过正常的ADC转换的方法读取第0通道的值,即可通过ADC的第9通道读取当前内部BandGap参考电压值。用户实现自己的低压检测功能的实现方法:首先用户需要在VCC很精准的情况下(比如5.0V),测量出内部BandGap参考电压的ADC转换值(比如为BGV5),并将这个值保存到EEPROM中,然后在低压检测的代码中,在实际VCC变化后,测量出的内部BandGap参考电压的ADC转换值(比如为BGVx),最后通过计算公式: 实际VCC = 5.0V * BGV5 / BGVx,即可计算出实际的VCC电压值 ,需要注意的是,第一步的BGV5的基准测量一定要精确。

测试程序:

#include "stc15.h"
#include "intrins.h"
#include "delay.h"#define uchar unsigned char
#define uint unsigned int#define FOSC 11059200L          //系统频率
#define BAUD 9600               //串口波特率void UatrInit();
void SendData(uchar dat);
void SendString(char *s);
void AdInit();
uint GetADCResult();uchar num[] = {'0','1','2','3','4','5','6','7','8','9'};
uint adc_result = 0;void main()
{P1M0 = 0x02;P1M1 = 0x00;UatrInit();AdInit();EA = 1;    // CPU开放中断while (1){adc_result = GetADCResult();SendData(num[adc_result/1000]);       SendData(num[adc_result%1000/100]);SendData(num[adc_result%100/10]);SendData(num[adc_result%10]);// 串口输出的是0259// 实际内部电压  259÷1024*5 = 1.264V// 这个假设电源电压是5V,和下载工具显示的内部电压1245mV很接近了SendString("\r\n");delayms(2000);}
}
// 初始化串口
void UatrInit()
{SCON = 0x50;                //8位可变波特率 串口工作模式1T2L = (65536 - (FOSC/4/BAUD));   //设置波特率重装值T2H = (65536 - (FOSC/4/BAUD))>>8;AUXR = 0x14;                //T2为1T模式, 并启动定时器2AUXR |= 0x01;               //选择定时器2为串口1的波特率发生器ES = 1;                     //使能串口1中断
}
// 初始化ADC
void AdInit()
{P1ASF = 0x00;  // P1不作为模拟功能A/D使用ADC_RES = 0;ADC_RESL = 0;   // 结果寄存器清零ADC_CONTR = 0x88;  // 打开ADC的电源  540个周期转换一次 选择P1.0作为A/D输入来用  delayus(20);
//  EADC = 1;  // 允许A/D转换中断
}
// 读取ADC结果
uint GetADCResult()
{ADC_CONTR = 0x88;_nop_();                        //等待4个NOP_nop_();_nop_();_nop_();while (!(ADC_CONTR & 0x10));  //等待ADC转换完成ADC_CONTR &= ~0x10;           //Close ADCreturn ADC_RES*4 + ADC_RESL;  //返回ADC结果
}
// 发送串口数据
void SendData(uchar dat)
{SBUF = dat;while(TI == 0);TI = 0;
}
// 发送字符串
void SendString(char *s)
{while (*s)                  //检测字符串结束标志{SendData(*s++);         //发送当前字符}
}
// 串口中断服务函数
void Uart() interrupt 4
{   // 接收中断标志位if (RI){RI = 0;                 //清除RI位//  P0 = SBUF;              //P0显示串口数据SendString("HELLO\r\n");}// 发送中断标志位if (TI){TI = 0;                 //清除TI位
//      SendString("发送完成!\r\n");}
}

五、利用BandGap推算出电源电压

在上面的例子中,我们通过A/D转换的第九通道得到了电源电压的AD值。由于内部BandGap参考电压很稳定,不会随芯片的工作电压的改变而变化,所以可以通过两次测量和一次计算便可得到外部的精确电压。

计算公式:

电源电压 = BandGap(电压mV)÷BandGap(AD转换值)×1024

获取内部BandGap电压的程序

#include "stc15.h"
#include "intrins.h"
#include "delay.h"#define uchar unsigned char
#define uint unsigned int#define FOSC 11059200L          //系统频率
#define BAUD 9600               //串口波特率#define ID_ADDR_RAM 0xef        //对于只有256字节RAM的MCU存放地址为0EFH//注意:需要在下载代码时选择"在ID号前添加重要测试参数"选项,才可在程序中获取此参数
#define ID_ADDR_ROM 0x1ff7      //8K程序空间的MCUvoid UatrInit();
void SendData(uchar dat);
void SendString(char *s);
void AdInit();
uint GetADCResult();uchar num[] = {'0','1','2','3','4','5','6','7','8','9'};
uint adc_result = 0;
uint BandGap = 0;
uint Vcc = 0;void main()
{uchar idata *iptr;uchar code *cptr;UatrInit();AdInit();EA = 1;    // CPU开放中断while (1){    iptr = ID_ADDR_RAM;         //从RAM区读取BandGap电压值(单位:毫伏mV)  实际结果和STC-ISP软件读取的一样  1245mVBandGap =  *iptr++ * 256 + *iptr++;  // 1245mVadc_result = GetADCResult();         // 结果为  259Vcc = (double)BandGap/adc_result * 1024; // 得到电源电压 4.92V  实际使用万用表测试的也是这个数值SendData(num[Vcc/1000]);SendData(num[Vcc%1000/100]);SendData(num[Vcc%100/10]);SendData(num[Vcc%10]);SendString("\r\n");     delayms(2000);}
}
// 初始化串口
void UatrInit()
{SCON = 0x50;                //8位可变波特率 串口工作模式1T2L = (65536 - (FOSC/4/BAUD));   //设置波特率重装值T2H = (65536 - (FOSC/4/BAUD))>>8;AUXR = 0x14;                //T2为1T模式, 并启动定时器2AUXR |= 0x01;               //选择定时器2为串口1的波特率发生器ES = 1;                     //使能串口1中断
}
// 初始化ADC
void AdInit()
{P1ASF = 0x00;  // P1不作为模拟功能A/D使用ADC_RES = 0;ADC_RESL = 0;   // 结果寄存器清零ADC_CONTR = 0x88;  // 打开ADC的电源  540个周期转换一次 选择P1.0作为A/D输入来用  delayus(20);
//  EADC = 1;  // 允许A/D转换中断
}
// 读取ADC结果 获取内部BandGap电压的AD转换值
uint GetADCResult()
{ADC_CONTR = 0x88;_nop_();                        //等待4个NOP_nop_();_nop_();_nop_();while (!(ADC_CONTR & 0x10));  //等待ADC转换完成ADC_CONTR &= ~0x10;           //Close ADCreturn ADC_RES*4 + ADC_RESL;  //返回ADC结果
}
// 发送串口数据
void SendData(uchar dat)
{SBUF = dat;while(TI == 0);TI = 0;
}
// 发送字符串
void SendString(char *s)
{while (*s)                  //检测字符串结束标志{SendData(*s++);         //发送当前字符}
}
// 串口服务函数
void Uart() interrupt 4
{   // 接收中断标志位if (RI){RI = 0;                 //清除RI位}// 发送中断标志位if (TI){TI = 0;                 //清除TI位}
}

10.STC15W408AS单片机A/D转换器相关推荐

  1. STC15W408AS单片机通过ADC端口采集模拟量并从串口打印数值

    STC15W408AS单片机通过ADC端口采集模拟量并从串口打印数值 0-1023数据采集 STC15W408AS引脚功能图 STC15系列单片机的A/D转换器 A/D转换器的结构 STC15系列单片 ...

  2. 基于STC15W408AS单片机的陀螺仪显示器设计

    提示:本文属于技术的交流,如有抄袭请联系删除. 文章目录 前言 一.STC15W408AS单片机 二.总体设计 1.硬件设计 (1)原理图设计 a.MCU设计 b.传感器接口设计 c.液晶显示 d.电 ...

  3. 单片机c语言参考文献最新,[2018年最新整理]10个单片机C语言实例.doc

    [2018年最新整理]10个单片机C语言实例 经典单片机实验帮你成功 1. 闪烁灯 1. 实验任务 如图4.1.1 所示:在P1.0 端口上接一个发光二极管L1,使L1 在不停地一亮一 灭,一亮一灭的 ...

  4. 6.STC15W408AS单片机外部中断

    一.外部中断简介 STC15W408AS单片机有4个外部中断,它们分别是:外部中断0(INT0).外部中断1(INT1).外部中断2(INT2).外部中断3(INT3). 外部中断0(INT0)和外部 ...

  5. 11.STC15W408AS单片机CCP/PCA/PWM应用

    STC15W408AS单片机集成了3路可编程计数器阵列(CCP/PCA)模块可用于软件定时器.外部脉冲的捕捉.高速脉冲输出以及脉宽调制(PWM)输出. 一.与CCP/PWM/PCA应用有关的特殊功能寄 ...

  6. 单片机c语言1ms 2ms 4ms方波,第4章 7~10节 单片机C语言.ppt

    第4章 7~10节 单片机C语言 4.7 函 数;4.7.2函数的定义无参函数的定义: 返回值类型 函数名 ( ) {函数体语句} 如果函数没有返回值,可以将返回值类型设为void 函数以&qu ...

  7. 2.STC15W408AS单片机时钟

    STC15W408AS单片机有两个时钟源:内部高精度R/C时钟和外部时钟(外部输入时钟或外部晶体振荡器产生的时钟).内部高精度R/C时钟(±0.3%),±1%温漂,常温下温漂±0.6%(-20℃~+6 ...

  8. STC15W408AS单片机串口切换与下载问题

    STC15W408AS单片机串口切换与下载问题 STC15W408AS这款单片机支持串口的引脚切换功能.但是在配置过程中,发现从默认引脚P3.0和P3.1切换到P3.6和P3.7切换不成功. 官方推荐 ...

  9. STC15W408AS单片机IIC驱动0.96寸OLED显示

    STC15W408AS单片机IIC驱动0.96寸OLED显示 不同页的滚动效果() 全页的滚动效果 STC15W408AS最新系统板 注意图片上的0欧姆电阻贴错了位置,应该是与GND相连的,图片上是P ...

最新文章

  1. OpenCV语义分割semantic segmentation的实例(附完整代码)
  2. 集群、分布式、负载均衡区别与联系
  3. 700多位老人的“智慧”养老记
  4. Mybatis—代理开发和核心配置文件深入
  5. Linux内核设计的艺术
  6. linux内核rop姿势详解,Linux内核ROP姿势详解(二)
  7. 第15章-使用远程服务
  8. 小猪的Python学习之旅 —— 22.安静!吵到我用TNT了
  9. 【SPSS笔记】主效应、交互效应
  10. java之成员变量(实例成员变量和静态成员变量)
  11. github 提交消息的emoji表情符号规范
  12. 【Unreal4】gitignore目录减小项目大小
  13. [team]开发中的“最速曲线”
  14. Android8.0 USB系统框架
  15. 嵌入式linux零基础培训,零基础精通嵌入式linux系统有那么容易吗
  16. java nio netty 教程,4. 彤哥说netty系列之Java NIO实现群聊(自己跟自己聊上瘾了),netty实现...
  17. 如何恢复微信删除的聊天记录
  18. 面向对象三大特征之继承
  19. 蓝桥杯嵌入式 - 资料整理
  20. unity字体效果-1分钟制作字体 荧光 效果(TextMeshPro)

热门文章

  1. 面试官:说一下Redis和MongoDB的区别?
  2. 个人电子邮箱怎么填写?电子邮箱格式怎么写?
  3. 批处理文件方式 加密windows系统目录
  4. 你了解这些常用器件封装及其名字来历么?
  5. 乱花渐欲迷人眼:浅谈关于分布式存储的五大 “谎言”
  6. 直观上理解PCA中特征值和特征向量
  7. Buct oj 1016
  8. STUN协议简要介绍
  9. npm设置淘宝镜像源
  10. mdobus传输数据为正接收到为负数