#include <reg52.h>
#include <intrins.h>
//IO口设置
sbit a=P1^1; //L298信号口,{ a=1 ;b=0;} //启动输出 正转
sbit b=P1^2; // { a=0 ;b=1;} //启动输出 反转
sbit K1 =P1^3 ; //减少键
sbit K2 =P1^4 ; //增加键
sbit K3 =P1^5 ; //正转键
sbit K4 =P1^6 ; //反转键
sbit K5 =P1^7 ;
unsigned int speed_s=0; //设置的转速,单位r/s
unsigned int speed_m=0; //测量的转速
unsigned char zhuanxiang=1; //转向标志,0不转,1正转,2反转.默认正转
//LCD模块IO口以及子程序定义
#define LCD_DATA P0
sbit LCD_RS = P2^0;
sbit LCD_RW = P2^1;
sbit LCD_EN = P2^2;
unsigned char dispBuff0[16]={'S','D',':',' ',' ',' ',' ',' ',' ',' ',' ','r','/','m','i','n'};//LCD第一行显示 不显示用空格
unsigned char dispBuff1[16]={'D','Q',':',' ',' ',' ',' ',' ',' ',' ',' ','r','/','m','i','n'};//LCD第二行显示
void Delay20ms() ;
void LCD_WriteDat(unsigned char lcd_dat);
void LCD_WriteCmd(unsigned char lcd_cmd);
unsigned char LCD_ReadStatus(void);
void LCD_Goto(unsigned char x,unsigned char y);
void LCD_Display(unsigned char row,unsigned char *str);
/*1、LCD模块子函数*/
void LCD_Init(void)
{
Delay20ms();
LCD_WriteCmd(0x38); //8位机接口、双行显示、5×7字符点阵;
LCD_WriteCmd(0x0c); //显示开启、光标不显示也不闪烁;
LCD_WriteCmd(0x01); //清屏;
LCD_WriteCmd(0x06); //光标右移一位、整屏不移动;
LCD_Goto(0,0);
}
void LCD_WriteDat(unsigned char lcd_dat)
{
unsigned char tmp;
tmp = LCD_ReadStatus(); //读状态;
while((tmp & 0x80)) //是否忙 ?
{
tmp = LCD_ReadStatus();
}
LCD_RS = 1;
LCD_RW = 0;
LCD_DATA = lcd_dat;
_nop_();
LCD_EN = 0;
_nop_();
_nop_();
LCD_EN = 1;
}
void LCD_WriteCmd(unsigned char lcd_cmd) //写指令数据到LCD
{
unsigned char tmp;
tmp = LCD_ReadStatus();
while((tmp & 0x80))
{
tmp = LCD_ReadStatus();
}
LCD_RS = 0;
LCD_RW = 0;
LCD_DATA = lcd_cmd;
_nop_();
LCD_EN = 0;
_nop_();
_nop_();
LCD_EN = 1;
}
unsigned char LCD_ReadStatus(void)
{
unsigned char tmp;
#if 0
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
tmp = LCD_DATA;
LCD_EN = 0;
#endif
LCD_DATA = 0xff;
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 0;
_nop_();
_nop_();
LCD_EN = 1;
tmp = LCD_DATA;
return tmp;
}
void LCD_Goto(unsigned char x,unsigned char y)
{
unsigned char tmp;
if(y) //若是第二行;
{
tmp = 0xc0 + x;
LCD_WriteCmd(tmp);
}
else
{
tmp = 0x80 + x;
LCD_WriteCmd(tmp);
}
}
void LCD_Display(unsigned char row,unsigned char *str)
{
if(row)
{
LCD_Goto(0,1);
}
else
{
LCD_Goto(0,0);
}
while(*str != ' ')
{
LCD_WriteDat(*str++);
}
}
void dectobit(unsigned int dec) //显示测得的速度
{
dispBuff1[4]=(dec/1000)%10+'0';dispBuff1[5]=(dec/100)%10+'0';
dispBuff1[6]=(dec/10)%10+'0';dispBuff1[7]=(dec)%10+'0';
LCD_Display(1,dispBuff1);
}
void Delay20ms() //粗略延时;
{
unsigned int tmp = 50000;
while(tmp--);
}
/*----------------按键识别程序----------------*/
void key() //正转反转调节 zhuanxiang; 转向标志,0不转,1正转,2反转
{
if(K1==0) //减速
{
speed_s=speed_s-50;
if (speed_s<0)
{ speed_s=0;}
}
if(K2==0) //加速
{ if (speed_s<300)
{ speed_s=speed_s+50;}
}
dispBuff0[4]=(speed_s/1000)%10+'0';dispBuff0[5]=(speed_s/100)%10+'0';
dispBuff0[6]=(speed_s/10)%10+'0';dispBuff0[7]=(speed_s)%10+'0';
LCD_Display(0,dispBuff0);
if(K3==0 ) //正转
{
zhuanxiang=1;
}
if(K4==0 ) //反转
{
zhuanxiang=2;
}
if(K5==0) //两键按下,停止
{
zhuanxiang=0;
}
switch (zhuanxiang)
{case 0:
{ a=0 ;b=0;break;} //停止
case 1:
{ a=1 ;b=0;break;} //启动输出 正转
case 2:
{ a=0 ;b=1; break;} //启动输出 反转
default:break;
}
}
/*------------------测转速程序------------------*/
unsigned int pusle=0;//脉冲个数
unsigned char count=0;//个数
void int0() interrupt 0 //外部中断0中断处理程序,用于脉冲计数
{
pusle++;
}
/*-------------电机调速程序,增量式PID算法------------*/
int Now_speed[3]={0,0,0}; //用于存储当前转速、前一次转速、再前一次转速
int KP=100;
int KI=20;
int KD=15;
int last_out=0;
#define out_max 10000
#define out_min 0
unsigned int PWMH=0;//PWM波在10000us内高电平时间
/********电机PID控制**********/
void Motor_control(void)
{
int PID=0;
int P=0;
int I=0;
int D=0;
int out=0;
Now_speed[2] = Now_speed[1];
Now_speed[1] = Now_speed[0];
Now_speed[0] = speed_s-speed_m;
P = KP*(Now_speed[0]-Now_speed[1]);
I = KI* Now_speed[0];
D = KD*(Now_speed[0]-2*Now_speed[1]+Now_speed[2]);
PID = P+I+D;
out=last_out+PID;
if(out>=out_max) out=out_max; //大于10000,取值为10000
if(out<=out_min) out=out_min; //小于0,取值为0
PWMH=out;
last_out=out;
}
unsigned char jishi=0;//计时
void
timer0 (void) interrupt 1 //定时器0中断,用于定时产生PWM周期,一个控制周期定为10000us
{
count++;
if(count>=100)//这就大约1s
{
speed_m=pusle/2;//测速转速,单位r/M.转一圈产生2个脉冲
count=0;//计数变量清零
pusle=0;
}
jishi++;
if (jishi>=100)//1s计算一次PID
{/*设置并打开定时器1*/
Motor_control() ;
jishi=0;
}
TH1=((65536-PWMH) & 0xff00)>>8; // 高8位
TL1=(65536-PWMH) & 0x00ff; // 低8位
TR1=1; //运行开关 打开计时器1
TH0=(65536-10000)/256; //10000us
TL0=(65536-10000)%256;
}
void timer1 (void) interrupt 3//定时器1中断,用于定时产生PWM波的高电平时间
{
a=0 ;b=0; //PWM输出低电平
TR1=0;
}
/*----------------主程序----------------------*/
void main()
{
a=0;
b=0;
/*计时器0设置,用于设置PWM的周期*/
TMOD=0x11; //定时器1、2都工作于方式1
TH0=(65536-10000)/256; //10000us
TL0=(65536-10000)%256;
ET0=1; //定时器0的中断允许
TR0=1; //运行开关 开始计时
/*计时器1设置,用于设置PWM的高电平时间*/
TH1=0;
TL1=0;
ET1=1; //定时器1的中断允许
TR1=0; //停止计时
/*外部中断0设置*/
IT0=1; //外部中断0,0低电平触发,1边沿触发
EX0=1; //打开外部中断0
EA=1;//开全局中断
/*LCD显示*/
LCD_Init();//LCD初始化
LCD_Display(0,dispBuff0);
LCD_Display(1,dispBuff1);
Delay20ms();
while(1)
{key();//按键识别
Delay20ms() ;
dectobit(speed_m);
}
}
一周热门 更多>