yanniwang

基于ADUC841的电机控制软件设计与流程分析

0
阅读(3424)

1.主程序工作过程

 基于ADUC841的电机控制系统要求能产生规定的典型的3种力矩波形,分别定义位状态0、状态1、状态2。控制系统主程序流程图如图所示,系统的工作过程为,上电后首先进行系统初始化,包括设置堆栈首地址,上电后将DAC输出2.5V电压,来平衡硬件电路中的2.5V的偏置电压,从而电机在商店以后控制率未投入以前保持静止状态。另外初始化定时器的控制字及定时市场的初始化,另外初始化中断设置,打开系统中断和定时器中断。在这里我们采用3.3ms的采样时间,它可以通过设置低能提供时器计数初值来完成。

 由于单片机在上电之后的一段时间之内,需要对系统内部的一些设置进行初始化,这样单片机将处于失控状态,而在这段时间内,模拟电路中的2.5V已经投入运行,在这种情况下2.5V的电压将加在了电机电枢的两端,从而使电机进行转动,而这种转动时我们所不希望见到的。因此,在这里我们采用了时间继电器来消除单片机的失控时间,采用常闭继电器,使得在上电后电机电枢两端处于短接状态,延时十秒后,等单片机系统的初始化过程结束后,见常闭结点打开,电机处于正常运行状态,就可消除失控时间的问题。延时10s后,单片机系统等待上位机发送命令指令,当上位机发送0x30到下位机时,电机投入运转状态0,当下位机接受到0x31的指令时,电机投入运转状态1,当下位机接受到0x32的指令时,电机投入运转状态2。下位机接受到上位机的命令指令以后,则触发定时器0开始计时,定时器溢出后,则系统进入定时器中断子程序,进行相应的控制和操作,当中断子程序执行完后,在主程序中,让程序在一个死循环中运转,第一次进入死循环时,下位机向上位机上传电机误差的初始值,然后再进入死循环时,每隔0.1s将电机的误差值上传到上位机进行运算和处理。

2.    定时器中断子程序工作过程

定时器中断子程序流程图如图所示,其工作过程如下,首先定义一些在中断子程序中使用到的变量,另外还要进行一些定时器的初始化处理。紧接着法出控制指令,控制光电码盘对电机的当前位置信息进行采集,获得三十二位的关于电机位置的计数值f。按照指标要求,给出电机运转的指令曲线u,将u和f相减得系统的偏差e(e = u - f),根据e的大小,将设计好的二型PID控制器投入,经过运算后得到系统的控制参数,为了防止系统溢出,加入限幅指令,然后根据上位机下达的控制指令,将不同的电机控制参数以不同的方式投入运转,从而实现不同的控制。

 

