小车制作时间2019年10月,当时我刚刚开始接触51单片机,参加了学校的电子设计比赛,我主要负责代码书写,刚刚开始学51的我,制作一个小车还是很有难度。现在把当时的代码分享到博客上希望对学习者有所帮助。
一、难点
1.51单片机的定时器只有两个,用51写蓝牙控制的循迹避障小车中,蓝牙、超声波避障、PWM调制都需要定时器,这样定时器是不够使用的,当时我在这里纠结了很久,最后避障有红外做的。
2.当时用51单片机书写这种功能的成熟代码,没有好的参考。
二、小车代码
1.程序
/*
功能:寻迹,跟踪,避障,由蓝牙控制
1).寻迹:在正常轨迹上时,前进;单边出线时,调整;双边出线时,停止
2).跟踪:跟着白色物体走
3).避障:躲避障碍物
4).调速:P2^5控制加速,P2^0控制减速
注:相关引脚定义,见小车头文件
*/
#include <reg52.h> //51头文件
#include <CAR51.h> //小车头文件
//宏定义常量
#define ZKB_left 69 //左轮占空比定义0~255
#define ZKB_right 64 //右轮占空比定义0~255
#define ZKB_max 255 //占空比最大值
//#define GaoSu 70
//#define DiSu 54
//PWM左右占空比等相关定义
uchar pwm_t; //pwm周期
uchar push_left = ZKB_left; //左轮占空比赋值
uchar push_right = ZKB_right; //右轮占空比赋值
uchar push_max = ZKB_max; //占空比最大值, 此时速度最慢
uchar flag = 's'; //功能切换标志
uchar flag1 = '0'; //持续返回标志
uint flag_a = 0;
uint flag2 = 0;
void Tinit(); //定时器初始化
void XunJi(); //红外寻迹
void XunJi_l(); //左转寻迹
void XunJi_r(); //右转寻迹
void XunJi_A(); //寻迹避人
void GenZong(); //红外跟踪
void Avoid(); //红外避障
void CK_Tinit(); //初始化串口
//主函数
void main()
{
uchar i;
stop(); //保证小车开始处于停止状态
Tinit(); //定时器初始化
CK_Tinit(); //初始化串口
while(1)
{
//TiaoSu();
flag = SBUF;
RI = 0;
switch(flag)
{
case 'f': forward(); flag = 'f'; break; //前进
case 'b': backward(); flag = 'b'; break; //后退
case 'l': left_run(); flag = 'l'; break; //左转
case 'r': right_run(); flag = 'r'; break; //右转
case 's': stop(); flag = 's'; break; //停止
case 'x': XunJi(); flag = 'x'; break; //循迹
case 'y': XunJi_A(); flag = 'y'; break; //循迹避障
case 'g': GenZong(); flag = 'g'; break; //跟踪
case 'a': Avoid(); flag = 'a'; break; //避障
default: flag = 's';
}
//返回数据,表示串口正常运行
if(flag != flag1)
for(i = 0; i < 36; i++)
{
SBUF = flag;
while(!TI);
flag1 = flag;
TI = 0;
}
flag2 = 0;
}
}
//寻迹
void XunJi()
{
//左右红外探头必须大于等于黑线长度
if(left_led1 == 0 && right_led1 == 0) //左右寻迹探头识别到白线
forward(); //前进
if(left_led1 == 1 && right_led1 == 0) //小车右边出线,左转修正
left_run(); //左转
if(left_led1 == 0 && right_led1 == 1) //小车左边出线,右转修正
right_run(); //右转
if(left_led1 == 1 && right_led1 == 1) //左右寻迹探头识别到黑线
{
left_run();
delay(17);
if(left_led1 == 0 && right_led1 == 0) //左右寻迹探头识别到白线
forward(); //前进
else
right_run(); //左转
}
//push_left = ZKB_left; //左轮占空比赋值
//push_right = ZKB_right; //右轮占空比赋值
}
//寻迹避人
void XunJi_A()
{
//左右红外探头必须大于等于黑线长度
if(left_led1 == 0 && right_led1 == 0) //左右寻迹探头识别到白线
{
if((left_led2 == 0) || (mid_led2 == 0) || (right_led2 == 0))
{
backward();
delay(20);
stop();
delay(20);
}
else
forward(); //前进
}
if(left_led1 == 1 && right_led1 == 0) //小车右边出线,左转修正
{
if((left_led2 == 0) || (mid_led2 == 0) || (right_led2 == 0))
{
backward();
delay(20);
stop();
delay(20);
}
else
left_run(); //左转
}
if(left_led1 == 0 && right_led1 == 1) //小车左边出线,右转修正
{
if((left_led2 == 0) || (mid_led2 == 0) || (right_led2 == 0))
{
backward();
delay(20);
stop();
delay(20);
}
else
right_run(); //右转
}
if(left_led1 == 1 && right_led1 == 1) //左右寻迹探头识别到黑线
stop();
}
//红外跟踪
void GenZong()
{
if((left_led2 == 0) && (right_led2 == 0)) //左右寻迹探头识别到白板
forward(); //前进
if((left_led2 == 0) && (right_led2 == 1)) //小车右边出轨迹,左转修正
left_run(); //左转
if((left_led2 == 1) && (right_led2 == 0)) //小车左边出轨迹,右转修正
right_run(); //右转
if((left_led2 == 1) && (right_led2 == 1)) //左右寻迹探头没识别到白板
stop(); //停止
}
void Avoid()
{
if((left_led2 == 0) && (mid_led2 == 0) && (right_led2 == 0))
{
delay(2);
if((left_led2 == 0) && (mid_led2 == 0) && (right_led2 == 0))
{
backward();
delay(20);
left_run(); //左转
delay(40);
}
}
if((left_led2 == 1) && (mid_led2 == 0) && (right_led2 == 0))
{
delay(2);
if((left_led2 == 1) && (mid_led2 == 0) && (right_led2 == 0))
{
backward();
delay(20);
left_run(); //左转
delay(40);
}
}
if((left_led2 == 0) && (mid_led2 == 0) && (right_led2 == 1))
{
delay(2);
if((left_led2 == 0) && (mid_led2 == 0) && (right_led2 == 1))
{
backward();
delay(20);
right_run(); //右转
delay(40);
}
}
if((left_led2 == 1) && (mid_led2 == 0) && (right_led2 == 1))
{
delay(2);
if((left_led2 == 1) && (mid_led2 == 0) && (right_led2 == 1))
{
backward();
delay(20);
right_run(); //右转
delay(40);
}
}
if((left_led2 == 0) && (mid_led2 == 1) && (right_led2 == 0)) //左右寻迹探头识别到白板
{
delay(2);
if((left_led2 == 0) && (mid_led2 == 1) && (right_led2 == 0)) //左右寻迹探头识别到白板
backward();
}
if((left_led2 == 0) && (mid_led2 == 1) && (right_led2 == 1)) //小车右边出轨迹,左转修正
{
delay(2);
if((left_led2 == 0) && (mid_led2 == 1) && (right_led2 == 1)) //小车右边出轨迹,左转修正
{
backward();
delay(20);
right_run(); //右转
delay(40);
}
}
if((left_led2 == 1) && (mid_led2 == 1) && (right_led2 == 0)) //小车左边出轨迹,右转修正
{
delay(2);
if((left_led2 == 1) && (mid_led2 == 1) && (right_led2 == 0)) //小车左边出轨迹,右转修正
{
backward();
delay(20);
left_run(); //左转
delay(40);
}
}
if((left_led2 == 1) && (mid_led2 == 1) && (right_led2 == 1)) //左右寻迹探头没识别到白板
{
delay(2);
if((left_led2 == 1) && (mid_led2 == 1) && (right_led2 == 1)) //左右寻迹探头没识别到白板
forward(); //停止
}
}
//定时器初始化
void Tinit()
{
TMOD |= 0x01; //8位自动重装模块
TH0 = 0xff;
TL0 = 0xff; //1us定时
TR0 = 1;
ET0 = 1;
EA = 1; //开总中断
}
//初始化串口
void CK_Tinit()
{
SCON = 0X50;
TMOD |= 0X20;
PCON = 0X80;
TH1 = 0Xfa;
TL1 = 0Xfa;
TR1 = 1;
REN = 1;
SM0 = 0;
SM1 = 1;
ES = 1;
EA = 1;
}
/******************pwm控制start******************/
//控制pwm的中断函数
void timer0() interrupt 1
{
TH0 = 0xff;
TL0 = 0xff; //1us定时
pwm_t++;
if(pwm_t == push_max)
pwm_t = 0;
if(push_left > pwm_t)
ENB = 1;
else
ENB = 0;
if(push_right > pwm_t)
ENA = 1;
else
ENA = 0;
}
/*******************pwm控制end*******************/
/*
void TiaoSu()
{
if(key_s1 == 0) //实时检测S1按键是否被按下
{
stop();
delay(3); //软件消抖
if(key_s1 == 0) //再检测S1是否被按下
{
stop();
flag2 = 1;
while(!key_s1); //松手检测
}
}
if(key_s2 == 0) //实时检测S1按键是否被按下
{
stop();
delay(3); //软件消抖
if(key_s2 == 0) //再检测S1是否被按下
{
stop();
flag = 2;
while(!key_s2); //松手检测
}
}
switch(flag2)
{
case 1: push_right += 10; push_left += 10; break;
case 2: push_right -= 10; push_left -= 10; break;
default: stop();
}
}
*/
2.头文件CAR51.h
#ifndef __CAR51_H__
#define __CAR51_H__
//L298N定义
sbit ENA = P1^2;//右电机使能
sbit IN1 = P1^3;//为1,右轮反转
sbit IN2 = P1^4;//为1,右轮正转
sbit IN3 = P1^5;//为1,左轮反转
sbit IN4 = P1^6;//为1,左轮正转
sbit ENB = P1^7;//左电机使能
//寻迹信号定义
sbit left_led1 = P3^2; //左寻迹信号 为0 没有识别到黑线 为1识别到黑线
sbit right_led1 = P3^3;//右寻迹信号 为0 没有识别到黑线 为1识别到黑线
//跟踪寻迹信号定义
sbit left_led2 = P3^4; //左跟踪寻迹信号 为0 跟踪
sbit right_led2 = P3^5;//右跟踪寻迹信号 为0 跟踪
sbit mid_led2 = P2^2; //中间避障信号
//按键定义
sbit key_s1 = P2^5;
sbit key_s2 = P2^0;
//小车车轮正反转定义
#define right_f IN1 = 0;IN2 = 1//右轮正转
#define right_b IN1 = 1;IN2 = 0//右轮反转
#define right_s IN1 = 0;IN2 = 0//右轮停止
#define left_f IN3 = 0;IN4 = 1//左轮正转
#define left_b IN3 = 1;IN4 = 0//左轮反转
#define left_s IN3 = 0;IN4 = 0//左轮停止
//毫秒延时函数xms
void delay(uint xms)
{
uint x, y;
for(x = xms; x > 0; x--)
for(y = 111; y > 0 ; y--);
}
/******************小车运动情况start******************/
///*
//小车前进
void forward()
{
left_f;
right_f;
}
//小车后退
void backward()
{
left_b;
right_b;
}
//小车左转
void left_run()
{
right_f;
left_b;
}
//小车右转
void right_run()
{
right_b;
left_f;
}
//*/
//小车停止
void stop()
{
left_s;
right_s;
}
/*******************小车运动情况end*******************/
#endif
三、启示
当时写程序没考虑后续使用,将程序都写到了主函数,看起来会用有点吃力,望见谅!
希望更多的大佬一起交流学习,一起进步!
5714

被折叠的 条评论
为什么被折叠?



