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

📄 main.c

📁 一个应用于LF2407的风扇转速控制系统
💻 C
字号:
/*************************************************************
 *Copyright (c) 2008,中国石油大学(华东)自动化05-1班
 *All rights reserved
 *
 *文件名称:main.c
 *文件标示:主函数
 *摘    要:电机控制程序主程序
 *
 *当前版本:3.0
 *作    者:
 *完成日期:2008年7月3日
 *************************************************************/

/************************文件预处理***************************/
#include "register.h" //寄存器定义
/*************************************************************/

/********************全局变量定义与初始化*********************/
unsigned int num=0x0000;    //定义转速
unsigned char show=0x0000;    //定义欲显示值
char send_buff_7279=0x00;    //LED显示值所需命令字及待显示数据
//LCD内容初始化
char lcd_buff[]="PV:     SV:     Kp:     Ti:     Td:     MV:    ";
char receive[6];//SCI接受缓冲区
char newpid=0;//PID重设与初始化
/*************************************************************/

/**************************************************************/
//PID算法变量定义
int openclose;//开闭环指示
int pidtype;  //PID类型指示
unsigned int SV,PV;
int MV;
float T,Kp,Ti,Td,q0,q1,q2;
int ekminus1,ekminus2,ek;
int dadata; //DAC输出值
/**************************************************************/

/*******************************************************/
//LCD相关
ioport unsigned port8002;       //写lcd指令地址
ioport unsigned port8003;       //写lcd数据地址
/*********************************************************/


/*******************函数、子程序声明与定义********************/
void PID();
void dac(unsigned int dacdata);

/***************************通用的延时子程序******************/
void delay_8us()             //延时8us子程序
{
     unsigned int i;
     for(i=0;i<2;i++); 
}

void delay_50us()            //延时50us子程序
{
     unsigned int j;
     for(j=0;j<25;j++);
}

void delay_40ms()            //延时40ms
{
  	 unsigned int a;
  	 for(a=0;a<10000;a++);
}

void delay_25ms()            //延时25ms
{
  	 unsigned int a;
  	 for(a=0;a<4800;a++);
}

void delay_us()           //延时100us
{
  	 unsigned int s;
  	 for(s=0;s<25;s++);
}

void delay()                  //延时子程序
{
     unsigned int k;
     for(k=0;k<5;k++);
}
/***************************通用的延时子程序******************/


/***************************初始化程序段***********************/

//系统初始化子程序
void sys_ini()
{
 /*关总中断*/
  asm(" setc INTM");         
 /*抑制符号位扩展*/
  asm(" clrc SXM");          
 /*累加器中结果正常溢出*/
  asm(" clrc OVM");          
 /*禁止看门狗*/
  * WDCR=0x00E8;             
 /*配置时钟锁相为4倍频CLKOUT=4*10=40M*/
  * SCSR1=0x0064; 
 /*将iope1,2,3配置为输出脚 ,且iope3初始值为0,iope1,iope2初始值为1*/
  * PEDATDIR=0x0E06;        
 /*将iopf6配置为输出脚,且iopf6初始值为1*/ 
  * PFDATDIR=0x4040;
 /*使能spi引脚*/
  * MCRB=0xFF3F;
  * MCRA=0x0003;   
 /*io、ram、program都设为0等待读写*/
 // WSGR=0x0649;                                    
 /*清除所有中断标志,"写1清0"*/ 
  * IFR=0xFFFF;           
}

//外部中断2初始化子程序
void int2_ini()               
{ 
    /*清除所有中断标志*/
     * IFR=0xFFFF;     
    /*使能int1,int2中断*/
     * IMR=0x0003;             
    /*使能xint2中断,上升沿有效,高优先级,清xint2中断标志*/
     * XINT2CR=0x8005; 
     /*使能T1PINT中断*/         
     * EVAIMRA=0x0080;   
    /*清EVA中断标志*/       
     * EVAIFRA=0xFFFF;   
    /*约100ms产生一次中断*/       
     * T1PER=0xB414;  
    /*计数器清零*/          
     * T1CNT=0x0000; 
    /*连续增计数模式,预分频为8,定时器计时使能,内部时钟,定时器1比较使能*/           
     * T1CON=0x164C;                                  
}

//spi初始化子程序
void spi_ini()              
{
    /*复位spi*/
     * SPICCR&=0x007F;       
    /*CLOCK POLARITY=0,16位数据格式*/   
     * SPICCR=0x000F;        
    /*禁止溢出中断,CLOCK PHASE=1,禁用spi中断,主模式,使能数据发送*/
     * SPICTL=0x000E;  
    /*清除接收溢出中断标志*/         
     * SPISTS=0x0080;           
    /*波特率为40/4=10M*/
     * SPIBRR=0x0000;        
    /*启动spi工作*/   
     * SPICCR|=0x0080;       
}

