STC15F2K60S2芯片A/D转换器的应用
1.目的
在工业控制过程中,它是控制系统与微机之间不可缺少的接口方式。要实现自动控制,就要检测有关参数,A/D转换器,把检测到的电压或电流信号(模拟量)转换成计算机能够识别的等效数字量,这些数字量经过计算机处理后输出结果,通过D/A转换器变为电压或电流信号,送到执行机构,达到控制某种过程的目的。
2.与A/D转换相关的寄存器
与STC15系列单片机A/D转换相关的寄存器列于下表所示。
符号 |
描述 |
地址 |
位地址及其符号 MSB LSB |
复位值 |
|||||||
P1ASF |
P1 Analog Function Configure register |
9DH |
P17ASF |
P16ASF |
P15ASF |
P14ASF |
P13ASF |
P12ASF |
P11ASF |
P10ASF |
0000 0000B |
ADC_CONTR |
ADC Control Register |
BCH |
ADC_POWER |
SPEED1 |
SPEED0 |
ADC_FLAG |
ADC_START |
CHS2 |
CHS1 |
CHS0 |
0000 0000B |
ADC_RES |
ADC Result high |
BDH |
|
|
|
|
|
|
|
|
0000 0000B |
ADC_RESL |
ADC Result low |
BEH |
|
|
|
|
|
|
|
|
0000 0000B |
CLK_DIV PCON2 |
时钟分频寄存器 |
97H |
MCKO_S1 |
MCKO_S0 |
ADRJ |
Tx_Rx |
Tx2_Rx2 |
CLKS2 |
CLKS1 |
CLKS0 |
0000 x000B |
IE |
Interrupt Enable |
A8H |
EA |
ELVD |
EADC |
ES |
ET1 |
EX1 |
ET0 |
EX0 |
0000 0000B |
IP |
Interrupt Priority Low |
B8H |
PPCA |
PLVD |
PADC |
PS |
PT1 |
PX1 |
PT0 |
PX0 |
0000 0000B |
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口模拟功能控制寄存器(该寄存器是只写寄存器,读无效)
SFR name |
Adess |
Bit |
B7 |
B6 |
B5 |
B4 |
B3 |
B2 |
B1 |
B0 |
P1ASF |
9DH |
Name |
P17ASF |
P16ASF |
P15ASF |
P14ASF |
P13ASF |
P12ASF |
P11ASF |
P10ASF |
P1ASF[7:0] |
P1.x的功能 |
其中P1ASF寄存器地址为:[9DH](不能进行位寻址) |
P1ASF.0 = 1 |
P1.0口作为模拟功能A/D使用 |
|
P1ASF.1 = 1 |
P1.1口作为模拟功能A/D使用 |
|
P1ASF.2 = 1 |
P1.2口作为模拟功能A/D使用 |
|
P1ASF.3 = 1 |
P1.3口作为模拟功能A/D使用 |
|
P1ASF.4 = 1 |
P1.4口作为模拟功能A/D使用 |
|
P1ASF.5 = 1 |
P1.5口作为模拟功能A/D使用 |
|
P1ASF.6 = 1 |
P1.6口作为模拟功能A/D使用 |
|
P1ASF.7 = 1 |
P1.7口作为模拟功能A/D使用 |
|
2.2. ADC_CONTR
ADC_CONTR寄存器的格式如下:
ADC_CONTR:ADC控制寄存器
SFR name |
Adess |
Bit |
B7 |
B6 |
B5 |
B4 |
B3 |
B2 |
B1 |
B0 |
ADC_CONTR |
BCH |
name |
ADC_POWER |
SPEED1 |
SPEED0 |
ADC_FLAG |
ADC_START |
CHS2 |
CHS1 |
CHS0 |
对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:模数转换器转换速度控制位
SPEED1 |
SPEED0 |
A/D转换所需时间 |
1 |
1 |
90个时钟周期转换一次,CPU工作频率21MHz时,A/D转换速度约300MHz |
1 |
0 |
180个时钟周期转换一次 |
0 |
1 |
360个时钟周期转换一次 |
0 |
0 |
540个时钟周期转换一次 |
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
CHS2 |
CHS1 |
CHS0 |
Analog Channel Select |
0 |
0 |
0 |
选择P1.0作为A/D输入来用 |
0 |
0 |
1 |
选择P1.1作为A/D输入来用 |
0 |
1 |
0 |
选择P1.2作为A/D输入来用 |
0 |
1 |
1 |
选择P1.3作为A/D输入来用 |
1 |
0 |
0 |
选择P1.4作为A/D输入来用 |
1 |
0 |
1 |
选择P1.5作为A/D输入来用 |
1 |
1 |
0 |
选择P1.6作为A/D输入来用 |
1 |
1 |
1 |
选择P1.7作为A/D输入来用 |
2.3.ADC转换结果调整寄存器位—ADRJ
ADC转换结果调整控制位——ADRJ位于寄存器CLK_DIV/PCON中,用于控制ADC转换结果存放的位置。
Mnemonic |
Add |
Name |
B7 |
B6 |
B5 |
B4 |
B3 |
B2 |
B1 |
B0 |
Reset Value |
CLK_DIV |
98H |
时钟寄存器 |
MCKO_S1 |
MCKO_S0 |
ADRJ |
Tx_Rx |
Tx2_Rx2 |
CLKS2 |
CLKS1 |
CLKS0 |
0000,x000 |
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结果
Mnemonic |
Add |
Name |
B7 |
B6 |
B5 |
B4 |
B3 |
B2 |
B1 |
B0 |
ADC_RES |
BDh |
A/D转换结果寄存器高 |
|
|
|
|
|
|
|
|
ADC_RES |
BDh |
A/D转换结果寄存器低 |
|
|
|
|
|
|
|
|
CLK_DIV |
97H |
时钟分频寄存器 |
MCKO_S1 |
MCKO_S0 |
ADRJ |
Tx_Rx |
TX2_Rx2 |
CLKS2 |
CLKS1 |
CLKS0 |
2.4.A/D转换结果寄存器ADC_RES、ADC_RESL
特殊功能寄存器ADC_RES和ADC_RESL寄存器用于保存A/D转换结果,其格式如下:
AUXRI寄存器的ADRJ位是A/D转换结果寄存器(ADC_RES、ADC_RESL)的数据格式调整控制位。
当ADRJ = 0时,10位A/D转换结果的高8位存放在ADC_RES中,低2位存放在ADC_RESL的低2位中。
Mnemonic |
Add |
Name |
B7 |
B6 |
B5 |
B4 |
B3 |
B2 |
B1 |
B0 |
ADC_RES |
BDh |
A/D转换结果寄存器高8位 |
ADC_RES7 |
ADC_RES6 |
ADC_RES5 |
ADC_RES4 |
ADC_RES3 |
ADC_RES2 |
ADC_RES3 |
ADC_RES2 |
ADC_RES |
BDh |
A/D转换结果寄存器低2位 |
- |
- |
- |
- |
- |
- |
ADC_RES1 |
ADC_RES0 |
CLK_DIV |
97H |
时钟分频寄存器 |
|
|
ADRJ = 0 |
|
|
|
|
|
此时,如果用户需取完整10位结果,按下面公式计算:
10-bit A/D ConversionResult:(ADC_RES[7:0],ADC_RESL1:0]) = 1024*Vin/Vcc
如果用户只需取8位结果,按下面公式计算:
8-bit A/D ConversionResult:(ADC_RES[7:0]) = 256*Vin/Vcc
式中,Vin为模拟输入通道输入电压,Vcc为单片机实际工作电压,用单片机工作
电压作为模拟参考电压。
当ADRJ = 1时,10位A/D转换结果的高2位存放在ADC_RES的低2位中,低8位存放在ADC_RESL中。
Mnemonic |
Add |
Name |
B7 |
B6 |
B5 |
B4 |
B3 |
B2 |
B1 |
B0 |
ADC_RES |
BDh |
A/D转换结果寄存器高2位 |
- |
- |
- |
- |
- |
- |
ADC_RES9 |
ADC_RES8 |
ADC_RES |
BDh |
A/D转换结果寄存器低8位 |
ADC_RES7 |
ADC_RES6 |
ADC_RES5 |
ADC_RES4 |
ADC_RES3 |
ADC_RES2 |
ADC_RES1 |
ADC_RES0 |
CLK_DIV |
97H |
时钟分频寄存器 |
|
|
ADRJ = 1 |
|
|
|
|
|
此时,如果用户需取完整10位结果,按下面公式计算:
10-bit A/D ConversionResult:(ADC_RES[1:0],ADC_RESL[7:0]) = 1024*Vin/Vcc
式中,Vin为模拟输入通道输入电压,Vcc为单片机实际工作电压,用单片机工作电压作为模拟参考电压。
2.5.中断允许寄存器IE
IE:中断允许寄存器(可位寻址)
SFR name |
Adess |
Bit |
B7 |
B6 |
B5 |
B4 |
B3 |
B2 |
B1 |
B0 |
IE |
A8H |
Name |
EA |
ELVD |
EADC |
ES |
ET1 |
EX1 |
ET0 |
EX0 |
EA:CPU的中断开放标志
EA = 1,CPU开放中断,
EA = 0,CPU屏蔽所有的中断申请。
EA的作用是使中断允许形成多级控制。即各中断源首先受EA控制;其次还受各中断源自己的中断允许控制位控制。
EADC:A/D转换中断允许位
EADC = 1,允许A/D转换中断,
EADC = 0,禁止A/D转换中断。
2.6.中断优先级控制寄存器IP
IP:中断优先级控制寄存器(可位寻址)
SFR name |
Adess |
Bit |
B7 |
B6 |
B5 |
B4 |
B3 |
B2 |
B1 |
B0 |
IP |
B8H |
Name |
PPCA |
PLVD |
PADC |
PS |
PT1 |
PX1 |
PT0 |
PX0 |
PADC:A/D转换中断优先级控制位。
当PADC = 0时,A/D转换中断为最低优先级中断(优先级0)
当PADC = 1时,A/D转换中断为最高优先级中断(优先级1)
3.A/D转换器的结构
4.程序
/****************************************************/
//利用STC12C5A60S2AD转换,实现温度计
//函数名:main.c
/****************************************************/
#include
#include"10bit_adc.c"
#define uchar unsigned char /*宏定义用uchar 代替unsignedchar*/
#define uint unsigned int /*宏定义用uint 代替 unsignedint*/
code uchar seven_seg[] ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
uchar cp0;
uint cp1,AD_DAT;
sbit P3_4 = P3^4;
sbit P3_5 = P3^5;
sbit P3_6 = P3^6;
/************Timer0中断服务函数***************/
void timer0_isr(void) interrupt 1
{
TH0= (65536 - 1000) / 256; //重装初值
TL0= (65536 - 1000) % 256; //重装初值
cp1++; //中断1次,变量加1
if(cp1>= 1000) //1秒到了
{
cp1= 0;
AD_DAT= get_adc();
AD_DAT= (790 - AD_DAT) * 0.095;
}
P2= 0xff;
P3= 0xff;
switch(cp0)
{
case0: P2 = seven_seg[AD_DAT % 100 % 10]; P3_6 = 0;break;
case1: P2 = seven_seg[AD_DAT % 100 / 10]; P3_5 = 0;;break;
case2: P2 = seven_seg[AD_DAT / 100]; P3_4 = 0;break;
}
cp0++;
if(cp0>=3)cp0 = 0;
}
/*********************Timer0初始化函数***********************/
void timer0_init(void)
{
TMOD= 0x01; //T0工作方式1
TH0= (65536 - 1000) / 256; //对机器脉冲计数1000个计满溢出引发中断
TL0= (65536 - 1000) % 256;
EA= 1; //开总中断
ET0= 1; //开T0中断
TR0= 1; //启动定时器T0
}
/**************************主函数****************************/
void main(void)
{
timer0_init();
adc_init();
while(1); //等待中断
}
/****************************************************/
//利用STC12C5A60S2AD转换,实现温度计
//函数名:10bit_adc.c
/****************************************************/
#include
#include
#define nop _nop_()
#define ADC_POWER 0x80
#define ADC_START 0x08
#define ADC_FLAG 0x10
#define ADC_SPEEDH 0x40 //转换速度为180个时钟周期
#define ADRJ 0x20 //ADRJ = 1;
#define AD_P1_0 0x00 //P1.0为AD输入;
sfr ADC_CONTR = 0xbc;
sfr ADC_RES = 0xbd;
sfr ADC_RESL = 0xbE;
sfr P1ASF = 0x9D;
sfr PCON2 = 0x97;
void adc_init(void)
{
P1ASF= 0x01; //设置P1为模拟输入端口
PCON2= PCON2 | ADRJ; //ADRJ = 1;
ADC_CONTR= ADC_POWER | ADC_SPEEDH | AD_P1_0;
//设置A/D电源开启、转换速度设置、A/D输入端口;
nop;nop;nop;nop;//等待电源稳定;
}
unsigned int get_adc(void)
{
unsignedint i,j;
ADC_CONTR= ADC_CONTR | ADC_START; //开始转换
while((ADC_CONTR& ADC_FLAG) != ADC_FLAG); //等待转换标志置位
i= ADC_RES;
j= ADC_RESL;
i= i << 8;
i= i | j;
ADC_CONTR= ADC_CONTR & ~ADC_FLAG ; //清零转换标志位
ADC_RES= 0;
ADC_RESL= 0;
return(i);
}