笔者碎念:此作品为某大学大一小学期的项目作品,笔者从0基础开始学习制作,摸鱼几周完成,完成后并没有进行更多优化代码规范和功能,所以许多模块仅限于能用就行,本文只适合为刚接触的同学提供一些我的思路和心得。(比如说在某些部分代码没有问题,但执行起来有奇怪的问题,可能是单片机某些处理问题,这时使用延时函数可能解决)
接线操作https://www.bilibili.com/video/BV1Ca4y1s7JA/(有接线不同可能是一些模块接上时需要改线)
更多相关问题查询各类学习网站解答
关于两个不同代码版本
因为最初编写代码时没有蓝牙模块只有2个空余可操作按键(若是会该线应该可以有更多)而通过这2个按键实现了切换模块和一些操作,之后有蓝牙又对代码进行部分修改,增加了功能,修改使用蓝牙传输数据来实现切换模式,按钮只实现一些操作。
无蓝牙
main.c
主函数包括引入最基本的函数库REGX52.H
和关于一些引脚定义和基本操作定义
延时函数可以在STC-ISP中生成(在一些地方添加延时函数可能可以处理一些非代码引起的问题,比如突然修改速度等函数调用之后)
然后是计时器T0和T1的初始化,其中在T0用于前几个模块的PWM的计时,在T1用于测距(魔术手中是使用T2作为PWM的计时),因为两者共用一个寄存器(意味着不能同时使用),所以需要更改TMOD值来改变使用的计时器
然后是包含不同模块函数的头文件引入
主函数最开始初始化T0和T1以及LCD1602,然后使用一个无限循环包含在各个模块下的无限循环,使用Pattern.h中的Change_Pa()来break,进入下一个模块
#include // or #include ?
#include
#include
void Delay1ms(int time) //@11.0592MHz
{
unsigned char data i, j;
int a;
for(a=0;a
#include
#include
#include
#include
#include
#include
void main()
{
timer01_init();
Lcd1602_init();
while(1)
{
while(1)
{
TMOD = 0x02;
Delay1ms(100);
LRspeed(150,150);
controll();
if(Change_Pa()==1)
break;
}
while(1)
{
TMOD = 0x02;
Delay1ms(100);
follow();
if(Change_P服务器托管网a()==1)
break;
}
while(1)
{
TMOD = 0x02;
Delay1ms(100);
avoidance();
if(Change_Pa()==1)
break;
}
TMOD = 0x10;
while(1服务器托管网)
{
LCD_ShowNum(distance());
Delay1ms(100);
Lcd1602_Write_Cmd(0x01);//清屏作用
Delay1ms(200);
if(Change_Pa()==1)
break;
}
T2_Init();
while(1)
{
flag_dis=distance();
keep_dis();
if(Change_Pa()==1)
break;
}
}
}
//It is difficult to switch from mode 2 to mode 1
//You are advised to restart the power supply to return to mode 1
QXA51.h
主要是
#ifndef __QXA51_H__
#define __QXA51_H__
/*电机驱动IO定义*/
sbit IN1 = P1^2; //为1左电机反转
sbit IN2 = P1^3; //为1左电机正转
sbit IN3 = P1^6; //为1右电机正转
sbit IN4 = P1^7; //为1右电机反转
sbit EN1 = P1^4; //为1左电机使能
sbit EN2 = P1^5; //为1右电机使能
sbit TrackSensorLeft = P1^1;//左循迹信号为0则没有识别到黑线,为1则识别到黑线
sbit TrackSensorRight = P1^0;//右循迹信号
sbit left_avoid = P2^7;//左避障信号
sbit right_avoid = P2^6;//右避障信号为0,识别到障碍物,为1则没有识别到障碍物
/*按键定义*/
sbit key_s4 = P3^2;
sbit key_s5 = P3^3;
sbit beep = P2^3;//蜂鸣器
unsigned int flag_dis;//记录距离
#define left_motor_en EN1 = 1 //左电机使能
#define right_motor_en EN2 = 1 //右电机使能
#define left_motor_stops IN1 = 0, IN2 = 0//左电机停止
#define right_motor_stops IN3 = 0, IN4 = 0//右电机停止
#define left_motor_go IN1 = 0, IN2 = 1//左电机正转
#define left_motor_back IN1 = 1, IN2 = 0//左电机反转
#define right_motor_go IN3 = 1, IN4 = 0//右电机正转
#define right_motor_back IN3 = 0, IN4 = 1//右电机反转
#endif
Controll.h
按键按下,则对应引脚变成低电平
快速单按s5时,小车前进,长按时小车原地左转(长按时间大于200ms),快速单按s4时,小车后退,长按时小车原地右转。通过一个段较长的时间来区分想要进行的操作
void controll()
{
if(key_s5==0&&key_s4==1)
{
Delay1ms(200);
if(key_s5==1&&key_s4==1)
{
left_motor_en;
right_motor_en;
left_motor_go;
right_motor_go;
Delay1ms(500);
left_motor_stops;
right_motor_stops;
}
else if(key_s5==0&&key_s4==1)
{
while(!key_s5);
left_motor_en;
right_motor_en;
left_motor_back;
right_motor_go;
Delay1ms(150);
left_motor_stops;
right_motor_stops;
}
}
else if(key_s4==0&&key_s5==1)
{
Delay1ms(200);
if(key_s4==1&&key_s5==1)
{
left_motor_en;
right_motor_en;
left_motor_back;
right_motor_back;
Delay1ms(500);
left_motor_stops;
right_motor_stops;
}
else if(key_s4==0&&key_s5==1)
{
while(!key_s4);
left_motor_en;
right_motor_en;
left_motor_go;
right_motor_back;
Delay1ms(150);
left_motor_stops;
right_motor_stops;
}
}
}
Pattern.h
当同时按下两个按键时,则返回1,主函数中对应的模块循环跳出循环
int Change_Pa() {
if (key_s4==0||key_s5==0) {
Delay1ms(5);
if(key_s4==0&&key_s5==0)
{
while(!key_s4||!key_s5);
right_motor_stops;
left_motor_stops;
return 1;
}
} //More sensitive after removing "return 0"
return 0; //Very important for the second pattern
}
Follow.h
void follow()
{
//当小车检测到前方有障碍物时,自动掉头回到黑线上
if(left_avoid == 0 && right_avoid == 0) //Rotate slowly in place until a black line is detected
{
LRspeed(150,150);
Delay1ms(1);
left_motor_en;
right_motor_en;
left_motor_go;
right_motor_back;
Delay1ms(200);
while(1)
{
if(TrackSensorLeft==1&&TrackSensorRight==1)
break;
}
}
//前进
if(TrackSensorLeft==1&&TrackSensorRight==1)
{
LRspeed(150,150);
Delay1ms(5);
left_motor_en;
right_motor_en;
left_motor_go;
right_motor_go;
}
//左转
else if(TrackSensorLeft==1&&TrackSensorRight==0)
{
/*LRspeed(250,20);
Delay1ms(10);
left_motor_en;
right_motor_en;
left_motor_en;
right_motor_go;
注释的为两轮相差更大的差速转弯,实际可能出现一些问题*/
LRspeed(250,170);
Delay1ms(1);
left_motor_stops;
right_motor_en;
right_motor_go;
}
//右转
else if(TrackSensorLeft==0&&TrackSensorRight==1)
{
/*LRspeed(20,250);
Delay1ms(10);
right_motor_en;
left_motor_en;
left_motor_go;
right_motor_go;
注释的为两轮相差更大的差速转弯,实际可能出现一些问题*/
LRspeed(170,250);
Delay1ms(1);
right_motor_stops;
left_motor_en;
left_motor_go;
}
else
//防出线操作 if(TrackSensorLeft==0&&TrackSensorRight==0)
{
LRspeed(200,200);
Delay1ms(1); //Overheat protection
left_motor_stops;
right_motor_stops;
Delay1ms(1);
left_motor_en;
right_motor_en;
left_motor_back;
right_motor_back;
}
}
Avoidance.h
int avoidance()
{
if(left_avoid == 1 && right_avoid == 1)//左右都没有识别到障碍物
{
LRspeed(200,200);
Delay1ms(10);
left_motor_en;
right_motor_en;
left_motor_go;
right_motor_go;
}
else if(left_avoid == 1 && right_avoid == 0)//小车右侧识别到障碍物
{
beep = 0; //使能有源蜂鸣器
Delay1ms(100);//100ms计时
beep = 1; //关闭蜂鸣器
LRspeed(150,150);
Delay1ms(10);
left_motor_en;
right_motor_en;
left_motor_back;
right_motor_go;
}
else if(left_avoid == 0 && right_avoid == 1)//小车左侧识别到障碍物
{
beep = 0; //使能有源蜂鸣器
Delay1ms(100);//100ms计时
beep = 1; //关闭蜂鸣器
LRspeed(150,150);
Delay1ms(10);
left_motor_en;
right_motor_en;
left_motor_go;
right_motor_back;
}
else if(left_avoid == 0 && right_avoid == 0)//都识别障碍物,实现一个原地掉头,根据实际而时间会不同
{
beep = 0; //
Delay1ms(100);//200
beep = 1; //
LRspeed(150,150);
Delay1ms(10);
left_motor_en;
right_motor_en;
left_motor_go;
right_motor_back;
Delay1ms(250);
}
}
//Issue forward and backward commands
LCD1602.h
sbit RS = P3^5;
sbit RW = P3^6;
sbit EN = P3^4;
void Lcd1602_Write_Cmd(unsigned char cmd)
{
EN=0;
RS=0;
RW=0;
Delay1ms(5);
P0=cmd;
Delay1ms(5);
EN=1;
Delay1ms(5);
EN=0;
Delay1ms(5);
}
void Lcd1602_Write_Data(unsigned char dat)
{
EN=0;
RS=1;
RW=0;
Delay1ms(5);
P0=dat;
Delay1ms(5);
EN=1;
Delay1ms(5);
EN=0;
Delay1ms(5);
}
void simle()
{
Lcd1602_Write_Cmd(0x40);
Lcd1602_Write_Data(0x00);
Lcd1602_Write_Cmd(0x41);
Lcd1602_Write_Data(0x00);
Lcd1602_Write_Cmd(0x42);
Lcd1602_Write_Data(0x0A);
Lcd1602_Write_Cmd(0x43);
Lcd1602_Write_Data(0x0A);
Lcd1602_Write_Cmd(0x44);
Lcd1602_Write_Data(0x00);
Lcd1602_Write_Cmd(0x45);
Lcd1602_Write_Data(0x11);
Lcd1602_Write_Cmd(0x46);
Lcd1602_Write_Data(0x0E);
Lcd1602_Write_Cmd(0x47);
Lcd1602_Write_Data(0x00);
Lcd1602_Write_Cmd(0xC0);
Lcd1602_Write_Data(0x00);
}//一个简单的笑脸实现
int LCD_Pow(unsigned int X,unsigned int Y) //X^Y
{
unsigned char i;
unsigned int Result=1;
for(i=0;i=0;i--)
Lcd1602_Write_Data(Number/LCD_Pow(10,i)%10+'0');
}//显示数字
}//写入数据
void Lcd1602_init()
{
Delay1ms(15);
Lcd1602_Write_Cmd(0x38);
Delay1ms(5);
Lcd1602_Write_Cmd(0x38);
Lcd1602_Write_Cmd(0x01);
Lcd1602_Write_Cmd(0x06);
Lcd1602_Write_Cmd(0x0c);
}//对1062初始化操作
Distance.h
此处使用定时器2作为PWM的计时器,之所以不使用一个定时器始终作为PWM定时器是因为原本的超声波魔术手并没有考虑控制速度,在之后添加控制速度的功能时因为改动整体比较麻烦,所以只把定时器2放在超声波魔术手模块中实现PWM
#define RX P2_0 //ECHO
#define TX P2_1 //TRIG
unsigned int time=0;
unsigned int S=0;
bit flag=0;
unsigned int pwm_t2;
unsigned int pwm2_left_val;
unsigned int pwm2_right_val;
void T2_Init()
{
T2MOD=0;
T2CON=0;
EXEN2=0;
TH2=0xFF;
TL2=0xCB;
RCAP2L = 0xCB;
RCAP2H = 0xFF;
TR2=1;
ET2=1;
EA=1;
}//T2初始化
void timer2() interrupt 5 //定时器2中断
{
TF2=0;
pwm_t2++;
if(pwm_t2 == 255)
pwm_t2 = EN1 = EN2 = 0;
if(pwm2_left_val == pwm_t2)
EN1 = 1;
if(pwm2_right_val == pwm_t2)
EN2 = 1;
}
int Conut()
{
time=TH1*256+TL1;
TH1=0;
TL1=0;
S=(int)((float)(time*1.085)*0.17); //计算结果为mm
if((S>=7000)||flag==1)
{
flag=0;
return 0;
}
return S;
}
void zd1() interrupt 3 //T1中断用来表示计数器溢出,超过测距范围
{ //中断溢出标志
flag=1;
}
int distance()
{
TMOD = 0x10;
Delay1ms(80);
TX=1; //80MS启动一次模块
Delay1ms(1);
TX=0;
while(!RX); //当RX(ECHO信号回响)为0时等待
TR1=1; //开启计数
while(RX); //当RX为1是计数并等待
TR1=0; //关闭计数
return Conut(); //计算
}
void keep_dis()
{
pwm2_left_val=180;
pwm2_right_val=180;
if(flag_dis230)
{
Delay1ms(10);
left_motor_en;
right_motor_en;
right_motor_go;
left_motor_go;
}
else
{
right_motor_stops;
left_motor_stops;
}
}
PWM.h
unsigned char pwm_left_val;//Left motor duty cycle
unsigned char pwm_right_val;//Right motor duty cycle
unsigned char pwm_t;//cycle
void timer0() interrupt 1 //0
{
TF0=0;
pwm_t++;
if(pwm_t == 255)
pwm_t = EN1 = EN2 = 0;
if(pwm_left_val == pwm_t)
EN1 = 1;
if(pwm_right_val == pwm_t)
EN2 = 1;
}
void LRspeed(unsigned char L_speed,unsigned char R_speed)
{
pwm_left_val=L_speed;
pwm_right_val=R_speed;
}
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
一、说文解字,学习一下Collation的字面意思:排序。 (https://en.wikipedia.org/wiki/Collation) 二、SQL中的Collation,描述了如何对查询出来的数据进行比较和排序,本质是定义了两个cell的数据进行比较的…