📄 fourchannel.c
字号:
#include <math.h>
#include <89c51rd2.h>
#include <ABSACC.H>
#define GS 56 //GS<65,受eliminate_pulse()中整型数的制约
#define GS2 28 //GS/2
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long int ulong;
/*-------变量定义区-----------*/
sbit pwmplus=P1^0; //步进电机驱动输出
sbit stb= P1^1; //打印机启动脉冲
sbit busy= P1^2; //打印机忙,不能接收字符
sbit ad_oe= P3^3; //AD输出允许
sbit ad_star=P3^4; //AD地址锁存及转换开始
sbit p_e= P3^5; //显示屏时钟
sbit p_rw= P3^6; //显示屏读/写切换
sbit p_di= P3^7; //显示屏命令/数据切换
float code rev_num[7]={5.0,6.666666,8.333333,10.0,11.66667,13.33333,16.66667};//转速300,400,500,600,700,800,1000
uint code pwm[7][2]={{0xF6FF,2400},{0xF93F,3200},{0xFA99,4000},{0xFB7F,4800},{0xFC24,5600},{0xFC9F,6400},{0xFD4C,8000}};
////uint code pwm[7][2]={{0xF6E2,2400},{0xF925,3200},{0xFA8D,4000},{0xFB6B,4800},{0xFC12,5600},{0xFC9C,6400},{0xFD4A,8000}};//pwm[x][1]存rcap2h,300,400,500,600,700,800,1000
/*-------中断定义区-----------*/
uchar data pwmtimeover=1; //T2 4mS定时时间到,清零;在pwmoutup()函数中使用
uint data pwma _at_ 0x30; //pwmoutup()中负责T2的RCAP2的读写
uchar data pwmh _at_ 0x31;
uchar data pwml _at_ 0x30;
//------------------------------------------------------------------------------------------
uint data vinp _at_ 0x2e; //catchrdy()中断函数中负责CAP的读写
uchar data vinh _at_ 0x2f;
uchar data vinl _at_ 0x2e; //CCAP0L,CCAP0H的值的映象
uchar data UseFlag; //AD使用标志用在AD转换标定起始位置
uint xdata PlusTemp0[GS]; //脉冲值测量数据暂存[84]
uint xdata PlusTemp1[GS]; //脉冲值测量数据暂存[84]
uchar data PlusCount0,PlusCount1; //通道已存个数-
uchar data PlusOver0,PlusOver1; //每通道错误次数
/*-------数理统计定义区-------*/
uint idata ComputTemp[GS2]; //数理统计暂存,由ptemp指针读写[42]
uchar idata SamQuan; //当前有效样本个数
float idata Ave,SquDec,HWidth,LWidth; //平均值;方差;每通道最大最小值
uchar PlusError,DError[4]; //无脉冲错误;错误标志位 位地址: 7:通道脉冲 6:最低高电平 5:最高低电平 4:最大占空比
// 3:最小占空比 2:最大相差 1:最小相差 0:NC
/*-------显示定义区-----------*/
uchar date[10]={0,5,0,9,0,3,0,9,0,0},numbers[4]={1,0,0,0},type=4;
uchar idata rev=4,channeltype; //通道类型,2是双同道,4是四通道
uchar idata mi; //转速
uchar data overtime=0,overtimeflag=1; //无脉冲测量超时错误,在overtimeinterr中使用overtimeflag<1:正常,0:超时>
struct displaybuffer
{ uchar PlusCount[3]; //脉冲值
uchar DLLevel[3]; //最高低电平0:1v 1:0.1v 2:0.01v
uchar DHLevel[3]; //最低高电平0:1v 1:0.1v 2:0.01v
uchar DHDutyRatio[2]; //最大占空比
uchar DLDutyRatio[2]; //最小占空比
uchar DHPhaseDiff[3]; //最大相差0:十位1:个位
uchar DLPhaseDiff[3]; //最小相差0:十位1:个位
float APlusWidth; //脉冲宽度-计算用-0xff
uchar LLevel; //最高低电平-计算用
uchar HLevel; //最低高电平-计算用
uchar HDutyRatio; //最大占空比-计算用
uchar LDutyRatio; //最小占空比-计算用
uchar HPhaseDiff; //最大相差-计算用
uchar LPhaseDiff; //最小相差-计算用
}Disp[3][4];
/*-------函数声明star---------*/
extern void _nop_(void);
void init(void);
void setxy(uchar xy);
void disphz(uchar valuh,uchar valul);
void dispen(uchar valuen);
void wrcommand(uchar u);
void delay(void);
uchar key(void);
void print(uchar prin);
void starovertime(void);
void stopovertime(void);
/*-------函数声明end----------*/
void catchrdy(void) interrupt 6 using 1 //CAP捕捉中断函数
{ uchar chan,irrchan;
irrchan=0x0f&CCON; UseFlag=1;
switch(irrchan)
{ case 1: vinh=CCAP0L; vinl=CCAP0H; chan=0;
if(PlusCount0<GS) PlusTemp0[PlusCount0++]=vinp;
else {PlusCount0=GS; ++PlusOver0;}break; //注意:如果写成case 0x01:irrchan=0;break;编译通过,但结果错了!!!
case 2: vinh=CCAP1L; vinl=CCAP1H; chan=1;
if(PlusCount1<GS) PlusTemp1[PlusCount1++]=vinp; //PlusCout1的计数范围是0-GS,共GS+1个,因此最后一个值废弃,
else {PlusCount1=GS; ++PlusOver1;}break;
case 4: vinh=CCAP2L; vinl=CCAP2H; chan=0;
if(PlusCount0<GS) PlusTemp0[PlusCount0++]=vinp;
else {PlusCount0=GS; ++PlusOver0;} break;
case 8: vinh=CCAP3L; vinl=CCAP3H; chan=1;
if(PlusCount1<GS) PlusTemp1[PlusCount1++]=vinp;
else {PlusCount1=GS; ++PlusOver1;} break;
default : CCON&=0X40;UseFlag=0;break;
} CCON=0x40;
} //如果没有剔除坏样本,则处理完毕
void ovtime(void) interrupt 1 using 2 //通道无脉冲,测量超时8S,则出错跳出测量
{ if(--overtime==0) {overtimeflag=0;} //overtimeflag<1:正常;0:超时>
}
void ovtime_pwm(void) interrupt 3 using 3
{ TH1=0Xf0;TL1=0X08;pwmtimeover=0; //时间到标志
}
float averg(void) //计算平均值.sampleQuantity是样本个数
{ uchar idata i;
float idata sum;
for(i=0,sum=0;i<SamQuan;i++) sum+=ComputTemp[i];
return(sum/SamQuan);
}
float tjs(void) //计算方差
{ uchar i;
float idata sum,c=0.0;
for(i=0,sum=0;i<SamQuan;i++)
{ c=ComputTemp[i]-Ave; sum+=c*c;
}
return(sqrt(sum/(SamQuan-1)));
}
uchar del(void) //剔除坏样本
{ uchar idata i,k; //合理样本的上下限
float idata low,high;
low =Ave-1.75*SquDec;
high=Ave+1.75*SquDec;
k=0; HWidth=0.0; LWidth=100000.0; //初始化剔除标志<k>
for(i=0;i<SamQuan;i++)
{ if(ComputTemp[i]<low||ComputTemp[i]>high) //如果发现坏样本
{ if(i<SamQuan-1){ComputTemp[i]=ComputTemp[SamQuan-1];i--;} //如果该坏样本不是最后一个样本,用最后一个样本来覆盖这个坏样本,//退回前一个位置,以便处理刚刚覆盖的样本
SamQuan--;k=1; //当前有效样本个数减一,设置剔除操作标志
}
else
{ if(ComputTemp[i]>HWidth) HWidth=ComputTemp[i];
if(ComputTemp[i]<LWidth) LWidth=ComputTemp[i];
}
}
return (k);
}
uchar datamanage_del(void) //能剔除粗大误差样本的统计算法.samplecount样本个数
{ uchar aderrordegree=0;
SamQuan=GS2;
while(1)
{ Ave=averg(); //计算平均值
SquDec=tjs();
if(!del()) return (0); //如果没有剔除坏样本,则HWidth,LWidth中是最大最小值
else if(++aderrordegree==6)return (1); //数理统计有错误返回重测
}
}
uchar datamanage_plus(uchar cnnumb,uchar group)//脉冲处理函数;cnnumb是ABCD通道选择(0,2),cndegr是自动测量中组的选择
{ uchar j; //注意:它们是以6 CLOCK模式测的,每个值代表的是1/2uS,但是有些不需要矫正
uint idata * idata ptemp=&ComputTemp[0];
for(j=2;j<GS;j=j+2) //A或C通道最大最小总脉宽
{ *ptemp=PlusTemp0[j]-PlusTemp0[j-2]; ptemp++;
}
if(1==datamanage_del()) return(1); //如果datamanage_del发现ptemp指向的数组中有多个错误-
else Disp[group][cnnumb].APlusWidth=Ave;
//--------------------------------------------------------------------------------------------
ptemp=&ComputTemp[0];
for(j=2;j<GS;j=j+2) //A或C通道最大最小总脉宽
{ *ptemp=PlusTemp1[j]-PlusTemp1[j-2]; ptemp++;
}
if(1==datamanage_del()) return(1); //如果datamanage_del发现ptemp指向的数组中有多个错误-
else Disp[group][1+cnnumb].APlusWidth=Ave;
////////////////////////////////////////////////////////////////////////////////////////////////////
ptemp=&ComputTemp[0];
for(j=1;j<(GS);j=j+2)
{ *ptemp=PlusTemp0[j]-PlusTemp0[j-1] ;ptemp++; //根据cnnumb进行A或C通道最大最小占空比宽度处理
}
if(1==datamanage_del()) return(1); //返回到cycleall,重新测量本组通道
else{ Disp[group][cnnumb].HDutyRatio=(uchar)(HWidth/Disp[group][cnnumb].APlusWidth*100); //HWidth,LWidth存的是1/2倍的高电平宽度
Disp[group][cnnumb].LDutyRatio=(uchar)(LWidth/Disp[group][cnnumb].APlusWidth*100);} //存入disp[]结构;返回到cycleall(),重新测量本组通道
//---------------------------------------------------------------------------------------------
ptemp=&ComputTemp[0]; //指针复位
for(j=1;j<(GS);j=j+2)
{ *ptemp=PlusTemp1[j]-PlusTemp1[j-1];ptemp++; //根据cnnumb进行B或D通道最大最小占空比宽度处理
}
if(1==datamanage_del()) return(1); //返回到cycleall,重新测量本组通道
else{ Disp[group][1+cnnumb].HDutyRatio=(uchar)(HWidth/Disp[group][1+cnnumb].APlusWidth*100);
Disp[group][1+cnnumb].LDutyRatio=(uchar)(LWidth/Disp[group][1+cnnumb].APlusWidth*100);}//存入disp[]结构;返回到cycleall(),重新测量本组通道
/////////////////////////////////////////////////////////////////////////////////////////////////////
ptemp=&ComputTemp[0]; //指针复位
for(j=0;j<(GS);j=j+2)
{ *ptemp=(PlusTemp1[j]-PlusTemp0[j]);ptemp++; //根据cnnumb进行AB或CD通道最大最小相位处理
}
if(1==datamanage_del()) return(1); //存入disp[]结构;返回到cycleall(),重新测量本组通道
else { Disp[group][cnnumb+1].HPhaseDiff=Disp[group][cnnumb].HPhaseDiff=(uchar)((HWidth*10)/Disp[group][cnnumb].APlusWidth*36); //显示最大相差0:十位1:个位
Disp[group][cnnumb+1].LPhaseDiff=Disp[group][cnnumb].LPhaseDiff=(uchar)((LWidth*10)/Disp[group][cnnumb].APlusWidth*36); //显示最小相差0:十位1:个位
} //HWidth,LWidth存的是1/2倍的AB上升沿差
}
void cycleall(uchar cnnumb,uchar group) //脉冲测量,值在interrupt中被存储,cnnumb组通道(0:AB组;1:组)cndegr自动测量中的组(300r/min;1:500r/min;2:1000r/min)
{ uchar errorcount=0;
wrcommand(0x0c);
CCAPM0=CCAPM1=CCAPM2=CCAPM3=0;P1|=0xf8; //定义为1,进行脉冲值测量;0,作为ad高低电平标记
while(1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -