本帖最后由 许明康2013 于 2015-5-1 20:33 编辑
4个按键实现小直流电机的加减速和正反转,L298N驱动,LCD1602显示设定速度和反馈速度的
仿真图和程序
完整的程序!!!
下面的图和程序,不知道哪里有问题,减速为0时,电机还在转,而且没有固定的波形??有哪位大神直到啊??
#include <reg52.h>
#include <intrins.h>
//IO口设置 a=IN1,b=IN2
sbit a=P2^4; //L298信号口,{ a=1 ;b=0;} //启动输出 正转
sbit b=P2^5; // { a=0 ;b=1;} //启动输出 反转
sbit K1 =P1^0 ; //减少键
sbit K2 =P1^1 ; //增加键
sbit K3 =P1^2 ; //正转键
sbit K4 =P1^3 ; //反转键
unsigned int speed_s=10; //设置的转速,单位r/s
unsigned int speed_m=0; //测量的转速
unsigned char zhuanxiang=1; //转向标志,0不转,1正转,2反转.默认正转 ....
#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);
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 Delay20ms() //粗略延时;
{
unsigned int tmp = 50000;
while(tmp--);
}
// .............................................................................
void key() //正转反转调节 zhuanxiang; 转向标志,0不转,1正转,2反转
{
if(!K1) //减速
{
speed_s--;
if (speed_s<0)
{ speed_s=0;
}
}
if(!K2) //加速
{ if (speed_s<20)
{ speed_s++;}
}
dispBuff0[4]=(speed_s*60/1000)%10+'0';
dispBuff0[5]=(speed_s*60/100)%10+'0';
dispBuff0[6]=(speed_s*60/10)%10+'0';
dispBuff0[7]=(speed_s*60)%10+'0';
LCD_Display(0,dispBuff0);
if(!K3 && K4) //正转
{
zhuanxiang=1;
}
if(!K4 && K3) //反转
{
zhuanxiang=2;
}
if(!K4 && !K3) //两键按下,停止
{
zhuanxiang=0;
}
}
/*------------------测转速程序------------------*/
unsigned int pusle=0;//脉冲个数
unsigned char count=0;//个数
void
timer2 (void) interrupt 5//定时器2中断 计时1s
{
if(TF2==1)
{
TF2=0; // 溢出标志必须软件清0
count++;
if(count>=20)//这就大约1s
{
speed_m=pusle/4;//测速转速,单位r/M.转一圈产生2个脉冲
dispBuff1[4]=(speed_m*60/1000)%10+'0';
dispBuff1[5]=(speed_m*60/100)%10+'0';
dispBuff1[6]=(speed_m*60/10)%10+'0';
dispBuff1[7]=(speed_m*60)%10+'0';
LCD_Display(1,dispBuff1);
count=0;//计数变量清零
pusle=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
{
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=0xb8; //10000us
TL0=0x00;
switch (zhuanxiang)
{case 0:
{ a=0 ;b=0;break;} //停止
case 1:
{ a=1 ;b=0;break;} //启动输出 正转
case 2:
{ a=0 ;b=1; break;} //启动输出 反转
case 3:
{
if(speed_s=0)
{
a=0;b=0;break;
}
}
default:break;
}
}
void timer1 (void) interrupt 3//定时器1中断,用于定时产生PWM波的高电平时间
{
a=0 ;b=0; //PWM输出低电平
TR1=0;
}
/*----------------主程序----------------------*/
void main()
{
/*计时器2设置,用于定时1s测速*/
TCLK=0; //可令T2CON=0;或TCLK=0,RCLK=0;
RCLK=0; //【T2CON中其他位可默认为0,而TCLK和RCLK必须手动置0】
//因RCAP2L和RCAP2H是由软件预设的
RCAP2H=0x3C;
RCAP2L=0xB0;
TL2=0x00;// TL2 = (65536-50000) % 256; //或TL2=0xb0
TH2=0x4C;// TH2 = (65536-50000) / 256; //或TH2=0x3c
ET2=1;
TR2=1;
/*计时器0设置,用于设置PWM的周期*/
TMOD=0x11; //定时器1、2都工作于方式1
TH0=0xb8; //10000us 高8位
TL0=0x00; //低8位
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_Init(); //LCD初始化
LCD_Display(0,dispBuff0);
LCD_Display(1,dispBuff1);
Delay20ms();
while(1)
{key();//按键识别
Delay20ms() ;
}
}
-
亲,要不你换个型号的单片机。我都回答恶心了!
一周热门 更多>