📄 main.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 + -