51单片机物联网智能小车系列文章目录
文章目录
前言
daodanjishui物联网核心原创技术之最简单DIY的51蓝牙遥控小车设计方案。
市面上有各种开源智能小车,但是有复杂的有简单的,如果想快速入门DIY物联网智能小车,这个方案会给你一个快捷高效的方案。
一、最简单DIY的51蓝牙遥控小车设计方案是什么?
几年前用51单片机写了一个最简单的蓝牙遥控智能小车,基本上榨干了51单片机的资源,用了定时器T1作为波特率发送器编写串口打印程序,接收串口蓝牙接收的信息产生中断,并且写了一个串口打印函数send()作为单片机操作响应返回给蓝牙发送端手机。定时器T0作为PWM发生使用,目的是作为舵机sg90控制信号,当时做一个蓝牙自拍杆用到,虽然小车没搭建舵机,但是可以方便扩展,也方便买家学习舵机PWM控制技术。
虽然市面上也有不少开源的智能小车制作方案,还有自己小时候也玩过不少无线遥控的航模,但是全部由自己软件硬件全部独立设计的方案到几年前才正式实现,现在用文字的形式记录下来,对自己童年时代深刻地回忆和对未来技术的展望。“闭门造车”虽然有点痛苦,但是当你看到自己亲手做的小车在地上通过自制的遥控器遥控动起来的时候,你会发现一切的付出都是值得的!小车的全家福如下图所示:
51单片机最小系统板如下:
二、制作步骤
1.购买现成的小车配件
全部零部件都是购买的配件:L298N电机驱动模块,电池夹和18650电池两个,电源变压器、51单片机最小系统板、HC05串口蓝牙模块、小车底座。按照上面的实物图结合模块组装成小车。
2.下载代码
这个51单片机的代码也是相当精简,虽然是自己写的,但是也是经过严格的推敲和验证。
#include <reg52.h>
#include <stdio.h>
#include "String.h"
//author:daodanjishui 2020.10.1
/*****************************************/
//下面是舵机程序的移植
unsigned char count; //0.5ms次数标识
sbit pwm =P2^7 ; //PWM信号输出
sbit jia =P3^7; //角度增加按键检测IO口
sbit jan =P3^6; //角度减少按键检测IO口
unsigned char jd; //角度标识
//下面是L298N的端口定义
sbit IN1 =P1^0;
sbit IN2 =P1^1;
sbit IN3 =P1^2;
sbit IN4 =P1^3;
char AA[20];//存储串口发送过来的字符串
char OK[]={"OK"};
char SSS[]={"SSS"};
unsigned char flag,a='B',i=0,j;
void delayms(unsigned int w){
unsigned m,n;
for(m=w;m>0;m--)
for(n=110;n>0;n--);
}
void stop(void){//小车停止
IN1 =0;
IN2 =0;
IN3 =0;
IN4 =0;
}
void front(void){//小车前进
IN1 =0;
IN2 =1;
IN3 =1;
IN4 =0;
delayms(1000);
stop();
}
void left(void){//小车左转
IN1 =1;
IN2 =0;
IN3 =0;
IN4 =0;
delayms(180);
stop();
}
void right(void){//小车右转
IN1 =0;
IN2 =0;
IN3 =0;
IN4 =1;
delayms(180);
stop();
}
void back(void){//小车后退
IN1 =1;
IN2 =0;
IN3 =0;
IN4 =1;
delayms(1000);
stop();
}
void send(unsigned char *s){
if(flag==1){
ES=0;//关闭串口中断
for(s;*s!='\0';s++){
SBUF=*s;
while(TI==0); //等待发送完成
TI=0; //清除发送中断标志位
}
SBUF=a;//返回接收到电脑的数据
while(TI==0); //等待发送完成
TI=0; //清除发送中断标志位
ES=1;
flag=0;//清除串口接收标志位
}
}
void Time0_Init() //定时器初始化
{
//TMOD = 0x01; //定时器0工作在方式1
//IE = 0x82;
//下面两行替代上面两行,防止影响到定时器1串口的设置
EA=1;//全局中断允许
ET0=1;//计数器0中断允许
TH0 = 0xfe;
TL0 = 0x33; //11.0592MZ晶振,0.5ms
TR0=1; //定时器开始
}
void Time0_Int() interrupt 1 //中断程序
{
TH0 = 0xfe; //重新赋值
TL0 = 0x33;
if(count< jd) //判断0.5ms次数是否小于角度标识
pwm=1; //确实小于,PWM输出高电平
else
pwm=0; //大于则输出低电平
count=(count+1); //0.5ms次数加1
count=count%40; //次数始终保持为40 即保持周期为20ms,舵机控制需要20ms的脉冲
}
void keyscan() //按键扫描
{
if(jia==0) //角度增加按键是否按下
{
delayms(20); //按下延时,消抖
if(jia==0) //确实按下
{
jd++; //角度标识加1
count=0; //按键按下 则20ms周期从新开始
if(jd==6)
jd=5; //已经是180度,则保持
while(jia==0); //等待按键放开
}
}
if(jan==0) //角度减小按键是否按下
{
delayms(20);
if(jan==0)
{
jd--; //角度标识减1
count=0;
if(jd==0)
jd=1; //已经是0度,则保持
while(jan==0);
}
}
}
/****************************************/
void receive() interrupt 4 //串口中断服务程序
{
if(RI==1){
RI=0; //重新清0等待接收
a=SBUF;//接收电脑传输过来的数据
//SBUF=a;//单片机把接收到的数据返回给电脑
//这里可以放置舵机中断服务程序需要处理的逻辑
/*
if(a=='R') //右转
{
jd++; //角度标识加1
count=0; //按键按下 则20ms周期从新开始
if(jd==6)
jd=5; //已经是180度,则保持
}else if(a=='L'){
jd--; //角度标识减1
count=0;
if(jd==0)
jd=1; //已经是0度,则保持
}
*/
//下面加入智能小车指令解析
AA[i++]=a;
if((AA[i-1]=='\n')&&(AA[i-2]=='\r')){//判断是否遇到了"\r\n"
AA[i-2]='\0'; //用"\0"替代了"\r"的字符变量
if((strstr(AA,"FFF")!=0)){//使用了字符串查找函数,这是第二种方法
send(AA);
front();//前进
}else if((strstr(AA,"BBB")!=0)){//使用了字符串查找函数,这是第二种方法
send(AA);
back();//后退
}else if((strstr(AA,"LLL")!=0)){//使用了字符串查找函数,这是第二种方法
send(AA);
left();//左转?
}else if((strstr(AA,"RRR")!=0)){//使用了字符串查找函数,这是第二种方法
send(AA);
right();//右转
}else {
send(AA);
stop();//停止
}
i=0;
for(j=0;j<20;j++){
AA[j]='\0';
}
//逻辑结束
flag=1;//接收标志位置1
TI=0; //清除发送中断标志位
}
}
}
void init(){
SCON=0x50;//串口控制寄存器,等价于SM0=0,SM1=1,SM2=0,串口方式一通信
//TMOD=0X20; //设置定时器1为模式2,做为波特率发生器,8位初值自动重装的8位定时器,定时到TH1的值自动装到TL1
TMOD=0X21; //这里同时设置定时器0工作在方式1
//PCON |=0X80; //电源管理寄存器,是否波特率倍增,SMOD=1,串口方式为123的时候波特率加倍
//TL1=0xFF; //57600波特率的初值,板子使用11.0592M晶振,初值=256-12000000/32/12/2400
//TH1=0xFF; //
TH1=0xfd;//设置波特率为9600
TL1=0xfd;
//TI = 1;//向CPU发送串口中断申请,直接使用printf必须加入此句才能实现发送
IE=0x90; //CPU允许中断,串行允许中断?
REN=1;//允许串口接收中断?
EA=1;//开全局中断
ES=1;//串口中断允许
TR1=1; //启动波特率发生器
}
void main(void)
{
//unsigned char ldat;
int num=88;
int a=99;
char *string="abde";
char str[]="adb";
init();
jd=1;
count=0;
Time0_Init();
while(1)
{
keyscan(); //按键扫描
//注意用了printf函数就不能使用串口中断了,这个函数根本是调用putchar函数,其工作方式是中断
}
}
程序说明:用的是MDK5写的工程。只有一个串口通信,所以这个串口要么接串口蓝牙实现无线遥控,要么这个串口接USB转TTL模块与电脑的串口调试助手进行有线通信。程序写有详细的注释,读者可以慢慢斟酌。
3.根据软件和硬件完成硬件连接
接线说明:根据源码接线,大概的接线关系是蓝牙模块接单片机的串口:蓝牙模块rxd接单片机P3.1,Txd接单片机P3.0,L298N四个in管脚接单片机P1.0到P1.3四个管脚。
用串口调试助手发指令给小车可以实现有线控制小车行走:发送十六进制指令,因为小车接收指令 要加\r\n作为结束符号
所以指令后面要加上十六进制0d 0a
比如FFF\r\n是前进,指令转化为十六进制是 4646460d0a
三、仿真与调试
1. 准备好硬件,小车上电和打开手机蓝牙和蓝牙调试助手,输入指令,点击发送。
比如FFF\r\n是前进,指令转化为十六进制是 4646460d0a
下面是后退:BBB\r\n 指令转化为十六进制是4242420d0a
下面是左转: LLL\r\n指令转化为十六进制是4c4c4c0d0a
最后是右转: RRR\r\n指令转化为十六进制是(以此类推)
2. 接收小车返回的响应
看上面的截图,收到:464646a 说明小车响应了前进指令。
后面以此类推。
3. 拔除串口蓝牙模块接上USB转TTL模块用串口调试助手调试小车
输入FFF,点击“发送”按钮,小车就前进,串口调试窗口就看到小车回复了FFF,输入BBB就是倒退,左转是LLL,右转是RRR。
注意波特率是115200
总结
小车是用安卓手机蓝牙调试助手用指令发送的形式来控制的,所以说是最简单的蓝牙遥控小车。不过加上舵机和机械手和操控摇杆或者是手机控制app,就变得高端了,敬请期待。这个版本是免费的,但是功能还是很齐全和强大的,代码也写得通俗易懂,不拖泥带水。
代码工程下载链接:https://www.cirmall.com/circuit/20328/
点我直接跳转