求大神教小弟怎么实现小车PMW调速,程序怎么写?
买块STC12系列的单片机,然后官网下份手册研究下,很简单的,配置下就好了~
小车的驱动一般分为左右轮。而每个驱动包含开关,设为E1。E2。前进A1和A2,后退B1和B2,(1为左轮,2为右轮)En就是控制是使能。可理解为开关,当En为0时,轮子不动,届时我们只要控制好En的开关时间,比如频率,这样就可以达到控制车速的效果,可与定时器的软件结合调节占空比,这就是最简单的车速控制,我之前有做成功,希望对你有帮助。
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit IRIN=P3^3; // 红外线接口
sbit PWM1 = P1^0;//直流电机1的使能端
sbit PWM2=P1^1;//直流电机2的使能端
sbit s1=P1^2;//控制端
sbit s2=P1^3;
sbit s3=P1^4;
sbit s4=P1^5;
sbit E=P2^7; //1602使能引脚
sbit RW=P2^6; //1602读写引脚
sbit RS=P2^5; //1602数据/命令选择引脚
uchar CYCLE; //定义周期
uchar distemp; //红外线控制数字
uchar IRCOM[7]; //红外线解码数组
uchar PWM_ON ; //定义低电平时间
void delay0(unsigned char x) //x*0.14MS 供IR_IN子函数
{
unsigned char i;
while(x--)
{
for (i = 0; i<13; i++) {}
}
}
void delay() // 大概为5US 供BUSY子函数
{
_nop_();
_nop_();
}
void Delay(uint del) //供1602初使化函数
{
uint i,j;
for(i=0;i<del;i++)
for(j=0;j<=148;j++)
{
}
}
void Busy() //液晶1602忙状态
{
bit busy_flag = 1;
P0 = 0xff;
RS = 0;
delay();
RW = 1;
delay();
E = 1;
while(1)
{
busy_flag = (bit)(P0 & 0x80);
if(busy_flag == 0)
{
break;
}
}
E = 0;
}
void wcmd(uchar del) //写指令
{
RS = 0;
delay();
RW = 0;
delay();
E = 0;
delay();
P0 = del;
delay();
E = 1;
delay();
E = 0;
}
void wdata(uchar del) //写数据
{
delay();
RS = 1;
delay();
RW = 0;
delay();
E = 0;
delay();
P0 = del;
delay();
E = 1;
delay();
E = 0;
}
void L1602_init(void) //1602初使化
{
Delay(15);
wcmd(0x38);
Delay(5);
wcmd(0x38);
Delay(5);
wcmd(0x38);
wcmd(0x38);
Busy();
wcmd(0x08);
Busy();
wcmd(0x01);
Busy();
wcmd(0x06);
Busy();
wcmd(0x0c);
}
void L1602_string(uchar hang,uchar lie,uchar *p) //读数据
{
uchar a;
if(hang == 1)
{
a = 0x80;
}
if(hang == 2)
{
a = 0xc0;
}
a = a + lie - 1;
while(1)
{
Busy();
wcmd(a);
Busy();
wdata(*p);
a++;
p++;
if((*p == '\0')||(a==0x90)||(a==0xd0))
{
break;
}
}
}
void Time0(void) //定时器初初化
{
TMOD = 0x01; //定时器设置 1ms in 11.0592M crystal
TH0 = 0xFC;
TL0 = 0x66; //定时1mS
ET0 = 1;
EA = 1;
TR0 = 1; //定时器打开
}
void out1() //外部中断初始化
{
EA=1;
PX1=1; //外部中断优先
EX1=1; //开外部中断
ET1=1; //启动外部中断
IT1=1; //电平触发方式
}
/********************************/
/* 定时中断 */
/********************************/
void tim(void) interrupt 1 using 1
{
static unsigned char count = 0;
TH0 = 0xFC;
TL0 = 0x66; //定时1mS
if(count == PWM_ON)
{
PWM1 = 1; //直流电机转
PWM2=1;
}
count++;
if(count == CYCLE)
{
count = 0;
PWM1 = 0; //直流电机不转
PWM2=0;
}
}
main()
{
uchar PWM_Num; //定义档位
Time0();
out1();
IRIN=1;
CYCLE = 20; //时间可以调整 这个是100步调整 周期100ms 8位PWM就是256步
PWM1 = 0;
PWM2=0;
L1602_init(); //初始化LCD
while(1)
{
if(distemp==5)
{
PWM_Num++; //红外按键按一次,就给直流电机换一个档位
if(PWM_Num==4)
{
PWM_Num=0;
}
switch(PWM_Num)
{
case 0:
P0=0x06;
PWM_ON=0;
break;
case 1:
P0=0x5B;
PWM_ON=1;
break;
case 2:
P0=0x4F;
PWM_ON=2;
break;
case 3:
P0=0x66;
PWM_ON=3;
break;
default:
break;
}
}
}
}
void IR_IN() interrupt 2 using 0 //外部中断服务程序
{
unsigned char j,k,N=0;
EX1 = 0;
delay0(15);
if (IRIN==1)
{ EX1 =1;
return;
}
//确认IR信号出现
while (!IRIN) //等IR变为高电平,跳过9ms的前导低电平信号。
{delay0(1);}
for (j=0;j<4;j++) //收集四组数据
{
for (k=0;k<8;k++) //每组数据有8位
{
while (IRIN) //等 IR 变为低电平,跳过4.5ms的前导高电平信号。
{delay0(1);}
while (!IRIN) //等 IR 变为高电平
{delay0(1);}
while (IRIN) //计算IR高电平时长
{
delay0(1);
N++;
if (N>=30)
{ EX1=1;
return;} //0.14ms计数过长自动离开。
} //高电平计数完毕
IRCOM[j]=IRCOM[j] >> 1; //数据最高位补“0”
if (N>=8) {IRCOM[j] = IRCOM[j] | 0x80;} //数据最高位补“1”
N=0;
} //end for k
} //end for j
if (IRCOM[2]!=~IRCOM[3])
{ EX1=1;
return; }
switch(IRCOM[2])
{
case 0x18:
distemp = 2;
L1602_string(1, 1,"State : Forward " );
s1=1;
s2=0;
s3=1;
s4=0;
break;
case 0x08:
distemp = 4;
L1602_string(1, 1,"State : Left " );
s1=1;
s2=1;
s3=1;
s4=0;
break;
case 0x1c:
distemp = 5;
L1602_string(2, 1,"Speed changing~ " );
break;
case 0x5a:
distemp = 6;
L1602_string(1, 1,"State : Right " );
s1=1;
s2=0;
s3=1;
s4=1;
break;
case 0x52:
distemp = 8;
L1602_string(1, 1,"State : Back ");
s1=0;
s2=1;
s3=0;
s4=1;
break;
case 0x4a:
distemp = 9;
L1602_string(1, 1,"State :Zizhuan ");
s1=1;
s2=0;
s3=0;
s4=1;
break;
}
EX1 = 1;
}
我什么都不会想制作简单一点的蓝牙小车可以不?
http://bbs.elecfans.com/jishu_334768_1_1.html
不错
程序很详细,对我有用