小车搭建的这个项目,取名为【SmartCar】,这次更新的主版本为V2,小版本为V2.0.1.20170929,算是在原来的基础上有了较大的提升了。
SmartCar V2.0.1.20170929全部功能:
-
前进方向自动避障
-
前下方自动避障。可以在桌子上跑,不至于会掉下桌子
-
小车加入蓝牙模块,蓝牙模块与最小系统使用串口通信
-
手机app控制手机蓝牙与小车蓝牙通信,能做到启、停、左、右
接下来,会对这个版本进行优化,使App能更方便的控制小车
记录下这个项目中经过的坑:
Android端
对于 Android 开发,话的时间比较长的是 Android 蓝牙开发,整个过程耗费了大概4天的业余时间,具体详情可以参考 Android 蓝牙开发
Android App 界面截图:
界面只是做了基本的控制和状态显示,项目见 github:https://github.com/xiongxianhe/SmartCar
小车端
小车端的坑主要是蓝牙模块的连接以及调试
蓝牙完全测试
在拿到蓝牙模块时,首先是确定它能不能正常的工作,所以先来简单测试,测试流程:
-
将蓝牙线接好
-
小车上电
-
打开 pc 端串口工具
-
在 pc 端串口工具里发送 AT 相关指令,看是否有结果返回
蓝牙接线
整个测试流程中,蓝牙接线是第一步,也是比较麻烦的一步,线没接好,那整个流程就走不下去了,来张我用的这款蓝牙图片:
共有6个引脚:
-
STATE:在命令模式下(串口 AT 指令模式)接 gnd,正常工作下可悬空
-
RX:串口读引脚,注意它的与单片机的接发,一旦接错,收发数据就异常了。我在这里被坑了好久,我的是接板子的 TX 引脚 P31
-
TX:串口发送数据引脚
-
GND:接地
-
+5V:接 VCC
-
EN:在命令模式下接高电平(VCC),正常工作下可悬空
当时在测试的时候,就是这几根线没接好,反反复复测试了好久,才测试好。
小车控制代码:
#include "STC12C5A60S2.h"include <intrins.h>
/** L293D 电机驱动 真值表
控制MOTO1 EN1 IN1 --> OUT1 EN1 IN2 --> OUT2 控制MOTO2 EN2 IN3 --> OUT3 EN2 IN4 --> OUT4 一个电机有两个接线端 一根正电源线 一根负电源线 控制这两根线的高低电平,使电平高低反转,使电机旋转
**/
/****/
/ 电机1 右电机 /
sbit en1 = P1 ^ 3;
sbit in1 = P1 ^ 5;
sbit in2 = P1 ^ 6;
/ 电机2 左电机 /
sbit en2 = P1 ^ 4;
sbit in3 = P1 ^ 1;
sbit in4 = P1 ^ 0;/ 红外传感器 /
sbit rp1 = P2 ^ 3; // 右前
sbit rp2 = P2 ^ 4; // 左前
sbit rp3 = P2 ^ 0; // 右下
sbit rp4 = P2 ^ 1; // 左下sbit k1 = P3 ^ 0;
sbit k2 = P3 ^ 1;
sbit k3 = P3 ^ 2;sbit led1 = P0 ^ 0;
sbit led2 = P0 ^ 1;
sbit led3 = P0 ^ 2;
sbit led7 = P0 ^ 6;
sbit led8 = P0 ^ 7;unsigned char TEST = 0;
unsigned char start = 0;unsigned char isInter = 0;
unsigned char recvData = 0;
unsigned char CAR_START = 0x01;
unsigned char CAR_STOP = 0x02;
unsigned char CAR_RIGHT = 0x03;
unsigned char CAR_LEFT = 0x04;
unsigned char CAR_FORWARD = 0x05;
unsigned char CAR_BACK = 0x06;void delay500ms(void) //误差 -0.000000000028us
{
unsigned char a,b,c;
for(c=189;c>0;c--)
for(b=230;b>0;b--)
for(a=33;a>0;a--);
}
void delay100ms(void) //误差 -0.000000000006us
{
unsigned char a,b,c;
for(c=244;c>0;c--)
for(b=8;b>0;b--)
for(a=152;a>0;a--);
nop(); //if Keil,require use intrins.h
nop(); //if Keil,require use intrins.h
}void delay10ms(void) //误差 -0.000000000001us
{
unsigned char a,b,c;
for(c=199;c>0;c--)
for(b=120;b>0;b--)
for(a=1;a>0;a--);
}// 停止
void Stop()
{
en1 = 0;
en2 = 0;
}// 向前
void Forward()
{
en1 = 1;
en2 = 1;
in1 = 1;
in2 = 0;
in3 = 1;
in4 = 0;
}
// 向后
void Back()
{
en1 = 1;
en2 = 1;
in1 = 0;
in2 = 1;
in3 = 0;
in4 = 1;
}
// 向左
void Left()
{
en1 = 1;
en2 = 1;
in1 = 1;
in2 = 0;
in3 = 0;
in4 = 1;
}
// 向右
void Right()
{
en1 = 1;
en2 = 1;
in1 = 0;
in2 = 1;
in3 = 1;
in4 = 0;
}void keyPros()
{
if(k1==0) {
delay10ms();
if(k1 == 0) {
led1 = ~led1;
TEST = 1;
//test1();
start = 1;
Forward();} while(!k1); } if(k2==0) { delay10ms(); if(k2 == 0) { led2 = ~led2; TEST = 2; start = 0; Stop(); } while(!k2); }
}
unsigned char monitor = 0;
void Scan()
{
if((rp1 == 1 && rp2 == 1) || (rp3 == 0 && rp4 == 0)) { // 前方有障碍物 或者 底部有坑
Back();
delay100ms();
delay100ms();
monitor = 1;
return;
}
if(rp1 == 1) { // 前右边有障碍物
Left();
delay100ms();
delay100ms();
delay100ms();
monitor = 1;
return;
}
if(rp2 == 1) { // 前左边有障碍物
Right();
delay100ms();
delay100ms();
delay100ms();
monitor = 1;
return;
}
if(rp3 == 0) { // 低右边有坑
Back();
delay100ms();
Left();
delay100ms();
delay100ms();
delay100ms();
monitor = 1;
return;
}
if(rp4 == 0) { // 低左边有坑
Back();
delay100ms();
Right();
delay100ms();
delay100ms();
delay100ms();
monitor = 1;
return;
}
monitor = 0;
}void TurnLeft()
{
Left();
delay100ms();
delay100ms();
}void TurnRight()
{
Right();
delay100ms();
delay100ms();
}void init()
{
TMOD = 0x20; // 定时器1 工作方式2 8位自动重装
TH1 = 0xf3;
TL1 = 0xf3;
PCON = 0x80; // 波特率加倍 f3 4800
TR1 = 1; // 定时器1启动 开始工作
REN = 1; // 允许串口接受数据 读数据
SM0 = 0; // 串口工作方式 10位数据异步 1位起始位 8位数据位 1位停止位
SM1 = 1;
EA = 1; // 开启总中断
ES = 1; // 串口中断允许 打开串口中断
}void main()
{
init();
isInter = 0;
while(1) {
if(isInter==1) {
ES = 0;
if(recvData == CAR_START) {} if(recvData == CAR_LEFT) { led7 = ~led7; TurnLeft(); Forward(); start = 1; SBUF = CAR_LEFT; while(!TI); TI = 0; } else if(recvData == CAR_RIGHT) { led8 = ~led8; TurnRight(); Forward(); start = 1; SBUF = CAR_RIGHT; while(!TI); TI = 0; } SBUF = 0x88; while(!TI); TI = 0; ES = 1; isInter = 0; if(recvData == CAR_STOP) { Stop(); start = 0; } } keyPros(); if(start == 0) continue; Scan(); if(monitor == 0) { Forward(); } }
}
void ser() interrupt 4
{
RI = 0;
isInter = 1;
recvData = SBUF;
}