目录
关于之前做的一个51循迹避障小车,当时找了相关代码并加以修改,自己仿制了一个出来,现在在下面介绍一下相关功能与代码。
可以分为几个大的部分,有蓝牙控制模块,四路红外循迹模块,超声波避障模块。利用pwm对调节占空比进行调速。
蓝牙控制模块
使用市面上常见的HC-05,蓝牙模块接在单片机上并与手机蓝牙通讯,能够互发数据并接收,进而控制小车。
蓝牙模块是串口异步通信,配置好9600的波特率,蓝牙的TXD连接51单片机的RXD,蓝牙的RXD连接51单片机的TXD,
void UartInit(void) //4800bps@11.0592MHz
{
PCON |= 0x80; //使能波特率倍速位SMOD
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xF4; //设定定时初值
TH1 = 0xF4; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
}
void ctrl() //蓝牙控制函数
{
switch(tmp)
{
case '0':
stop();break;
case '1':
if(Distance()>=40)
fwd();
else
stop();break;
case '2':
back();break;
case '3':
tl_1();break;
case '4':
tr_1();break;
case '5':
bizhang();break;
case '6':
move();break;
case '7':
move2();break;
case '8':
move1();break;
}
超声波避障模块
超声波模块采用的HC–SR04超声波模块,该模块可提供 2cm-400cm 的非接触式距离感测功能,测距精度可达高到 3mm,测量角度小于15度。模块包括超声波发射器、接收器与控制电路。基本工作原理:采用 IO 口 TRIG 触发测距,给至少20us 的高电平信号;模块自动发送 8个40khz 的方波,自动检测是否有信号返回;有信号返回,通过 IO 口 ECHO 输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2。其中VCC 供5V 电源,GND 为地线,TRIG 触发控制信号输入,ECHO 回响信号输出等四支线。
使用可自动重载的定时器2,是一个16位定时器/计数器,通过设置特殊功能寄存器T2CON中的C/T2位,可将其作为定时器或计数器。定时器2有3种模式:捕获、自动重新装载(递增或递减计数)和波特率发生器,这3种模式由T2CON进行设置。T2CON寄存器的字节地址为C8H,单片机复位时T2CON全部被清0。
在本程序中
void ChaoSheng()实现超声波模块初始化,unsigned long Distance()函数实现测距并返回数值
//超声波模块
void ChaoSheng()
{
Trig=1;
Delay10us();
_nop_();
Trig=0;
}
unsigned long Distance()
{
T2CON = 0; //初始化控制寄存器使用定时器2
TL2 = 0; //设置定时初始值
TH2 = 0; //设置定时初始值
RCAP2L = 0; //设置定时重载值
RCAP2H = 0; //设置定时重载值
ChaoSheng();
while(!Echo);
TR2 = 1;
while(Echo);
TR2 = 0;
/*计算*/
time = (TH2*256+TL2)*1.085;//单位为us
TH2 = 0;
TL2 = 0;
juli = (time*1.7)/100; //单位为cm
return juli;
}
————————————————
版权声明:本文为优快云博主「看这个大魔王」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/qq_29705767/article/details/121470168
四路红外循迹
模块正确感连接并通电后,小板传感器开始工作。模块应到传感器反射回来的红外光时,红指示灯亮,输出低电平;没有红外光时,指示灯不亮,输出高电平。以检测黑线为例,如果传感器检测到黑线,红外光无法反射回来则模块红指示灯熄灭,同时小板对应的OUT口输出高电平;如果未检测到黑线,红外光可以反射回来则模块红指示灯亮,小板对应的OUT口输出低电平。其中需要注意一种特殊情况,也就是说当测量物体超出测量范围时,此时红指示灯熄灭,OUT口输出高电平。
每个小板前面对应的电位器可以用来调整使用精度。
代码的实现就是判断io口的高低电平,从而判断是否沿着黑线行驶。中间的两个红外控制走直线,最左边和最右边的实现走弯道的控制。
void move()
{
if(R2==1&&R3==1)
{
go();
}
if(R2==1&&R3==0)
{
x = 'R' ;
tr_0();
Delay10us();
}
if(R2==0&&R3==1)
{
x = 'L';
tl_0();
Delay10us();
}
if(R2==0&&R3==0)
{
while(R2==0&&R3==0)
{
if(x == 'L')
{
tl_1();
Delay10us();
}
else if(x == 'R')
{
tr_1();
Delay10us();
}
}
}
if(R1==1&&R4==0&&(R2==1||R3==1))
{
y = 'L';
tl_2();
Delay10us();
}
if(R1==0&&R4==1&&(R2==1||R3==1))
{
y = 'R';
tr_2();
Delay10us();
}
if(R1==0&&y=='L')
{
while(R1==0&&y=='L')
{
tl_2();
Delay10us();
}
y = 'N';
}
if(R4==0&&y=='R')
while(R4==0&&y=='R')
{
tr_2();
Delay10us();
}
y = 'N';
}
PWM调速
PWM(Pulse Width Modulation)脉冲宽度调制。
pwm占空比就是一个脉冲周期内有效电平在整个周期所占的比例。
通过调节PWM的占空比就能调节IO口上电压的持续性变化,因此也能够控制外设的功率进行持续性变化,也就能控制直流电机的转速快慢。
PWM调速是通过调节占空比来调节速度,也就是说在高电平的时候转动,低电平时候停止转动,由于间隙很小,所以给我们的感觉就是一直在转动,只不过速度减慢。本来供给L298N的电压为12V,但是调节占空比就可以模拟出0~12V之间任意一个电压。
在代码中利用定时器中断调节占空比。
//小车运动函数
void stop()
{
rank0 = 0;
rank1 = 0;
rank2 = 0;
rank3 = 0;
}
void fwd()
{
rank0 = 40;
rank1 = 40;
rank2 = 40;
rank3 = 40;
flag0 = 1;
flag1 = 1;
flag2 = 1;
flag3 = 1;
}
void back()
{
RGB(G);
rank0 = 30;
rank1 = 30;
rank2 = 30;
rank3 = 30;
flag0 = 0;
flag1 = 0;
flag2 = 0;
flag3 = 0;
}
void tl_0()
{
rank0 = 20;
rank3 = 20;
rank2 = 70;
rank1 = 70;
flag0 = 1;
flag1 = 1;
flag2 = 1;
flag3 = 1;
}
void tr_0()
{
rank0 = 70;
rank3 = 70;
rank2 = 20;
rank1 = 20;
flag0 = 1;
flag1 = 1;
flag2 = 1;
flag3 = 1;
}
void tl_1()
{
rank0 = 30;
rank3 = 30;
rank2 = 80;
rank1 = 80;
flag0 = 0;
flag1 = 1;
flag2 = 1;
flag3 = 0;
}
void tr_1()
{
rank0 = 80;
rank3 = 80;
rank2 = 30;
rank1 = 30;
flag0 = 1;
flag1 = 0;
flag2 = 0;
flag3 = 1;
}
void Timer() interrupt 1
{
TH0=0XFE;
TL0=0X33; //重新赋计数初值为0.5ms
//控制车轮转速
count++;
if(count >= 100)
{
count = 0;
}
if(count < rank0)
{
if(flag0 == 1)
{
IN1 = 1;
IN2 = 0;
}
else
{
IN1 = 0;
IN2 = 1;
}
}
else
{
IN1 = 0;
IN2 = 0;
}
if(count < rank1)
{
if(flag1 == 1)
{
IN3 = 1;
IN4 = 0;
}
else
{
IN3 = 0;
IN4 = 1;
}
}
else
{
IN3 = 0;
IN4 = 0;
if(count < rank2)
{
if(flag2 == 1)
{
IN5 = 1;
IN6 = 0;
}
else
{
IN5 = 0;
IN6 = 1;
}
}
else
{
IN5 = 0;
IN6 = 0;
}
if(count < rank3)
{
if(flag3 == 1)
{
IN7 = 1;
IN8 = 0;
}
else
{
IN7 = 0;
IN8 = 1;
}
}
else
{
IN7 = 0;
IN8 = 0;
}
}