目录
一、前言
二、硬件
三、软件
四、手机端设置
五、总结
基于前面的51小车模块,我增加了循迹模块,先给大家看看效果吧:
循迹模块
1.循迹模块三个IO,硬件原理,亮灯返回1,灭灯返回0,当检测到黑线时返回0,检测到白色时返回1,因此可以设置寻黑线设置
2.P16接左边循迹,P17接右边循迹
完整代码可在本文末尾下载
main.c
#include
#include "UART.h"
#include "Timer0.h"
#include "Nixie.h"
#include "Delay.h"
sbit IN1 = P1^0; // 左上
sbit IN2 = P1^1; // 左下
sbit IN3 = P1^2; // 右上
sbit IN4 = P1^3; // 右上
sbit ENA = P2^6; //使能A
sbit ENB = P2^7; //使能B
sbit out0 = P2^0; // 右边避障,有障碍物就亮,输出0
sbit out1 = P2^1; // 左边避障,有障碍物就亮,输出0
sbit outleft = P1^6; //左边循迹,亮灯返回值为1
sbit outright = P1^7; //右边循迹,检测到黑线灭灯,返回0
unsigned char PWM; //PWM波
unsigned char date;//输入缓冲区
static unsigned char speed = 100; //设置速度初始值
void stop() // 停
{
IN1=0;
IN2=0;
IN3=0;
IN4=0;
}
void forward() // 向前
{
IN1=1;
IN2=0;
IN3=1;
IN4=0;
}
void back() // 向后
{
IN1=0;
IN2=1;
IN3=0;
IN4=1;
}
void left() // 向左,只有左轮动
{
IN1=1;
IN2=0;
IN3=1;
IN4=1;
}
void avoid_left()//向左,左右伦同时转动
{
IN1=1;
IN2=0;
IN3=0;
IN4=1;
}
void right() // 向右,只有右轮动
{
IN1=1;
IN2=1;
IN3=1;
IN4=0;
}
void avoid_right()//向左,左右伦同时转动
{
IN1=0;
IN2=1;
IN3=1;
IN4=0;
}
void increase(void)//加速
{
speed += 5; // 每次增加5
if(speed >= 100) // 上限是100
{
speed = 100;
}
}
void reduce(void)//减速
{
speed -= 5; // 每次减少5
if(speed <= 0) // 下限是0
{
speed = 0;
}
}
void avoid(void)//避障模式
{
if(out0 == 0) // 右边有障碍物,左转
{
avoid_left();
}
if(out1 == 0) // 左边有障碍物,右转
{
avoid_right();
}
if(out0 == 1 && out1 == 1) // 没有障碍物,前进
{
forward();
}
if(out0 == 0 && out1 == 0) // 有障碍物,停止
{
stop();
}
}
void Follow_the_trail (void)
{
if(outleft == 0 && outright == 0)//悬空,停止移动
{
stop();
}
if(outleft == 1 && outright == 1) //在赛道上,直线行驶
{
forward();
}
if(outleft == 1 && outright == 0) //偏离赛道向右,因向左行驶
{
left();
}
if(outleft == 0 && outright == 1) //偏离赛道向左,因向右行驶
{
right();
}
}
//串口中断
void Time_Int () interrupt 4
{
if(RI == 1) // RI为1时软件置0
{
RI = 0; // 清除接受标志
date = SBUF; // 接收数据缓存在date中
switch (date)
{
case ('1'):
{
forward();
break;
}
case ('2'):
{
back();
break;
}
case ('3'):
{
left();
break;
}
case ('4'):
{
right();
break;
}
case ('0'):
{
stop();
break;
}
case ('5'):
{
increase();
break;
}
case ('6'):
{
reduce();
break;
}
}
}
}
//定时器0
void time_control() interrupt 1
{
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
PWM++;
if (PWM == 100)
{
PWM = 0;
}
if(PWM <= speed)//大于PWM波则打开使能
{
ENA = 1;
ENB = 1;
}
if(PWM > speed)//小于PWM波则关闭使能
{
ENA = 0;
ENB = 0;
}
}
void main ()
{
UsartConfiguration(); // 串口初始化
Timer0Init();//定时器0初始化
while(1)
{
//在数码管可以看到当前的速度是多少
Nixie(1, speed/100);
Delay(5);
Nixie(2, (speed/10)%10);
Delay(5);
Nixie(3, speed%10);
Delay(5);
//启动避障模式,将此模式存放在主函数当中
if(date == '7')
{
avoid();
}
//启动循迹模式,将此模式存放在主函数当中
if(date == '8')
{
Follow_the_trail();
}
}
}
UART.h(中断)
#ifndef __UART_H__
#define __UART_H__
void UsartConfiguration(void);
void UART_SendByte(unsigned char byte);
#endif
UART.c
#include
/**
* @brief 串口初始化,[email protected]
* @param 无
* @retval 无
*/
void UsartConfiguration(void) //[email protected]
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xFD; //设定定时初值
TH1 = 0xFD; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
ES = 1; //开启串口中断
EA = 1; //开启总中断
}
/**
* @brief 串口发送一个字节数据
* @param byte 是接收的数据
* @retval 无
*/
void UART_SendByte(unsigned char byte)
{
SBUF = byte;
while (TI == 0);
TI = 0;
}
Timer0.h(定时器0)
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0Init(void);
#endif
Timer0.c
#include
/**
* @brief 定时器0,1毫秒@11.0592MHz
* @param 无
* @retval 无
*/
void Timer0Init(void) //1毫秒@11.0592MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1; //定时器开关
EA = 1; //总开关
}
/*模板
void time_control() interrupt 1
{
static unsigned int counst;//局部变量,静态变量,防止每次进入中断,都将counst置为0
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
counst++;
if (counst == 1000)
{
counst = 0;
}
}
*/
Nixie.h(数码管)
#ifndef __NIXIE_H__
#define __NIXIE_H__
void Nixie(unsigned char Location,Number);
#endif
Nixie.c
#include
#include "Delay.h"
//数码管段码表
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
/**
* @brief 数码管显示
* @param Location 要显示的位置,范围:1~8
* @param Number 要显示的数字,范围:段码表索引范围
* @retval 无
*/
void Nixie(unsigned char Location,Number)
{
switch(Location) //位码输出
{
case 1:P2_4=1;P2_3=1;P2_2=1;break;
case 2:P2_4=1;P2_3=1;P2_2=0;break;
case 3:P2_4=1;P2_3=0;P2_2=1;break;
case 4:P2_4=1;P2_3=0;P2_2=0;break;
case 5:P2_4=0;P2_3=1;P2_2=1;break;
case 6:P2_4=0;P2_3=1;P2_2=0;break;
case 7:P2_4=0;P2_3=0;P2_2=1;break;
case 8:P2_4=0;P2_3=0;P2_2=0;break;
}
P0=NixieTable[Number]; //段码输出
Delay(1); //显示一段时间
P0=0x00; //段码清0,消影
}
Delay.h(延时)
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Delay.c
/**
* @brief 毫秒延时
* @param xms输入的毫秒
* @retval 无
*/
void Delay(unsigned int xms) //@11.0592MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
在开关设置:
有待加强的地方:
1.本次循迹只使用了两个循迹模块,在精准度上还有待提升,间接限制了速度的提升
代码下载:
Txet: 记录代码 - Gitee.com
--------------------------------------------------------------------------------------------------------------------------
欢迎大家观看我的文章,希望对你有所帮助。
作者大一新生,一起加油努力丫~!
来个赞阿布~