开篇前言:小车这一块,以下是我个人认为要解释的部分。
1–.波特率-------这是一个用来两个东西之间传输数据的,属于电子类专业名词,我们这次学习小车,添加的模块例如蓝牙和超声波,都需要数据传输,所以代码中会定义这个东西。
2–.我这次整理的是每个模块单独使用,如果想做一个整合的小车,就是把我以下整理的代码合到一块,单独烧录的话,单片机会自动覆盖上一个代码,所以在模块学习完后,还是建议大家可以试试,自己做出来的真的好玩。
3–.小车这一块,我会把我都个人理解写出来,希望能帮助到大家的学习,如果有什么错误,也希望大家指出来,一块学习!
1.智能小车的整体模块框架:
单片机最小系统—L298N模块连接—电池—开关—电机
电池提供能量,最小系统编录代码,通过L298N进行一个转换,用以驱动电机进行反应输出,然后再这个框架上进行蓝牙,红外,超声波,循迹的添加。
2.L298N:
连接:12v连接电池盒正极,电源地接地,5v连接VCC,两个马达输出连接小车电机
3.蓝牙:
1+.蓝牙模块上的VCC接51单片机上的VCC,GND接51单片机上的GND
2+.蓝牙模块上的TXD与RXD分别接单片机上的RXD与TXD,即输出连接接收,接收连接输出。(单片机给蓝牙模块说悄悄话,你往左走,蓝牙模块照做了,然后给单片机说我走完了,求夸!)
3+代码中,蓝牙主要是为了方便手机连接,然后让小车前进forward(),后退 back(),向左 left(),向右right(),停下stop()。这里一般是下载一个手机蓝牙助手(应用商店里就有哦!)
4+.代码
(下方代码部分串口,建议配合图片一起观看)
#include <REGX52.H> //头文件
sbit AIN1 = P1^1; //定义L298N上的四个接口,方便电机驱动
sbit AIN2 = P1^2;
sbit AIN3 = P1^3;
sbit AIN4 = P1^4;
int fx = 0; //定义一个变量
void turnleft() //向左
{
AIN1 = 1 ; //右边电机转动,左边不动,以下同理
AIN2 = 0 ; //左右控制的接口需要自行调试
AIN3 = 0 ;
AIN4 = 1 ;
}
void turnright()
{
AIN1 = 0 ;
AIN2 = 1 ;
AIN3 = 1 ;
AIN4 = 0 ;
}
void run() {
AIN1 = 1 ;
AIN2 = 0 ;
AIN3 = 1 ;
AIN4 = 0 ;
}
void stop(){
AIN1 = 0 ;
AIN2 = 0 ;
AIN3 = 0 ;
AIN4 = 0 ;
}
void back(){
AIN1 = 0 ;
AIN2 = 1 ;
AIN3 = 0 ;
AIN4 = 1 ;
}
void timer() //定时器
{
PCON = 0x00; //单片机上管脚名的全称
TMOD=0x20;
TH1 = 0xfd;
TL1 = 0xfd;
TR1=1; //开启串口
REN=1; //允许接收
SM0=0;
SM1=1; //串口
EA=1; //中断
ES=1;
}
void runtimer() //运行计时器
interrupt 4
{
char receive_data; //定义数据接收
if(RI == 1) //赋值,if语句
{
RI = 0;
receive_data = SBUF; //SBUF单片机数据存储处,读取存储
if(receive_data == 'w') //蓝牙助手上显示的指令“w”,以下同理
{
fx = 1 ;
}
else if(receive_data == 's')
{
fx = 2 ;
}
else if(receive_data == 'a')
{
fx = 3 ;
}
else if(receive_data == 'd')
{
fx = 4 ;
}
else if(receive_data == 'x')
{
fx = 0 ;
}
}
}
void main() //定义主函数,运用上边描述的fx
{
timer();
while(1)
{
if ( fx == 1 )
{
run() ;
} else if ( fx == 2 ){
back();
}
else if ( fx == 3 ){
turnleft();
}
else if ( fx == 4 ){
turnright();
}
else if ( fx == 0 ){
stop();
}else {
stop();
}
}
}
5+.蓝牙小车的连接很简单,就是在原框架上添加一个蓝牙模块罢了,至于代码其实主要就是在小车前进后退上,添加一个蓝牙模块定义与打开。
6+.以上这是自己写的一段代码,可能有点长,我还从网上找了一段比较短的代码,复制了过来,方便大家进行比对,如有侵权,立删。
#include <reg51.h>
sbit int1=P0^0;
sbit int2=P0^1;
sbit int3=P0^2;
sbit int4=P0^3;
char i;
void stop()//停止
{
int1=0;
int2=0;
int3=0;
int4=0;
}
void back()//后退
{
int1=1;
int2=0;
int3=1;
int4=0;
}
void forward()//前进
{
int1=0;
int2=1;
int3=0;
int4=1;
}
void right() //右转
{
int1=0;
int2=1;
int3=1;
int4=0;
}
void left()//左转
{
int1=1;
int2=0;
int3=0;
int4=1;
}
void main()
{
TMOD=0x20; //设置T1为工作方式2
TH1=0xfd; //装入初值,比特率为9600bps
TL1=0xfd;
TR1=1; //开启T1
REN=1; //接收允许
SM0=0; //方式1
SM1=1;
EA=1; //开全局中断
ES=1; //开串口中断
while(1)
{
i=SBUF;//SBUF为单片机接收到的数据,单片机接收到的数据都存放在SBUF里;
RI=0;
switch(i)
{
case '1':
forward();
break;
case '2':
back();
break;
case '3':
left();
break;
case '4':
right();
break;
case '5':
stop();
break;
}
}
}
4.红外:(一般小车上用两个红外模块)
1+.VCC,GND通用连接,见上。红外模块三个接口,除去VCC,GND剩下的一个管脚接,单片机的代码定义口。
2+.代码
#include <reg52.h>
sbit IN1 = P1^0;
sbit IN2 = P1^1;
sbit IN3 = P1^2;
sbit IN4 = P1^3;
sbit out1 = P2^0; //红外模块定义输出
sbit out2 = P2^1;
void forward(); //前进
void back(); //后退
void left(); //向左
void right(); //向右
void stop(); //停止
void main()
{
while(1)
{
if(out2 == 0) //检测到右边有障碍物时,向左移动
{
left();
}
else if(out1 == 0) //检测到左边边有障碍物时,向右移动
{
right();
}
else if(out1 == 1 && out2 == 1) //检测到都没有有障碍物时,向前移动,&&同的意思
{
forward();
}
}
}
void forward()
{
IN1=1;
IN2=0;
IN3=1;
IN4=0;
}
void back()
{
IN1=0;
IN2=1;
IN3=0;
IN4=1;
}
void left()
{
IN1=0;
IN2=0;
IN3=0;
IN4=1;
}
void right()
{
IN1=1;
IN2=1;
IN3=1;
IN4=0;
}
void stop()
{
IN1=0;
IN2=0;
IN3=0;
IN4=0;
}
红外我觉得是这些小车模块里最简单存在,他只是在原有的小车行动代码的原基础上添加了一个嵌套if语句。
5.超声波:(实物图来源于百度,原理图来自于csdn。)
1+.超声波模块—采用IO触发测距,给至少10us的高电平信号;模块自动发送8个40khz的方波,自动检测是否有信号返回;有信号返回,通过IO输出一高电平,高电平持续的时间就是,超声波从发射到返回的时间。
(我给你时间掏竹竿,你自己把竹竿捅出去,等竹竿碰到障碍物,你在把竹竿收回来,告诉我障碍物理我有多远。)
2+.仿真
3+.代码
#include <reg52.h>
#include <stdio.h>
sbit Trig=P1^1; //定义超声波模块的两个接口
sbit Echo=P1^0;
void delay10us() //延时10us函数
{
TMOD |=0X1;
TH0=0xff;
TL0=0xf6;
TR0=1;
while(!TF0);
TF0=0;
}
void delay(unsigned long time) //延时函数
{
int i;
int j;
for(i=0;i<100;i++)
for(j=0;j<time;j++);
}
void init_9600()//波特率9600串口初始化函数
{
SCON=0x50;
TMOD=0x20;
TH1=0xFD;
TL1=0xFD;
TR1=1;
EA=1;
ES=1;
}
void init_115200()//波特率115200串口初始化函数
{
SCON=0x50;
TH2=0xFF;
TL2=0xFD;
RCAP2H=0xFF;
RCAP2L=0xFD;
T2CON|=0x1<<4|0x1<<5;
TR2=1;
EA=1;
ES=1;
}
void startCSB()//启动超声波模块
{
Trig=0;
Trig=1;
delay10us();
Trig=0;
}
void getSBUF(char c)//获得单个字符,跟下面的printstr函数配合打印字符串
{
SBUF=c;
while(TI!=1);
TI=0;
}
void printstr(char *pstr)//打印字符串函数
{
while(*pstr!='\0')
{
getSBUF(*pstr);
pstr++;
}
}
float getDistance()//获取距离的函数
{
float distance;
unsigned int time;
time=TH0<<8|TL0;
distance=(float)time*(0.017);
return distance;
}
void startTime()//超声波发出时刻,启动记时
{
TH0=0;
TL0=0;
TR0=1;
}
void endTime()//超声波回来,停止记时
{
TR0=0;
}
int main()//主函数
{
unsigned int time=0;
char buf[20]={'\0'};//用来在串口调试助手显示的字符组
float dis;
init_9600();//串口初始化
while(1)
{
startCSB();//启动超声波模块
while(Echo!=1);//发出超声波,开始计算时间
startTime();
while(Echo!=0);//超声波回来,时间截止
endTime();
dis=getDistance();//获取距离
sprintf(buf,"getdistance=%fcm\r\n",dis);//输出结果
printstr(buf);
delay(200);
}
}
4+.超声波测距的大体操作我在超声波开头这里写了。而代码就是定义串口后,他不是需要时间吗,我就给他一个来回的延时时间,他还要两个波,一个负责探路,一个负责计算距离。当测距的波发送出去的时候,超声波模块开始计时,回来后结束即使,距离等于速度乘以时间,所以超声波输出结果后,测距完成!
在计算距离之后我们要获取结果,所以得定义一个获取函数的代码。
当然小车如果一直动的话,超声波模块不可能只测一次,要来回的测试,所以就出现了串口协议初始化,重头再来一遍!
6.循迹:
1+.循迹就是通过高发射功率红外光电二极管和高灵敏光电晶体管组成的传感器循迹模块判断黑线路径,利用红外反射,遇黑不反的原理,跟着黑线走,一般使用四个模块。
#include <REGX52.H>
sbit IN1 = P3^0;
sbit IN2 = P3^1;
sbit IN3 = P3^2;
sbit IN4 = P3^3;
sbit ENA = P3^4;
sbit ENB = P3^5;
sbit leg1 = P1^2; //定义传感器
sbit leg2 = P1^3;
unsigned int zkb;
void delay(int a ){ //延时函数
int i ,j ;
for(i=1; i<a ; i++ )
for(j=1; j<120 ; j++ );
}
void turnleft(){
IN1 = 1 ;
IN2 = 0 ;
IN3 = 0 ;
IN4 = 0 ;
delay(46);
}
void turnrigh(){
IN1 = 0 ;
IN2 = 0 ;
IN3 = 1 ;
IN4 = 0 ;
delay(46);
}
void run() {
IN1 = 1 ;
IN2 = 0 ;
IN3 = 1 ;
IN4 = 0 ;
}
void stop(){
IN1 = 0 ;
IN2 = 0 ;
IN3 = 0 ;
IN4 = 0 ;
}
void xunji()
{
int flag ; //检测黑线
if( leg1 == 1 && leg2 == 1 )
{
flag = 0 ;
}else if(leg1 == 1 && leg2 == 0 )
{
flag = 1 ;
}else if( leg1 == 0 && leg2 == 1 )
{
flag = 2 ;
}else if( leg1 == 0 && leg2 == 0 )
{
flag = 3 ;
}
switch(flag)
{
case 0 : run();break;
case 1 : turnrigh();break;
case 2 : turnleft();break;
case 3 : stop();break;
}
}
void timer()
{
TMOD = 0x01 ;
TH0 = (65536-200)/256;
TL0 = (65536-200)%256;
EA = 1 ;
ET0 = 1 ;
TR0 = 1 ;
}
void runtimer() interrupt 1
{
TH0 = (65536-220)/256;
TL0 = (65536-220)%256;
zkb++;
if(120>zkb){
ENA = 1 ;
ENB = 1 ;
}
else if ( 120<zkb && 219 >zkb )
{
ENA = 0 ;
ENB = 0 ;
}else if ( zkb == 219 )
{
zkb = 0 ;
}
}
void main(){
timer();
while(1){xunji();}
}