#include<reg51.h>
#include<math.h>
#define bianshu 1
#define qshu 50
#define buchangTH1 0Xfe
#define buchangTL1 0X0c //1000us 1000hz 10000us 考虑给取值过程留点时间(200us) 用700us 65536-700=64836
sfr ADC_CONTR =0XBC; //定义ad相关特殊功能寄存器地址
sfr ADC_RES =0XBD;
sfr ADC_RESL =0XBE;
sfr ADC_LOW2 =0XBE;
sfr P1ASF =0X9D;
#define ADC_POWER 0X80 //配合ADC_CONTR置相应位 因为ADC_CONTR不可位寻址,所以采用与或方式置相应位
#define ADC_FLAG 0X10
#define ADC_START 0X08
#define ADC_SPEEDLL 0X00
#define ADC_SPEEDL 0X20
#define ADC_SPEEDH 0X40
#define ADC_SPEEDHH 0X60
unsigned char code Disp_Tab[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40}; //段码
sbit LS138A = P2^2; //定义138译码器的输入A脚由P2.2控制 控制8个数码管
sbit LS138B = P2^3; //定义138译码器的输入脚B由P2.3控制
sbit LS138C = P2^4; //定义138译码器的输入脚C由P2.4控制
sbit EADC=IE^5;//ad中断允许位
sbit cha1=P2^0;
sbit cha2=P2^1;
sbit cha3=P2^7;
sbit cha4=P2^6;
sbit cha5=P1^7;
char y,M,i,j,k,s,x,geshu,u; //控制位
char shijian;
unsigned char CH=2;//通道 p1^2
char flag1; //等待取完的标志位 中断控制完整周期
char N=qshu;
double bus,sum,zhi1; //数据传输 媒介(实数) 数据区
double zhi[qshu],zhi2[qshu]; //要取的 n个数(转换完的整数)
int LedNumVal,zhenzhi;
char LedOut[8]; //取要显示数的 个 十 百... 数码管8位
int Gbuchang,Lbuchang;
void delay(int q);
void main()
{
while(1)
{
x=0; //显示遍数标志位
y=0;
i=0;//i是取数中的变量
j=0;//j,k,s都是显示程序中的变量
k=0;
s=0;
u=0;
geshu=0;
zhi1=0;
sum=0;
zhenzhi=0;
shijian=0;
CH=2;//通道 p1^2 辅助置ADC_CONTR的通道位
flag1=1;//用“1”符合逻辑!控制开始与结束标志位
M=bianshu;
N=qshu;
bus=0; //数据传输 媒介(实数) 数据区
//**********zhi[i]清零************
for(i=0;i<N;i++)
{
zhi[i]=0;
}
//********ad初始化********
EADC=1; //允许ad中断
P1ASF=0x04; //通道0000 0100
ADC_RES=0; //寄存器清零
ADC_CONTR=ADC_POWER|ADC_SPEEDHH|CH;//设置 电源 速度 通道2 注意此处不开启ADC_START 取完数之后每次都需要再置位
delay(1); //第一次需要时间来置位
//********外部中断1初始化********
EX1=1; //外部中断1允许 中断号2 引脚P3^3
IT1=1; //设置为下降沿触发
//********定时器1初始化(采用查询方式)所以没有开启定时器1的中断允许位ET1位
TMOD=0X11; //0001 0001 定时1,0 方式1 16位
Gbuchang=buchangTH1;
Lbuchang=buchangTL1;
TH1=Gbuchang;
TL1=Lbuchang; //1000us 无定时器中断允许 采用查询方式控制步长
// 用定时器0来查看一下取数时间
TH0=0;
TL0=0;
//*****取数要求:ad从零点开始,按相同步长取到确定的N个数***************************
EA=1;//等待外部中断1来开启ad与定时器1
//****flag1=1(等待同步方波下降沿开启)>>flag1=0(采集数据)>>flag1=1(等待同步方波下降沿关闭)>>
//*******ad取数阶段**********!!!???要保证下次循环不被打扰!!!
while(flag1==1);
TR0=1;
cha3=0;
while(flag1==0)
{
cha4=0;
for(i=0;i<N-2;i++) //ad转换完一次后ADC_START会自动清零
{
TR1=1; //此处开启定时器 开始定时器 控制步长
ADC_CONTR|=ADC_START; //此处开启ad转换 统一开始时间 开始ad 时间很短
while(TF1==0); //因为步长大于ad采集时间,所以此处会进入ad中断取!!ADC_RES》bus!!等待定时器控制步长完再把数bus>>zhi[i]
TF1=0;//软件查询,需软件清中断申请位
TR1=0;//此处关闭为了不让它再计时***定时器计满溢出回零之后(方式0、1、3) 会重新开始从零计数 所以要先关闭再说 ****
TH1=Gbuchang;
TL1=Lbuchang;
zhi[i]=(bus*5*1000)/256;//vin/bus=5/256 //要显示的数 ?要不要预留出计算时间
zhi2[i]=zhi[i]/1000;
bus=0;//清零
geshu=i+1;
if(flag1==1)// 此处本意是想:用同步方波来控制取数的结束时间,而不是以前的固定取N个数在等待结束
break;
}
}
EA=0;
flag1=1;
TR0=0;
zhi[geshu+2]=geshu;
zhi[geshu+4]=256*TH0+TL0;//看看取数时间是否超过20000us
cha4=0;
//此处关闭定时器
//************循环M遍 显示取到的N个数值*************************************
while(M--)
{
for(u=0;u<geshu;u++)
{
zhi2[u]*=zhi2[u];
sum+=zhi2[u];//平方和 此处bus已经乘了1000,可以说已经取了4位有效数字
}
zhi1=sum/(geshu);//2.82是正确答案幅值为4
zhenzhi=sqrt(zhi1)*1000;
zhi[geshu+6]=zhenzhi;
for(j=0;j<N;j++) //循环显示N个数
{
LedNumVal=zhi[j];
LedOut[0]=Disp_Tab[LedNumVal%100000000/10000000]; //取各个位
LedOut[1]=Disp_Tab[LedNumVal%10000000/1000000];
LedOut[2]=Disp_Tab[LedNumVal%1000000/100000];
LedOut[3]=Disp_Tab[LedNumVal%100000/10000];
LedOut[4]=Disp_Tab[LedNumVal%10000/1000]|0x80; //千位
LedOut[5]=Disp_Tab[LedNumVal%1000/100]; //百位
LedOut[6]=Disp_Tab[LedNumVal%100/10];//十位
LedOut[7]=Disp_Tab[LedNumVal%10]; //个位
//EA=0; //此处关中断 有效的解决了ad打断程序进行的问题 去掉它就可以循环了!!
for(k=0;k<125;k++) //循环显示这个数300次,为了能看清 它大点 cha2就不亮了到了200以上怎么就那么长时间??
{
cha1=1;
for(s=0;s<8;s++) //只显示8个数字
{
P0=LedOut[s];
switch(s) //使用switch 语句控制位选 也可以是用查表的方式 学员可以试着自己修改
{
case 0:LS138A=0; LS138B=0; LS138C=0; break;
case 1:LS138A=1; LS138B=0; LS138C=0; break;
case 2:LS138A=0; LS138B=1; LS138C=0; break;
case 3:LS138A=1; LS138B=1; LS138C=0; break;
case 4:LS138A=0; LS138B=0; LS138C=1; break;
case 5:LS138A=1; LS138B=0; LS138C=1; break;
case 6:LS138A=0; LS138B=1; LS138C=1; break;
case 7:LS138A=1; LS138B=1; LS138C=1; break;
}
delay(5);
cha1=0;
}
cha2=1; //
}
cha2=0; //每换数一次显示一下
}
x++;
P0=Disp_Tab[x]; //显示管显示为“0”
delay(2000);//搞清楚此处延时的影响!!
}
cha5=0;
cha3=1;
cha4=1;
//delay(10000);
}
}
//**********外部中断1控制取数从零点开始 flag1和flag3的作用仅仅是控制完整周期(不再开启和关闭中断或定时器)**********//
void adc_kai() interrupt 2//外部中断1 中断号2 3^3引脚
{
// flag1=!flag1;
// if(flag1==1)
// flag1=0;
// else flag1=1;
y++;
if(y==1)
{
flag1=1;
//EA=1;
}
if(y==2)
{
//EA=0; //关总中断
//ADC_CONTR&=!ADC_POWER;//此处关闭ad电源 不关电源就可以循环了
//TR1=0; //此处关闭定时器
y=0;
flag1=0;
}
}
//**********ad中断程序 定时器查询和再置数(控制步长) ad取数**********//
void adc_qushu() interrupt 5
{
ADC_CONTR&=!ADC_FLAG; //每次都要用软件清中断标志位
bus=ADC_RES;
ADC_RES=0;
ADC_CONTR=ADC_POWER|ADC_SPEEDHH|CH; //?是否需要每次都上电 选速度 和通道
}
//**********延时**********//
void delay(int q)
{
int z;
while(q--)
{
z=100;
while(z--);
}
}