/*-----------------------------------------------
名称:遥控器红外解码数液晶显示
------------------------------------------------*/
#include<STC12C5A60S2.h>
#include<1602.h>
#define uchar unsigned char
#define uint unsigned int
uchar i,a,b,c,d;
uint jj;
uchar code table[]={'0','1','2','3','4','5','6','7','8','9'};
long bb;
uint mm=1234;
sbit IR=P3^2;
sbit beep=P2^2;
uint m,sum,s[];
/*------------------------------------------------
全局变量声明
------------------------------------------------*/
unsigned char ir
time; //红外用全局变量
bit irpro_ok,irok; //irpro_ok处理完成标志,接收好了,
unsigned char IRcord[4]; //储存4个红外码的四个字节
unsigned char irdata[33]; //储存32+1位
unsigned char TempData[16]; //定义零时数据
/*------------------------------------------------
定时器0中断处理
------------------------------------------------*/
void tim0_isr (void) interrupt 1 using 1
{
irtime++; //用于计数2个下降沿之间的时间
}
/*------------------------------------------------
外部中断0中断处理
------------------------------------------------*/
void EX0_ISR (void) interrupt 0 //外部中断0服务函数
{
static unsigned char i; //接收红外信号处理
//static bit startflag=1; //是否开始处理标志位
//if(startflag)
//{
if(irtime>=33&&irtime<63) //引导码 TC9012的头码,9ms+4.5ms
i=0;
irdata[i]=irtime; //存储每个电平的持续时间,用于以后判断是0还是1
irtime=0;
i++;
if(i==33)
{
irok=1;
i=0;
}
/*}
else
{
irtime=0;
startflag=1;
} */
}
/*------------------------------------------------
外部中断0初始化
------------------------------------------------*/
void EX0init(void)
{
IT0 = 1; //指定外部中断0下降沿触发,INT0 (P3.2)
EX0 = 1; //使能外部中断
EA = 1; //开总中断
}
/*------------------------------------------------
键值处理
------------------------------------------------*/
void Ir_work(void)//红外键值散转程序
{
switch(IRcord[2])//判断第三个数码值
{
case 0x16:m=0;write_string("0");break;//0
case 0x0c:m=1;write_string("1");break;//1
case 0x18:m=2;write_string("2");break;//2
case 0x5E:m=3;write_string("3");break;//3
case 0x08:m=4;write_string("4");break;//4
case 0x1c:m=5;write_string("5");break;//5
case 0x5A:m=6;write_string("6");break;//6
case 0x42:m=7;write_string("7");break;//7
case 0x52:m=8;write_string("8");break;//8
case 0x4A:m=9;write_string("9");break;//9
default:break;
}
irpro_ok=0;//处理完成标志
}
/*------------------------------------------------
红外码值处理
------------------------------------------------*/
void Ircordpro(void)//红外码值处理函数
{
unsigned char i, j, k;
unsigned char cord,value;
k=1;
for(i=0;i<4;i++) //处理4个字节
{
for(j=1;j<=8;j++) //处理1个字节8位
{
cord=irdata[k]; //此处去除头码 故从一开始
if(cord>7) //大于某值为1,这个和晶振有绝对关系,这里使用12M计算,此值可以有一定误差
value|=0x80; //2.25>256X7>1.125ms
if(j<8)
{
value>>=1; //数据串行发送,低位(bit0)在前,高位(bit7)在后
}
k++;
}
IRcord[i]=value;
value=0;
}
irpro_ok=1;//处理完毕标志位置1
}
xian_shi()
{
uchar qian,bei,shi,ge;
jj=mm;
jj*=40;
//jj+=1;
qian=jj/1000;
bei=jj%1000/100;
shi=jj%100/10;
ge=jj%10;
write_data_lcd(2,7,table[qian]);
write_data_lcd(2,8,table[bei]);
write_data_lcd(2,9,table[shi]);
write_data_lcd(2,10,table[ge]);
}
timer_init() //定时器计数器初始化函数
{
EA=1;
ET0=1;
ET1=1;
TMOD=0X51;
TH0=(65535-50000)/256;
TL0=(65535-50000)%256;
TH1=0;
TL1=0;
TR0=1;
TR1=1;
}
void timer0() interrupt 1
{ TR0=0;
TR1=0;
TH0=(65535-50000)/256;
TL0=(65535-50000)%256;
mm=0;
mm|=TH1;
mm=(mm<<8)|TL1;
// mm-=55536;
TH1=0;
TL1=0;
TR0=1;
TR1=1;
}
void timer1() interrupt 3
{
TR1=0;
TR0=0;
mm=0;
// TH1=0; // TL1=0; // TR1=1;
}
/*********************************************************************************************
函数名:PWM初始化函数
调 用:PWM_init();
参 数:无
返回值:无
结 果:将PCA初始化为PWM模式,初始占空比为0
备 注:需要更多路PWM输出直接插入CCAPnH和CCAPnL即可
/**********************************************************************************************/
void CPU_ini(void)
{
CCON=0x00;
CL=0;
CH=0;
AUXR1=0x00;//0x00----P1.3输出;0x40----P1.3输出
CMOD=0x00;
CCAP0L=0x00;
CCAP0H=0x00;
CCAPM0=0x42;
CCON=0x40;
}
/*********************************************************************************************
函数名:PWM0占空比设置函数
调 用:PWM0_set();
参 数:0x00~0xFF(亦可用0~255)
返回值:无
结 果:设置PWM模式占空比,为0时全部高电平,为1时全部低电平
备 注:如果需要PWM1的设置函数,只要把CCAP0L和CCAP0H中的0改为1即可
/**********************************************************************************************/
void PWM0_set (unsigned char n)
{
CCAP0L= n; //设置值直接写入CCAP0L
CCAP0H= n; //设置值直接写入CCAP0H
}
/****************************PID算法***********************************************************/
//定义PID参数
#define VV_KPVALUE 3 //比例
#define VV_KIVALUE 40 //积分
#define VV_KDVALUE 3//微分
#define VV_MAX 10000//返回的最大值,是pwm的周期值
#define VV_MIN 0
//#define VV_DEADLINE 0X08 //速度PID,设置死区范围
typedef struct PID //定义数法核心数据
{
signed int vi_Ref; //速度PID,速度设定值 Velocity
signed int vi_FeedBack; //速度PID,速度反馈值 m*50
signed long vi_PreError; //速度PID,前一次,速度误差,,vi_Ref - vi_FeedBack
signed long vi_PreDerror; //速度PID,前一次,速度误差之差,d_error-PreDerror;
unsigned int v_Kp; //速度PID,Ka = Kp
unsigned int v_Ki; //速度PID,Kb = Kp * ( T / Ti )
unsigned int v_Kd; //速度PID,
signed long vl_PreU; //电机控制输出值
}PID;
static PID sPID; // PID Control Structure
static PID*sptr=&sPID;
void PIDInit(void)
{
sptr->vi_Ref =sum; //速度设定值
sptr->vi_FeedBack =jj ; //速度反馈值
sptr->vi_PreError = 0 ; //前一次,速度误差,,vi_Ref - vi_FeedBack
sptr->vi_PreDerror = 0 ; //前一次,速度误差之差,d_error-PreDerror;
sptr->v_Kp = VV_KPVALUE;
sptr->v_Ki = VV_KIVALUE;
sptr->v_Kd = VV_KDVALUE;
sptr->vl_PreU = 0; //电机控制输出值
}
uint speed_pid(int v)
{
signed long error,d_error,dd_error; //
error = (signed long)(sptr->vi_Ref - sptr->vi_FeedBack); // 偏差计算
d_error = error - sptr->vi_PreError;
dd_error = d_error - sptr->vi_PreDerror;
sptr->vi_PreError = error; //存储当前偏差
sptr->vi_PreDerror = d_error; //储存当前误差之差
sptr->vl_PreU += (signed long)( sptr -> v_Kp * d_error +sptr -> v_Ki * error +sptr->v_Kd*dd_error); //速度PID计算
if( sptr->vl_PreU >= VV_MAX )//速度PID,防止调节最高溢出
sptr->vl_PreU = VV_MAX;
else
if( sptr->vl_PreU <= VV_MIN ) //速度PID,防止调节最低溢出
sptr->vl_PreU = VV_MIN;
else
return ( sptr->vl_PreU ); // 返回预调节占空比
}
/****************************主函数***********************************************************/
main()
{
uint p=0,num=0;
timer_init();
EX0init(); //初始化外部中断
CPU_ini(); //PWM初始化
lcd_init();
PIDInit();
write_string_lcd(1,0,"shezhi: r/min");
write_string_lcd(2,0,"zuizhi: r/min");
while(num<4)//主循环
{
if(irok) //如果接收好了进行红外处理
{
beep=0;
Delay(200);
beep=1;
Ircordpro(); //红外码处理
irok=0;
}
if(irpro_ok) //如果处理好后进行工作处理,如按对应的按键后显示对应的数字等
{
set_display_place(1,7);
Ir_work();
s[num]=m;
num++ ;
}
sum=s[0]*1000+s[1]*100+s[2]*10+s[3] ;
}
while(1)
{
p+=speed_pid(jj);
PWM0_set ((1-p)*255) ;
xian_shi();
Delay(1); //刷新时间单位毫秒
}
}
一周热门 更多>