⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fourchannel.c

📁 89V51RD2单片机驱动步进电机带动一个测速的四通道光电传感器,分析传感器四个通道是否正常,并在12864的显示屏上显示并用TP微打根据屏幕显示的打印.内附ProtelPCB板并已成功制作样机两台.
💻 C
📖 第 1 页 / 共 5 页
字号:
#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 + -