//SCI初始化子程序
void sci_ini()                  
{
    /*1位停止位,禁用奇偶校验,禁用回馈测试,地址位协议模式,8位数据位*/
     * SCICCR=0x000F;   
    /*禁止接收错误中断,禁用传输唤醒模式,禁用休眠模式,使能数据发送和接收*/         
     * SCICTL1=0x0023; 
    /*40M CLKOUT,波特率为4800*/         
     * SCIHBAUD=0x0004;
     * SCILBAUD=0x0010;     
    /*使用接收中断,使用发送中断*/    
     * SCICTL2=0x0003;  
    /*高中断优先级,仿真挂起时完成当前操作*/        
     * SCIPRI=0x0010;            
}
/*************************************************************/

//PID算法初始化程序
void pid_ini()
{
	if(newpid==0)
	{
	    openclose=1;
	    pidtype=3;
	    Kp=4;
	    Ti=5;
	    Td=0;
	    T=1;
	    SV=15;
	    MV=0;
	    ek=ekminus1=ekminus2=0;
	    q0=Kp*(1+T/Ti+Td/T);
    	q1=(-1)*Kp*(1+2*Td/T);
    	q2=Kp*Td/T;
    }
    else
    {
	    q0=Kp*(1+T/Ti+Td/T);
	    q1=(-1)*Kp*(1+2*Td/T);
	    q2=Kp*Td/T;
	}
}

//LCD初始化
void lcd_ini()
{
  delay_40ms();                //延时40ms
  port8002=0x0030;           //8位控制界面,基本指令集
  delay_us();
  port8002=0x0030;           //8位控制界面,基本指令集
  delay_us();
  port8002=0x000C;           //整体显示,显示游标 ,显示游标位置
  delay_us();
  port8002=0x0001;           //清除显示
  delay_40ms();
  port8002=0x0006;           //光标右移
  delay_us();
}  

/**************************************************************/

/************************初始化子程序完************************/


/*********************LCD显示函数定义**************************/
//LCD显示程序(查看相关资料)
void lcd_show(char a[])
{
	int x;
	char * string=a;
	port8002=0x0001;           //清除显示
  	delay_40ms();
  

	for(x=0;x<strlen(a);x++)
	{
	port8003=*string;
	string++;
	delay_us();
	}
} 
/***********************************************************/

/***************************LED 显示程序段******************/
//7279的使能函数
void cs_low()
{
          * PFDATDIR&=0xFFBF; //7279cs低
}
//发送数据或命令函数
void send()
{         
      unsigned int m;
      cs_low();
      delay_50us();                 //延时50us;
      for(m=0;m<8;m++)
      {
           switch(send_buff_7279&0x80)
           {
               case 0x00:* PEDATDIR&=0xFFFB;break; //7279data低
               case 0x80:* PEDATDIR|=0x0004; //7279data高
           }
           * PEDATDIR|=0x0008; //7279clk高
           delay_8us();
           * PEDATDIR&=0xFFF7; //7279clk低
           delay_8us();
           send_buff_7279<<=1;
       }

}

/*************************************************************/
//上位机参数执行
void execute()
{
	switch(receive[1])
	{
		case 'L':
			openclose=1-openclose;
			break;
		case 'X':
                         MV=(receive[3]-0x30)*10+receive[4]-0x30;
                         break;
		case 'S':
                         SV=(receive[3]-0x30)*10+receive[4]-0x30;
                         break;
		case 'P':
                         Kp=(receive[3]-0x30)*10+receive[4]-0x30;
                         newpid=1;	pid_ini();
                         break;
		case 'I':
                         Ti=(receive[3]-0x30)*10+receive[4]-0x30;
                         newpid=1;	pid_ini();
                         break;
		case 'D':
                         Td=(receive[3]-0x30)*10+receive[4]-0x30;
                         newpid=1;	pid_ini();
                         break;
		case 'T':
						if(receive[4]=='1') pidtype=1;
						if(receive[4]=='2') pidtype=2;
						if(receive[4]=='3') pidtype=3;
						break;
	}
	newpid=0;
}

//上位机刷新参数
void refresh()
{
        static int j=0;
        if(*SCIRXBUF=='$') {j=0;receive[j]='$';}
        if((j>=1)&&(j<6)) 
        {
        	receive[j]=*SCIRXBUF;
        	if(j==5)  
        		{execute();j=-1;}
        }
        j++;
        *IFR=0x0010;                            //清除接收中断标志
}
/*************************************************************/


/*****************中断服务子程序声明与定义********************/
interrupt void GISR1()       //外部中断2中断子程序
{
     switch(*PVIR)
     {
     //外部中断2的中断处理
     case 0x0011:    
				 /*显示值取反*/
				 num++;      
				 /*使能xint2中断,上升沿有效,高优先级,清xint2中断标志*/         
				 * XINT2CR=0x8005;
                 break; 
     //SCI接收中断处理                
     case 0x0006:
                 refresh();
                 break;
     }    
     return;
}
/*************************************************************/

