硬件驱动
- 初始化
拿到蓝牙模块先将其串口与电脑连接,波特率一般默认为9600,由于我用的是12M的晶阵,产生9600的波特率精度不行所以用4800的波特率。通过电脑串口调式助手发送AT指令修改蓝牙模块的波特率为4800,这些指令在资料里应该都有。(指令之后还有个回车)
AT+BAUD3
- 然后接贴下面代码烧到单片机上去观察相应输出IO的电平看是否正确完事,再按照备注上的说明搭建小车就完美执行(电机驱动用的L289N)
#include "reg52.h"
#include<intrins.h>
//控制四轮的小车IO
#define control P0
typedef unsigned int u16;
typedef unsigned char u8;
//车灯控制,为0时亮
sbit LED = P2^4;
//电机驱动使能控制IO
//前面(俯视)
//motor1 motor2
//motor3 motor4
//control 11 11 11 11
// m1 m2 m3 m4
//所有的都是01向前,10向后
sbit motor1=P2^0;
sbit motor2=P2^1;
sbit motor3=P2^2;
sbit motor4=P2^3;
//保存串口接收到的数据
u8 recv[50];
u8 count=0,length=0;
//速度调节
u16 time=0;
u16 speed=50;
//小车状态
u8 state=4;
//延迟10us
void delay(u16 i)
{
while(i--);
}
//初始化
void init()
{
//发送AT指令初始化蓝牙模块和客户端对应,客户端的UUID就是这个,还有蓝牙的名称为hardy
char *a="at+namehardy\r\n";
char *b="at+UUID0xFFE0\r\n";
char *c="at+char0xFFE1\r\n";
TMOD = 0x21; //T1工作方式2,T0工作方式2
//设置波特率为4800
SCON = 0x50;
PCON = 0X80; //波特率加倍
TL1 = 0XF3;
TH1 = 0XF3;
TR1 = 1; //打开定时器
//T0定时器初始化 100us
TH0 = 0x0FF;
TL0 = 0x0A4;
ET0 = 1;
TR0 = 1;
IT0=1; //设置外部中断0的触发方式为下降沿
EX0=1; //开启外部中断0
EA = 1; //允许总中断
ES = 0;
delay(50000); //适当延迟给模块反应时间
while(*a!='\0')
{
SBUF=*a;
while(!TI);
TI=0;
a++;
}
delay(50000);
while(*b!='\0')
{
SBUF=*b;
while(!TI);
TI=0;
b++;
}
delay(50000);
while(*c!='\0')
{
SBUF=*c;
while(!TI);
TI=0;
c++;
}
ES = 1;
}
//输出PWM控制车速
void PWM(){
if(time>100) //PWM周期为100*100us
{
time=0;
}
if(time <speed)
{
motor1=1;
motor2=1;
motor3=1;
motor4=1;
}
else
{
motor1=0;
motor2=0;
motor3=0;
motor4=0;
}
}
//通过串口发送字符串,发送到手机客户端用于提示
void send(char *str)
{
ES=0; //发送时先将串口接收中断关掉发送完成再打开
while(*str!='\0')
{
SBUF=*str;
while(!TI);
TI=0;
str++;
}
ES=1;
}
//获取速度用以传入客户端显示
char* getspeed(){
if(speed<20){
return (char*)"speed:1";
}
if(speed>=20&&speed<40){
return (char*)"speed:2";
}
if(speed>=40&&speed<60){
return (char*)"speed:3";
}
if(speed>=60&&speed<80){
return (char*)"speed:4";
}
if(speed>=80){
return (char*)"speed:5";
}
return "error";
}
//获取小车状态用以传入客户端显示
char* getstate(){
if(state==0){
return (char*)"go";
}
if(state==1){
return (char*)"back";
}
if(state==2){
return (char*)"trun left";
}
if(state==3){
return (char*)"trun right";
}
if(state==4){
return (char*)"stop";
}
if(state==5){
return (char*)"speed:5";
}
if(state==6){
return (char*)"speed:5";
}
return "error";
}
//前进
void forword(){
motor1=1;
motor2=1;
motor3=1;
motor4=1;
//对应01010101
control=0x55;
state = 0;
send(getstate());
}
//后退
void back(){
motor1=1;
motor2=1;
motor3=1;
motor4=1;
//对应10101010
control=0xAA;
state = 1;
send(getstate());
}
//左转
void trunLeft(){
//只有电机2前进,其他停止
motor1=0;
motor2=1;
motor3=0;
motor4=1;
//对应xx01xxxx
control=0x55;
state = 2;
send(getstate());
}
//右转
void trunRight(){
//只有电机1前进,其他停止
motor1=1;
motor2=0;
motor3=3;
motor4=0;
//对应01xxxxxx
control=0x55;
state = 3;
send(getstate());
}
//停止
void stop(){
//全部电机使能停止
motor1=0;
motor2=0;
motor3=0;
motor4=0;
state = 4;
LED=1;
send(getstate());
}
//开灯
void trunOnLight(){
char *error = "light on";
send(error);
LED = 0;
_nop_();
_nop_();
_nop_();
LED = 1;
}
//加速
void acce(){
if(speed<100){
speed = speed+10;
}
send(getspeed());
}
//减速
void slow(){
if(speed>0){
speed = speed-10;
}
send(getspeed());
}
//其他
void other(){
char *error = "error";
send(error);
}
void main()
{
init();
//初始化全部电机使能停止
motor1=0;
motor2=0;
motor3=0;
motor4=0;
control=0xff;
LED = 1;
P1=0xFF;
while(1)
{
//客户端发出指令
if(length != 0){
switch(recv[0]){
//前进指令
case 'f': forword();break;
//后退指令
case 'b': back();break;
//左转指令
case 'l': trunLeft();break;
//右转指令
case 'r': trunRight();break;
//停止指令
case 's': stop();break;
//开灯指令
case 'o':trunOnLight();break;
//加速指令
case 'c':acce();break;
//减速指令
case 'w':slow();break;
//未知指令
default:other(); break;
}
length=0;
}
//如果前进或者后退则speed速度有效,转弯全速
if(state==0||state==1){
PWM();
}
}
}
//外部中断0触发时,读取P0中的控制数据
//这个用于另外单片机互动的,由于这个单片机只有两个定时器用完了,超声波模块需要用没有了
void ex0() interrupt 0
{
//外部信号拉低,对电机进行控制
if(P1 != 0xFF){
if(P1 == 0xFE){
forword();
}
if(P1 == 0xFD){
back();
}
if(P1 == 0xFB){
trunLeft();
}
if(P1 == 0xF7){
trunRight();
}
if(P1 == 0xEF){
stop();
}
P1 = 0xFF;
}
}
//计数做PWM的产生
void Time0(void) interrupt 1
{
TH0 = 0x0FF;
TL0 = 0x0A4;
time++;
}
//串口接收中断接收蓝牙模块发来的数据
void rev() interrupt 4
{
//接收数据并且手动清空标志位
char res;
res=SBUF;
RI = 0;
//将字符串在符号$和符号#之间的保存到数组中 ,并记录长度,用$#两个符号包围数据防止干扰这里接收到的是数据的ASCII,比如客户端发送$过来接收到的ASCII码是35
if(res == 35){
length=count;
count = 0;
}
else{
if(res == 36){
length=0;
count = 0;
}
else{
recv[count]=res;
count++;
}
}
}
手机客户端——微信小程序
- 客户端需要很麻烦的蓝牙连接过程,已经全部写好了直接调用接收和发送函数就可以了。代码上千行就不帖了,Gitee地址https://gitee.com/eedui/xiaoche