51单片机之智能小车(避障、跟随、循迹)

2023-05-16

目录

基本概述

硬件组成

功能

关键字

模块介绍

电机模块L9110S

循迹模块(TCRT5000传感器)

红外避障模块

测速模块 

小车 

移动小车(控制电机转动,使小车前进、后退、左转、右转 )

遥控小车( 使用蓝牙模块,通过串口发送信息控制小车移动)

调速小车(利用PWM波对电机进行调速)

循迹小车 (利用循迹模块进行黑白色的检测)

跟随小车(利用红外避障模块完成跟随行为)

避障小车(利用超声波测距完成避障行为)

测速小车,使用OLED屏显示小车速度

语音控制小车,循迹、跟随、避障三种功能切换

 

基本概述

硬件组成

电机模块L9110S、循迹模块、红外避障模块、超声波模块、测速模块、OLED屏、蓝牙模块、4G,模块、语音模块SU-03T

功能

蓝牙控制小车、WiFi控制小车、4G控制小车、小车的避障、跟随、循迹

关键字

单片机中一般都有两块存储区域,ROM和RAM,程序代码存储在ROM中,程序要用的变量存储在RAM中。而“code”的作用就是将其修饰过的变量存储在ROM中而非RAM。 在单片机中,RAM空间都比较小,是比较宝贵的,当存放在RAM中的数据过多时,会导致编译不成功。

  • exturn:使用exturn关键字修饰的全局变量或函数,作用域不再局限本文件,其他文件同样能访问到这些变量或函数,跟static关键字恰恰相反。
  • code:使用code关键字修饰的变量(一般是初始化后,值保持不变的变量)后会被存放到ROM区,从而节省RAM的空间。

模块介绍

电机模块L9110S

aa5cb1e961d8406699bf75655fa90f4b.png

L0110S模块的A、B分别控制着两个电机,如果需要控制四个电机,则需要两个L0110S模块

  • 当B-1A为高电平,B-2A为低电平时,电机反转或正转
  • 当B-1A为低电平,B-2A为高电平时,电机正转反转
  • 当B-1A为低电平,B-2A为低电平时,电机不转
  • 电机的正转和反转与跟电机的接线不同而不同,注意自己调试

循迹模块(TCRT5000传感器)

de5641f570fd4adba541c272a8063677.png

  • 当发射出的红外线没有被反射回来或被反射回来但强度不够大时,DO输出高电平,灯灭。 黑色吸收红外线,DO输出高电平,灯亮
  • 当发射出的红外线被反射回来或被反射回来且强度足够大,DO输出低电平,灯亮。 白色反射红外线,DO输出低电平,灯亮
  • 即黑色输出高电平,灯灭,白色输出低电平,灯亮

红外避障模块

6265a10e74644db7b3c133fa870458c8.png

  • 当发射出的红外线没有被反射回来或被反射回来但强度不够大时,DO输出高电平,灯灭。没有障碍物
  • 当发射出的红外线被反射回来,DO输出低电平,灯亮。有障碍物
  • 即有障碍物输出低电平,灯亮,没有障碍物输出高电平,灯灭

测速模块 

0877a6d59b6b4a61a22d38b3c0c7b352.png

  • 发射的红外线被物体遮挡时,输出高电平,发射的红外线没被物体遮挡时,输出低电平
  • 有物体高电平,没物体低电平
  • 当搭配小车测速盘,会形成下降沿(有遮挡高电平,没遮挡低电平)

小车 

移动小车(控制电机转动,使小车前进、后退、左转、右转 

#include "reg52.h"
#include <intrins.h>

sbit left_con1A = P1^1;
sbit left_con2A = P1^2;
sbit right_con1A = P1^3;
sbit right_con2A = P1^4;

void Delay2000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 15;
	j = 2;
	k = 235;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

//两个电机反转,前进
void goForward()
{
	left_con1A = 1;
	left_con2A = 0;
	
	right_con1A = 1;	
	right_con2A = 0;
}

//两个电机正转,后退
void goBack()
{
	left_con1A = 0;
	left_con2A = 1;
	
	right_con1A = 0;	
	right_con2A = 1;
}

//两个电机不转,停止
void goStop()
{
	left_con1A = 0;
	left_con2A = 0;
	
	right_con1A = 0;	
	right_con2A = 0;
}

//左电机不转,右电机反转,左转
void goLeft()
{
	left_con1A = 0;
	left_con2A = 0;
	
	right_con1A = 1;	
	right_con2A = 0;
}

//左电机反转,右电机不转,右转
void goRight()
{
	left_con1A = 1;
	left_con2A = 0;

	right_con1A = 0;	
	right_con2A = 0;
}

void main()
{
	while(1){
		goForward();
		Delay2000ms();
		goBack();
		Delay2000ms();
		goLeft();
		Delay2000ms();
		goRight();
		Delay2000ms();
		goStop();
		Delay2000ms();
	}
}

遥控小车( 使用蓝牙模块,通过串口发送信息控制小车移动)

#include "reg52.h"
#include <intrins.h>
#include <string.h>

sfr AUXR = 0x8E;

sbit left_con1A = P1^1;
sbit left_con2A = P1^2;
sbit right_con1A = P1^3;
sbit right_con2A = P1^4;
sbit led1 = P3^7;
char mybuf[24] ;
 
void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;
 
	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
 
void uartInit()
{
	AUXR = 0x01;
	PCON &= 0x7F;  //配置波特率正常
	SCON = 0x50;  //配置串口选择工作方式1,允许串口接收数据
	
	//配置定时器1为8位自动重装模式
	TMOD &= 0x0F;
	TMOD |= 0x20;
	
	//给定时器1,9600波特率初值
	TH1 = 0xFD;  //定时器1初值
	TL1 = 0xFD;  //定时器1重装值
 
	ET1 = 0;  //不允许定时器1产生中断
	TR1 = 1;  //开启定时器1
 
	EA = 1;  //开启总中断
	ES = 1;  //开启串口中断
 
}
 
void sendByte(char mydata)
{
	SBUF = mydata;  //向串口发送一帧信息
	while(!TI);  //等待硬件置位
	TI = 0;  //TI软件清0 
}
 
void sendString(char *str)
{
	while(*str != '\0'){
		sendByte(*str);
		str++;
	}
}

//两个电机反转,前进
void goForward()
{
	left_con1A = 1;
	left_con2A = 0;
	
	right_con1A = 1;	
	right_con2A = 0;
}

//两个电机正转,后退
void goBack()
{
	left_con1A = 0;
	left_con2A = 1;
	
	right_con1A = 0;	
	right_con2A = 1;
}

//两个电机不转,停止
void goStop()
{
	left_con1A = 0;
	left_con2A = 0;
	
	right_con1A = 0;	
	right_con2A = 0;
}

//左电机不转,右电机反转,左转
void goLeft()
{
	left_con1A = 0;
	left_con2A = 0;
	
	right_con1A = 1;	
	right_con2A = 0;
}

//左电机反转,右电机不转,右转
void goRight()
{
	left_con1A = 1;
	left_con2A = 0;

	right_con1A = 0;	
	right_con2A = 0;
}

void main()
{
	uartInit();
	while(1){
		sendString("jiangxiaoya\r\n");  //发送心跳包,确保串口通信没有中断
		Delay1000ms();
	}
}
 

void myUart() interrupt 4
{
	static int i = 0;
	char tmp;
 
	//接收数据后,RI硬件置位产生的中断
	if(RI){
		RI = 0;  //RI软件清0
		//获取从pc端接收到的数据
		tmp = SBUF;
 
		if(tmp == 'f' || tmp == 'b' || tmp == 'l' || tmp == 'r' || tmp == 's'){
			i = 0;
		}
		mybuf[i] = tmp;
		i++;
 
		//forward
		if(mybuf[0] == 'f' && mybuf[1] == 'o'){
			goForward();
			memset(mybuf,'\0',24);
		}
 
		//forward
		if(mybuf[0] == 'b' && mybuf[1] == 'a'){
			goBack();
			memset(mybuf,'\0',24);
		}
 
		//left
		if(mybuf[0] == 'l' && mybuf[1] == 'e'){
			goLeft();
			memset(mybuf,'\0',24);
		}
		//right
		if(mybuf[0] == 'r' && mybuf[1] == 'i'){
			goRight();
			memset(mybuf,'\0',24);
		}
 
		//stop
		if(mybuf[0] == 's' && mybuf[1] == 't'){
			goStop();
			memset(mybuf,'\0',24);
		}
 
		if(i == 24){
			i = 0;
		}
 
	}
 
	//发送数据后,TI硬件置位产生的中断
	if(TI);  
}

调速小车(利用PWM波对电机进行调速)

  • 利用定时器0软件模拟PWM波控制小车左轮速度,定时器1软件模拟PWM波控制小车右轮速度,通过控制轮子的速度来达到前进、停止、左转、右转
  • 在20ms的过程中,部分时间让电机正转,剩下时间让电机停止不动就能改变电机获得的功率,从而改变电机速度。
#include "reg52.h"
#include <intrins.h>
#include <string.h>

sfr AUXR = 0x8E;

sbit left_con1A = P1^1;
sbit left_con2A = P1^2;
sbit right_con1A = P1^3;
sbit right_con2A = P1^4;
sbit led1 = P3^7;

char mybuf[24] ;
char leftSpeed;
char rightSpeed;
int cntLeft = 0;
int cntRight = 0;

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;
 
	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
 
//左电机反转
void goLeftForward()
{
	left_con1A = 1;
	left_con2A = 0;
}

//左电机不转
void goLeftStop()
{
	left_con1A = 0;
	left_con2A = 0;
}

//右电机反转
void goRightForward()
{
	right_con1A = 1;	
	right_con2A = 0;
}

//右电机不转
void goRightStop()
{
	right_con1A = 0;	
	right_con2A = 0;
}

//前进
void goForward()
{
	leftSpeed = 18;
	rightSpeed = 20;
}

//停止
void goStop()
{
	leftSpeed = 0;
	rightSpeed = 0;
}

//左转
void goLeft()
{
	leftSpeed = 10;
	rightSpeed = 20;
}

//右转
void goRight()
{
	leftSpeed = 20;
	rightSpeed = 10;
}

void Timer0Init(void)		//1毫秒@11.0592MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	//定时器初值为1ms
	TL0 = 0x66;		
	TH0 = 0xFC;		
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA  = 1;
}

