STC89C52 小车-舵机转向/蓝牙控制/寻迹,有PCB有讲解,更新

推荐单片机:STC89C52或51(尽量52

还有提供可用于测试直接烧录的89单片机文件(hex),不需要重新编译

还是老话:

源代码可以直接编译通过。

本人是自学,原创内容--转载请务必说明!!

所有下载在文章结尾(包全代码,附件)

代码:为个人gitHub库,无法或不会下载的可以评论,我在考虑发布到gitee或者其他的国内的,(CSDN好像下载收费所以我一直以来都是选择gitHub)。

附件文件:

1.说明书,2.材料一览

然后再附上开发时候用的3.仿真电路,还有单片机最小电路图,下载在文章尾。

目录

0.制作前言:

一、硬件与材料

0、车辆车身CAD

1.所需材料

二.硬件参数与电路图

0.参数:

1,太阳能板与电池

2,PWM控制舵机:

3,线路转接、控制PCB

4,5V单通道继电器模块电路图 (可选): 

5,L298N电机驱动板模块

6,电打火(15KV逆变升压变压器)

7,灯电路

8,寻迹电路

三、软件

1.编程必须要的软件:

2.不是必须但是推荐:

四、指令表

五、程序代码与代码部分讲解:

 1.程序(脚位与常量/宏/TYPE定义):

2.详细的代码

更新内容

所有下载


0.制作前言:

成功制作了3辆小车!

小车截图:

c856f225340e4f2e9bb7f08c32fc0672.jpeg

5c382114671c4214b8b978ff0e29b1b1.jpeg

 71d6331018874833b1bca9f465fa1cfe.jpeg

这真的是三辆😂,一辆有寻迹模块,其辆没有(太贵了)。


一、硬件与材料

0、车辆车身CAD

需要自己画,当然我可以公布我用的,但是这个我用的车身CAD不是我绘制的,有需要的留言,我问下我的兄弟。

1.所需材料

制作注意:小车的供电一定要用降压模块,如果嫌贵的话可以用L298N双H桥直流电机驱动!

以下数量都可以自定义,数量内只是我其中一辆车使用的,绿色为可选项目(可以不要):测试(绿色)

序号名称数量单位
118650锂电池2
218650锂电池盒2
3太阳能板2
4继电器2
515KF高压发生器
6转接板-洞洞板与最小系统板或者“车辆板”3
7ic:STC89C521
8亚克力板4
9寻迹模块(必须是红外)注13
10火焰传感器 1
119g舵机1
12T型马达2
13轮胎2
14M3螺丝9
15M3螺母24
16M3螺栓6
17M2螺丝4
18M2螺母1
195mmLED灯~12
203mmLED灯  
21热缩管  
22锡线  
23热熔胶棒  
24环氧树脂  
25LM2596S降压稳压器模块1
26L298N双H桥直流电机驱动1
275v蜂鸣器1
28HC-05蓝牙模块1
32双串8A锂电池保护板(7.4-8.4V 8A)1
33杜邦线  
348.4V1A锂电池充电器(按你的设计选择电流)  
35SM2.54mm2P公母插头  
36毛刷2
37传动杆2
38万向联轴器2
39N20电机联轴器2
40蜗轮蜗杆减速马达2
41二极管  
42黑胶布(寻迹识别的为黑色线2

注1:寻迹模块,必须为这样的而且本程序,识别的为黑色线

6fe67369872948099fd1925dc13ab279.png

注1:寻迹模块

 

二.硬件参数与电路图

 因为过去好久了,而且现在有事,就不给现场的实物连接图了,不过如果人多的话,4月后补实物图。

0.参数:

太阳能电池板:单个标准6.0V-6.2V,二块串联输出电压(MAX)12.1V。

18650电池(同规格):单个额定:3.7V 充满电: 4.2V,二块串联输出电压(MAX)8.4V。

18650锂电池串联充放电保护板(7.4-8.4V 8A),充电电压为DC8.4V。

 

太阳能电池板经过:LM2596S降压稳压器模块和二个储能、滤波10V220uF电容。

LM2596系列稳压器是为降压开关稳压器提供所有有效 功能的单片集成电路,能够驱动 3A 的负载,并且拥有 出色的线路和负载调节性能。这些器件可提供 3.3V、 5V、12V 固定输出电压和可调节输出电压版本。输出负载电流为 3A ,输入电压范围高达 40V。

 

1,太阳能板与电池

太阳能电池板:二块串联输出电压(MAX)12.1V,经过:二个储能、滤波10V220uF电容和LM2596S降压稳压器模块。

bf84a08e8c1c48e2a32157f372fa81eb.png

H0为电池测试端口(MAX4.2V),H1为电压输出端口(MAX8.4V), 保护板上B+、B-、BM

为电池接口,经过L298N把DC8.4V降压为+5V。

08b19420c92b41159a06ef2e9451ae6f.png

 

2,PWM控制舵机:

当舵机接收到一个小于1.5ms的脉冲,输出轴会以中间位置为标准,逆时针旋转一定角度。接收到的脉冲大于1.5ms情况相反。不同品牌,甚至同一品牌的不同舵机,都会有不同的最大值和最小值。一般而言,最小脉冲为1ms,最大脉冲为2ms。

舵机CTRL连接单片机的P3.7接口。

504480c4c4e74d2e841f1d1294af99ba.png

3,线路转接、控制PCB

共计二个电路板:

1.为单片机最小系统板或者使用“车辆板”,都有电路图,下载见文章末尾(EDA分享)这二个板讲解,见立创EDA分享的个人电路图与,PCB。

2.为转接板-洞洞板(集线傻瓜板),电路图见下面。

转接板-洞洞板为转接单片机输出、输入IO脚位,方便连接、控制电源开关、喇叭、状态灯(转向、照明、停车,倒车)、模块(蓝牙、寻迹)电路。

转接板-洞洞板电路定义:

J2为电源输入接口,J3、J4为电源输出接口,J5为寻迹模块接口,J6为喇叭、状态灯接口,J7为喇叭接口,J8为蓝牙接口,

其中J1到J8为一个PCB板,J9和J10为另一个PCB板。

c428b6fbd6df44afbb3fb2c77fab3858.png

 J9、J10为电源输入输出接口。

2a2c60723b974f3ab87faae5f806da7d.png

4,5V单通道继电器模块电路图 (可选): 

讲解将不不讲了,CSDN和其他平台上有人讲过。

共计二个,其中:

继电器一为:J1连接+5V电源,STC89C516RD+单片机的P1.0 IO端口,P1的COM连接GND,NO控制电打火开关(15KV逆变升压变压器)的VCC端口。

继电器二为:J2连接+5V电源,STC89C516RD+单片机的P1.1 IO端口,P1的COM2连接+5V,NO控制开关(1218-N20马达)的VCC端口。

 

Input IO输入高电平开启NO、关闭NC,低电平开启NC、关闭NO

84db4b1a871f466bb4f092a3bac03d30.png

 

                   

5,L298N电机驱动板模块

参数我就不讲了,否则太多了!

 实物图:

03ff6de21c9c4952b4e14ecefefc9e2d.png

电路仿真:

J11为电池源输入(B+/B-),5V电源输出接口(+5V/GND),J12、J13为电机控制输出接口,J14为单片机信号电机控制的PWM接口。

该元件因为有自带的降压电路OUT(DC5V),所以也是单片机等核心模块供电电路!。

3b4fbdc7c167473592109a1d2f85aa85.png

6,电打火(15KV逆变升压变压器)

控制:使用继电器!。

J15为电源输入端。【某宝有卖的】。

 7a8d5a732e5249239213e5872c799070.png

 

7,灯电路

脚位定义:

I/O 口

输入(IN)/输出(OUT)

功能概述

功能

程序-变量名

P2.0

OUT

外部设备    初始化为1    

输出状态 1/0     OFF/ON

左转向灯

Left_Beam

P2.1

OUT

右转向灯

Right_Beam

P2.2

OUT

倒车灯

Inverse_Beam

P2.3

OUT

刹车灯

Brake_Beam

P2.4

OUT

近光灯

Low_Beam

P2.5

OUT

远光灯

High_Beam

P2.6

OUT

外围设备口

Peripheral

P2.7

OUT

喇叭-提醒

R_Horn

 讲解:

全部端口可以引出到线路转接PCB的J6排针上(该电路图可以去2.3查看),目前小车已经使用左右转向灯、倒车灯、刹车灯、近光灯、喇叭,剩余的可以自己增加,不需要修改代码,注意初始化为高电平(1),输入相关命令P2的IO口输出为低电平(0),在次输入为高电平(1初始化状态)。 

相关命令(可能发生更改,所以详细见文章指令表或者附件):W、S、A、D、P、F、O、L、H、Q,分别为前进、倒车、左转、右转、 停车、车辆初始化、车辆方向初始化、开关近光灯、开关远光灯、开关喇叭。

特殊命令灯状态设置为:

前进关闭倒车灯与刹车灯,倒车关闭刹车灯,左转范围内关闭右转灯、右转范围内关闭左转灯,不在左右转范围内关闭左右转向灯、 停车关闭倒车灯、车辆初始化关闭所有、车辆方向初始化关闭左右转向灯(与不在左右转范一样)。 

电路:

电阻可以更换,只要注意输入电压为DC5V,BUZ1为5V有源蜂鸣器,

b5ab2a98a4d14b33adbed96e7bb712a8.png

 

8,寻迹电路

寻迹电路讲解:

详细讲解就算了,自己百度因为文章有限

简单的讲:

可以通过判断接收红外管的红外光的多少,来判定目前障碍物的黑白,黑色的为跑道,白色的为背景。

状态:

当物体为黑色时寻迹模块输出为高电平(1),当物体为白色时寻迹模块输出为低电平(0),使用可以依此做判断。

模块上自带频率调节电位器用来调节红外发射管的载波频率,因为一体化接收头要在特定的38KHZ载波频率的时候才是灵敏的.将502电阻顺时针调到尽(也就是将发射管的亮度调到最大)然后对准白色的墙调103电阻,一直调到感应距离是远为止,这样传感器就工作在最佳状态了。

EA为使能端,EN端为高电平“1”时传感器不工作,为低电平“0”时工作。传感器自带上跳帽插上后EN端长期接地(EN长期为“0"),要使用EN端功能时请把跳帽拿掉。

EA使能端已经由新的单片机程序控制。

I/O 口

输入(IN)/输出(OUT)

功能概述

功能

程序-变量名

P0.0

IN

跟踪传感器状态:1/0

前方中

Front_MiddleTracking

P0.1

IN

前方左

FrontL_MiddleTracking

P0.2

IN

前方右

FrontR_MiddleTracking

P0.3

IN

后方(保留)

Rear_MiddleTracking

bbcaca36819a4d53b7752c0855ca169a.png

    可以输入为DC3V-6V电源,车辆上使用的是DC5V。

 


 

三、软件

以下软件,附件的说明书可是给下载地址了(作者的怨念)

1.编程必须要的软件:

  1. stc-isp  程序烧录软件(附件说明书有下载,或者是去官网)
  2. Keil uVision4   程序编写和编译器(附件说明书有下载,或者是去官网)

2.不是必须但是推荐:

Proteus  Professional  电路仿真   (附件说明书有下载,或者是去官网)

控制需要:智能设备(手机、电脑)或者单片机(忙完会发布)。

参数:

蓝牙模块:HC-05从机模式

波特率: 9600(默认),8个数据位。

STC89C516RD+单片机无线参数:

波特率: 9600(默认),8个数据位,输入即反应不用按回车。

手机推荐使用:

(以下二个附件说明书有下载,或者是去Google Pay)

3b57efdde4a9494fb62057a847e5b9b4.jpeg Arduino bluetooth Controller,版本v1.3及以上。

298f20a277bc4dca84c4956887b6db9a.jpeg 蓝牙串口,版本v7.4.9及以上。

电脑版:

c5569baa6e434221bfdc3feb4938babc.png sscom(附件说明书有下载,或者是去官网)

或者stc-isp 

 

 

四、指令表

用户/操作者指令:

“也可见附件之一命令表”

命令   command

介绍

使用

B

进入/退出寻迹

通用模式

ENTER(回车)

预留-未启用 确定/获得信息

通用模式

  +或者-

 +为速度值+1    -为速度值-1

通用模式

Z或者X

 Z为速度值+10    X速度值10

通用模式

( 和 )

(为多个命令开始符号和 )结束

通用模式

W

前进(保持开关)

通用模式

S

倒车(保持开关)

通用模式

A

左转向(保持开关)

通用模式

D

右转向(保持开关)

通用模式

P

停车(保持开关)

通用模式

F

车辆初始化-所有设置初始化

通用模式

O

车辆转向初始化

通用模式

L

近光灯-按下(保持开关)开启/关闭

通用模式

H

远光灯-按下(保持开关)开启/关闭

通用模式

Q

喇叭-提醒-按下(保持开关)开启/关闭

通用模式

c

外围设备-按下(保持开关)开启/关闭

通用模式

0

自定义0-按下(保持开关)开启/关闭

通用模式

1

自定义1-按下(保持开关)开启/关闭

通用模式

2

自定义2-按下(保持开关)开启/关闭

通用模式

3

自定义3-按下(保持开关)开启/关闭

通用模式

4

自定义4-按下(保持开关)开启/关闭

通用模式

5

自定义5-按下(保持开关)开启/关闭

通用模式

6

自定义6-按下(保持开关)开启/关闭

通用模式

7

自定义7-按下(保持开关)开启/关闭

通用模式

更新内容2023-01-23:

C停车,使用户校准舵机

通用模式,字面意思:在目前版本下不论那个模式都可以使用。


五、程序代码与代码部分讲解:

 1.程序(脚位与常量/宏/TYPE定义):

接线见硬件!!!!

1.单片机p0脚

/*p0.0到p0.3 为黑色寻迹模块信号*/

sbit Front_MiddleTracking=P0^0;      //寻迹前方,中间
sbit FrontL_MiddleTracking=P0^1; //前方左边
sbit FrontR_MiddleTracking=P0^2; //前方右边
sbit Rear_MiddleTracking=P0^3;      //后方,中间[模块一定要与0.0对直]。

2.辅助

sbit Retai_zeron=P0^4;      //保留口0
sbit Retain_One=P0^5;      //保留口
sbit Retain_two=P0^6;       //保留口
sbit Retain_three=P0^7;       //保留口


P1 自定义
sbit Custom_zero=P1^0;    //0
sbit Custom_One=P1^1;    //1
sbit Custom_two=P1^2;    //2                
sbit Custom_three=P1^3; //3
sbit Custom_four=P1^4;   //4        
sbit Custom_five=P1^5;  //5
sbit Custom_six=P1^6;  
sbit Custom_seven=P1^7; 



//p2   灯与喇叭                       
sbit Left_Beam=P2^0;         //左
sbit Right_Beam=P2^1;    //右                
sbit Inverse_Beam=P2^2; //倒车
sbit Brake_Beam=P2^3;   //刹车        
sbit Low_Beam=P2^4;  //近光灯
sbit High_Beam=P2^5;  //远光灯
sbit Peripheral=P2^6;  //外围设备
sbit R_Horn=P2^7;  //喇叭-提醒


//P3  串口通信 
sbit UART_RXD=P3^0;
sbit UART_TXD=P3^1;
sbit UART_bit9=P3^2;//预留,可改



//电机控制-接线见硬件-5,L298N电机驱动板模块
sbit EM_OUT1=P3^3; 
sbit EM_OUT2=P3^4;             
sbit EM_OUT3=P3^5;           
sbit EM_OUT4=P3^6;



//舵机信号线
sbit SE_OUT1=P3^7;


主要的常量/宏定义:

#define LAMP_ON   0 

#define LAMP_OFF  1
上面就不用解释吧,开关意思。


#define P1_INIT 0xFF    //0X80。该常量为P1口的初始化状态。
#define LAMP_P2_INIT 0xFF    //0X80。与上一个一样,不过是P2




/*******舵机状态定义********/
#define SE_TIMINGLNITIAL 10         //舵机初始计时
#define SE_RANGEMAX 17           //舵机范围
#define SE_RANGEMIN 0             //舵机范围
#define SE_TIMINGMAX 30              //舵机计时上限
/*******马达定义*********/
#define MOTOR_TIMINGMAX 200      //马达计时上限


/*#################常量/宏定义声明#######################*/

/*******************************************************************************
注意:本程序单片机的波特率来自STC手册提供!!
*FOSC        为外部晶振    12000000L为12MHz    11059200L==11.0592MHz

*BAUD         为波特率

*PARITYBIT  奇偶校验位 0-无  1-奇校验位 2-偶校验位  3-标记校验位  4-空间校验位        

********************************************************************************/
#define FOSC 11059200L   // 也就是说为晶振11.0592MHz
//要是需要12MHz的替换为12000000L
#define BAUD  9600 //波特率9600
#define PARITYBIT 0//奇偶位



3.ypedef 类型声明

typedef enum{false=0,true,blck}Front_bool;

/*注:无特别说明,函数返回Front_bool类型

*则true 为成功(真),false为失败(假)   */    

typedef unsigned char uchar;

typedef unsigned int  uint;

2.详细的代码

注2023-01-23更新了代码,添加了一个功能,不需要的可以用以下这个版本。

最新版见文章末尾,我个人gitHub中项目代码文件是同步更新的。

注意最新版功能区分了STC89C51/52和516区别,除了89C516都可以正常使用,516准备可I2C与外模EEPROM通信(后更新,并放出全源文件),或者不使用新的功能也可以。

旧版按引用排序:

project.h

#ifndef _POROJECT_H_
#define _POROJECT_H_

/*#################引用头文件#######################*/
#include<reg52.h>
#include<intrins.h>
#include<stdio.h>
#include<stdlib.h>

/*###########################typedef 类型声明#######################*/
typedef enum{false=0,true,blck}Front_bool;
/*注:无特别说明,函数返回Front_bool类型
*则true 为成功(真),false为失败(假)   */	
typedef unsigned char uchar;
typedef unsigned int  uint;

/*###########################脚位定义#######################*/
//p0 
/*p0.0-p0.3 为黑色跟踪->寻迹*/
sbit Front_MiddleTracking=P0^0;	  //前方中
sbit FrontL_MiddleTracking=P0^1; //前方左
sbit FrontR_MiddleTracking=P0^2; //前方右
sbit Rear_MiddleTracking=P0^3;	  //后方

sbit Retai_zeron=P0^4;	  //保留口0
sbit Retain_One=P0^5;	  //保留口
sbit Retain_two=P0^6;	   //保留口
sbit Retain_three=P0^7;	   //保留口

//P1 自定义
sbit Custom_zero=P1^0;	//0
sbit Custom_One=P1^1;	//1
sbit Custom_two=P1^2;	//2			    
sbit Custom_three=P1^3; //3
sbit Custom_four=P1^4;   //4 	   
sbit Custom_five=P1^5;  //5
sbit Custom_six=P1^6;  
sbit Custom_seven=P1^7; 
  
//p2						   
sbit Left_Beam=P2^0;	     //左
sbit Right_Beam=P2^1;	//右			    
sbit Inverse_Beam=P2^2; //倒车
sbit Brake_Beam=P2^3;   //刹车 	   
sbit Low_Beam=P2^4;  //近光灯
sbit High_Beam=P2^5;  //远光灯
sbit Peripheral=P2^6;  //外围设备
sbit R_Horn=P2^7;  //喇叭-提醒

					 
//P3  串口
sbit UART_RXD=P3^0;
sbit UART_TXD=P3^1;
sbit UART_bit9=P3^2;
//电机控制
sbit EM_OUT1=P3^3; 
sbit EM_OUT2=P3^4;             
sbit EM_OUT3=P3^5;           
sbit EM_OUT4=P3^6;
sbit SE_OUT1=P3^7;

#endif

UART.h

UART.c

#include"UART.h"

/*#################定义变量#######################*/
Front_bool busy,rbusy;  //串口状态
uchar info='*';	   //串口缓存

void delay_nus(uint time) 
{
    unsigned int i=0;
        for (i=0;i<time;i++)
            _nop_();
}
void delay_ms(uint time)   
{
 uint a,b;
	for(a=time;a>0;a--)
		for(b=110;b>0;b--); //延时
}
/**************UART************************/
void UART_init()
{
	rbusy=false;
	TMOD|=0x20; //设置定时器1工作在模式2作为串口通讯
	/*RCAP2L =TL2=(UCHAR_MAX-(FOSC/32/BAUD));		//UART
	//RCAP2H =TH2=(UCHAR_MAX-(FOSC/32/BAUD))>>8;
	//PT1=1;	
	T2CON=0x34;
	//PT0=0;
	*/
	IP=0x10;
	//根据STC官网提供的波特率计算公式
	TH1=TL1=-(FOSC/12/32/BAUD); 
	 
	#if(PARITYBIT==0)
		SCON=0X50; 	
	#elif(PARITYBIT==1)
		SCON=0Xda;
	#elif(PARITYBIT==2)
		SCON=0Xd2; 
	#endif

	TR1=1;//启动T1  
	
	ES=1; //响应中断
	EA=1; //开放中断
}
//结束标志
Front_bool End_Flag()
{	
	if(info==0x0D){//回车
		rbusy=false;
		return true;
	}
	return false;
}
/***************接受字节********************************/
//1.使用rbusy判断,true为已经获得1字节数据,相反false为没有获得1字节数据
/*2.Get_InputString 
*Front_bool Get_InputString_UcharType(uchar *array,const uint length);
*
*/
uint Get_InputString_UcharType(uchar *array,const uint length)
{
	uint ergodic;
	rbusy=false;

	for(ergodic=0; ergodic < length;)
	{
		if(rbusy){
			if(End_Flag())
				return ergodic;
			array[ergodic++]=info;
			rbusy=false;
		}
		
	}
	array[ergodic]='\0';
	return ergodic;
} 
uint Get_InputNumber_UintType(uint *array,const uint length)
{
	/*因为不支持VLA(C99),所以无法简单使用Get_InputString_UcharType()
	因为所需要的数组元素长度无法确定.*/
	//uint arr[length];
	uchar ergodic,overtime=0;
	rbusy=false;	 

	for(ergodic=0;ergodic<length;)
	{
		if(rbusy){
			if(End_Flag())
				return ergodic; 	
			array[ergodic++]=(info%48);
			rbusy=false;				
		}
	} 
		return ergodic;  
}
/***************发送字节********************************/
void SendByte(const uchar date)
{
	while(busy==true);
		ACC=date;  

	if(P)
	{	
		#if(PARITYBIT==1)
			TB8=0;
		#elif(PARITYBIT==2)
			TB8=1; 
		#endif
	}
	else
	{
		#if(PARITYBIT==1)
			TB8=1;
		#elif(PARITYBIT==2)
			TB8=0; 
		#endif
	}
	busy=true;
	SBUF=ACC;
}
//发送字符串
void SendString(const uchar* date)
{
	while(*date)
	 SendByte(*date++);	
//	SendByte('\0');	
}
//发送整(int)数
void SendNum(uint i)
{
	int a[10];
	int j=0;
	if(!i)
	{
		SendByte(0x30);
	}
	else
	{
		while(i > 0)
		{
			a[j++]=i%10+'0';
			i/=10;
		}
	}
	for(j--;j >=0;j--)
	   SendByte(a[j]);
}



/*----------------------中断------------------------------*/
void Uart_SerialPort() interrupt 4 
{
	if(RI)
	{
		EA=0;  //关闭中断
		RI=0;
  		info=SBUF;
		UART_bit9=RB8;
		rbusy=true;
  	} 	 
  if(TI)
  {
  		EA=0;  //关闭中断
  		TI=0;
		busy=false;  //串口繁忙
	} 
	EA=1;  //开启中断
}


vehicle.h

#ifndef _VEHICLE_H_
#define _VEHICLE_H_

/*#################引用头文件#######################*/
#include"project.h"

/*#################引用变量#######################*/
extern uchar info;	   //串口缓存
extern Front_bool busy,rbusy;  //串口状态
/*#################常量/宏定义声明#######################*/
/*******灯状态定义*********/
#define LAMP_ON	 0
#define LAMP_OFF  1
#define P1_INIT 0xFF    //0X80     //0x00
#define LAMP_P2_INIT 0xFF    //0X80     //0x00
/*******舵机状态定义********/
#define SE_TIMINGLNITIAL 10      //舵机初始计时
#define SE_RANGEMAX 17      //舵机范围
#define SE_RANGEMIN 0      //舵机范围
#define SE_TIMINGMAX 30			  //舵机计时上限
/*******马达定义*********/
#define MOTOR_TIMINGMAX 200      //马达计时上限
/*******数组大小定义*********/
#define ARRAY_SIZE 10 //数组大小

/*###########################函数原型#######################*/

/************************************
*-名称: Car_Initi                   *
*-函数功能: 车辆初始化              *
*-后果: 外置设备,模式,速度初始化,	*
* B_Horn口80us变化,设置定时器0		*
*-无参数                            *
*-无返回值			                */
void Car_Initi();
/************************************
*-名称: Vehicle_Stop                *
*-函数功能: 停止,停车               *
*-后果: 打开刹车灯,EA变化一次	    *
*  EM_OUT1-4为1*					*
*-无参数                            *
*-无返回值			                */
void Vehicle_Stop();
/************************************
*-名称: Vehicle_ForwardRotation     *
*-函数功能: 正转                    *
*-后果: 刹车倒车灯,EM_OUT2和4为0	*
*-无参数                            *
*-无返回值			                */
void Vehicle_ForwardRotation();
/************************************
*-名称: Vehicle_Reverse             *
*-函数功能: 反转                    *
*-后果: 倒车,EM_OUT1和3为1          *					
* 关闭刹车灯					    *
*-无参数                            *
*-无返回值			                */
void Vehicle_Reverse();
/***************************
*-名称: Cornering_Lamp     *
*-函数功能: 控制转向灯     *
*-后果: 控制转向灯         *					
*-无参数                   * 
*-无返回值			       */
void Parameter_Steering(const uchar direction);
/****************************************************
*-名称: Parameter_Steering                          *
*-函数功能: 初始位置,右转,左转                      *
*-后果: 灯+舵机转向(--/++/==SE_PwmCount),调用	    *
*   Cornering_Lamp函数  							*					
*-参数:                             				*
*#uchar direction 转向方向(L,R,O) 右转,左转,初始位置*  
*-无返回值			                                */
void Parameter_Steering(uchar direction);
/**********************************************
*-名称: VehicleTurnLeft                       *
*-函数功能: 转向保持时间                      *
*-后果: 首先以参数direction转向,然后保持参数  *
* keepus(单位:us)后,恢复{注:相反方向转动一次} *					
*-参数:const								  *
*#uchar direction  转向方向(L,R)			  *
*#uint keepus      保持时间/us                *
*#uint angle	   转向角度0到舵机范围:       *
* 初始位置为0 左右区间:(MIN<-初始0位置->MAX)  *
*说白了就是执行几次                           *
*-Front_bool类型返回值-成功失败			      */
Front_bool Steering_HoldingTime(const uchar direction,const uint keepus,const uint angle);

/**********************************************
*-名称: Stop_SettingSpeed_Parameters   		  *
*-函数功能: 停车设置速度参数                  *
*-后果:停车,使用Modernspeed参数设置速度并且	  *
* 返回原来的速度						      *
*-参数:										  *
*#uint Modernspeed  设置的速度		     	  *
*-uint类型返回值-原来速度(uint)			      */
uint Stop_SettingSpeed_Parameters(uint Modernspeed);
/**********************************************
*-名称: Speed_Value                           *
*-函数功能: 停车设置速度参数                  *
*-后果: 调用Get_InputNumber_UintType获取速度值*
* 并且设置获取的速度,				          *
*-无参数                                      * 
*-Front_bool类型返回值-成功失败			      */
Front_bool Speed_Value();
/**********************************************
*-名称: SpeedMode_Din                         *
*-函数功能: 车参数设置                        *
*-后果: 调用大部分车辆函数,根据参数设置速度等,*				          
*-参数:										  *
*#uchar command,传入的命令                    * 
*-Front_bool类型返回值-成功/失败		      */
Front_bool SpeedMode_Din(uchar command);
/************************************
*-名称: Option_prompt               *
*-函数功能: 命令选项提示            *
*-后果: 打印速度和方向参数       	*
*-无参数                            *
*-无返回值			                */
void Option_prompt();
/************************************
*-名称: CommandProcessing           *
*-函数功能: 字符串命令              *
*-后果: 获取输入ARRAY_SIZE宏个命令 	*
* 并且延时执行						*
*-无参数                            *
*-Front_bool类型返回值-成功/失败    */
Front_bool CommandProcessing();

/****************黑色跟踪->寻迹 Black tracking****************/
/*###########################函数原型#######################*/

/****************************************
*-名称: Black_Tracking_Action         	*
*-函数功能: 寻迹逻辑的移动函数          *
*-后果: 检测车辆是否在轨迹线上,在:		*
* 运行,转向,停止,输入'B'退出函数		*
*    串口命令							*
优先  *								    *
*-无参数                                *
*-无返回值			                    */
void Black_Tracking_Action();

#endif

vehicle.c 

2023-01-23更新 只需要更新vehicle.c 和vehicle.h并且下载EEPROM.h与EEPROM.c就可以!

在GitHub可下载。

#include"vehicle.h"
#include"UART.h"
#include"EEPROM.h"

/*#################定义变量#######################*/
uchar Mode_Selection;  //模式选择
/*PWM占空比
*当xx_pwmcount为20时
*因为if(Pwm_EMtime<=Pwm_EMcount) pwmx=1 else pwm=0;
*所以%20的时间输出高电平,剩余%输出低电平
*/
uint MOTOR_PwmTime,SE_PwmTime;   //PWM时间
uint MOTOR_Pwmcount,SE_PwmCount;  //PWM电机频率
	 
/*----------------------车辆初始化--------------------------*/
void Car_Initi()
{
	P2=LAMP_P2_INIT;  //P2初始化
	P1=P1_INIT;  //P1初始化
	
	/* 变量初始化 */
	//状态
	Brake_Beam=LAMP_ON; //刹车灯开		
	EM_OUT3=EM_OUT4=EM_OUT1=EM_OUT2=1;
	//变量
	Mode_Selection='F';  //模式选择
	MOTOR_Pwmcount =80;
	MOTOR_PwmTime=0;
	/*舵机初始化-IAP_ADDRESS+1 校验位*/
	if(IapReadByte(IAP_ADDRESS+1)=='Y')
		SE_PwmCount=IapReadNum(IAP_ADDRESS);  //舵机初始化为读入EEPROM
	else
		SE_PwmCount=SE_TIMINGLNITIAL;  //舵机初始化为默认SE_TIMINGLNITIAL

	SE_PwmTime=0;   //PWM时间

	//定时器
	EA=1;
	TR0=ET0=0;
	
	TH0=0xff;//(65536-10)/256;//赋初值定时
	TL0=0xf7;//(65536-10)%256;//0.01ms
	TMOD|=0x01;
	TR0=1;
	ET0=1;

}

/*停止*/
void Vehicle_Stop()
{
	EA=0;
	Inverse_Beam= LAMP_OFF;
	Brake_Beam=LAMP_ON; //刹车灯开		
	EM_OUT3=EM_OUT4=EM_OUT1=EM_OUT2=1;
	
	Mode_Selection='P';
	EA=1;
}
/*正转*/
void Vehicle_ForwardRotation()
{
	EM_OUT2=EM_OUT4=0;
	Inverse_Beam= Brake_Beam =LAMP_OFF;  //刹车,倒车灯关	
	Mode_Selection='W';
}
/*反转*/
void Vehicle_Reverse()
{
	EM_OUT1=EM_OUT3=0;
	Brake_Beam =LAMP_OFF;  //刹车灯关
	Inverse_Beam=LAMP_ON; //倒车灯开	
	Mode_Selection='S';
}				  
//转向灯
void Cornering_Lamp()
{	 	
	 //对比SE_TIMINGLNITIAL初始位置
  	if(SE_PwmCount == SE_TIMINGLNITIAL)
	{	//舵机在初始位置,关闭左右灯
		Right_Beam=Left_Beam=LAMP_OFF;
	}
	else if(SE_PwmCount < SE_TIMINGLNITIAL) 
	{	/*右转*/
		Right_Beam=LAMP_ON;
		Left_Beam=LAMP_OFF;
	}
	else if(SE_PwmCount > SE_TIMINGLNITIAL)	
	{	 /*左转*/
		Left_Beam=LAMP_ON;
		Right_Beam=LAMP_OFF;
	}
				
}
//转向控制-根据参数
void Parameter_Steering(const uchar direction)
{
	if(direction=='O')
	{
		/*舵机初始化-IAP_ADDRESS+1 校验位*/
		if(IapReadByte(IAP_ADDRESS+1)=='Y')
			SE_PwmCount=IapReadNum(IAP_ADDRESS);  //舵机初始化为读入EEPROM
		else
			SE_PwmCount=SE_TIMINGLNITIAL;  //舵机初始化为默认SE_TIMINGLNITIAL

	}
	else if(direction== 'L')
	{	 /*左转*/
		++SE_PwmCount;
	}
	else if(direction == 'R')
	{	 /*右转*/
		--SE_PwmCount;
	}
	Cornering_Lamp();

}
//转向保持时间
Front_bool Steering_HoldingTime(const uchar direction,const uint keepus,const uint angle)
{
	uint frequency;
	if(direction=='L'||direction=='R')
	{	//计算区间
		frequency=SE_RANGEMAX-SE_TIMINGLNITIAL;
		if(angle && angle <= frequency)
		{  //限制范围
			for(frequency=0;frequency < angle;frequency++)
			{
				Parameter_Steering(direction);			
			}
			delay_nus(keepus);//保持时间
			for(frequency=0;frequency < angle;frequency++)
			{
				/*回归*/
				if(direction=='L')
					Parameter_Steering('R');	
				else
				Parameter_Steering('L');
			}
			return true;	
		}
	}						 
	 
	//超过限制范围||direction! 'L'/'R'
	return false;		
}

// 停车,使用户校准舵机
void SteeringGear_Calibration()
{	
	uchar CalibrationValue='0';//校准值
	uchar Calibration='N'; //校准位
	int i=0;
	rbusy=false;
	
   	RESTART:
	Vehicle_Stop();	//停车
	SendString("请输入舵机校准值:\r\n");

	while(!rbusy) ;	//使用输入串口状态判断

	CalibrationValue=info;
	rbusy=false;

   	SendString("舵机校准值:");
	SendNum(CalibrationValue%48);
	INPUTERROR:

	SendString("是否保存舵机值(‘Y’or'N':\r\n");

	while(!rbusy) ;	//使用输入串口状态判断值

	Calibration=info; //校准位
	rbusy=false;

	if(Calibration=='Y')
	{
		IapEraseSector(IAP_ADDRESS);	//删除一个扇区区域

		IapProgramByte(IAP_ADDRESS,CalibrationValue);  //写入一个扇区区域
		IapProgramByte(IAP_ADDRESS+1,Calibration);  //写入一个扇区区域

		Delay(2);
		SendString("\r\n舵机校准值:");
		SendByte(IapReadByte(IAP_ADDRESS));
		SendByte(IapReadByte(IAP_ADDRESS+1));
		SendString("\r\n");
	}
	else if(Calibration=='N')
		goto RESTART;
	else
		goto INPUTERROR;
		
}

/**设置速度-根据输入的数值
*/
Front_bool Speed_Value()
{
	uint speednum[3],ergodic,speed=0,length=0;

	SendString("请输入速度值(0-200):\r\n");
	length=Get_InputNumber_UintType(speednum,3);
	if(length)
	{
		for(ergodic=0;ergodic<length;ergodic++)
			speed=(speed * 10)+speednum[ergodic];
	}
	
	MOTOR_Pwmcount=speed;
	return true;
}

//速度模式/方向选择
Front_bool SpeedMode_Din(uchar command)
{	
	if(rbusy)
	{				   
		if((command=='X'||command=='Z')||(command=='+'||command=='-'))
		{	  
			if(command=='+'){
		 		if(( MOTOR_Pwmcount +1) <= MOTOR_TIMINGMAX)
					++ MOTOR_Pwmcount ;
		 	}	
			 else if(command=='Z'){	 
		 		if(( MOTOR_Pwmcount +10) <= MOTOR_TIMINGMAX)
		 		 	 MOTOR_Pwmcount +=10;
		 	} //注:Pwm_EMcount是unsigned
		 	else if(command=='-'){
		 		if(( MOTOR_Pwmcount -1) <= MOTOR_TIMINGMAX)
					-- MOTOR_Pwmcount ;			
		 	} 
		 	else if(command=='X'){
		 		if(( MOTOR_Pwmcount -10) <= MOTOR_TIMINGMAX)
		 	 		 MOTOR_Pwmcount -=10;
			}	
		}
		else if(command=='(')
		{
			return CommandProcessing();
		}
		else	//防止以上满足后执行switch
		switch(command)
		{
			case'W':
				if(Mode_Selection=='S')//保护
					Vehicle_Stop();		
				Vehicle_ForwardRotation();
				break;
			case'S':
				if(Mode_Selection=='W')//保护
					Vehicle_Stop();
				Vehicle_Reverse();
				break;
			case'P':Vehicle_Stop();break;
	  	 	case'A':Parameter_Steering('L');break;
			case'D':Parameter_Steering('R');break;
			case'O':Parameter_Steering('O');break;
			case'F':Car_Initi(); break;
			case'B':
				rbusy=false;
				return blck;//Black_Tracking_Action(); break;
			case'H': High_Beam=~High_Beam;  //远光灯
				break;
			case'L': Low_Beam =~Low_Beam; //近光灯
				break; 
			case'Q': R_Horn =~R_Horn;//喇叭-提醒
				break;
			case'C': SteeringGear_Calibration(); 	//停车,使用户校准舵机 
				break;	 
			case'c': Peripheral =~Peripheral; 	//外围设备 
				break;	 
			
			case'0': Custom_zero=~Custom_zero; 
				break;
			case'1': Custom_One=~Custom_One;
				break;
			case'2': Custom_two=~Custom_two;
				break;
			case'3':  Custom_three=~Custom_three;
				break;
			case'4':  Custom_four=~Custom_four;
				break;
			case'5':  Custom_five=~Custom_five;
				break;
			case'6':  Custom_six=~Custom_six;
				break;
			case'7':  Custom_seven=~Custom_seven;
				break;

			default:
			SendString("无该指令\r\n");
			rbusy=false;
			return false;	
		}

		rbusy=false;
		return true;
	}
	return false;
}
//命令选项提示
void Option_prompt()
{
	SendString("->Speed|angle|\r\n->  ");
	SendByte(Mode_Selection);

	 //对比SE_TIMINGLNITIAL初始位置
	if(SE_PwmCount&& SE_PwmCount< SE_TIMINGLNITIAL )
		SendString("+D");
	else if(SE_PwmCount> SE_TIMINGLNITIAL)
		SendString("+A");
		
	SendString("| ");
	SendNum( MOTOR_Pwmcount );
	SendString("| ");
	SendNum(SE_PwmCount);
	SendString("\r\n");
	delay_nus(2);
}		  
/*************************字符串命令*********************************/
Front_bool CommandProcessing()
{
	uchar comarr[ARRAY_SIZE];
	uint range=0,ranges=0;

	SendString("String: "); 

	while(info!=')'||range <= ARRAY_SIZE-1)
	{//结束字符
		if(rbusy)
		{
			comarr[range]=info;
			SendByte(comarr[range++]);
			rbusy=false;
		}	
		delay_nus(2); //延时,
	 }
	rbusy=false;
	SendString("\r\n");

	ranges=range;
	for(range=0;range < ranges;)
	{
		SendNum(range);
		SpeedMode_Din(comarr[range]);
		SendByte(comarr[range++]);	
		SendString("\r\t");
		delay_nus(50); //延时,
	}
	
		//delay_nus(2);
	return true;
} 


/*****************************中断********************************/
void PWM_ElectricMachinery() interrupt 1  
{
		
	 TR0=0;		//赋初值时,关闭定时器
     TH0=0xff;	//(65536-10)/256;//赋初值定时
     TL0=0xf7;	//(65536-10)%256;//0.01ms
	 TR0=1;

	SE_PwmTime++;
	if(SE_PwmTime <=SE_PwmCount)
		SE_OUT1=0;
	else
		SE_OUT1=1;

	if(SE_PwmTime >= SE_TIMINGMAX)
		SE_PwmTime=0;

	MOTOR_PwmTime++;        
	
	if(MOTOR_PwmTime<= MOTOR_Pwmcount )	 //占空比由Pwm_EMcount值控制高电平
	{	
		if(Mode_Selection=='W')
			EM_OUT1=EM_OUT3=1;
		if(Mode_Selection=='S')
			EM_OUT2=EM_OUT4=1;
	}
	else
	{  
		if(Mode_Selection=='W')	 //占空比由if控制低电平
			EM_OUT1=EM_OUT3=0;
		if(Mode_Selection=='S')
			EM_OUT2=EM_OUT4=0;
	}
	if(MOTOR_PwmTime>=MOTOR_TIMINGMAX)   //马达计时上限
		MOTOR_PwmTime=0;		
} 

 

main.c:

#include"UART.h"
#include"vehicle.h"

//#define _TRACING_

int main()
{
	Front_bool Mods;	
	UART_init();
	rbusy=false;	
	Car_Initi();
   //if(UART_bit9)
		SendString(" \"连接成功\" \r\n");
	while(1){
		if(rbusy)//使用输入串口状态判断
		{
			if(Rear_MiddleTracking)
				SendString(" 火焰传感器被激活 \r\n");
					
			Mods=SpeedMode_Din(info);
			if(Mods == true)
			   Option_prompt();
			else if(Mods == blck)
				Black_Tracking_Action();
		}
				
		
		while(!UART_bit9){
			Vehicle_Stop();
			delay_ms(10);
			if(rbusy)
				SendString("Not connected \r\n");	
			rbusy=false;	
		}
		
	 }			 

	return 0;

}

 

BlackTracking.c

/*黑色跟踪->寻迹 Black tracking */
/*########该文件使用"vehicle.h"头文件##*/
#include"vehicle.h"
#include"UART.h"
/*#################引用变量#######################*/
extern uchar Mode_Selection;  //模式选择
extern uint MOTOR_PwmTime,SE_PwmTime;   //PWM时间
extern uint MOTOR_Pwmcount,SE_PwmCount;  //PWM电机频率


void Black_Tracking_Action()
{
	uint RestrictedMode='.',infos;

	Car_Initi();//初始化
	SendString("轨迹程序 \n\r");
	MOTOR_Pwmcount=66;

   	while(1)
	{
		//串口操作 执行前提无 优先 0
		if(rbusy)//使用输入串口状态判断
		{
			infos=info;
			if(infos != 'B'){
				if(SpeedMode_Din(infos))
			   		Option_prompt();
			}
			else 
			{
				rbusy=false;
				Vehicle_Stop();
				SendString("Sign Out\r\n");	
				return ;
			}
		}

		/*寻迹基础逻辑*/ 

		//停车检测 执行前提无 优先1
		if(!Front_MiddleTracking &&(!FrontL_MiddleTracking && !FrontR_MiddleTracking)) //!Front_MiddleTracking   
		{
			SendString("NO Trajectories\r\n");
			Vehicle_Stop();	
		}

		//启动检测 执行前提停车 优先2 
		if((Mode_Selection=='P' || Mode_Selection=='F') && Front_MiddleTracking)
		{
			Vehicle_ForwardRotation();//直行
			Option_prompt();	 
		}

		//转向检测,执行前提启动 优先3
		if(Mode_Selection=='W')
		{	
			//转向,执行前提未转向
			if(RestrictedMode =='.')
			{					
				if(FrontL_MiddleTracking && !FrontR_MiddleTracking)
				{	
					Parameter_Steering('L');
					RestrictedMode='L';
					delay_nus(8);
				   SendString("|L|");
				}
				else if(FrontR_MiddleTracking && !FrontL_MiddleTracking)
				{
					Parameter_Steering('R');
					RestrictedMode='R';
					delay_nus(8);
					SendString("|R|");
				}
			}

			//回向,执行前提转过向
			if(Front_MiddleTracking&& (!FrontL_MiddleTracking && !FrontR_MiddleTracking))
			{
				if(RestrictedMode =='L')
				{
					Parameter_Steering('R');
					SendString("|-R|\r\n");
					RestrictedMode='.';
				}
				else if(RestrictedMode =='R')
				{ 
					Parameter_Steering('L');
					SendString("|-L|\r\n");
					RestrictedMode='.';	
				}
			}	

		}			
					
	}


}


ps:终于讲完了,之前一直多少人看,现在我可是下了功夫,在没有得到预期(呜呜呜,我的要求很低的),以后还是简单的发布吧。

更新内容

日期:2023-1-23更新内容:小车添加新功能,方便安装转向舵机前桥,舵机调零。详谈为STC89Cxx内EEPROM读写。注意最新版功能区分了STC89C51/52和516区别,除了89C516都可以正常使用,516准备可I2C与外模EEPROM通信(后更新,并放出全源文件),或者不使用新的功能也可以。使用方法:输入大写C,进入舵机校0,然后输入适合自己车辆的值,EEPROM写入,以后开机自动使用该值(注意判断无保护,下个版本更新保护!)。

 


所有下载

 个人gitHub:  点击我

 附件百度网盘链接:https://pan.baidu.com/s/1zvONRWAvCiVst_idjAuEQw?pwd=AS12 
提取码:AS12

或者点击我

EDA:

1.最小系统板   

79a478708c4d4c339aa7ca920d70bfdd.jpg

 请使用pcb2

​​​​​​https://oshwhub.com/Starry_night/stc89c51-min

 

 

 

 

 

 

 

  • 13
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星空长夜i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值