#include
unsigned int xdata data_f_h[2];//电机0f当前和上一次的高16位(0-上一次,1-当前)
unsigned int xdata data_f_l[2]; //电机0f当前和上一次的低16位(0-上一次,1-当前)
float xdata x[2];
float xdata u[2];
unsigned long xdata midsx;
float xdata r[2];
unsigned int xdata time;
unsigned int xdata flag;
unsigned char xdata receivedata;//,flagsx,flagsx0,flagsx1;
unsigned int  xdata uploaddata; 
void receivechar()
{
     while(RI==0){;}
     RI = 0; 
     receivedata = SBUF;
}
void sendflag()
{
     while(TI==0){;}
     TI = 0; 
     SBUF = 10;
     while(TI==0){;}
     TI = 0;
     SBUF = 13;
} 
void sendchar(unsigned char senddata)
{
    unsigned char data temp,tempH,tempL//数据转换
	temp = senddata;
    senddata = (senddata>>4);
	senddata = (senddata&0x0F);
	if(senddata < 0x0A)
	{ 
		senddata = senddata + '0';      //0x30;
    }
	else
	{
		senddata = senddata + '0'+7;    //0x37;
    }
    tempH = senddata;
	senddata = temp; 
    senddata = (senddata&0x0F);
	if(senddata < 0x0A)
	{ 
		senddata = senddata + '0';      //0x30;
    }
	else
	{
		senddata = senddata + '0'+7;    //0x37;
    }
    tempL = senddata;//发送
    while(TI==0){;}
    TI = 0;
    SBUF = tempH;
    while(TI==0){;}
    TI = 0;
    SBUF = tempL;
}
unsigned int receivePosi16()
{   
    unsigned int data countersx;
    unsigned char data i;
	unsigned char data countersx1,countersx2;
    P07 = 0;
    P06 = 1;
	for(i=0;i<3;i++)
	{
	}
    countersx1 = P1;//读取高八位计数值
	P06 = 0;	
    for(i=0;i<3;i++)
	{
	}
    countersx2 = P1;//高八位计数值送入itemp,低八位计数值送入temp
    for(i=0;i<3;i++)
	{
	}
    P07 = 1;//关闭cpld输出
    countersx = countersx1;
	countersx = (countersx<<8);
	countersx= countersx + countersx2;
	return countersx; 
}
unsigned long receivePosi32(unsigned int data itempsx)
{   
    unsigned long xdata re1;
    data_f_h[0]=data_f_h[1];
    data_f_l[0]=data_f_l[1];
    if((data_f_l[0]<1000)&&(itempsx>64536)) //当反转时,data_f_h[1]减。条件由
	{                                   //一次控制期间的最大计数决定    
	    data_f_h[1] = data_f_h[1] - 1;   		   
	} 
    else if((data_f_l[0]>64536)&&(itempsx<1000)) 
	{
	    data_f_h[1] = data_f_h[1] + 1;
	}
	else{;}
	data_f_l[1] = itempsx;
    re1 = data_f_h[1];
	re1 = (re1<<16);
	re1 = re1 + data_f_l[1];
    return re1;
}
void IT0P()interrupt 1
{
    float data ltempsx;
    long  data ltempsx1;
    unsigned long data receive32;
	unsigned int data receivesx16;
    TR0 = 0;	
	TL0=0xBC;
    TH0=0x27;//更新本计数器计数器值
	TR0 = 1;
    flag = 0;
    receivesx16=receivePosi16();//读取光电码盘计数值
	receive32=receivePosi32(receivesx16);//读取光电码盘三十二位计数值
	time++;
    r[0]=r[1];//更新偏差值
    u[0]=u[1];
    u[1]=0x00010000;
    if(time==3001)
    {
        time=1;
    }
	else{;}
    if(time<=150)
    {
        u[1] = u[0]+0.0354958813*time+0.0177479407;
		signsx = 1;
	    }
    else if(time<=1350)
    {
        u[1] = u[0]+5.3781638370;
		signsx = 2;
    }
    else if(time<=1500)
    {
        u[1] = u[0]-0.0354958813*time+53.2798556836;
		signsx = 3;
    }
    else if(time<=1650)
    {
        u[1] = u[0]-0.0354958813*time+53.2798556836;
		signsx = 4;
    }
    else if(time<=2850)
    {
        u[1] = u[0]-5.3781638370;
		signsx = 5;
    } 
    else
	{
	    u[1] = u[0]-106.5236776695+0.0354958813*time;
		signsx = 6;
	}*/
	if(receive32>0x90000)
	{
	    u[1] = u[1]-0x90000;
		receive32 = receive32 - 0x90000;
		data_f_h[1] = data_f_h[1] - 9;
	}
	else {;}*/
	r[1]=u[1]-receive32;//更新当前的偏差值
    x[0] = x[1];                                                       
    x[1] = (498.95 * r[1])/2+ (0.362245 * x[0]) - (471.6344833 * r[0])/2;
	 x[1]=x[1]+0x0800;
    if(signsx ==1)
	{
	    x[1] = x[1] + 0x088C;
	}
    else if(signsx ==2)
	{
	    x[1] = x[1] + 0x087C;
	}
	else if(signsx ==3)
	{
	    x[1] = x[1] + 0x086C;
	}
	else if(signsx ==4)
	{
	    x[1] = x[1] + 0x0774;
	}
	else if(signsx ==5)
	{
	    x[1] = x[1] + 0x0784;
	}
    else if(signsx ==6)
	{
	    x[1] = x[1] + 0x0794;
	}
	else{;}*/
	ltempsx = x[1];         //ltempsx为浮点数
	if(ltempsx>0)
	{
	    ltempsx = ltempsx + 0.5;
	}
	else
	{
	    ltempsx = ltempsx - 0.5;
	}
	ltempsx1 = ltempsx;  //ltempsx1为长整形
	if(ltempsx1<0)
	{
	     ltempsx1 = 0;
	}	
    else if(ltempsx1>0x00000FFF)
    {
     ltempsx1 = 0x00000FFF;     
    }
	else{;}  
    ltempsx1 = ltempsx1&0x00000FFF;//取低十二位DA值 
    DAC0H = (ltempsx1>>8);
    DAC0L = ltempsx1;
}
   / if(flagsx0 ==0)
    {   
	    if(flagsx == 0 )
		{
            DAC0H = (ltempsx01>>8);//取高四位DA值
            DAC0L = ltempsx01;//启动DA0//T0=0x7F98;
		    DAC1H = (ltempsx11>>8);//取高四位DA值
            DAC1L = ltempsx11;//启动DA0//T0=0x7F98;
            P37=0;
	        spi_w(0x08);
	        spi_w(0x00);
	        P37=1;       // 上电后DAC2给出2.5V电压
   	     }
        else if(flagsx == 1)
  	    {
		    DAC0H = (ltempsx01>>8);//取高四位DA值
            DAC0L = ltempsx01;//启动DA0//T0=0x7F98;
            DAC1H = 0x08;
            DAC1L = 0x00;//上电后DAC1给出2.5V电压 
            P37=0;
	        spi_w(0x08);
	        spi_w(0x00);
	        P37=1;       // 上电后DAC2给出2.5V电压
		}
		else if(flagsx ==2)
		{
		    DAC0H = (ltempsx01>>8);//取高四位DA值
           DAC0L = ltempsx01;//启动DA0//T0=0x7F98;
           DAC0H = 0x08;
           DAC0L = 0x00;//上电后DAC0给出2.5V电压
           DAC1H = 0x08;
           DAC1L = 0x00;//上电后DAC1给出2.5V电压 
           P37=0;
	        spi_w(0x08);
	        spi_w(0x00);
	        P37=1;       // 上电后DAC2给出2.5V电压 
		}
		else{;}
	}
    else if(flagsx0 ==1)
    {
	    if(time0 ==1500)
		{
			 flagsx1 = 1;
		}
		else
		{
		     flagsx1 = 0;
        }
		if((flagsx1==1)&&(flagsx==0))
		{
		    DAC0H = (ltempsx01>>8);//取高四位DA值
            DAC0L = ltempsx01;//启动DA0//T0=0x7F98;
		    DAC1H = (ltempsx11>>8);//取高四位DA值
            DAC1L = ltempsx11;//启动DA0//T0=0x7F98;
            P37=0;
	        spi_w(0x08);
	        spi_w(0x00);
	        P37=1;       // 上电后DAC2给出2.5V电压   
		}
		else if((flagsx1==0)&&(flagsx==0))
		{
             DAC0H = (ltempsx01>>8);//取高四位DA值
             DAC0L = ltempsx01;//启动DA0//T0=0x7F98;
             DAC1H = 0x08;
             DAC1L = 0x00;//上电后DAC1给出2.5V电压 
             P37=0;
	         spi_w(0x08);
	         spi_w(0x00);
	         P37=1;       // 上电后DAC2给出2.5V电压
		}
	        
		else if (flagsx ==1)
		{
		     DAC0H = (ltempsx01>>8);//取高四位DA值
             DAC0L = ltempsx01;//启动DA0//T0=0x7F98;
             DAC1H = 0x08;
             DAC1L = 0x00;//上电后DAC1给出2.5V电压 
             P37=0;
	         spi_w(0x08);
	         spi_w(0x00);
	         P37=1;       // 上电后DAC2给出2.5V电压
		}
		else if(flagsx ==2) 
		{
		       
		     DAC0H = 0x08;
             DAC0L = 0x00;//上电后DAC0给出2.5V电压
             DAC1H = 0x08;
             DAC1L = 0x00;//上电后DAC1给出2.5V电压 
             P37=0;
	         spi_w(0x08);
	         spi_w(0x00);
	         P37=1;       // 上电后DAC2给出2.5V电压     
		}
		else{;}
    }
    else if(flagsx0 ==2)
    {
	    if(flagsx==0)
		{
		     DAC0H = (ltempsx01>>8);//取高四位DA值
             DAC0L = ltempsx01;//启动DA0//T0=0x7F98;
		     DAC1H = (ltempsx11>>8);//取高四位DA值
             DAC1L = ltempsx11;//启动DA0//T0=0x7F98;
             P37=0;
	         spi_w(0x08);
	         spi_w(0x00);
	         P37=1;       // 上电后DAC2给出2.5V电压    
		}
		else if(flagsx ==1)
		{
		     DAC0H = (ltempsx01>>8);//取高四位DA值
             DAC0L = ltempsx01;//启动DA0//T0=0x7F98;
             DAC1H = 0x08;
             DAC1L = 0x00;//上电后DAC1给出2.5V电压 
             P37=0;
	         spi_w(0x08);
	         spi_w(0x00);
	         P37=1;       // 上电后DAC2给出2.5V电压    
		}
		else if(flagsx ==2)
		{
	         DAC0H = 0x08;
             DAC0L = 0x00;//上电后DAC0给出2.5V电压
             DAC1H = 0x08;
             DAC1L = 0x00;//上电后DAC1给出2.5V电压 
             P37=0;
	         spi_w(0x08);
	         spi_w(0x00);
	         P37=1;       // 上电后DAC2给出2.5V电压 
		}
		else{;}
      }
        else{;}
