#include<reg52.h>
#include<stdio.h>
#define uchar unsigned char
#define uint unsigned int
unsigned char code Duan[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//共阴极数码管,0-9段码表
unsigned char Data_Buffer[8]={0,0,0,0,0,0,0,0}; // 显示缓冲
uchar i=0;
sbit AddSpeed=P1^0;//加速按键置位
sbit SubSpeed=P1^1;//减速按键置位
sbit Turn=P1^2;//正转按键置位
sbit Stop=P1^3;//停止按键置位
sbit IN1=P3^6;
sbit IN2=P3^7;//控制电机正反转和停止状态
sbit PWM_FC=P1^7;//输出PWM口
bit ENA=1;
float pid_p=0.003,pid_i=0.003,pid_d=0.002; //PID三个参数 初值
unsigned int lastError=0;
long int sumError=0;//sum偏差和
int out=0; //PWM高电平时间控制标志位
int SpeedSet=0;//速度初值
uint cnt=0; //PWM的周期标志位
uint Inpluse=0,num=0;//脉冲计数
int pid_val_mid=0;//脉冲宽度
//void PIDControl();//PID控制子函数
void SystemInit();//定时器和中断初始化子函数
void delay(uchar x); //延时子函数
void PWMOUT(); //PWM输出子函数
void SetSpeed(); //按键进行速度和转向控制子函数
void SegRefre(); //显示刷新子函数
/**************主函数************/
void main() //定时器和中断初始化
{
SystemInit();
while(1)
{
SetSpeed(); //按键设定速度
SegRefre(); //数码管显示刷新
if(SpeedSet==0)
{
ENA=0;
}
}
}
/***************pid偏差计算子函数 ***************/
unsigned int PID()
{
int dError=0,Error=0,B;
Error=SpeedSet-num;//当前误差
sumError=Error+sumError;//误差和
dError=Error-lastError;//误差偏差
lastError=Error;
B=pid_p*Error+pid_i*sumError+pid_d*dError;
if(B>100) pid_val_mid=100;
if(B<0) pid_val_mid=0;
if(B>=0&&B<=100)
pid_val_mid=B;
return(0);
}
/**************延时子函数**************/
void delay(uchar x)//延时子函数平
{
uint i,j;
for(i=x;i>0;i--)
for(j=50;j>0;j--);
}
/************PWM输出子函数*************/
void PWMOUT() //输出PWM脉冲子函数,进行PWM高低电平时间的判别
{
if(cnt<pid_val_mid) //高电时间为PID输出PWMTime
{
PWM_FC=1;
}
else
{
PWM_FC=0;
}
if(cnt>=100)
cnt=0; //100次定时器T1中断触发时间为一个PWM周期为1ms,故所取PWM频率为1k
}
/****************定时器和中断初始化子函数*************************/
void SystemInit()//定时器和中断初始化子函数
{
TMOD=0X11;//TOMD寄存器设置,T0为16位定时器,T1为8位自动重装定时器
TH0=(65536-2000)/256;
TL0=(65536-2000)%256; //定时器T0定时2ms
TH1=0xfc;
TL1=0X66; //定时器T1定时10us
ET1=1; //T1中断允许
ET0=1; //T0中断允许
TR0=1; //启动定时器T0
TR1=1; //启动定时器T0
EX0=1; //允许外部中断0,中断0用来测量转速
IT0=1; //跳变沿触发方式计数
EA=1; //全局中断允许
IN1 = 1; //默认电机初始转向为正向
IN2 = 0;
}
/**************按键进行速度和转向控制子函数**************/
void SetSpeed() //按键进行速度和转向控制子函数
{
if(AddSpeed==0) //加速按键按下
{
delay(200); //按键消抖处理
if(AddSpeed==0)
{
SpeedSet=SpeedSet+100;
if(SpeedSet>2500)
{
SpeedSet=2500;
}
while(AddSpeed==0);
}
}
if(SubSpeed==0) //减速按键按下
{
delay(200); //按键消抖处理
if(SubSpeed==0)
{
SpeedSet=SpeedSet-100;
if(SpeedSet<=0)
{
SpeedSet=0;
}
while(SubSpeed==0);
}
}
if(Turn==0) //正/反转按键按下
{
delay(200); //按键消抖处理
if(Turn==0) //实现电机正反转切换
{
IN1 = ~IN1;
IN2 = ~IN2;
while(Turn==0);
}
}
if(Stop==0) //停止按键按下
{
delay(200); //按键消抖处理
if(Stop==0) //实现电机停止
{
ENA=~ENA;
while(Stop==0);
}
}
}
/**********显示刷新子函数*********/
void SegRefre() //显示刷新
{
Data_Buffer[0]=SpeedSet/1000; //分离速度设定值各位
Data_Buffer[1]=SpeedSet%1000/100;
Data_Buffer[2]=SpeedSet%100/10;
Data_Buffer[3]=SpeedSet%10;
Data_Buffer[4]=num/1000; //分离实际速度采集脉冲数各位
Data_Buffer[5]=num%1000/100;
Data_Buffer[6]=num%100/10;
Data_Buffer[7]=num%10;
}
/**************外部中断0********进行脉冲计数*******/
void int0() interrupt 0 // 外部中断0 ,P3.2口采集脉冲
{
Inpluse++; //采集外部脉冲
}
/***********定时器T0中断*********/
void t0() interrupt 1 //定时器T0中断
{
static unsigned char Bit=0;//静态变量,退出程序值保留
static unsigned int time=0;
TH0=(65536-2000)/256;
TL0=(65536-2000)%256;
time++; //转速测量周期
Bit++;
if(Bit>7)
{ Bit=0;}
switch(Bit) //数码管位选
{
case 0:P0=0xff;P2=Duan[Data_Buffer[0]]; P0=0X7F;break;
case 1:P0=0xff;P2=Duan[Data_Buffer[1]]; P0=0XBF;break;
case 2:P0=0xff;P2=Duan[Data_Buffer[2]]; P0=0XDF;break;
case 3:P0=0xff;P2=Duan[Data_Buffer[3]]; P0=0XEF;break;
case 4:P0=0xff;P2=Duan[Data_Buffer[4]]; P0=0XF7;break;
case 5:P0=0xff;P2=Duan[Data_Buffer[5]]; P0=0XFB;break;
case 6:P0=0xff;P2=Duan[Data_Buffer[6]]; P0=0XFD;break;
case 7:P0=0xff;P2=Duan[Data_Buffer[7]]; P0=0XFE;break;
}
if(time==250) //取0.5s
{
num=Inpluse*2; //0.5s内的脉冲乘以2,再对脉冲数进行放大5倍,算得1s采集的脉冲数
PID(); //调用PID算法, 更新PWM占空比
Inpluse=0;
time=0;
}
}
/*************定时器T1中断*************/
void timer_1() interrupt 3 //定时器T1中断
{
TH1=0xfc;
TL1=0x66;
cnt++;
if(ENA==1)
{
PWMOUT();
}
if(ENA==0)
{
PWM_FC=0;
}
}