为什么叫模块化呢,当然是因为分开写的缘故。每个模块拼在一起,组合成一个可用的程序。
正好比赛结束了,来年应该也没机会参加了,干脆写下思路,做个纪念。
本例提供ESP8266控制小车的模块代码,但并没有装载,而实际上,下位机LPC已经预留了一个定时器待用,这个定时器可以用来控制串口波特率,也就是给ESP8266用,也可以用来控制占空比。当然,我是没有控制占空比的,因为只有两节电池,还得使用升压模块,尽可能提速,依靠算法来解决转向和偏线问题。
事先说明,本案例所有的代码程序均基于现成小车调试,因小车已被赛事方回收,这里只能大概罗列所需零部件和配置环境,另外,该小车为赛事方提供零件,由选手自由组装,样式规格不一。
注意:芯片的烧写通过其他的渠道(如普中51开发板)进行烧写后换芯片,或者直接使用USB转TTL的CH340烧写器,这里不再详细阐述。
正常来讲,L298N转向应该是这样的。
但我在最初的时候弄反了,所以整个代码就变成了,IN1-高,IN2-低,电机是反转,所以,如果不想改代码的,那就把电机方向换成跟我一样,也就是IN1和IN2互换,IN3和IN4互换(如果你的方向是正转的话)。如果改代码的话,就是把LEFT_IN3
和LEFT_IN4
的端口互换(前提是你的方向是正转,也就是上图的标准)
总之你看着情况改,循迹模块所在方向是小车前进方向。
5V1A输出充电宝×1、USB线×1、杜邦线若干。
组装完成图:
以图中上下两芯片称为上位机(UPC)和下位机(LPC)。
Echo
端接UPC的P1^6
Trig
端接UPC的P1^7
DIO
接UPC的P1^3
,CLK
接P1^4
,STB
接P1^5
UPC
超声波检测障碍发送低电平端口ULTRASONIC_INT
=P2^4
,LPC
接收触发外部中断1端口ULTRASONIC_INT1
=P3^3
,将这两个口连接起来IRIN
接外部中断0端口P3^2
OUT3、OUT4
,右轮接线到OUT1、OUT2
IN1
-P1^0
、IN2
-P1^1
、IN3
-P1^2
、IN4
-P1^3
、ENA
-P1^4
、ENB
-P1^5
OUT1-OUT5
分别接P2^0-P2^4
RXD
接UPC
的TXD
,TXD
接RXD
#ifndef __MAIN_H__
#define __MAIN_H__
#include
#include "TM1638.h"
#include "Ultrasonic.h"
//#include "beep.h"
//#include "connect_wifi.h"
#define True 1
#define False 0
typedef unsigned int uint;
typedef unsigned char uchar;
sbit ECHO = P1^6;
sbit TRIG = P1^7;
sbit ULTRASONIC_INT = P2^4;
#endif
#include "main.h"
void main()
{
init_timer0();
init_TM1638();
//init_esp8266();
while (True)
{
ultrasonic_launch();
process_ul_data();
Write_DATA(4 * 2, tab[num[0]]);
Write_DATA(5 * 2, tab[num[1]]);
Write_DATA(6 * 2, tab[num[2]]);
Write_DATA(7 * 2, numSymbols[num[3]]);
if (num[0] == 0 && num[1] == 0 && num[2] <= 3 && num[3] <= 5)
ULTRASONIC_INT = 0;
else
ULTRASONIC_INT = 1;
}
}
Ultrasonic.h
#ifndef __ULTRASONIC_H__
#define __ULTRASONIC_H__
#include "reg52.h"
#define DIG P0
#define ON 1
#define OFF 0
sbit Trig = P1^7;
sbit Echo = P1^6;
unsigned int distance = 0;
static unsigned int num[4];
// 初始化定时器0
void init_timer0()
{
TMOD |= 0x01;
TH0 = 0;
TL0 = 0;
ET0 = 1;
}
void delay(unsigned int i)
{
while (i --)
;
}
void process_ul_data()
{
num[0] = distance / 1000 % 10;
num[1] = distance / 100 % 10;
num[2] = distance / 10 % 10;
num[3] = distance / 1 % 10;
}
void ultrasonic_launch()
{
unsigned int time = 0;
Trig = 1;
delay(20);
Trig = 0;
while (Echo == 0)
;
TR0 = 1;
while (Echo)
;
TR0 = 0;
time = TH0 * 256 + TL0;
distance = (int)(time * 0.017);
TH0 = 0;
TL0 = 0;
process_ul_data();
}
// 定时器0中断
void timer0() interrupt 1 using 2
{
TH0 = 0;
TL0 = 0;
}
#endif
TM1638.h(官方的,非本人写,微改引脚)
#ifndef _TM1638_H
#define _TM1638_H
#include
#define DATA_COMMAND 0X40
#define DISP_COMMAND 0x80
#define ADDR_COMMAND 0XC0
//TM1638模块引脚定义
sbit DIO=P1^3;
sbit CLK=P1^4;
sbit STB=P1^5;
//共阴数码管显示代码
unsigned char code tab[]= {
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
0x40 // ' - '
};
unsigned char code numSymbols[] = {
0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF
};
void TM1638_Write(unsigned char DATA) //写数据函数
{
unsigned char i;
for(i=0; i<8; i++)
{
CLK=0;
if(DATA&0X01)
DIO=1;
else
DIO=0;
DATA>>=1;
CLK=1;
}
}
void Write_COM(unsigned char cmd) //发送命令字
{
STB=0;
TM1638_Write(cmd);
STB=1;
}
void Write_DATA(unsigned char add,unsigned char DATA) //指定地址写入数据
{
Write_COM(0x44);
STB=0;
TM1638_Write(0xc0|add);
TM1638_Write(DATA);
STB=1;
}
//TM1638初始化函数
void init_TM1638(void)
{
unsigned char i;
Write_COM(0x8b); //亮度 (0x88-0x8f)8级亮度可调
Write_COM(0x40); //采用地址自动加1
STB=0; //
TM1638_Write(0xc0); //设置起始地址
for(i=0; i<16; i++) //传送16个字节的数据
TM1638_Write(0x00);
STB=1;
}
#endif
#ifndef __MAIN_H__
#define __MAIN_H__
#include
#include "pwm_control.h"
//#include "connect_wifi.h"
#define True 1
#define False 0
#define ON 1
#define OFF 0
#define REMOTE_CONTROL 0x00
#define TRACKING_GP 0x01
#define TRACKING_MAZE 0x02
#define TRACKING_ZEBRA 0x03
typedef int flag;
typedef unsigned int uint;
typedef unsigned char uchar;
sbit IRIN = P3^2;
sbit ULTRASONIC_INT1 = P3^3;
#endif
#include "main.h"
// 定时器计数
static uint T0_CT = 0;
static uint T1_CT = 0;
static uint T2_CT = 0;
// 左右轮占空比,在需要时可以使用,目前保留待用(限T0)
uint t0_vue_left = 0;
uint t0_vue_right = 0;
// 延时设值
uint t1_vue = 0;
uint t2_vue = 0;
// 定时器1是否已经使用过一次,只有再次判到其他条件才能复位
flag is_timing_flag = False;
// 循迹模式:TRACKING_GP(默认)
flag flag_mod_tracking = REMOTE_CONTROL;
// 红外遥控事件,收到红外则处理
flag flag_infrared = OFF;
// 红外所需基本参数
uchar Time;
uchar IrValue[6];
// 控制占空比(可选)
/********************************************************************/
void set_speed(uint left, uint right)
{
t0_vue_left = left;
t0_vue_right = right;
}
// 维持占空比,维持(非调整)各电机运转速度(可选)
/********************************************************************/
void keep_motor_speed()
{
if (T0_CT >= 100)
T0_CT = 0;
if (T0_CT <= t0_vue_right)
RIGHT_ENA = ON;
else
RIGHT_ENA = OFF;
if (T0_CT <= t0_vue_left)
LEFT_ENB = ON;
else
LEFT_ENB = OFF;
}
// 不精准延时
/********************************************************************/
void delay(uint i)
{
while (i--)
;
}
// T2延时
/********************************************************************/
void delay_timer2(uint set_timing)
{
t2_vue = set_timing;
TR2 = ON;
while (TR2)
;
}
// 初始化定时器0(可选)
/********************************************************************/
void init_timer0()
{
TMOD |= 0x01;
ET0 = ON;
TH0 = 0xff;
TL0 = 0x9c;
}
// 初始化定时器1、2
/********************************************************************/
void init_timer()
{
TMOD |= 0x10;
RCLK = TCLK = 0;
CP_RL2 = EXEN2 = 0;
ET1 = ET2 = ON;
TH1 = TH2 = RCAP2H = 0xfc;
TL1 = TL2 = RCAP2L = 0x18;
//init_timer0(); //(可选)
}
// 外部中断0初始化
/********************************************************************/
void init_int0()
{
IT0 = 1;
EX0 = 1;
IRIN = 1;
}
// 外部中断1初始化
/********************************************************************/
void init_int1()
{
IT1 = 0;
EX1 = ON;
}
// WiFi控制模式(保留待用)
/********************************************************************/
void wifi_control()
{
// uchar tmp = P0 & 0x0f;
// switch (tmp)
// {
// case 0x0a: // IN1 = 0 IN2 = 1 IN3 = 0 IN4 = 1 向前 1010
// motor_go_straight();
// break;
//
// case 0x05: // IN1 = 1 IN2 = 0 IN3 = 1 IN4 = 0 向后 0101
// motor_back_reversal();
// break;
//
// case 0x09: // IN1 = 1 IN2 = 0 IN3 = 0 IN4 = 1 向左 1001
// motor_turn_left();
// break;
//
// case 0x06: // IN1 = 0 IN2 = 1 IN3 = 1 IN4 = 0 向右 0110
// motor_turn_right();
// break;
//
// case 0x00: // IN1 = 0 IN2 = 0 IN3 = 0 IN4 = 0 制动
// motor_stop();
// break;
//
// default:
// motor_stop();
// }
}
// 普通循迹
/********************************************************************/
void tracking_gp()
{
uchar tmp = P2 & 0x1f;
switch (tmp)
{
case 0x1f: // 11111 - 11111
case 0x18: // 11000 - 00011 TL
case 0x10: // 10000 - 00001 TL
if (is_timing_flag == OFF)
{
if (!TR1)
{
t1_vue = 500;
TR1 = ON;
}
}
if (TR1)
motor_turn_right();
else
motor_turn_left();
break;
case 0x03: // 00011 - 11000 TR
case 0x01: // 00001 - 10000 TR
motor_turn_right();
delay_timer2(320);
is_timing_flag = OFF;
break;
case 0x00: // 00000 - 00000 -
motor_go_straight();
delay_timer2(120);
motor_stop();
delay_timer2(1500);
motor_turn_right();
delay_timer2(450);
is_timing_flag = OFF;
break;
case 0x0f: // 01111 - 11110 →
case 0x07: // 00111 - 11100 CR
case 0x17: // 10111 - 11101 CR
motor_turn_right();
delay_timer2(20);
is_timing_flag = OFF;
break;
case 0x1e: // 11110 - 01111 ←
case 0x1d: // 11101 - 10111 CL
case 0x1c: // 11100 - 00111 CL
motor_turn_left();
delay_timer2(20);
is_timing_flag = OFF;
break;
case 0x1b: // 11011 - 11011 |
case 0x13: // 10011 - 11001 CR
case 0x19: // 11001 - 10011 CL
motor_go_straight();
is_timing_flag = OFF;
break;
case 0x0a: // 01010 - 01010 P
motor_stop();
break;
default:;
}
}
// 迷宫循迹
/********************************************************************/
void tracking_maze()
{
uchar tmp = P2 & 0x1f;
switch (tmp)
{
case 0x1f: // 11111 - 11111
case 0x18: // 11000 - 00011 TL
case 0x10: // 10000 - 00001 TL
if (is_timing_flag == OFF)
{
if (!TR1)
{
t1_vue = 460;
TR1 = ON;
}
}
if (TR1)
motor_turn_right();
else
motor_turn_left();
break;
case 0x03: // 00011 - 11000 TR
case 0x01: // 00001 - 10000 TR
motor_turn_right();
delay_timer2(300);
is_timing_flag = OFF;
break;
case 0x00: // 00000 - 00000 -
motor_turn_right();
delay_timer2(300);
is_timing_flag = OFF;
break;
case 0x0f: // 01111 - 11110 CR
case 0x07: // 00111 - 11100 CR
case 0x17: // 10111 - 11101 CR
motor_turn_right();
delay_timer2(20);
is_timing_flag = OFF;
break;
case 0x1e: // 11110 - 01111 CL
case 0x1d: // 11101 - 10111 CL
case 0x1c: // 11100 - 00111 CL
motor_turn_left();
delay_timer2(10);
is_timing_flag = OFF;
break;
case 0x1b: // 11011 - 11011 |
case 0x13: // 10011 - 11001 CR
case 0x19: // 11001 - 10011 CL
motor_go_straight();
is_timing_flag = OFF;
break;
case 0x0a: // 01010 - 01010 P
motor_stop();
break;
default:;
}
}
// 斑马线循迹
/********************************************************************/
void tracking_zebra()
{
uchar tmp = P2 & 0x1f;
switch (tmp)
{
case 0x1f: // 11111 - 11111
break;
case 0x1b: // 11011 - 11011 |
motor_go_straight();
is_timing_flag = OFF;
break;
case 0x07: // 00111 - 11100 CR
case 0x17: // 10111 - 11101 CR
case 0x0f: // 01111 - 11110 CR
motor_stop();
motor_turn_right();
delay_timer2(10);
break;
case 0x13: // 10011 - 11001 CR
case 0x15: // 10101 - 10101 |
case 0x0b: // 01011 - 11010 TR
case 0x03: // 00011 - 11000 TR
case 0x01: // 00001 - 10000 TR
motor_turn_right();
delay_timer2(420);
motor_stop();
break;
case 0x1c: // 11100 - 00111 CL
case 0x1d: // 11101 - 10111 CL
case 0x1e: // 11110 - 01111 CL
motor_stop();
motor_turn_left();
delay_timer2(10);
break;
case 0x19: // 11001 - 10011 CL
case 0x1a: // 11010 - 01011 TL
case 0x18: // 11000 - 00011 TL
case 0x10: // 10000 - 00001 TL
motor_turn_left();
delay_timer2(420);
motor_stop();
break;
/* 左转再右转 未实现*/
// case 0x0b: // 01011 - 11010 TR
// case 0x1a: // 11010 - 01011 TL
// case 0x15: // 10101 - 10101 TR then TL
// if (is_timing_flag == OFF)
// {
// if (!TR1)
// {
// t1_vue = 390;
// TR1 = ON;
// }
// }
// if (TR1)
// motor_turn_right();
// else
// motor_turn_left();
// break;
case 0x0a: // 01010 - 01010 P
motor_stop();
break;
default:
;
}
}
// INT0红外接收处理函数:切换模式、电机运动
/********************************************************************/
void process_infrared()
{
switch (IrValue[2] / 16)
{
case 0:
switch (IrValue[2] % 16)
{
case 7: // 0x07
// TL
if (flag_mod_tracking == REMOTE_CONTROL || flag_mod_tracking == TRACKING_ZEBRA)
motor_turn_left();
break;
case 8: // 0x08
// MOD: TRACKING_ZEBRA
motor_stop();
flag_mod_tracking = TRACKING_ZEBRA;
break;
case 9: // 0x09
// TR
if (flag_mod_tracking == REMOTE_CONTROL || flag_mod_tracking == TRACKING_ZEBRA)
motor_turn_right();
break;
case 12: // 0x0c
// MOD: REMOTE_CONTROL
motor_stop();
flag_mod_tracking = REMOTE_CONTROL;
break;
}
break;
case 1:
switch (IrValue[2] % 16)
{
case 5: // 0x15
// stop
motor_stop();
delay_timer2(2000);
break;
case 8: // 0x18
// MOD: TRACKING_GP
motor_stop();
flag_mod_tracking = TRACKING_GP;
break;
case 9: // 0x19
// back
if (flag_mod_tracking == REMOTE_CONTROL || flag_mod_tracking == TRACKING_ZEBRA)
motor_back_reversal();
break;
}
break;
case 4:
switch (IrValue[2] % 16)
{
case 0: // 0x40
// Go
if (flag_mod_tracking == REMOTE_CONTROL || flag_mod_tracking == TRACKING_ZEBRA)
motor_go_straight();
break;
case 5: // 0x45
// stop
motor_stop();
delay_timer2(2000);
break;
}
break;
case 5:
switch (IrValue[2] % 16)
{
case 14: // 0x5e
// MOD: TRACKING_MAZE
motor_stop();
flag_mod_tracking = TRACKING_MAZE;
break;
}
break;
}
flag_infrared = OFF;
}
// MAIN函数
/********************************** MAIN **********************************/
void main()
{
EA = 1;
init_int0();
init_int1();
init_timer();
init_motor();
set_speed(80, 80);
while (True)
{
/*需要时打开定时器控制占空比,可选*/
// if (flag_mod_tracking == TRACKING_ZEBRA)
// TR0 = ON;
// else
// TR0 = OFF;
if (flag_mod_tracking == REMOTE_CONTROL)
wifi_control();
else if (flag_mod_tracking == TRACKING_GP)
tracking_gp();
else if (flag_mod_tracking == TRACKING_MAZE)
tracking_maze();
else if (flag_mod_tracking == TRACKING_ZEBRA)
tracking_zebra();
if (flag_infrared)
process_infrared();
}
}
// 定时器0中断函数:控制占空比(可选)
/*------------------------------------------------------------------*/
void timer0() interrupt 1
{
TH0 = 0xff;
TL0 = 0x9c;
T0_CT ++;
keep_motor_speed();
}
// 定时器1中断函数:转向计数
/*------------------------------------------------------------------*/
void timer1() interrupt 3
{
TH1 = 0xfc;
TL1 = 0x18;
T1_CT++;
if (T1_CT == t1_vue)
{
T1_CT = t1_vue = 0;
is_timing_flag = ON;
TR1 = OFF;
}
}
// 定时器2中断函数:延时功能
/*------------------------------------------------------------------*/
void timer2() interrupt 5
{
TH2 = RCAP2H = 0xfc;
TL2 = RCAP2L = 0x18;
TF2 = 0;
T2_CT++;
if (T2_CT == t2_vue)
{
T2_CT = t2_vue = 0;
TR2 = OFF;
}
}
// 外部中断1中断函数:检测到超声波达标停止运动
/*------------------------------------------------------------------*/
void int1() interrupt 2
{
if (ULTRASONIC_INT1 == 0)
motor_stop();
}
// 外部中断0中断函数:控制模式、运作
/*------------------------------------------------------------------*/
void int0() interrupt 0
{
uchar j, k;
uint err;
Time = 0;
delay(700);
if (IRIN == 0)
{
err = 1000;
while ((IRIN == 0) && (err > 0))
{
delay(1);
err--;
}
if (IRIN == 1)
{
err = 500;
while ((IRIN == 1) && (err > 0))
{
delay(1);
err--;
}
for (k = 0; k < 4; k++)
{
for (j = 0; j < 8; j++)
{
err = 60;
while ((IRIN == 0) && (err > 0))
{
delay(1);
err--;
}
err = 500;
while ((IRIN == 1) && (err > 0))
{
delay(10);
Time++;
err--;
if (Time > 30)
{
return;
}
}
IrValue[k] >>= 1;
if (Time >= 8)
{
IrValue[k] |= 0x80;
}
Time = 0;
}
}
flag_infrared = ON;
}
if (IrValue[2] != ~IrValue[3])
{
return;
}
}
}
#ifndef __PWM_CONTROL_H__
#define __PWM_CONTROL_H__
#include
#include "main.h"
sbit RIGHT_IN1 = P1 ^ 0;
sbit RIGHT_IN2 = P1 ^ 1;
sbit LEFT_IN3 = P1 ^ 2;
sbit LEFT_IN4 = P1 ^ 3;
sbit LEFT_ENB = P1 ^ 4;
sbit RIGHT_ENA = P1 ^ 5;
void init_motor();
void motor_go_straight();
void motor_back_reversal();
void motor_stop();
void motor_turn_left();
void motor_turn_right();
#endif
#include "pwm_control.h"
#define ON 1
#define OFF 0
// 初始化电机函数
/********************************************************************/
void init_motor()
{
motor_stop();
LEFT_ENB = ON;
RIGHT_ENA = ON;
}
// 向前
/********************************************************************/
void motor_go_straight()
{
motor_stop();
LEFT_IN3 = 0;
LEFT_IN4 = 1;
RIGHT_IN1 = 0;
RIGHT_IN2 = 1;
}
// 向后
/********************************************************************/
void motor_back_reversal()
{
motor_stop();
LEFT_IN3 = 1;
LEFT_IN4 = 0;
RIGHT_IN1 = 1;
RIGHT_IN2 = 0;
}
// 制动
/********************************************************************/
void motor_stop()
{
LEFT_IN3 = 0;
LEFT_IN4 = 0;
RIGHT_IN1 = 0;
RIGHT_IN2 = 0;
}
// 左转
/********************************************************************/
void motor_turn_left()
{
motor_stop();
LEFT_IN3 = 1;
LEFT_IN4 = 0;
RIGHT_IN1 = 0;
RIGHT_IN2 = 1;
}
// 右转
/********************************************************************/
void motor_turn_right()
{
motor_stop();
LEFT_IN3 = 0;
LEFT_IN4 = 1;
RIGHT_IN1 = 1;
RIGHT_IN2 = 0;
}
这里仍然使用的是定时器2,需要可以自行更改为定时器0
#ifndef __CONNECT_WIFI_H__
#define __CONNECT_WIFI_H__
#include
#include
#include "pwm_control.h"
void init_uart();
void init_esp8266();
void send_char(unsigned char ch);
void send_string(unsigned char *str);
void send_msg(unsigned char msg[]);
void process_mcu_receive_data();
void delay_us();
void delay_s();
#endif
#include "connect_wifi.h"
unsigned char receive[50];
unsigned char sign = 0;
//初始化串口
/********************************************************************/
void init_uart()
{
PCON &= 0x7f;
SCON = 0x50;
T2CON = 0x34;
TH2 = RCAP2H = 0xff;
TL2 = RCAP2L = 0xdc;
TR2 = 1;
ES = 1;
}
// 初始化ESP8266,设置AP模式
/********************************************************************/
void init_esp8266()
{
init_uart();
delay_s();
send_string("AT+CWMODE=2\r\n");
delay_us();
send_string("AT+CIPMUX=1\r\n");
delay_us();
send_string("AT+CIPSERVER=1,8086\r\n");
}
// 发送位数据
/********************************************************************/
void send_char(unsigned char ch)
{
SBUF = ch;
while (TI == 0)
;
TI = 0;
}
// 发送字节数据
/********************************************************************/
void send_string(unsigned char *str)
{
while (*str != '\0')
{
send_char(*str);
str++;
}
}
// 透传发送消息
/********************************************************************/
void send_msg(unsigned char msg[])
{
unsigned int i;
char cmd[] = "AT+CIPSEND=0,1\r\n";
cmd[11] = i + '0';
send_string(cmd);
delay_us();
send_string(msg);
delay_us();
// for (i = 0; i < 5; i++)
// {
// cmd[11] = i + '0';
// send_string(cmd);
// delay_us();
// send_string(msg);
// delay_us();
// }
memset(receive, 0, 50);
}
// 单片机接收数据处理
/********************************************************************/
void process_mcu_receive_data()
{
switch (receive[0])
{
case '0':
send_msg("0x00");
motor_stop();
break;
case '1':
motor_turn_left();
send_msg("0x01");
break;
case '2':
motor_turn_right();
send_msg("0x02");
break;
case '3':
motor_go_straight();
send_msg("0x03");
break;
case '4':
motor_back_reversal();
send_msg("0x04");
break;
case '5':
motor_stop();
send_msg("0x05");
break;
}
}
// 串口中断,此程序只把+IPD,x,x:后的有用数据存进receive数组里
/********************************************************************/
void uart() interrupt 4
{
if (RI)
{
RI = 0;
if (sign == 1)
{
receive[0] = SBUF;
sign = 0; //保存receive[0]的数据
}
if (SBUF == ':')
sign = 1;
}
process_mcu_receive_data();
}
// 短延时
/********************************************************************/
void delay_us()
{
unsigned char count = 1000;
while (count--)
;
}
// 长延时
/********************************************************************/
void delay_s()
{
unsigned char a, b, c, d;
for (a = 5; a > 0; a--)
for (b = 4; b > 0; b--)
for (c = 116; c > 0; c--)
for (d = 214; d > 0; d--)
;
}
已知:检测到黑线,循迹模块输出低电平给LPC
假设:小车前进方向左侧检测到黑线,为01111↑,根据接线方式,得到的BIN应该是xxx11110↓,那么得到的HEX为0x1E。
下面均基于小车前进方向进行阐述,主要讲解迷宫循迹,因为虚线循迹还不是很完善,有20%的概率出错。普通循迹和迷宫循迹只有5%的概率。
is_timing_flag = OFF;
ULTRASONIC_INT
置0,引发下位机的外部中断。下面是部分代码:
uchar Duty_left,Duty_right,j=0,i=0,k=0,h=0,g=0,flag=0;t=0,m=0,n=0,f=0,v=0;
uint_16 hwdate=0x00;
void ting(){
IN1=0;
IN2=0;
IN3=0;
IN4=0;
}
//向左矫正(用于left2检测到黑线)
void correct_left()
{
Duty_left=40;
Duty_right=15;
IN1=1;
IN2=0;
IN3=1;
IN4=0;
}
//向右校正(用于right4检测到黑线)
void correct_right()
{
Duty_left=15;
Duty_right=40;
IN1=1;
IN2=0;
IN3=1;
IN4=0;
}
//小车左转赋值(用于left1检测到黑线)
void Left_turning()
{
Duty_left=50;
Duty_right=50;
IN1=1;
IN2=0;
IN3=0;
IN4=1;
}
//小车右转赋值(用于right5检测到黑线)
void Right_turning()
{
Duty_left=50;
Duty_right=50;
IN1=0; //转弯时一个正转一个反转
IN2=1;
IN3=1;
IN4=0;
}
//小车左转赋值(用于left1检测到黑线)
void Left_turning1()
{
Duty_left=42;
Duty_right=42;
IN1=1;
IN2=0;
IN3=0;
IN4=1;
}
//小车右转赋值(用于right5检测到黑线)
void Right_turning1()
{
Duty_left=42;
Duty_right=42;
IN1=0; //转弯时一个正转一个反转
IN2=1;
IN3=1;
IN4=0;
}
//小车直走前行,不拐弯速度赋值
void forward_move()
{
Duty_left=40;
Duty_right=40;
IN1=1;
IN2=0;
IN3=1;
IN4=0;
}
//小车直走前行,不拐弯速度赋值
void forward_move1()
{
Duty_left=27;
Duty_right=35;
IN1=1;
IN2=0;
IN3=1;
IN4=0;
}
//小车后退
void houtui(){
Duty_left=15;
Duty_right=45;
IN1=0;
IN2=1;
IN3=0;
IN4=1;
}
void detect_infrared2(){
hwdate = P2 & 0x1F; //读取循迹的值
switch(hwdate)
{
case 0x1b: //11011 直走
forward_move1();
t=1;
break;
case 0x1d: //11101 向右矫正
Right_turning();v=1;
break;
case 0x17: //10111 向左矫正
Left_turning();f=1;
break;
case 0x0f:
Left_turning();m=1;
break;
case 0x1e:
Right_turning();n=1;
break;
//左直角 //00011 00111 01011 10011
case 0x03:
case 0x07:
case 0x13:
case 0x0b:
case 0x01:
h=1;
Left_turning();
delay_timer1(150);
break;
//右直角 //11000 11100 11010 11110 11001
case 0x18:
case 0x1c:
case 0x1a:
case 0x10:
case 0x19:
k=1;
Right_turning();
delay_timer1(150);
break;
case 0x09:
Left_turning();delay_timer1(50);
break;
//11111
case 0x1f:
if(k==1) {
Right_turning();
k=0;t=0;
}
else if (h==1){
Left_turning();
h=0;t=0;
}
else if(f==1){
Left_turning();
f=0;t=0;
}
else if(m==1){
Left_turning();
m=0;t=0;
}
else if(n==1){
Right_turning();
n=0; t=0;
}
else if(v==1){
Right_turning();
v=0;t=0;
}
else if(t==1)
{
flag++;
if(flag>20){
// Left_turning();
houtui();
flag=0;t=0;
}
delay(1500);
}
break;
case 0x0A: ting();delay_timer1(5000);
break;
}
}
总结就是没总结,其实虚线循迹还是有点问题的,遇到直角的时候速度太快会转不过来,另外就是WiFi模块加进去还没弄好,在备份代码里面是好的,但移植到决赛代码里面就出了BUG,单独使用没问题。
其他的,等我想到先再补充吧。
这些是我初赛用的代码,还有一些其他东西,各种奇奇怪怪的,反正都是之前写的代码。
本来想上传文件的,但有点懒,还是算了,反正也不是重点。
初赛用到了占空比:main.c
#include "main.h"
uint t2_vue = 0; // 定时器2延时值
static uint T0_CT = 0;
flag flag_is_timing0 = False; // 判断定时器0是否使用过一次,需手动置False
flag motor_statu = ON; // 电机状态
uint left_time = 60;
uint right_time = 60;
// 定时器2延时
/********************************************************************/
void delay_timer2(uint set_timing)
{
t2_vue = set_timing;
TR2 = ON;
while (TR2)
;
}
// 初始化定时器0、2
/********************************************************************/
void init_timer()
{
TMOD |= 0x01;
RCLK = TCLK = 0;
CP_RL2 = EXEN2 = 0;
ET0 = ET2 = ON;
TH0 = 0xff;
TL0 = 0xf7;
TH2 = RCAP2H = 0xfc;
TL2 = RCAP2L = 0x18;
TR0 = ON;
}
// 循迹
/********************************************************************/
void tracking()
{
uchar tmp = P2 & 0x1f;
switch (tmp)
{
case 0x1f: // 11111 - 11111
break;
case 0x18: // 11000 - 00011 TL
case 0x14: // 10100 - 00101 V
case 0x10: // 10000 - 00001 TL
case 0x03: // 00011 - 11000 TR
case 0x01: // 00001 - 10000 TR
case 0x0e: // 01110 - 01110 V
case 0x05: // 00101 - 10100 V
case 0x00: // 00000 - 00000 -
case 0x1b: // 11011 - 11011 |
case 0x17: // 10111 - 11101 CR
case 0x1d: // 11101 - 10111 CL
case 0x0f: // 01111 - 11110 CR
case 0x07: // 00111 - 11100 CR
case 0x13: // 10011 - 11001 CR
case 0x1e: // 11110 - 01111 CL
case 0x1c: // 11100 - 00111 CL
case 0x19: // 11001 - 10011 CL
case 0x0a: // 01010 - 01010 P
default:
;
}
}
// 主函数
/*##################################################################*/
void main()
{
EA = 1;
init_esp8266();
init_motor();
init_timer();
while (True)
{
}
}
// 定时器0中断:控制占空比
/*------------------------------------------------------------------*/
void Timer0() interrupt 1
{static uint T0_CT = 0;
TR0 = OFF;
TH0=0xff;
TL0=0xf7;
T0_CT ++;
// tracking();
if (T0_CT >= 100)
T0_CT = 0;
// if (T0_CT <= left_time)
// RIGHT_ENA = ON;
// else
// RIGHT_ENA = OFF;
// if (T0_CT <= right_time)
// LEFT_ENB = ON;
// else
// LEFT_ENB = OFF;
TR0 = ON;
}
// 定时器2中断:延时功能
/*------------------------------------------------------------------*/
void Timer2() interrupt 5
{
static uint T2_CT = 0;
TH2 = RCAP2H = 0xfc;
TL2 = RCAP2L = 0x18;
TF2 = 0;
T2_CT ++;
if (T2_CT == t2_vue)
{
T2_CT = 0;
t2_vue = 0;
TR2 = OFF;
}
}
其实这些没什么,只是希望大家能多注意备份,因为很多我之前能跑的代码,改着改着就动都不动了
最后,大家加油,奥里给!!