void Timer1Init(void)		//1毫秒@11.0592MHz
{
	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	//定时器初值为1ms
	TL1 = 0xCD;		
	TH1 = 0xD4;		
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	ET1 = 1;
	EA  = 1;
}

void main()
{
	Timer0Init();
	Timer1Init();
	while(1){
		Delay1000ms();
		goForward();
		Delay1000ms();
		goLeft();
		Delay1000ms();
		goRight();
	}
}
 
//定时器0的中断函数
void Time0Handler() interrupt 1
{
	cntLeft++;
	TL0 = 0x66;		
	TH0 = 0xFC;
	if(cntLeft < leftSpeed)
	{
		goLeftForward();
	}else{
		goLeftStop();
	}
	if(cntLeft == 20){
		cntLeft = 0;
	}
}

void Time1Handler() interrupt 3
{
	cntRight++;
	TL1 = 0x66;		
	TH1 = 0xFC;
	if(cntRight < rightSpeed)
	{
		goRightForward();
	}else{
		goRightStop();
	}
	if(cntRight == 20){
		cntRight = 0;
	}
}

循迹小车 (利用循迹模块进行黑白色的检测)

#include "reg52.h"
#include <intrins.h>
#include <string.h>

sfr AUXR = 0x8E;

sbit left_con1A = P1^1;
sbit left_con2A = P1^2;
sbit right_con1A = P1^3;
sbit right_con2A = P1^4;
sbit tracingLeft = P1^5;
sbit tracingRight = P1^6;

char leftSpeed;
char rightSpeed;
int cntLeft = 0;
int cntRight = 0;

//左电机反转
void goLeftForward()
{
	left_con1A = 1;
	left_con2A = 0;
}

//左电机不转
void goLeftStop()
{
	left_con1A = 0;
	left_con2A = 0;
}

//右电机反转
void goRightForward()
{
	right_con1A = 1;	
	right_con2A = 0;
}

//右电机不转
void goRightStop()
{
	right_con1A = 0;	
	right_con2A = 0;
}

//前进
void goForward()
{
	leftSpeed = 17;
	rightSpeed = 20;
}

//停止
void goStop()
{
	leftSpeed = 0;
	rightSpeed = 0;
}

//左转
void goLeft()
{
	leftSpeed = 5;
	rightSpeed = 20;
}

//右转
void goRight()
{
	leftSpeed = 20;
	rightSpeed = 5;
}

void Timer0Init(void)		//1毫秒@11.0592MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	//定时器初值为1ms
	TL0 = 0x66;		
	TH0 = 0xFC;		
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA  = 1;
}

void Timer1Init(void)		//1毫秒@11.0592MHz
{
	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	//定时器初值为1ms
	TL1 = 0xCD;		
	TH1 = 0xD4;		
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	ET1 = 1;
	EA  = 1;
}

void tracingMode()
{	
	if(tracingLeft == 0 && tracingRight == 0){  //
		goForward();
	}

	if(tracingLeft == 0 && tracingRight == 1){
		goRight();
	}

	if(tracingLeft == 1 && tracingRight == 0){
		goLeft();
	}

	if(tracingLeft == 1 && tracingRight == 1){
		goStop();
	}
}

void main()
{
	Timer0Init();
	Timer1Init();
	while(1){
		tracingMode();
	}
}
 
//定时器0的中断函数
void Time0Handler() interrupt 1
{
	cntLeft++;
	TL0 = 0x66;		
	TH0 = 0xFC;
	if(cntLeft < leftSpeed)
	{
		goLeftForward();
	}else{
		goLeftStop();
	}
	if(cntLeft == 20){
		cntLeft = 0;
	}
}

void Time1Handler() interrupt 3
{
	cntRight++;
	TL1 = 0x66;		
	TH1 = 0xFC;
	if(cntRight < rightSpeed)
	{
		goRightForward();
	}else{
		goRightStop();
	}
	if(cntRight == 20){
		cntRight = 0;
	}
}

跟随小车(利用红外避障模块完成跟随行为)

#include "reg52.h"
#include <intrins.h>
#include <string.h>

sfr AUXR = 0x8E;

sbit left_con1A = P1^1;
sbit left_con2A = P1^2;
sbit right_con1A = P1^3;
sbit right_con2A = P1^4;
sbit followLeft = P2^1;
sbit followRight = P2^2;

char leftSpeed;
char rightSpeed;
int cntLeft = 0;
int cntRight = 0;