void main( void )
 {   
    unsigned int data receive16;
    SP = 0x30; 
	SCON = 0x52;
	T3CON = 0x86;
	T3FD = 0x2D;
	CFG841 = 0x01;
	PLLCON = 0x50;
    DACCON = 0x7F;
    DAC0H = 0x08;
    DAC0L = 0x00;//上电后DAC0给出2.5V电压
    DAC1H = 0x08;
    DAC1L = 0x00;//上电后DAC1给出2.5V电压 
	P0 = 0xFF;
	IE = 0x82;//开系统中断和定时期0中断
    TMOD = 0x11;//设置计数器控制字
    TL0=0xBC;
    TH0=0x27;//定时期计数值赋初值  
    data_f_h[0]=1;
	data_f_h[1]=1;//返回值高十六位赋初始值
    receive16=receivePosi16();//读取码盘初始值
    data_f_l[0] =receive16;
	data_f_l[1] =receive16;//返回值低十六位赋初始值为码盘上电初始值
    u[0] = data_f_h[0];
	midsx = u[0];
	midsx = (midsx<<16);
	u[0] = midsx;
	u[0] = u[0] + data_f_l[0];
	u[1] = u[0];
    x[0] = 0;
    x[1] = 0;	
    r[0] = 0;
    r[1] = 0;
	time = 0;
	flag = 0;//显示数据的间隔标志
    sendflag();
	sendchar(0x00);
    sendchar(0x00);
	sendflag();
/*	receivechar();
	if(receivedata == 0x00)
    {
	    while(1);
	}
	else if(receivedata == 0x30)
	{
	    flagsx = 0;
		flagsx0 = flagsx;
	} 
	else if (receivedata == 0x31)
	{
	    flagsx  = 1;
		flagsx0 = flagsx;
	}
	else if (receivedata == 0x32)
	{   flagsx = 2;
		flagsx0 = flagsx;}
	else{;}*/
	TR0 = 1;	
	while(1)
	{    
	    /* flagsx0 = SBUF-0x30;
         if(RI ==1)
         {   
             RI =0;
	         if(SBUF == 0x30)
             {flagsx=0;}
	         else if(SBUF == 0x31)
	         {flagsx = 1;} 
	         else if (SBUF == 0x32)
	         {flagsx = 2;}
	         else {;}
	      }
          else{;}*/
         if((flag==0)&&(time%30==0))
		 {   flag = 1;
		     uploaddata = r[1];
			 sendflag();
             sendchar(0x00);
    		 sendchar(uploaddata);
			 sendflag(); }
		 else{;} 
	}
}
2.	逻辑电路程序(4 倍频程序):
module ab(clk,oe,out,ina,inb,sel);
input clk,oe,ina,inb,sel;
output[7:0] out;
reg[1:0] prestate,state;
reg[15:0] counter;
reg[15:0] counter1;
wire[7:0] counter2;
reg lock;
wire [7:0]out;
always @(posedge clk)      
begin
	    state[0]<=inb;
	    state[1]<=ina;
 begin
   if((prestate===2'b11)&&(state===2'b01))     //判向计数
		begin
		counter<=counter+16'b1;
		end
   else
	  if((prestate===2'b01)&&(state===2'b00))
		    begin
			counter<=counter+16'b1;
			end
	  else
		  if((prestate===2'b00)&&(state===2'b10))
			  begin
				counter<=counter+16'b1;
			  end
		 else
		     if((prestate===2'b10)&&(state===2'b11))
				begin
				counter<=counter+16'b1;
				end
			else
				if((prestate===2'b00)&&(state===2'b01))
					begin
					counter<=counter-16'b1;
					end
				else
					if((prestate===2'b01)&&(state===2'b11))
						begin
						counter<=counter-16'b1;
						end
					else
						if((prestate===2'b11)&&(state===2'b10))
							begin
							counter<=counter-16'b1;
							end
						else
							if((prestate===2'b10)&&(state===2'b00))
							   begin
								counter<=counter-16'b1;
								end
							else
							counter<=counter;
            end
  prestate<=state;
end
always@(negedge clk)
begin
     lock<=oe;
     if((lock==1)&&(oe==0))
      begin 
     counter1<=counter;    
      end
      else
     begin
      counter1<=counter1;
     end
end
assign counter2=(sel)?counter1[15:8]:counter1[7:0];
assign out=(lock)?8'bz:counter2;
endmodule