最近学校举办了个小比赛,使用51单片机集成 蓝牙控制,舵机摇头超声波避障,红外目标跟随,测距显示。来简单分享下。完整代码会在文末贴出。
定时器初始化
一开始直接让我疑惑的是51单片机只有两个定时器,而蓝牙通信波特率需要一个,超声波也需要一个,剩下舵机和PWM调速也要定时器明显不够用,
好在实际上比赛小车的芯片为52RC,拥有3个定时器,我的分配方案如下:
T0舵机和PWM调速共用;
T1给超声波使用;
T2给蓝牙使用;
定时器的初始化:
void Init()
{
/*T1和T0的初始化*/
TMOD|=0x11;//定时器1工作方式1 (超声波),定时器0舵机
TH1=0x00;
TL1=0x00; //超声波
TH0=(65536-100)/256;
TL0=(65536-100)%256;
ET1=1;
ET0=1;
EA=1;
TR0=1;//定时器开始
IE=0x92;//中断允许控制寄存亲
/*T2的初始化*/
T2MOD=0x01;//定时器1工作方式1 (超声波),定时器0舵机
T2CON = 0x30;
TH2=0xFd;
TL2=0xfd; //蓝牙
RCAP2H =0XFF;
RCAP2L=0xDC;
SCON=0x50;
PCON=0x00;
PS=1;//将蓝牙串行设置为高优先级
TR2=1;
PT1=0;
EA=1;
ES=1;
}
蓝牙控制部分
蓝牙通信发送指定字符控制小车运行
#define up 'A'//前进
#define down 'B'//后退
#define le 'C'//左转
#define ri 'D'//右转
#define stop 'F'//停止
#define gx 'G'//跟随
#define csb 'S'//超声波
发送信号蓝牙串行口产生中断写入数组buff[]
ON引导字符,例如前进需要发送“ONA”
if(buff[0]=='O'&&buff[1]=='N') //第一个字节为O,第二个字节为N,第三个字节为控制码
switch(buff[2])
{
case up : // 前进
send_str( );
run();
ShowPort=LedShowData[1];
break;
case down: // 后退
send_str1( );
backrun();
ShowPort=LedShowData[2];
break;
case le: // 左转
send_str3( );
leftrun();
ShowPort=LedShowData[3];
break;
case ri: // 右转
send_str2( );
rightrun();
ShowPort=LedShowData[4];
break;
case stop: // 停止
send_str4( );
ShowPort=LedShowData[0];
stoprun();
break;
case gx: //跟随
send_str5( );
ShowPort=LedShowData[5];
GX();
break;
case csb: //超声波
send_str6( );
ShowPort=LedShowData[5];
CSB();
break;
}
跟随
使用小车前面的两个红外避障传感器来跟随(有点傻)
代码:
void GX(void)
{
while(1)
{
if(Left_1_led==1&&Right_1_led==1)//
stoprun(); //调用停止函数
else
{
if(Left_1_led==1&&Right_1_led==0)//右边检测到目标
{
rightrun(); //调用小车右转函数
delay(20);
}
if(Right_1_led==1&&Left_1_led==0) //左边检测到红外信号
{
leftrun(); //调用小车左转函数
delay(20);
}
if(Right_1_led==0&&Left_1_led==0)//两边传感器同时检测到目标
{
run(); //调用前进函数
delay(20);
}
}
if(buff[2]!=gx) return;//如果收到蓝牙不是gx则退出
}
return;
}
超声波
超声波和舵机是一起使用的
检测到前方有障碍后停车,舵机扭头判断左右的空间来转向
也顺便显示距离
void CSB()
{
Delay1ms(5);//延时片刻
angle=12;//舵机居中
count=0;
//Display_LCD();
TIM0init();//初始化定时器
while(1)
{
chaoshengbo();
Display_LCD();
Front_Distance = S;
DelayMs(20);
if(Front_Distance > 30)//如果大于一定距离
{run();}//前进
if(Front_Distance < 30)//如果小于一定距离
{
stoprun();//停车
angle=4;
count=0;
DelayMs(400);
chaoshengbo();
Display_LCD();
Right_Distance= S;
DelayMs(20);
angle=12;
count=0;
DelayMs(400);
angle=20;
count=0;
DelayMs(400);
chaoshengbo();
Display_LCD();
Left_Distance = S;
DelayMs(20);
angle=12;
count=0;
DelayMs(400);
if((Left_Distance < 30 ) &&( Right_Distance < 30 )) //左右两边距离都小于30
{
backrun();//后退
DelayMs(80);
leftrun;//左转
DelayMs(40);
}
else
{
if(Left_Distance < Right_Distance) //左边距离小于右边的距离
{
rightrun(); //调用小车右转 函数
DelayMs(100);
}
if(Left_Distance >= Right_Distance)
{
leftrun(); //调用小车左转 函数
DelayMs(100);
}
}
}
if(buff[2]!=csb) return;
}
return;
}
测距
测距放在了主函数里和蓝牙一起;实时显示障碍物距离
主函数:
/****************************/
void main(void)
{
TIM0init();//初始化定时器
Init();
ShowPort=LedShowData[0];
Delay1ms(400); //启动等待,等LCM讲入工作状态
LCMInit(); //LCM初始化
while(1) /*无限循环*/
{
CSBCJ();
if(flag_REC==1) //
{
flag_REC=0;
if(buff[0]=='O'&&buff[1]=='N') //第一个字节为O,第
switch(buff[2])
{
case up : // 前进
send_str( );
run();
ShowPort=LedShowData[1];
break;
case down: // 后退
send_str1( );
backrun();
ShowPort=LedShowData[2];
break;
case le: // 左转
send_str3( );
leftrun();
ShowPort=LedShowData[3];
break;
case ri: // 右转
send_str2( );
rightrun();
ShowPort=LedShowData[4];
break;
case stop: // 停止
send_str4( );
ShowPort=LedShowData[0];
stoprun();
break;
case gx: //循迹
send_str5( );
ShowPort=LedShowData[5];
GX();
break;
case csb: //循迹
send_str6( );
ShowPort=LedShowData[5];
CSB();
break;
}
}
}
}
完整代码和头文件
https://pan.baidu.com/s/1KwuljekV4HlLfgnRLmuShg
链接:https://pan.baidu.com/s/1KwuljekV4HlLfgnRLmuShg
提取码:e4if
复制这段内容后打开百度网盘手机App,操作更方便哦