//左电机反转
void goLeftForward()
{
	left_con1A = 1;
	left_con2A = 0;
}

//左电机不转
void goLeftStop()
{
	left_con1A = 0;
	left_con2A = 0;
}

//右电机反转
void goRightForward()
{
	right_con1A = 1;	
	right_con2A = 0;
}

//右电机不转
void goRightStop()
{
	right_con1A = 0;	
	right_con2A = 0;
}

//前进
void goForward()
{
	leftSpeed = 17;
	rightSpeed = 20;
}

//停止
void goStop()
{
	leftSpeed = 0;
	rightSpeed = 0;
}

//左转
void goLeft()
{
	leftSpeed = 8;
	rightSpeed = 20;
}

//右转
void goRight()
{
	leftSpeed = 20;
	rightSpeed = 10;
}

void Timer0Init(void)		//1毫秒@11.0592MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	//定时器初值为1ms
	TL0 = 0x66;		
	TH0 = 0xFC;		
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;
	EA  = 1;
}

void Timer1Init(void)		//1毫秒@11.0592MHz
{
	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x10;		//设置定时器模式
	//定时器初值为1ms
	TL1 = 0xCD;		
	TH1 = 0xD4;		
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	ET1 = 1;
	EA  = 1;
}

void followMode()
{	
	if(followLeft == 0 && followRight == 0){  //
		goForward();
	}

	if(followLeft == 0 && followRight == 1){
		goRight();
	}

	if(followLeft == 1 && followRight == 0){
		goLeft();
	}

	if(followLeft == 1 && followRight == 1){
		goStop();
	}
}

void main()
{
	Timer0Init();
	Timer1Init();
	while(1){
		followMode();
	}
}
 
//定时器0的中断函数
void Time0Handler() interrupt 1
{
	cntLeft++;
	TL0 = 0x66;		
	TH0 = 0xFC;
	if(cntLeft < leftSpeed)
	{
		goLeftForward();
	}else{
		goLeftStop();
	}
	if(cntLeft == 20){
		cntLeft = 0;
	}
}

void Time1Handler() interrupt 3
{
	cntRight++;
	TL1 = 0x66;		
	TH1 = 0xFC;
	if(cntRight < rightSpeed)
	{
		goRightForward();
	}else{
		goRightStop();
	}
	if(cntRight == 20){
		cntRight = 0;
	}
}

避障小车(利用超声波测距完成避障行为)

  • 利用定时器0软件模拟PWM波控制sg90舵机转动方向
  • 利用定时器1和超声波不断测量前方距离
#include "reg52.h"
#include <intrins.h>

sbit left_con1A = P1^1;
sbit left_con2A = P1^2;
sbit right_con1A = P1^3;
sbit right_con2A = P1^4;
sbit Trig = P2^3;
sbit Echo = P2^4;
sbit sg90 = P2^5;

int angle;
int angleBack;
int cnt = 0;

void Delay100ms()		//@11.0592MHz
{
	unsigned char i, j;
 
	i = 180;
	j = 73;
	do
	{
		while (--j);
	} while (--i);
}

