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

📄 isr.c

📁 2005年全国大学生电子设计竞赛论文集
💻 C
字号:
#include "spce061v004.h"
#include "lcd_disp.h"
#include "math.h"
#include "s480.h"
#include "voice.h"
#define Step 0.05   //表示电机转动最小单位
#define Division 1/Step //表示把1cm分成的格数
#define LineStep (19.44/6400) //表示电机动一格绳子实际变动数
#define Limit 80
void IRQ4(void) __attribute__ ((ISR));
double abs(double in);
double change(unsigned int input,unsigned int rec);
extern const double table[Limit*2];
extern const double vectortab[16];
extern double vertices[Limit*2];	//任务队列 偶数为x坐标 奇数为y坐标 容纳50个点
extern unsigned int pointer;		//指向当前任务
extern unsigned int num;		//任务队列中还有多少个点
extern unsigned int arrive;	//当前坐标是否到达指定点
extern unsigned int left;		//左电机剩余驱动步数
extern unsigned int leftdir;	//左电机方向
extern unsigned int right;		//右电机剩余驱动步数
extern unsigned int rightdir;	//左电机方向
extern unsigned long a,b;			//a为左边绳子步长 b为右边绳子步长
extern double x,y;				//当前坐标
extern double prex,prey;	//一次直线运动前x,y的位置
extern unsigned int status;		//当前系统状态
//1 直线设置模式 2画圆模式 3自动跟踪模式 4手动调整模式 5运动模式
extern unsigned int temp1,temp2,temp3,temp4,temp5; //输入值的各位暂存值
extern unsigned int flashnum;       //闪烁值
extern unsigned int dispcon[32];
extern long time;
extern double vector[2];
extern double vectorlast[2];
//x=(a*a-b*b-11875)/250
//(15+x)^2+(115-y)^2=a^2
//(95-x)^2+(115-y)^2=b^2
extern unsigned int rec[8];	//探测结果变量 (是否接收到)
extern unsigned int reccounter;
//=========================================================================================
//
//=========================================================================================
void IRQ4(void)
{	
	//IRQ4_1KHz做为处理中断、喂狗
	unsigned int recup,recleft,recdown,recright;	//探测结果变量 (是否接收到)
	double xtemp,ytemp;	//临时x,y坐标
	double atemp,btemp;	//临时左边绳步长和临时右边绳步长
	double vx,vy;	//运动矢量的x和y分量
	unsigned int alast,blast;	//a,b的临时存储
	unsigned int i,j;
	unsigned int f,l;	//分别用于表示所使用点起始的编号和结束编号 从小到大
	if(*P_INT_Ctrl&0x0010)
	{	
		*P_INT_Clear=0x0010;
	}
	else if(*P_INT_Ctrl&0x0020)
	{
		*P_INT_Clear=0x0020;
	}
	else if(*P_INT_Ctrl&0x0040)
	{
		*P_Watchdog_Clear=0x0001; //喂狗
		time++;
		switch (status)
		{
			case 5:
		//画线功能
		if(left||right)//判断当前驱动队列中是否还有任务
		{
			if(left)//驱动左电机 IOA0
			{
				left--;
				if(*P_IOA_Buffer&0x0001)
					*P_IOA_Data=*P_IOA_Buffer&0xfffe;
				else
					*P_IOA_Data=*P_IOA_Buffer|0x0001;
			}
			if(right)//驱动右电机 IOA12
			{
				right--;
				if(*P_IOA_Buffer&0x1000)
					*P_IOA_Data=*P_IOA_Buffer&0xefff;
				else
					*P_IOA_Data=*P_IOA_Buffer|0x1000;
			}
		}
		//有 则驱动 减去相应的队列
		else
		{
			if(arrive)
			//无 则判断当前坐标是否已经达到目的坐标
			{
				if(num)
				{
					num--;
					if(pointer++==(Limit-1))
						pointer=0;  //共400个点
					arrive=0;
					prex=x;
					prey=y;
					xtemp=x;
					ytemp=y;
					dispcon[0]=0x0061;
					dispcon[1]=0x0078;
					dispcon[2]=0x0069;
					dispcon[3]=0x0073;
					dispcon[4]=0x0020;
					dispcon[5]=0x003a;
					dispcon[6]=0x0020;
					dispcon[7]=0x0020;
					dispcon[8]=0x0058;
					dispcon[9]=0x0020;
					dispcon[10]=0x0020;
					dispcon[11]=0x0020;
					dispcon[12]=0x0020;
					dispcon[13]=0x0059;
					dispcon[14]=0x0020;
					dispcon[15]=0x0020;
					dispcon[16]=0x0076;
					dispcon[17]=0x0061;
					dispcon[18]=0x006c;
					dispcon[19]=0x0075;
					dispcon[20]=0x0065;
					dispcon[21]=0x003a;
					dispcon[22]=0x0020;
					dispcon[23]=0x0020;
					dispcon[26]=0x0020;
					dispcon[27]=0x0020;
					dispcon[31]=0x0020;
				}
				//是 则从目标点队列中取出下一个点(且arrive置0)、无点则结束
				else
				{
					status=1;
					pointer=0;
					temp1=0;
					temp2=0;
					temp3=0;
					temp4=0;
					temp5=0;
					dispcon[24]=temp1+0x0030;
					dispcon[25]=temp2+0x0030;
					dispcon[28]=temp3+0x0030;
					dispcon[29]=temp4+0x0030;
					dispcon[30]=temp5+0x0030;
					flashnum=24;
					voice_complete();
					lcd_disp(dispcon,flashnum);
					asm("IRQ OFF");
					//否 则转到键盘设定模式
				}
			}
			else
			{
				//暂定把1cm分成20份
				if(abs(x-vertices[pointer*2])>abs(y-vertices[pointer*2+1]))
				{
					//斜率小于1
					if(x>vertices[pointer*2])
						xtemp=floor(x*20-0.5)/20;
					else
						xtemp=floor(x*20+1.5)/20;
					ytemp=prey+(xtemp-prex)/(vertices[pointer*2]-prex)*(vertices[pointer*2+1]-prey);
				}
				else
				{
					if(y>vertices[pointer*2+1])
						ytemp=floor(y*20-0.5)/20;
					else
						ytemp=floor(y*20+1.5)/20;
					xtemp=prex+(ytemp-prey)/(vertices[pointer*2+1]-prey)*(vertices[pointer*2]-prex);
					//斜率大于等于1
				}
				//没有达到目标 则算出当前位置到下一个点间两步进电机各应该走的步数
				//(15+x)^2+(115-y)^2=a^2
				//(95-x)^2+(115-y)^2=b^2
				atemp=sqrt((15+xtemp)*(15+xtemp)+(115-ytemp)*(115-ytemp));
				atemp=atemp/LineStep;	//算出新的位置对应左绳长度
				btemp=sqrt((95-xtemp)*(95-xtemp)+(115-ytemp)*(115-ytemp));
				btemp=btemp/LineStep;	//算出新的位置对应右绳长度
				alast=floor(atemp+0.5);
				blast=floor(btemp+0.5);
				if(alast>a)	//左电机 IOA1 下拉
				{
					left=(alast-a)*2;
					*P_IOA_Data=*P_IOA_Buffer|0x0002;
				}
				else if(alast<a) //上拉
				{
					left=(a-alast)*2;
					*P_IOA_Data=*P_IOA_Buffer&0xfffd;
				}
				if(blast>b)	//右电机 IOA13 下拉
				{
					right=(blast-b)*2;
					*P_IOA_Data=*P_IOA_Buffer&0xdfff;
				}
				else if(blast<b)	//上拉
				{
					right=(b-blast)*2;
					*P_IOA_Data=*P_IOA_Buffer|0x2000;		
				}
				//步数取整 若取整后步数为都为0则认为已经达到目标点(arrive置1) 
				//x=(a*a-b*b+8800)/250
				x=(alast*LineStep*alast*LineStep-blast*LineStep*blast*LineStep+8800)/220;
				y=115-sqrt(alast*LineStep*alast*LineStep-(15+x)*(15+x));
				dispcon[24]=((int)(x+0.5))/10+0x0030;
				dispcon[25]=((int)(x+0.5))%10+0x0030;
				dispcon[28]=((int)(y+0.5))/100+0x0030;
				dispcon[29]=((int)(y-(((int)(y+0.5))/100)*100+0.5))/10+0x0030;
				dispcon[30]=((int)(y+0.5))%10+0x0030;
				//根据取整后步数算出新的坐标点
				a=alast;
				b=blast;
				if((abs(x-vertices[pointer*2]))<0.05&&(abs(y-vertices[pointer*2+1])<0.05))
					arrive=1;
				lcd_disp(dispcon,32);
			}
		}
		break;
			case 6:
			//根据驱动任务驱动电机
		if(left||right)//判断当前驱动队列中是否还有任务
		{
			if(left)//驱动左电机 IOA0
			{
				left--;
				if(*P_IOA_Buffer&0x0001)
					*P_IOA_Data=*P_IOA_Buffer&0xfffe;
				else
					*P_IOA_Data=*P_IOA_Buffer|0x0001;
			}
			if(right)//驱动右电机 IOA12
			{
				right--;
				if(*P_IOA_Buffer&0x1000)
					*P_IOA_Data=*P_IOA_Buffer&0xefff;
				else
					*P_IOA_Data=*P_IOA_Buffer|0x1000;
			}
		}
		//有 则驱动 减去相应的队列
		else
		{
			//无驱动任务则 探测当前状态
			
			reccounter=0;
			for(j=0;j<8;j++)
			{
				*P_IOB_Data=(*P_IOB_Buffer&0xfff0)|j;
				for(i=0;i<100;i++)
					;
				if(*P_IOA_Data&0x8000)
				{
					rec[j]=0;
					reccounter++;
				}
				else
					rec[j]=1;
			}
			vx=vectorlast[0];

			vy=vectorlast[1];
			
			//根据上一次运动矢量 判断应该读取哪些点的信息
			if(abs(vy)>abs(vx))
			{
				//上次运动方向的Y值比X值大
				if(vx==0&&vy>0)
				{
					f=4;
					l=8;
					//使用4 5 6 7 0
				}
				else if(vx==0&&vy<0)
				{
					f=0;
					l=4;
					//使用0 1 2 3 4
				}
				else if(vy>0&&vx>0)
				{
					f=5;
					l=8;
					//使用5 6 7 0
				}
				else if(vy>0&&vx<0)
				{
					f=4;
					l=7;
					//使用4 5 6 7
				}
				else if(vy<0&&vx>0)
				{
					f=0;
					l=3;
					//使用0 1 2 3
				}
				else if(vy>0&&vx<0)
				{
					f=1;
					l=4;
					//使用1 2 3 4
				}
			}
			else
			{	
				//上次运动方向的Y值小于等于X值
				if(vx==vy&&vx>0)
				{
					f=5;
					l=9;
					//使用5 6 7 0 1
				}
				else if(vx==vy&&vx<0)
				{
					f=1;
					l=5;
					//使用1 2 3 4 5
				}
				else if(vx==-vy&&vx>0)
				{
					f=7;
					l=11;
					//使用7 0 1 2 3
				}
				else if(vx==-vy&&vx<0)
				{
					f=3;
					l=7;
					//使用3 4 5 6 7
				}
				else if(vy==0&&vx>0)
				{
					f=6;
					l=10;
					//使用6 7 0 1 2
				}
				else if(vy==0&&vx<0)
				{
					f=2;
					l=6;
					//使用2 3 4 5 6
				}
				else if(vx>0&&vy>0)
				{
					f=6;
					l=9;
					//使用6 7 0 1
				}
				else if(vx>0&&vy<0)
				{
					f=7;
					l=10;
					//使用7 0 1 2
				}
				else if(vx<0&&vy<0)
				{
					f=2;
					l=5;
					//使用2 3 4 5
				}
				else if(vx<0&&vy>0)
				{
					f=3;
					l=6;
					//使用3 4 5 6
				}
			}
			*P_Watchdog_Clear=0x0001;
			//根据使用编号确定新的运动矢量
			vector[0]=0;
			vector[1]=0;
			for(i=f;i<=l;i++)
			{
				if(rec[i%8]==0)
				{
					vector[0]+=vectortab[(i%8)*2];
					vector[1]+=vectortab[(i%8)*2+1];
				}//如果在黑线内,则使用其运动方向
			}
			vectorlast[0]=vector[0];
			vectorlast[1]=vector[1];
			if(vector[0]==0&&vector[1]==0)
			{
				status=1;
				pointer=0;
				temp1=0;
				temp2=0;
				temp3=0;
				temp4=0;
				temp5=0;
				dispcon[24]=temp1+0x0030;
				dispcon[25]=temp2+0x0030;
				dispcon[28]=temp3+0x0030;
				dispcon[29]=temp4+0x0030;
				dispcon[30]=temp5+0x0030;
				flashnum=24;
				voice_complete();
				lcd_disp(dispcon,flashnum);
				asm("IRQ OFF");
				*P_INT_Ctrl=0x0040;
				return;
			}
			//预留结束条件
			//跟据运动矢量填写驱动任务
			//暂定把1cm分成20份
			if(abs(vector[0])>abs(vector[1]))
			{
				//斜率小于1
				if(vector[0]<0)
					xtemp=floor(x*4-0.5)/4;
				else
					xtemp=floor(x*4+1.5)/4;
				ytemp=y+(xtemp-x)*vector[1]/vector[0];
			}
			else
			{
				//斜率大于等于1
				if(vector[1]<0)
					ytemp=floor(y*4-0.5)/4;
				else
					ytemp=floor(y*4+1.5)/4;
				xtemp=x+(ytemp-y)*vector[0]/vector[1];
			}
			//(15+x)^2+(115-y)^2=a^2
			//(95-x)^2+(115-y)^2=b^2
			atemp=sqrt((15+xtemp)*(15+xtemp)+(115-ytemp)*(115-ytemp));
			atemp=atemp/LineStep;	//算出新的位置对应左绳长度
			btemp=sqrt((95-xtemp)*(95-xtemp)+(115-ytemp)*(115-ytemp));
			btemp=btemp/LineStep;	//算出新的位置对应右绳长度
			alast=floor(atemp+0.5);
			blast=floor(btemp+0.5);
			if(alast>a)	//左电机 IOA1 下拉
			{
				left=(alast-a)*2;
				*P_IOA_Data=*P_IOA_Buffer|0x0002;
			}
			else if(alast<a) //上拉
			{
				left=(a-alast)*2;
				*P_IOA_Data=*P_IOA_Buffer&0xfffd;
			}
			if(blast>b)	//右电机 IOA13 下拉
			{
				right=(blast-b)*2;
				*P_IOA_Data=*P_IOA_Buffer&0xdfff;
			}
			else if(blast<b)	//上拉
			{
				right=(b-blast)*2;
				*P_IOA_Data=*P_IOA_Buffer|0x2000;		
			}
			//步数取整 若取整后步数为都为0则认为已经达到目标点(arrive置1) 
			//x=(a*a-b*b+8800)/250
			x=(alast*LineStep*alast*LineStep-blast*LineStep*blast*LineStep+8800)/220;
			y=115-sqrt(alast*LineStep*alast*LineStep-(15+x)*(15+x));
			dispcon[18]=88;
			dispcon[19]=58;
			dispcon[20]=((int)(x+0.5))/10+0x0030;
			dispcon[21]=((int)(x+0.5))%10+0x0030;
			dispcon[24]=89;
			dispcon[25]=58;
			dispcon[26]=((int)(y+0.5))/100+0x0030;
			dispcon[27]=((int)(y-(((int)(y+0.5))/100)*100+0.5))/10+0x0030;
			dispcon[28]=((int)(y+0.5))%10+0x0030;
			//根据取整后步数算出新的坐标点
			a=alast;
			b=blast;
			lcd_disp(dispcon,32);
		}
		break;
		}
		*P_INT_Clear=0x0040;
	}
}
//=========================================================================================
//
//=========================================================================================
double abs(double in)
{
	return in>0?in:-in;
}
//=========================================================================================
//
//=========================================================================================
double change(unsigned int input,unsigned int rec)
{
	if(rec)
		return input;
	else
		return 0;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -