基于stc89c52单片机避障+舵机两驱三轮智能小车
前期准备:学会使用Keil4,学好51单片机基本知识,学会控制IO的输入与输出,内容学到外部中断,定时器,(串口通信,可以实现蓝牙控制)
准备材料:stc89c52最小系统,超声波模块,L298N电机驱动模块,智能小车两驱底盘套件,18650电池(12V)
源代码:
#include "reg52.h"
#include "intrins.h"
//重定义数据类型
typedef unsigned char u8;
typedef unsigned int u16;
//定义电机控制管脚
sbit MOTOA=P1^0;
sbit MOTOB=P1^1; //右侧电机
sbit MOTOC=P1^2;
sbit MOTOD=P1^3; //左侧电机
//定义超声波模块控制管脚
//TRIG 为控制端
sbit TRIG = P1^6; //超声波的 TRIG端 插在了P1.6口
//ECHO 为接收端
sbit ECHO = P1^7; //超声波的 ECHO端 插在了P1.7口
//定义舵机控制管脚
sbit PWM=P3^2; //舵机橙线(信号线)插在p3.7口
u8 count=0;
u8 timer1;
u8 lFlag;
u8 rFlag; //判断左右是否有障碍物的标志
/*延时程序*/
void delay1s(void) //误差 0us
{
u8 a,b,c;
for(c=167;c>0;c--)
for(b=171;b>0;b--)
for(a=16;a>0;a--);
_nop_();
}
void delay(u8 time) //定义一个延迟函数
{
u8 i;
for(;time>0;time--)
{
for(i=0;i<255;i++)
{
}
}
}
void run(void)//前进
{
MOTOA=1;
MOTOB=0;
MOTOC=1;
MOTOD=0;
}
void backrun(void)//后退
{
MOTOA=0;
MOTOB=1;
MOTOC=0;
MOTOD=1;
}
void leftrun(void)//左转
{
MOTOA=1;
MOTOB=0;
MOTOC=0;
MOTOD=0;
}
void rightrun(void)//右转
{
MOTOA=0;
MOTOB=0;
MOTOC=1;
MOTOD=0;
}
void stoprun(void)//停止
{
MOTOA=0;
MOTOB=0;
MOTOC=0;
MOTOD=0;
}
//超声波模块
u8 overflow_flag=0; //标志定时器是否溢出
void delay_20us(void) //延时20us
{
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
}
/*定时器T0初始化*/
void Timer0Init(void)
{
TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
TH0=0;
TL0=0; //给定时器赋初值
ET0=1; //打开定时器0中断允许
EA=1; //打开总中断
TR0=0; //关闭定时器0
}
void Timer0_Init() interrupt 1
{
overflow_flag=1;//溢出标志位置1
}
u16 Get_Distance(void)
{
u16 distance_data,out_TH0,out_TL0;
TRIG=0; // 先给控制端初始化为0
Timer0Init(); //初始化定时器
overflow_flag=0; //置溢出标志位为0
TRIG=1;
delay_20us();
TRIG=0; //等待接收端出现高电平
while(!ECHO);
TR0=1; //启动计时器 开始计时
while(ECHO); //等待高电平结束
TR0=0; //关闭低电平
out_TH0=TH0; //取定时器的值
out_TL0=TL0;
out_TH0<<=8; //左移8位
distance_data=out_TH0|out_TL0; //合并为16位的值
distance_data/=58; // 微秒/58 = 厘米
if(overflow_flag)
{
distance_data=999;
}
return distance_data; //返回
}
/*定时器T1初始化*/
void Timer1Init()
{
TMOD&=0x00;
TMOD|=0x10; //定时器T1设置成方式1
TH1=0xff;
TL1=0xa4; //定时常数 0.1ms 晶振为11.0592MHz
ET1=1; //打开定时器1中断允许
TR1=1; //打开定时器1
EA=1; //打开总中断
}
void Timer1_Init() interrupt 3
{
TR1=0; //关闭定时器1
TH1=0xff;
TL1=0xa4; // 0.1ms 产生舵机产生转动所需要的pwm信号
if(count<=timer1)
{
PWM=1; //输出高电平
}
else
{
PWM=0; //输出低电平
}
count++;
if (count>=200) //T = 20ms清零
{
count=0;
}
TR1=1; //打开定时器T1
}
u16 cnt=25,num=440;
//主函数
void main()
{
Timer0Init();
Timer1Init(); //引入定时器0和定时器1
timer1=6; //控制舵机使超声波正对前方
count=0; //让定时器重新计数
delay1s();
while(1)
{
if(Get_Distance()>=cnt)
{
run();
delay(8);
stoprun();
delay(5); //主要是为了控制小车速度,可以根据自身改变
}
else
{
stoprun();
delay(50);
timer1=12; //使舵机左转
count=0; //让定时器1重新计数
delay1s();
lFlag=Get_Distance(); //测量左侧距离
timer1=6; //使舵机正对前方
count=0; //让定时器1重新计数
delay1s(); //可能可以去掉,待测试
timer1=2; //使舵机右转
count=0; //让定时器1重新计数
delay1s();
rFlag=Get_Distance(); //测量右侧距离
timer1=6; //使舵机正对前方
count=0; //让定时器1重新计数
delay1s(); //可能可以去掉,待测试
backrun();
delay(num);
if(lFlag<cnt&&rFlag>cnt)
{
rightrun();
delay(num);
}
else if(lFlag>cnt&&rFlag<cnt)
{
leftrun();
delay(num);
}
else if(lFlag>cnt&&rFlag>cnt)
{
rightrun();
delay(num);
}
else if(lFlag<cnt&&rFlag<cnt)
{
backrun();
delay(num);
}
}
}
}
源代码可根据自身情况进行修改,该项目适合学习51单片机中断之后进一步巩固。
PS:第一次写文章,如有错误,望读者指征
|