/*************************************************************/
interrupt void timer1()         //定时器1中断子程序
{    
    static int i=0;
    i=i+1;
    if(i>=10)
    {										
	    /*定时器每1s产生一次中断,读取转速值num*/
	     show=num;  
	     PV=num;
	    /*转速清零*/
	     num=0;
	
	    /*显示转速*/
	     send_buff_7279=0xA4;          //先对7279复位清除
	     send();
	     send_buff_7279=0xC8;          //显示最低位指令
	     send();
	     send_buff_7279=show%10;
	     send();
	     send_buff_7279=0xC9;          //显示第二位指令
	     send();
	     send_buff_7279=show/10;
	     send();
	    /*向上位机发送数据*/
	    //转速
	     *SCITXBUF=0x23;
	     delay_25ms();
	     *SCITXBUF=0x56;
	     delay_25ms();
	     *SCITXBUF=0x30;
	     delay_25ms();
	     *SCITXBUF=0x30;
	     delay_25ms();
	     *SCITXBUF=0x30+show/100;
	     delay_25ms();
	     *SCITXBUF=0x30+(show/10)%10;
	     delay_25ms();
	     *SCITXBUF=0x30+show%10;
	     delay_25ms();
	     *SCITXBUF=0x3B;
	     delay_25ms();
	
	     PID(); //执行PID算法并输出控制量

	     //控制量
	     *SCITXBUF=0x23;
	     delay_25ms();
	     *SCITXBUF=0x55;
	     delay_25ms();
	     *SCITXBUF=0x30;
	     delay_25ms();
	     *SCITXBUF=0x30;
	     delay_25ms();
	     *SCITXBUF=0x30+dadata/100;
	     delay_25ms();
	     *SCITXBUF=0x30+(dadata/10)%10;
	     delay_25ms();
	     *SCITXBUF=0x30+dadata%10;
	     delay_25ms();
	     *SCITXBUF=0x3B;
	     delay_25ms();
	     
	/**************构造LCD显示内容*****************************/
	
	//SV:
	     lcd_buff[3]=0x30+PV/10;
	     lcd_buff[4]=0x30+PV%10;
	//PV:
	     lcd_buff[11]=0x30+SV/10;
	     lcd_buff[12]=0x30+SV%10;
	//Kp:
	     lcd_buff[19]=0x30+(int)Kp%10;
	     lcd_buff[20]='.';
	     lcd_buff[21]=0x30+(int)(Kp*10)%10;
	//Ti:
	     lcd_buff[27]=0x30+(int)Ti%10;
	     lcd_buff[28]='.';
	     lcd_buff[29]=0x30+(int)(Ti*10)%10;
	//Td:
	     lcd_buff[35]=0x30+(int)Td%10;
	     lcd_buff[36]='.';
	     lcd_buff[37]=0x30+(int)(Td*10)%10;
	//MV:
	     lcd_buff[43]=0x30+MV/100;
	     lcd_buff[44]=0x30+(MV/10)%10;
	     lcd_buff[45]=0x30+MV%10;
	
	     lcd_show(lcd_buff);
	     
	     i=0;
     }
    /*计数器清零*/
     * T1CNT=0x0000;            
    /*清EVA中断标志*/
     * EVAIFRA=0xFFFF;          
     return;
}
     
/*************************************************************/


interrupt void nothing()     //哑中断子程序
{
  return;         
}

/**********************两路DA输出函数***************************/

void dac(unsigned int dacdata)
{    
    unsigned int data1;
    unsigned int data2;
    data1 = dacdata&0x00ff|0x0100;
    data2 = dacdata&0x00ff|0x2500; 
     /*将数据写入AD7303*/
     * SPITXBUF=data1;    
     delay();
    /*将数据写入AD7303*/
     * SPITXBUF=data2;    
     delay();                                                                                                                                                      
}

/******************PID运算模块*******************************/
void PID() 
{	
	PV=show;
	ek=PV-SV;
	if(openclose==0)
		MV=(int)(255-51/6.0*SV);
	else if(pidtype==3)
	{   
		MV+=q0*ek+q1*ekminus1+q2*ekminus2;
	}
	else if(pidtype==2)
	{
		MV+=Kp*(1+T/Ti)*ek-Kp*ekminus1;
	}
	else if(pidtype==1)
	{
		MV+=Kp*ek-Kp*ekminus1;
	}
	
	ekminus2=ekminus1;
	ekminus1=ek;
	
	if(MV>255) MV=255;
	if(MV<0) MV=0;
	
	dadata=MV;
	dac(dadata);
}

/***************************************************************************/
void main(void)
{
	sys_ini();
  	int2_ini();
  	spi_ini();
  	sci_ini();
	lcd_ini();
    pid_ini();
    /*开总中断*/       
   asm(" clrc INTM");
   while(1);
}

⌨️ 快捷键说明

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