void Delay300ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 3;
	j = 26;
	k = 223;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Delay500ms()		//@11.0592MHz
{
	unsigned char i, j, k;
 
	_nop_();
	i = 4;
	j = 129;
	k = 119;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
 
void Delay10us()		//@11.0592MHz
{
	unsigned char i;
 
	i = 2;
	while (--i);
}

//两个电机反转,前进
void goForward()
{
	left_con1A = 1;
	left_con2A = 0;
	
	right_con1A = 1;	
	right_con2A = 0;
}

//两个电机正转,后退
void goBack()
{
	left_con1A = 0;
	left_con2A = 1;
	
	right_con1A = 0;	
	right_con2A = 1;
}

//两个电机不转,停止
void goStop()
{
	left_con1A = 0;
	left_con2A = 0;
	
	right_con1A = 0;	
	right_con2A = 0;
}

//左电机不转,右电机反转,左转
void goLeft()
{
	left_con1A = 0;
	left_con2A = 0;
	
	right_con1A = 1;	
	right_con2A = 0;
}

//左电机反转,右电机不转,右转
void goRight()
{
	left_con1A = 1;
	left_con2A = 0;

	right_con1A = 0;	
	right_con2A = 0;
}

void timer0Init()
{
	//设置定时器0为16为计时模式
	TMOD &=0xF0; 
	TMOD |=0x01; 
 
	//设置定时器0定时时间为0.5ms
	TH0 = 0xFE;
	TL0 = 0x33;
 
	TR0 = 1;  //定时器0开始计时
	TF0 = 0;  //不执行定时器0爆表时导致的中断
 
	ET0 = 1;  //定时器0中断开关
	EA = 1;  //总中断开关
}
 
void timer1Init()
{	
	//设置定时器1为16为计时模式
	TMOD &= 0x0F;
	TMOD |= 0x10;  
 
	TH1 = 0x00;
	TL1 = 0x00;
}

void ultrasonicStart()
{
	Trig = 0;
	Trig = 1;
	Delay10us();
	Trig = 0; 
}

double getDistance()
{
	double time = 0;
	
	//定时器1清0
	TH1 = 0x00;
	TL1 = 0x00;
 
	ultrasonicStart();
		
	while(Echo == 0);  //当Echo引脚从低电平跳到高电平时开启定时器1
	TR1 = 1;
		
	while(Echo == 1);  //当Echo引脚从高电平跳到低电平时关闭定时器1
	TR1 = 0;
 
	time = (TH1*256 + TL1) * 1.085;  //微秒
 
	return (time * 0.017);
}

void sg90Left()
{
	angle = 5;  //180°
	if(angleBack != angle){  
		cnt = 0;
	}
	angleBack = angle;
	Delay100ms();
} 

void sg90Middle()
{
	angle = 3;  //90°
	if(angleBack != angle){  
		cnt = 0;
	}
	angleBack = angle;
	Delay100ms();
} 

void sg90Right()
{
	angle = 1;  //0°
	if(angleBack != angle){  
		cnt = 0;
	}
	angleBack = angle;
	Delay100ms();
} 

void main()
{
	double leftDistance;
	double rightDistance;
	double middleDistance;

	timer0Init();
	timer1Init();
	
	sg90Middle();
	Delay500ms();

	while(1){
		sg90Middle();
		Delay300ms();
		middleDistance = getDistance();
		if(middleDistance > 35){
			goForward();
		}else{
			goStop();

			sg90Left();
			Delay300ms();
			leftDistance = getDistance();

			sg90Middle();
			Delay300ms();

			sg90Right();
			Delay300ms();
			rightDistance = getDistance();

			if(leftDistance < 15 && rightDistance < 15){
				goBack();
				Delay500ms();
				goStop();
			}else{

				if(leftDistance > rightDistance){
					goLeft();
					Delay500ms();
					goStop();
				}

				if(rightDistance > leftDistance){
					goRight();
					Delay500ms();
					goStop();
				}
			}
		}
	}
}

//定时器0的中断函数
void Time0Handler() interrupt 1
{
	
	TH0 = 0xFE;
	TL0 = 0x33;
	cnt++;
	//控制占空比
	if(cnt < angle){
		sg90 = 1;
	}else{
		sg90 = 0;
	}
 
	if(cnt == 40){  //每个周期为20ms
		cnt = 0;
		sg90 = 1;
	}
}

测速小车,使用OLED屏显示小车速度

  • 轮子走一圈,经过一个周长,C = 2x3.14x半径= 3.14 x 直径(6.5cm),对应的转速码盘也转了一圈
  • 码盘有20个格子,每经过一个格子,会遮挡(高电平)和不遮挡(低电平),即产生下降沿,一个下降沿就是走了 3.14 * 6.5 cm /20 = 1.0205CM
  • 定时器可以设计成一秒,统计下降沿,一个下降沿就是1cm,假设一秒有80脉冲,那么就是80cm/s
#include "reg52.h"
#include <intrins.h>
#include <string.h>
#include <stdio.h>

sfr AUXR = 0x8E;

sbit left_con1A = P1^1;
sbit left_con2A = P1^2;
sbit right_con1A = P1^3;
sbit right_con2A = P1^4;
sbit Tachometer = P3^2;  //测速模块产生下降沿,让外部中断0产生中断
sbit scl = P2^6;
sbit sda = P2^7;

char mybuf[24];

int signal;  
unsigned int cnt;
unsigned int speedCnt = 0;
unsigned int speed;
char speedMsg[24];

void Delay5us()		//@11.0592MHz
{
}
 
//两个电机反转,前进
void goForward()
{
	left_con1A = 1;
	left_con2A = 0;
	
	right_con1A = 1;	
	right_con2A = 0;
}

//两个电机正转,后退
void goBack()
{
	left_con1A = 0;
	left_con2A = 1;
	
	right_con1A = 0;	
	right_con2A = 1;
}

//两个电机不转,停止
void goStop()
{
	left_con1A = 0;
	left_con2A = 0;
	
	right_con1A = 0;	
	right_con2A = 0;
}

//左电机不转,右电机反转,左转
void goLeft()
{
	left_con1A = 0;
	left_con2A = 0;
	
	right_con1A = 1;	
	right_con2A = 0;
}

//左电机反转,右电机不转,右转
void goRight()
{
	left_con1A = 1;
	left_con2A = 0;

	right_con1A = 0;	
	right_con2A = 0;
}

//串口初始化
void uartInit()
{
	AUXR = 0x01;
	PCON &= 0x7F;  //配置波特率正常
	SCON = 0x50;  //配置串口选择工作方式1,允许串口接收数据
	
	//配置定时器1为8位自动重装模式
	TMOD &= 0x0F;
	TMOD |= 0x20;
	
	//给定时器1,9600波特率初值
	TH1 = 0xFD;  //定时器1初值
	TL1 = 0xFD;  //定时器1重装值
 
	ET1 = 0;  //不允许定时器1产生中断
	TR1 = 1;  //开启定时器1
 
	EA = 1;  //开启总中断
	ES = 1;  //开启串口中断
 
}

//定时器0初始化,初值为1ms
void Time0Init()
{
	TMOD &=0xF0; 
	TMOD |=0x01;
	//1ms
	TL0 = 0x66;		
	TH0 = 0xFC;
	TR0 = 1;
	ET0 = 1;
	EA  =1;
}

//外部中断0初始化
void int0Init()
{
	EX0 = 1;
	EA = 1;
	IT0 = 1;  //下降沿触发外部中断0
}

//IIC起始信号
void IIC_start()
{
	sda = 0;
	scl = 1;
	sda = 1;
	Delay5us();
	sda = 0;
	Delay5us();
	scl = 0;
}
 
//IIC终止信号
void IIC_stop()
{
	scl = 0;
	sda = 0;
	scl = 1;
	Delay5us();
	sda = 1;
	Delay5us();
	sda = 0;
}
 
//IIC的ACK应答信号
char IIC_ack()
{
	char flag;
 
	scl = 0;
	sda = 1;  //在时钟脉冲9期间释放数据线
	Delay5us();  //延时5微秒后,为读取sda数据做准备
 
	scl = 1;  
	Delay5us();  
	flag = sda;  //读取数据线,0为应答
	Delay5us();  
	
	scl = 0;
	Delay5us();
	return flag;
}
 
//IIC发送一个字节
void IIC_sendByte(char myData)
{
	int i;
	for ( i = 0; i < 8; i++){
		//发生数据翻转,选择即将发送的是0还是1
		scl = 0;
		sda = myData & 0x80;  //获取需要发送字节的最高位到SDA
		Delay5us();  //数据建立时间
		
		//开始发送数据
		scl = 1;
		Delay5us();  //数据发送时间
		
		scl = 0;  //发送完毕拉低,等待下1bit数据的传输
		Delay5us();
		
		myData = myData << 1;
	}	
}
 
//OLED写入一条指令
void oledWriteCmd(char writeCmd)
{
	IIC_start();
	IIC_sendByte(0x78);  //选择一个OLED屏,写模式
	IIC_ack();
	IIC_sendByte(0x00);  //写入命令,D/C位为0
	IIC_ack();
	IIC_sendByte(writeCmd);
	IIC_ack();
	IIC_stop();
}
 
//OLED写入一个数据
void oledWriteData(char writeData)
{
	IIC_start();
	IIC_sendByte(0x78);  //选择一个OLED屏,写模式
	IIC_ack();
	IIC_sendByte(0x40);  //写入命令,D/C位为0
	IIC_ack();
	IIC_sendByte(writeData);
	IIC_ack();
	IIC_stop();
}
 
//OLCD初始化
void oledInit()
{
	oledWriteCmd(0xAE);
	oledWriteCmd(0x00);
	oledWriteCmd(0x10);
	oledWriteCmd(0x40);
	oledWriteCmd(0xB0);
	oledWriteCmd(0x81);
	oledWriteCmd(0xFF);
	oledWriteCmd(0xA1);
	oledWriteCmd(0xA6);
	oledWriteCmd(0xA8);
	oledWriteCmd(0x3F);
	oledWriteCmd(0xC8);
	oledWriteCmd(0xD3);
	oledWriteCmd(0x00);
	oledWriteCmd(0xD5);
	oledWriteCmd(0x80);
	oledWriteCmd(0xD8);
	oledWriteCmd(0x05);
	oledWriteCmd(0xD9);
	oledWriteCmd(0xF1);
	oledWriteCmd(0xDA);
	oledWriteCmd(0x12);
	oledWriteCmd(0xDB);
	oledWriteCmd(0x30);
	oledWriteCmd(0x8D);
	oledWriteCmd(0x14);
	oledWriteCmd(0xAF);
}
 
void olceClean()
{
	int i,j;
	for(i=0;i<8;i++){
		oledWriteCmd(0xB0 + i);  //选择PAGE
		//选择PAGE的第0列开始显示
		oledWriteCmd(0x00);  
		oledWriteCmd(0x10);
		for(j = 0;j < 128; j++){
			oledWriteData(0);  //写入字符0
		}
	}
}
 
//OLED的字符构造点阵
const unsigned char code oledFont[]=
{
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
  0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
  0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
  0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
  0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
  0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
  0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
  0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
  0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
  0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
  0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
  0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
  0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
  0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
  0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
  0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
  0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
  0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
  0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
  0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
  0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
  0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
  0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
  0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
  0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
  0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
  0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
  0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
  0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
  0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
  0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
  0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
  0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
  0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
  0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
  0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
  0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
  0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
  0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
  0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
  0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
  0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
  0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
  0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
  0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
  0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
  0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
  0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
  0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
  0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
  0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
  0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
  0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
  0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
  0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
  0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
  0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
  0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
  0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
  0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
  0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
  0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
  0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
  0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
  0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
  0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
  0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
  0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
  0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
  0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
  0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
  0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
  0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
  0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
  0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
  0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
  0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
  0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
  0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
  0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
  0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
  0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
  0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
  0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
  0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
  0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
  0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};
 
//OLED显示一个字符
void oledShowByte(char rows,char columns,char oledByte)
{ 
	unsigned int i;
 
	//显示字符的上半部分
	oledWriteCmd(0xb0+(rows*2-2));  //选择行
	//选择列                        
	oledWriteCmd(0x00+(columns&0x0f));                          
	oledWriteCmd(0x10+(columns>>4));      
	//显示数据                       
	for(i=((oledByte-32)*16);i<((oledByte-32)*16+8);i++){
		oledWriteData(oledFont[i]);                            
	}
 
 	//显示字符的上半部分
	oledWriteCmd(0xb0+(rows*2-1));  //选择行  
	//选择列                    
	oledWriteCmd(0x00+(columns&0x0f));                          
	oledWriteCmd(0x10+(columns>>4)); 
	//显示数据                           
	for(i=((oledByte-32)*16+8);i<((oledByte-32)*16+8+8);i++){
		oledWriteData(oledFont[i]);                            
	}       
}
 
//OLED显示一个字符串
void oledShowString(char rows,char columns,char *str)
{
	while(*str != '\0'){
		oledShowByte(rows,columns,*str);
		str++;
		columns += 8;   
	}       
}

void main()
{
	uartInit();
	Time0Init();
	int0Init();

	oledInit();
	olceClean();  //清屏函数
	oledWriteCmd(0x20);  //设置内存
	oledWriteCmd(0x02);  //选择页寻址模式

	while(1){
		if(signal == 1){
			sprintf(speedMsg,"speed:%dcm/s ",speed);
			olceClean();
			oledShowString(2,5,speedMsg);
			signal = 0;
		}
	}
}

//定时器0产生的中断的处理函数
void Time0Handle() interrupt 1
{
	cnt++;
	TL0 = 0x66;		
	TH0 = 0xFC;
	//每过一秒统计一次产生了多少次下降沿,让main函数向串口发送当前小车速度
	if(cnt == 1000){
		cnt = 0;
		signal = 1;  
		speed = speedCnt;
		speedCnt = 0;
	}
}

//外部中断0产生的中断的处理函数
void int0Handle() interrupt 0
{
	speedCnt++;  //每产生一个下降沿让标志位+1
}

//串口产生的中断的处理函数
void myUart() interrupt 4
{
	static int i = 0;
	char tmp;
 
	//接收数据后,RI硬件置位产生的中断
	if(RI){
		RI = 0;  //RI软件清0
		//获取从pc端接收到的数据
		tmp = SBUF;
 
		if(tmp == 'f' || tmp == 'b' || tmp == 'l' || tmp == 'r' || tmp == 's'){
			i = 0;
		}
		mybuf[i] = tmp;
		i++;
 
		//forward
		if(mybuf[0] == 'f' && mybuf[1] == 'o'){
			goForward();
			memset(mybuf,'\0',24);
		}
 
		//forward
		if(mybuf[0] == 'b' && mybuf[1] == 'a'){
			goBack();
			memset(mybuf,'\0',24);
		}
 
		//left
		if(mybuf[0] == 'l' && mybuf[1] == 'e'){
			goLeft();
			memset(mybuf,'\0',24);
		}
		//right
		if(mybuf[0] == 'r' && mybuf[1] == 'i'){
			goRight();
			memset(mybuf,'\0',24);
		}
 
		//stop
		if(mybuf[0] == 's' && mybuf[1] == 't'){
			goStop();
			memset(mybuf,'\0',24);
		}
 
		if(i == 24){
			i = 0;
		}
 
	}
 
	//发送数据后,TI硬件置位产生的中断
	if(TI);  
}

语音控制小车,循迹、跟随、避障三种功能切换

#include "reg52.h"
#include <intrins.h>

#define BZ 1
#define XJ 2
#define GS 3

sfr AUXR = 0x8E;

//sg90
sbit sg90 = P2^5;
//ultrasonic
sbit Trig = P2^3;
sbit Echo = P2^4;
//oled
sbit scl = P2^6;
sbit sda = P2^7;
//car
sbit left_con1A = P1^1;
sbit left_con2A = P1^2;
sbit right_con1A = P1^3;
sbit right_con2A = P1^4;
//循迹
sbit tracingLeft = P1^5;
sbit tracingRight = P1^6;
//跟随
sbit followLeft = P2^1;
sbit followRight = P2^2;
//su-03t
sbit A25 = P0^1;
sbit A26 = P0^2;
sbit A27 = P0^3;

int angle;
int angleBack;
int cnt = 0;

double leftDistance;
double rightDistance;
double middleDistance;

//OLED的字符构造点阵
const unsigned char code oledFont[]=
{
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
  0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
  0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
  0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
  0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
  0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
  0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
  0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
  0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
  0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
  0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
  0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
  0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
  0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
  0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
  0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
  0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
  0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
  0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
  0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
  0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
  0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
  0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
  0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
  0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
  0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
  0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
  0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
  0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
  0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
  0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
  0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
  0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
  0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
  0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
  0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
  0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
  0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
  0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
  0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
  0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
  0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
  0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
  0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
  0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
  0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
  0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
  0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
  0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
  0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
  0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
  0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
  0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
  0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
  0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
  0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
  0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
  0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
  0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
  0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
  0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
  0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
  0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
  0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
  0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
  0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
  0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
  0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
  0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
  0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
  0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
  0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
  0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
  0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
  0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
  0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
  0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
  0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
  0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
  0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
  0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
  0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
  0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
  0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
  0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
  0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
  0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};

void Delay5us()		//@11.0592MHz
{
}

void Delay10us()		//@11.0592MHz
{
	unsigned char i;
 
	i = 2;
	while (--i);
}

void Delay100ms()		//@11.0592MHz
{
	unsigned char i, j;
 
	i = 180;
	j = 73;
	do
	{
		while (--j);
	} while (--i);
}

void Delay300ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 3;
	j = 26;
	k = 223;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Delay500ms()		//@11.0592MHz
{
	unsigned char i, j, k;
 
	_nop_();
	i = 4;
	j = 129;
	k = 119;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

//sg90
void timer0Init()
{
	//设置定时器0为16为计时模式
	TMOD &=0xF0; 
	TMOD |=0x01; 
 
	//设置定时器0定时时间为0.5ms
	TH0 = 0xFE;
	TL0 = 0x33;
 
	TR0 = 1;  //定时器0开始计时
	TF0 = 0;  //不执行定时器0爆表时导致的中断
 
	ET0 = 1;  //定时器0中断开关
	EA = 1;  //总中断开关
}

void sg90Left()
{
	angle = 5;  //180°
	if(angleBack != angle){  
		cnt = 0;
	}
	angleBack = angle;
	Delay100ms();
} 

void sg90Middle()
{
	angle = 3;  //90°
	if(angleBack != angle){  
		cnt = 0;
	}
	angleBack = angle;
	Delay100ms();
} 

void sg90Right()
{
	angle = 1;  //0°
	if(angleBack != angle){  
		cnt = 0;
	}
	angleBack = angle;
	Delay100ms();
}

//ultrasonic
void timer1Init()
{	
	//设置定时器1为16为计时模式
	TMOD &= 0x0F;
	TMOD |= 0x10;  
 
	TH1 = 0x00;
	TL1 = 0x00;
}

void ultrasonicStart()
{
	Trig = 0;
	Trig = 1;
	Delay10us();
	Trig = 0; 
}

double getDistance()
{
	double time = 0;
	
	//定时器1清0
	TH1 = 0x00;
	TL1 = 0x00;
 
	ultrasonicStart();
		
	while(Echo == 0);  //当Echo引脚从低电平跳到高电平时开启定时器1
	TR1 = 1;
		
	while(Echo == 1);  //当Echo引脚从高电平跳到低电平时关闭定时器1
	TR1 = 0;
 
	time = (TH1*256 + TL1) * 1.085;  //微秒
 
	return (time * 0.017);
}

//oled
//IIC起始信号
void IIC_start()
{
	sda = 0;
	scl = 1;
	sda = 1;
	Delay5us();
	sda = 0;
	Delay5us();
	scl = 0;
}
 
//IIC终止信号
void IIC_stop()
{
	scl = 0;
	sda = 0;
	scl = 1;
	Delay5us();
	sda = 1;
	Delay5us();
	sda = 0;
}
 
//IIC的ACK应答信号
char IIC_ack()
{
	char flag;
 
	scl = 0;
	sda = 1;  //在时钟脉冲9期间释放数据线
	Delay5us();  //延时5微秒后,为读取sda数据做准备
 
	scl = 1;  
	Delay5us();  
	flag = sda;  //读取数据线,0为应答
	Delay5us();  
	
	scl = 0;
	Delay5us();
	return flag;
}
 
//IIC发送一个字节
void IIC_sendByte(char myData)
{
	int i;
	for ( i = 0; i < 8; i++){
		//发生数据翻转,选择即将发送的是0还是1
		scl = 0;
		sda = myData & 0x80;  //获取需要发送字节的最高位到SDA
		Delay5us();  //数据建立时间
		
		//开始发送数据
		scl = 1;
		Delay5us();  //数据发送时间
		
		scl = 0;  //发送完毕拉低,等待下1bit数据的传输
		Delay5us();
		
		myData = myData << 1;
	}	
}
 
//OLED写入一条指令
void oledWriteCmd(char writeCmd)
{
	IIC_start();
	IIC_sendByte(0x78);  //选择一个OLED屏,写模式
	IIC_ack();
	IIC_sendByte(0x00);  //写入命令,D/C位为0
	IIC_ack();
	IIC_sendByte(writeCmd);
	IIC_ack();
	IIC_stop();
}
 
//OLED写入一个数据
void oledWriteData(char writeData)
{
	IIC_start();
	IIC_sendByte(0x78);  //选择一个OLED屏,写模式
	IIC_ack();
	IIC_sendByte(0x40);  //写入命令,D/C位为0
	IIC_ack();
	IIC_sendByte(writeData);
	IIC_ack();
	IIC_stop();
}
 
//OLCD初始化
void oledInit()
{
	oledWriteCmd(0xAE);
	oledWriteCmd(0x00);
	oledWriteCmd(0x10);
	oledWriteCmd(0x40);
	oledWriteCmd(0xB0);
	oledWriteCmd(0x81);
	oledWriteCmd(0xFF);
	oledWriteCmd(0xA1);
	oledWriteCmd(0xA6);
	oledWriteCmd(0xA8);
	oledWriteCmd(0x3F);
	oledWriteCmd(0xC8);
	oledWriteCmd(0xD3);
	oledWriteCmd(0x00);
	oledWriteCmd(0xD5);
	oledWriteCmd(0x80);
	oledWriteCmd(0xD8);
	oledWriteCmd(0x05);
	oledWriteCmd(0xD9);
	oledWriteCmd(0xF1);
	oledWriteCmd(0xDA);
	oledWriteCmd(0x12);
	oledWriteCmd(0xDB);
	oledWriteCmd(0x30);
	oledWriteCmd(0x8D);
	oledWriteCmd(0x14);
	oledWriteCmd(0xAF);
}

//OLED清屏函数
void olceClean()
{
	int i,j;
	for(i=0;i<8;i++){
		oledWriteCmd(0xB0 + i);  //选择PAGE
		//选择PAGE的第0列开始显示
		oledWriteCmd(0x00);  
		oledWriteCmd(0x10);
		for(j = 0;j < 128; j++){
			oledWriteData(0);  //写入字符0
		}
	}
}
 
//OLED显示一个字符
void oledShowByte(char rows,char columns,char oledByte)
{ 
	unsigned int i;
 
	//显示字符的上半部分
	oledWriteCmd(0xb0+(rows*2-2));  //选择行
	//选择列                        
	oledWriteCmd(0x00+(columns&0x0f));                          
	oledWriteCmd(0x10+(columns>>4));      
	//显示数据                       
	for(i=((oledByte-32)*16);i<((oledByte-32)*16+8);i++){
		oledWriteData(oledFont[i]);                            
	}
 
 	//显示字符的上半部分
	oledWriteCmd(0xb0+(rows*2-1));  //选择行  
	//选择列                    
	oledWriteCmd(0x00+(columns&0x0f));                          
	oledWriteCmd(0x10+(columns>>4)); 
	//显示数据                           
	for(i=((oledByte-32)*16+8);i<((oledByte-32)*16+8+8);i++){
		oledWriteData(oledFont[i]);                            
	}       
}
 
//OLED显示一个字符串
void oledShowString(char rows,char columns,char *str)
{
	while(*str != '\0'){
		oledShowByte(rows,columns,*str);
		str++;
		columns += 8;   
	}       
}

//car
//两个电机反转,前进
void goForward()
{
	left_con1A = 1;
	left_con2A = 0;
	
	right_con1A = 1;	
	right_con2A = 0;
}

//两个电机正转,后退
void goBack()
{
	left_con1A = 0;
	left_con2A = 1;
	
	right_con1A = 0;	
	right_con2A = 1;
}

//两个电机不转,停止
void goStop()
{
	left_con1A = 0;
	left_con2A = 0;
	
	right_con1A = 0;	
	right_con2A = 0;
}

//左电机不转,右电机反转,左转
void goLeft()
{
	left_con1A = 0;
	left_con2A = 0;
	
	right_con1A = 1;	
	right_con2A = 0;
}

//左电机反转,右电机不转,右转
void goRight()
{
	left_con1A = 1;
	left_con2A = 0;

	right_con1A = 0;	
	right_con2A = 0;
}

//循迹模式
void tracingMode()
{	
	if(tracingLeft == 0 && tracingRight == 0){  
		goForward();
	}

	if(tracingLeft == 0 && tracingRight == 1){
		goRight();
	}

	if(tracingLeft == 1 && tracingRight == 0){
		goLeft();
	}

	if(tracingLeft == 1 && tracingRight == 1){
		goStop();
	}
}

//跟随模式
void followMode()
{	
	if(followLeft == 0 && followRight == 0){  //
		goForward();
	}

	if(followLeft == 0 && followRight == 1){
		goRight();
	}

	if(followLeft == 1 && followRight == 0){
		goLeft();
	}

	if(followLeft == 1 && followRight == 1){
		goStop();
	}
}

//避障模式
void avoidMode()
{
	sg90Middle();
    Delay300ms();
    middleDistance = getDistance();
    if(middleDistance > 35){
        goForward();
    }else{
        goStop();

        sg90Left();
        Delay300ms();
        leftDistance = getDistance();

        sg90Middle();
        Delay300ms();

        sg90Right();
        Delay300ms();
        rightDistance = getDistance();

        if(leftDistance < 15 && rightDistance < 15){
            goBack();
            Delay500ms();
            goStop();
        }else{

            if(leftDistance > rightDistance){
                goLeft();
                Delay500ms();
                goStop();
            }

            if(rightDistance > leftDistance){
                goRight();
                Delay500ms();
                goStop();
            }
        }
    }
}

void main()
{
	int mark = 0;
	timer0Init();
	timer1Init();
	sg90Middle();
	Delay500ms();
	oledInit();
	olceClean();
	oledShowString(2,5,"haozige");
	while(1){

		if(A25 == 0 && A26 == 1 && A27 == 1){
			if(mark != GS){
				olceClean();
				oledShowString(2,5,"genshuai");
			}
			mark = GS;
			followMode();	
		}


		if(A25 == 1 && A26 == 0 && A27 == 1){
			if(mark != BZ){
				olceClean();
				oledShowString(2,5,"bizhang");
			}
			mark = BZ;
			avoidMode();	
		}

		if(A25 == 1 && A26 == 1 && A27 == 0){
			if(mark != XJ){
				olceClean();
				oledShowString(2,5,"xunji");
			}
			mark = XJ;
			tracingMode();	
		}

	}
}

//定时器0的中断函数
void Time0Handler() interrupt 1
{
	
	TH0 = 0xFE;
	TL0 = 0x33;
	cnt++;
	//控制占空比
	if(cnt < angle){
		sg90 = 1;
	}else{
		sg90 = 0;
	}
 
	if(cnt == 40){  //每个周期为20ms
		cnt = 0;
		sg90 = 1;
	}
}

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

51单片机之智能小车(避障、跟随、循迹) 的相关文章

  • SOAP传输协议

    一 HTTP传输协议 超文本传输协议 xff08 HyperText Transfer Protocol xff0c 缩写 xff1a HTTP xff09 xff0c 它是基于请求 响应的模式协议 xff0c 客户端发出请求 xff0c
  • ONVIF简介

    一 什么是ONVIF ONVIF规范描述了网络视频的模型 接口 数据类型以及数据交互的模式 并复用了一些现有的标准 xff0c 如WS系列标准等 ONVIF规范的目标是实现一个网络视频框架协议 xff0c 使不同厂商所生产的网络视频产品 x
  • gsoap工具生成onvif设备搜索(remotediscovery)代码框架

    什么是gsoap工具 xff1f gSOAP 提供了两个工具来方便开发人员使用 C C 43 43 语言快速开发Web 服务应用 xff0c 通过 gSOAP 提供的这两个工具 xff0c 开发人员可以快速生成服务端与客户端代码框架 xff
  • Latex之给字符上加横线、波浪等

    Latex 前几天想在 x x x 上加波浪号 xff0c 一时间忘记怎么打 xff0c 现在记录下来 xff0c 以后好查阅 加 号 xff1a hat x 加横线 xff1a overline x 加宽 xff1a widehat x
  • 数据结构笔记-2(线性表)

    线性表 2 1 线性表 1 定义 是零个或多个具有相同类型的数据元素的有序数列 xff1b xff08 长度等于零的线性表为空表 xff09 非空线性表通常记为 xff1a L xff1d a 1 xff0c a 2 xff0c xff0c
  • 数据结构-6(图)

    图 图的逻辑结构 图的定义 xff1a 图是由顶点的有穷非空集合和顶点之间边的集合组成 xff0c 通常表示为 xff1a G 61 V xff0c E 其中 xff1a G表示一个图 xff0c V是图G中顶点的集合 xff0c E是图G
  • 【leetcode常见面试题】螺旋矩阵解题思路

    文章目录 螺旋矩阵解题思路先找行进路线找每条路线的结束位置再找每条路线的结束位置模拟行走 螺旋矩阵 II总结 螺旋矩阵 解题思路 本题可以采用模拟的方式 xff0c 设4种行走方向 xff0c 如下图 xff1a 先找行进路线 4个方向的行
  • C++面向对象程序设计学习心得

    C 43 43 面向对象程序设计学习心得 经过几周c 43 43 面向对象程序设计的学习 xff0c 对面向对象程序设计有了一些了解 递归 简单地讲 xff0c 递归就是程序直接或间接调用本身的编程技巧 xff0c 通过把一个不能或不好解决
  • STL学习心得

    STL概述 STL组件 1 容器 xff08 Container xff09 xff0d 管理某类对象的集合 2 迭代器 xff08 Iterator xff09 xff0d 在对象集合上进行遍历 xff08 注意 xff1a 这些集合可能
  • 安装nodejs和vue出现问题

    安装nodejs国内镜像时报错 npm install g cnpm registry 61 https registry npm taobao org不知道这是啥错误 xff0c 怎么改啊 xff1f 安装vue 从官网点击下载 下载后点
  • Jetson nano/nx通过网线连接电脑实现远程控制

    Jetson nano nx通过网线连接电脑实现远程控制 摘要1 nano nx桌面共享设置2 安装dconf editor解除加密3 自启VNC server4 网络共享5 获取IP地址6 安装PuTTy7 安装VNC Viewwer8
  • 一文解决MySQL突击面试,关键知识点总结

    文章目录 MySQL重要知识点回顾一 索引1 为什么需要索引2 索引的结构3 避免索引失效3 1 联合索引不满足最左匹配原则3 2 隐式转换3 3 like查询3 4 索引列存在运算或者使用函数3 5 优化器 4 执行计划4 1 type4
  • 51单片机应用篇-- --数码管60秒计时,独立按键可调

    开篇先说一句废话 本旺名字叫萨摩耶 xff0c xff0c Please 叫我旺财 xff0c xff0c xff0c 哈哈 xff0c 招财进宝嘛 xff01 缘由 本来按照我的学习计划 xff0c 我现在应该是单片机的学习过程 xff0
  • 【ESP32+freeRTOS学习笔记之“ESP32环境下使用freeRTOS的特性分析(3-多核环境下的调度)”】

    目录 1 不同核心上分别调度2 tick中断3 关于抢占4 关于同优级的任务按时间片调度5 空闲任务6 调度程序暂停7 启动和终止8 禁用中断9 总结 Vanilla FreeRTOS调度器是具有时间切片的固定优先级抢占调度器 xff0c
  • C++ STL 总结(持续更新)

    因为机试需要用c 43 43 xff0c 暴风吸入式学习 xff08 套用 xff09 它的模板 xff0c 发现还真的挺好用的 xff0c 总结一下 时间紧急 xff0c 取自各个网上的博客 xff0c 没来得及仔细整理 xff0c 都给
  • STM32F103笔记(二)——GPIO原理

    GPIO的工作原理与两个实验实例 一 STM32F103 GPIO说明1 stm32 GPIO引脚的主要功能2 GPIO相关配置寄存器的简介3 STM32F103 GPIO的8种工作方式4种输入模式4种输出模式 二 点亮LED实例 xff0
  • VINS-Fusion代码阅读(五)

    对应解析13页 xff0c 四 前端视觉处理 主要包括特征点检测和特征点跟踪两部分 xff0c 似乎是基于openCV实现的 openCV2 4官方文档 xff0c xff08 暂时未找到openCV3 4有类似的文档 xff09 这一节在
  • 利用putty在windows上通过脚本在远程Linux机器执行指令

    一 前言 借用百度百科关于putty的描述 xff1a PuTTY是一个Telnet SSH rlogin 纯TCP以及串行接口连接软件 较早的版本仅支持Windows平台 xff0c 在最近的版本中开始支持各类Unix平台 xff0c 并
  • 结构体嵌套对齐以及结构体中含有数组的对齐,也基本总结了各类结构体对齐的问题

    目录 结构体嵌套对齐以及结构体中含有数组的对齐 其余的对齐规则 基本的结构体对齐知识点击这里 结构体嵌套对齐以及结构体中含有数组的对齐 32位系统环境 规则一 xff1a 结构体中含有数组 xff0c 数组元素类型和结构中其余的最大类型取较
  • 【杂记1】PC-Ubuntu18.04.5+ROS-melodic环境下安装cartographer功能包

    提示 xff1a 文章写完后 xff0c 目录可以自动生成 xff0c 如何生成可参考右边的帮助文档 文章目录 前言一 ROS下命令行安装 xff08 简单 xff0c 稍微提一下 xff09 二 源码安装cartographer xff0

随机推荐

  • rosdep init 错误解决方法

    遇到的错误如下 mo 64 mo span class token operator span ThundeRobot span class token operator span span class token operator spa
  • stm32+TB6612驱动直流电机

    因为单片机的不可以直接的驱动电机 xff0c 所以需要在他们之间加上一个电机的驱动模块 xff0c 之前的文章里面用过L298N电机驱动模块 xff0c 现在再给大家推荐一个新的电机驱动模块 xff0c 他比L298N好用许多 xff0c
  • 1-范数、2-范数、∞-范数、F-范数,向量范数与矩阵范数

    目录 向量范数1 范数2 范数 范数 矩阵范数1 范数 xff08 列范数 xff09 范数 xff08 行范数 xff09 2 范数 xff08 谱范数 xff09 F范数Frobenius 向量范数 1 范数 2 范数 范数 矩阵范数
  • MATLAB中删除矩阵的某些列或某些行

    MATLAB中删除矩阵的某一列或某一行 删除某一行例子 删除某一列例子 删除多行例子 删除多列例子 删除某一行 span class token function b span span class token punctuation sp
  • 向量叉乘计算公式

    二维向量叉乘 A 61 a1 a2 B 61 b1 b2 A B 61 a1 a2 b1 b2 61 a1b2 a2b1 三维向量叉乘 A 61 a1 a2 a3 B 61 b1 b2 b3 A B 61 a1 a2 a3 b1 b2 b3
  • VINS-Fusion代码按执行顺序阅读(二)

    main 函数的最后一句 xff0c std thread sync thread sync process 可以看出 xff0c 只有time0在time1前后0 03s内的两幅图片 xff0c 才会被发布estimator inputI
  • 将Origin Pro设置成中文显示

    Origin Pro设置成中文显示 在键盘上同时按 win 43 R 键 xff0c 输入 regedit xff0c 点击 确定 找到路径 HKEY CURRENT USER SOFTWARE OriginLab Origin xff0c
  • 严重性代码说明项目文件行 禁止显示状态错误C4996 ‘scanf‘: This function or variable may be unsafe.最全解决方法

    方法一 xff1a 在程序最前面加 span class token macro property span class token directive keyword define span CRT SECURE NO DEPRECATE
  • 指针加1的含义、指针减法运算

    指针加1的含义 一 p 43 1实例运行结果 二 p 43 1 与 p 43 1实例运行结果 三 p 43 43 实例运行结果 四 指针减法运算实例运行结果 五 void 六 指针用来做什么 xff1f 一 p 43 1 p 43 1 表示
  • VMware从零配置安装CentOS 7

    不跳步图文详细安装教程 一 VMware的下载二 VMware的安装三 CentOS7的下载第一步 xff1a 根据自己电脑操作系统的位数点击选择 xff08 大多数都是64位操作系统 xff09 第二步 xff1a 任意挑选一个镜像源进入
  • VMware虚拟机CentOS 7系统:图形模式与文字命令行模式的切换快捷键

    切换快捷键 图形模式切换到文字命令行模式Ctrl 43 Alt 43 F2 F6 文字命令行模式切换到图形模式Ctrl 43 Alt 43 F1 图形模式切换到文字命令行模式 Ctrl 43 Alt 43 F2 F6 文字命令行模式切换到图
  • Linux 常用快捷键与指令总结(不断更新ing)

    命令快捷键含义Tab命令补全 文件补全Ctrl 43 C停掉错误的指令或参数Ctrl 43 D结束离开文字接口Shift 43 Page Up往前翻页Shift 43 Page Down往后翻页 61 61 61 61 61 61 61 6
  • Pytorch关于卷积核(Conv2d)的简单操作与模型修剪

    在使用Pytorch搭建深度学习算法时 xff0c torch nn Conv2d是用得最多的函数之一 Conv2d函数主要是对输入数据做卷积运算 输入参数如下图 xff1a torch nn Conv2d函数所生成的卷积核主要包括weig
  • 小觅相机运行VINS-Fusion(一)

    写在前面的话 xff1a 1 本文基于自己的另一篇博文win10 43 ubuntu16 04 43 ROS Kinetic 2 参考 4 是一篇非常好的帖子 xff0c 但由于小觅托管在github的代码在不断更新 xff0c 故需在某些
  • 正点原子stm32F407学习笔记3——蜂鸣器实验

    一 硬件设计 蜂鸣器为有源蜂鸣器 xff0c 当 PF 8 输出高电平的时候 xff0c 蜂鸣器将发声 xff0c 当 PF 8 输出低电平的时候 xff0c 蜂鸣器停止发声 xff0c 硬件原理图如下 二 软件设计 1 新建beep c文
  • Ubuntu 安装Cmake

    1 安装Cmake 1 Cmake与makefile xff1a Cmake好处是 1 可以自动化生成makefile xff0c 不需要手动编写 2 跨平台 可生成 native 编译配置文件 在 Linux Unix 平台 生成 mak
  • 什么是字节序?

    字节序 字节序 xff0c 顾名思义 xff0c 就是字节组织的顺序 我们可以将其根据其存储时从低位开始还是从高位开始分为两种 xff0c 具体如下 xff1a 类型简写本质大端BE big endian 将高序字节存储在起始地址小端LE
  • PX4开发基础

    文章目录 一 与无人机的缘分二 开发前三 背景知识硬件PIXHAWKpixhawkV1 xff1a pixhawkV2 xff1a pixhawkV3x xff1a PX4 xff08 推荐 xff09 地面站 xff08 GCS xff0
  • 利用蜂鸣器播放音乐

    我们知道 xff0c 蜂鸣器可分为有源蜂鸣器和无源蜂鸣器 xff0c 有源蜂鸣器内置了频率发生电路 xff0c 因此其通电就能够发出声音 xff0c 但是其频率是固定的 xff0c 而无源蜂鸣器内部没有频率发生电路 xff0c 需要外界给予
  • 51单片机之智能小车(避障、跟随、循迹)

    目录 基本概述 硬件组成 功能 关键字 模块介绍 电机模块L9110S 循迹模块 xff08 TCRT5000传感器 xff09 红外避障模块 测速模块 小车 移动小车 xff08 控制电机转动 xff0c 使小车前进 后退 左转 右转 x