51单片机智能小车:实现避障、跟随及循迹功能

目录

基本概述

硬件组成

功能

关键字

模块介绍

电机模块L9110S

循迹模块(TCRT5000传感器)

红外避障模块

测速模块 

小车 

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

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

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

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

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

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

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

基本概述

硬件组成

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

功能

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

关键字

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

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

    电机模块L9110S

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

  • 当B-1A为高电平,B-2A为低电平时,电机反转或正转
  • 当B-1A为低电平,B-2A为高电平时,电机正转反转
  • 当B-1A为低电平,B-2A为低电平时,电机不转
  • 电机的正转和反转与跟电机的接线不同而不同,注意自己调试
  • 循迹模块(TCRT5000传感器)

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

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

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

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

    #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 = 2×3.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;
    	}
    }

    物联沃分享整理
    物联沃-IOTWORD物联网 » 51单片机智能小车:实现避障、跟随及循迹功能

    发表评论