实验三STC15系列单片机内部双通道10位AD转换程序

/*T8接T3和T2;或T8接T3,T7接T2;调电位器R36可改变内部10位AD转换0和1通道的电
压Vin0或Vin1,采样周期5ms;送AD的电压用万用表在T8(对T6)测量;按照十六进制,0
通道数字量由LCD显示(1行);1通道数字量由LCD显示(2行);0通道对应理论值在左边
5个数码管显示(1个符号位,2个整数位,2个小数位);1通道对应理论值在右边
5个数码管显示(1个符号位,2个整数位,2个小数位);研究2通道间是否需要适当延时*/
#include <15f2k.h>
#include
#define u8c unsigned char code//存放于代码中的无符号8位字符型缩写定义
#define u8 unsigned char //无符号8位字符型缩写定义
#define u16 unsigned int //无符号16位整型缩写定义
#define writecmd XBYTE[0xECFF]//1602写指令端口地址,E正脉冲有下降沿(A12=0),R/W=A9=0写,RS=A8=0写指令
#define readstate XBYTE[0xEEFF]//1602读状态端口地址,E正脉冲有高电平(A12=0),R/W=A9=1读,RS=A8=0读状态
#define writedata XBYTE[0xEDFF]//1602写数据端口地址,E正脉冲有下降沿(A12=0),R/W=A9=0写,RS=A8=1读数据
#define Displayseg XBYTE[0x7FFF]//数码管段码锁存器写端口地址(A15=0)
#define Displaybit XBYTE[0xBFFF]//数码管位码锁存器写端口地址(A14=0)
#define LCD_CLR 0x01 //清屏,清DDRAM内容为空,AC=00H
#define LCD_MODE 0x38 //模式设置,001DLNF**,DL=1是8位数据接口,N=1两行显示,F=0是5*7点阵字符
#define LCD_ON 0x0c //显示开关控制,00001DCB,D=1开显示,C=0关光标,B=0关闪烁
#define LCD_A_MODE 0x06 //输入方式设置,000001I/DS,I/D=1数据读写后AC自动增1,S=0数据读写后画面不动
bit new_cycle_flag=0; //有新采样数据标志,1有新数据
sbit LSIGN=P1^6; //左边的符号位数码管公共端连接引脚,=0可能亮
sbit RSIGN=P1^7; //右边的符号位数码管公共端连接引脚,=0可能亮
u8 r_kTH,m_kTH,r_kTL,m_kTL;//0通道和1通道AD转换结果
u8 dispbuf[10],status,i; //10个数码管显示段码缓存区数组和AD转换状态及计算用中间变量
int Vin0x100,Vin1x100; //据AD值推算的0通道和1通道输入的100倍(显示用)
u16 Axx,j; //显示时用的中间变量
float Vin0,Vin1; //据AD值推算的0通道和1通道输入-11.0V~+10.914V
u8 M=0; //扫描显示位计数变量定义
u8c SG[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//0-F段码表
u8c BT[10]={0xfe,0xfd,0xfb,0xf7,0xff,0xef,0xdf,0xbf,0x7f,0xff};//位码表
u8c disp1[16]={'0',' ','C','h','a','n','n','e','l',' ','A','D',' ',' ','H',' '};
u8c disp2[16]={'1',' ','C','h','a','n','n','e','l',' ','A','D',' ',' ','H',' '};
/***********LCD写指令************/
void LCDwritecmd(char cmd) //要传递指令
{ while((readstate&0x80)!=0); //查询LCD忙否?BF=1表示忙,循环,

直到BF=0退出循环
writecmd=cmd; //写指令,即把指令送[0xE3FF]端口
}
/***********LCD写数据************/
void LCDwritedata(char dat) //要传递数据
{ while((readstate&0x80)!=0); //查询LCD忙否?BF=1表示忙,循环,直到BF=0退出循环
writedata=dat; //写数据,即把数据送[0xE7FF]端口
}
/***********LCD初始化************/
void LCD_init(void) //清屏/8位数据接口/1行/5*7点阵字符/关显示/AC自动增1
{ LCDwritecmd(LCD_MODE); //写模式设置指令
LCDwritecmd(LCD_ON); //写显示开关控制指令
LCDwritecmd(LCD_A_MODE); //写输入方式设置指令
LCDwritecmd(LCD_CLR); //写清屏指令
}
/*******1602液晶屏幕初始化*******/
void Display_init(void) //1602显示初始化
{ LCDwritecmd(0x80); //写指令,设置DDRAM指针AC=0x00
for(i=0;i<16;i++) LCDwritedata(disp1[i]);//往第1行写数据:"0channel AD: H "
LCDwritecmd(0xc0); //写指令,设置DDRAM指针AC=0x40
for(i=0;i<16;i++) LCDwritedata(disp2[i]);//往第2行写数据:"1channel AD: H "
}
/**********内部AD初始化**********/
void AD_init(void) //内部AD初始化
{ CLK_DIV&=0xDF; //MCKO_S1 MCKO_S0 ADRJ TX_RX - CLKS2 CLKS1 CLKS0
//ADRJ=0,ADC_RES[7:0]存高8位ADC结果,ADC_RESL[1:0]存低2位ADC结果
ADC_CONTR=0x80; //开A/D转换电源
for(j=0;j<10000;j++); //适当延时,一般延时1ms以内即可
P1ASF=0x03; //开启P1.0和P1.1作为0通道和1通道模拟量输入通道
ADC_CONTR=0xC0; //ADC_POWER SPEED1 SPEED0 ADC_FLAG ADC_START CHS2 CHS1 CHS0=1 10 0 0 000B
//选择180个时钟周期转换1次,暂时不启动AD转换,选择0通道
for(j=0;j<200;j++); //适当延时,20us~200us即可
}
/***********T0T1初始化***********/
void T0T1_init(void) //10数码管扫描1周AD转换1次,每管显1ms,AD周期10ms
{ AUXR|=0xc0; //T0、T1定时器时钟1T模式,T0定时1ms,AD时间127.3us
TMOD=0x20; //设置定时器模式,T0方式0定时,T1方式2定时
TL0=0x66; //频率=11059200/(65536-0xea66)=1999.855Hz
TH0=0xea; //定时周期=1/1999.855=0.000500036s=0.500036ms
EA=1; //允许中断
ET0=1; //允许T0中断
TR0=1; //定时器0开始计时
}
/*AD值倒推输入电压显示缓存区的更新*/
void disp_g(void) //AD值倒推输入电压显示缓存区的更新
{ if(Vin0x100<0) //如果据0通道AD值推算的输入Vin0的100倍是负数
{ Axx=-Vin0x100; //取绝对值
dispbuf[9]=0x40; //符号位数码管对应送负号的段码
}
else //据0通道AD值推算

的输入Vin0的100倍是正数
{ Axx=Vin0x100; //取据AD值推算的输入Vin0的100倍
dispbuf[9]=0x00; //符号位数码管对应送正号的段码
}
i=(u8)(Axx/1000); //计算电压伏特十位
dispbuf[8]=SG[i]; //电压十位数码管显示缓存更新段码
i=(u8)(Axx/100%10); //计算电压伏特个位
dispbuf[7]=SG[i]|0x80; //电压个位数码管显示缓存更新段码(含小数点)
i=(u8)(Axx/10%10); //计算电压小数后第1位
dispbuf[6]=SG[i]; //电压小数后第1位数码管显示缓存更新段码
i=(u8)(Axx%10); //计算电压小数后第2位
dispbuf[5]=SG[i]; //电压小数后第2位更新
if(Vin1x100<0) //如果据1通道AD值推算的输入Vin1的100倍是负数
{ Axx=-Vin1x100; //取绝对值
dispbuf[4]=0x40; //符号位数码管对应送负号的段码
}
else //据1通道AD值推算的输入Vin1的100倍是正数
{ Axx=Vin1x100; //取据AD值推算的输入Vin1的100倍
dispbuf[4]=0x00; //符号位数码管对应送正号的段码
}
i=(u8)(Axx/1000); //计算电压伏特十位
dispbuf[3]=SG[i]; //电压十位数码管显示缓存更新段码
i=(u8)(Axx/100%10); //计算电压伏特个位
dispbuf[2]=SG[i]|0x80; //电压个位数码管显示缓存更新段码(含小数点)
i=(u8)(Axx/10%10); //计算电压小数后第1位
dispbuf[1]=SG[i]; //电压小数后第1位数码管显示缓存更新段码
i=(u8)(Axx%10); //计算电压小数后第2位
dispbuf[0]=SG[i]; //电压小数后第2位更新
}
/*****AD结果显示缓存区的更新******/
void disp_f(void) //AD结果显示缓存区的更新
{ //0通道AD结果显示缓存区的更新
LCDwritecmd(0x8c); //写指令,设置DDRAM指针AC=0x4d
i=(r_kTH&0xf0)>>4; //取0通道8位AD数据的十六进制高位
if(i<10) LCDwritedata(i+0x30);//更新AD数十六进制高位(数字)的ASCII码
else LCDwritedata(i+0x37); //更新AD数十六进制高位(大写字母)的ASCII码
i=r_kTH&0x0f; //取0通道8位AD数据的十六进制低位
if(i<10) LCDwritedata(i+0x30);//更新AD数十六进制高位(数字)的ASCII码
else LCDwritedata(i+0x37); //更新AD数十六进制高位(大写字母)的ASCII码
LCDwritedata('H'); //
LCDwritedata(r_kTL+0x30); //更新AD数十六进制高位(数字)的ASCII码
//1通道AD结果显示缓存区的更新
LCDwritecmd(0xcc); //写指令,设置DDRAM指针AC=0x4d
i=(m_kTH&0xf0)>>4; //取1通道8位AD数据的十六进制高位
if(i<10) LCDwritedata(i+0x30);//更新AD数十六进制高位(数

字)的ASCII码
else LCDwritedata(i+0x37); //更新AD数十六进制高位(大写字母)的ASCII码
i=m_kTH&0x0f; //取1通道8位AD数据的十六进制低位
if(i<10) LCDwritedata(i+0x30);//更新AD数十六进制高位(数字)的ASCII码
else LCDwritedata(i+0x37); //更新AD数十六进制高位(大写字母)的ASCII码
LCDwritedata('H'); //
LCDwritedata(m_kTL+0x30); //更新AD数十六进制高位(数字)的ASCII码
}
/*************主程序*************/
void main(void) //
{ LCD_init(); //1602液晶显示模块初始化
Display_init(); //1602液晶屏显示内容初始化
AD_init(); //内部AD初始化
T0T1_init(); //T0、T1初始化程序(11.0592MHz)
do
{ if(new_cycle_flag==1) //有新采样数据标志,Vs1=-(R6/R5)*Vin0=-0.2Vin0
{ //Vs2=-(R10/R8)*Vs1-(R10/R9)*(-5)=2.5+0.2Vin0
//当Vin0=-10V时,Vs2=0.5V;当Vin0=10V时,Vs2=4.5V
//N=((2.5+0.2Vin0)/5)*256;Vin0=0.09765625*N-12.5
//Vs3=-(R17/R18)*Vin1=-0.2Vin1
//Vs4=-(R13/R15)*Vs3-(R13/R14)*(-5)=2.5+0.2Vin1
Vin0*=(float)r_kTH; //AD转换需要127.3us,抽空做点计算
Vin0-=12.5; //
Vin0x100=(int)(Vin0*100); //AD值倒推输入电压的100倍;小数点定点在第7位
Vin1*=(float)m_kTH; //当Vin1=-10V时,Vs4=0.5V;当Vin1=10V时,Vs4=4.5V
Vin1-=12.5; //N=((2.5+0.2Vin1)/5)*256;Vin1=0.09765625*N-12.5
Vin1x100=(int)(Vin1*100); //AD值倒推输入电压的100倍;小数点定点在第2位
disp_g(); //0通道和1通道AD值倒推的输入电压显示缓存区的更新
disp_f(); //0通道和1通道AD结果显示缓存区的更新
new_cycle_flag=0; //新采样数据标志清0
}
}while(1);
}
/*********T0中断服务程序*********/
void t0() interrupt 1 using 1 //0.5ms中断,自动重装,每次均要进行显示处理
{ if(M==10) //5ms到了吗?因为0.5ms*10=5ms
{ ADC_CONTR|=0x08; //到了5ms,启动0输入通道AD转换
new_cycle_flag=1; //置有新采样数据标志
M=0; //M清0
status=0; //状态变量先清0
while(status==0) status=ADC_CONTR & 0x10;//转换结束否?
ADC_CONTR=0xC1; //ADC_POWER SPEED1 SPEED0 ADC_FLAG ADC_START CHS2 CHS1 CHS0=1 10 0 0 001B
//选择180个时钟周期转换1次,将ADC_FLAG清0,暂时不启动AD转换,选择1通道
r_kTH=ADC_RES; //读取0通道AD结果的高8位
r_kTL=ADC_RESL&0x03; //读取0通道AD结果的低2位,不用
Vin0=0.09765625; //AD转换需要127.3us,抽空预置常数
ADC_C

ONTR|=0x08; //启动1输入通道AD转换
Vin1=0.09765625; //
status=0; //状态变量先清0
while(status==0) status=ADC_CONTR & 0x10;//转换结束否?
ADC_CONTR=0xC0; //ADC_POWER SPEED1 SPEED0 ADC_FLAG ADC_START CHS2 CHS1 CHS0=1 10 0 0 000B
//选择180个时钟周期转换1次,将ADC_FLAG清0,暂时不启动AD转换,选择0通道
m_kTH=ADC_RES; //读取1通道AD结果的高8位
m_kTL=ADC_RESL&0x03; //读取1通道AD结果的低2位,不用
}
RSIGN=1; //关闭右边符号位显示
LSIGN=1; //关闭左边符号位显示
Displaybit=0xff; //关闭8个数码管的显示
Displayseg=dispbuf[M]; //查显示缓存表送数显的段端口
Displaybit=BT[M]; //查位码表送数显的位端口
if(M==4) RSIGN=0; //扫描到右边符号位则该位显示
if(M==9) LSIGN=0; //扫描到左边符号位则该位显示
M++; //修改下一次的显示位
}

相关文档
最新文档