推荐单片机: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辆小车!
小车截图:
这真的是三辆😂,一辆有寻迹模块,其辆没有(太贵了)。
一、硬件与材料
0、车辆车身CAD
需要自己画,当然我可以公布我用的,但是这个我用的车身CAD不是我绘制的,有需要的留言,我问下我的兄弟。
1.所需材料
制作注意:小车的供电一定要用降压模块,如果嫌贵的话可以用L298N双H桥直流电机驱动!
以下数量都可以自定义,数量内只是我其中一辆车使用的,绿色为可选项目(可以不要):测试(绿色)
序号 | 名称 | 数量 | 单位 |
1 | 18650锂电池 | 2 | 个 |
2 | 18650锂电池盒 | 2 | 个 |
3 | 太阳能板 | 2 | 片 |
4 | 继电器 | 2 | 个 |
5 | 15KF高压发生器 | 1 | 个 |
6 | 转接板-洞洞板与最小系统板或者“车辆板” | 3 | 个 |
7 | ic:STC89C52 | 1 | 个 |
8 | 亚克力板 | 4 | 片 |
9 | 寻迹模块(必须是红外)注1 | 3 | 个 |
10 | 火焰传感器 | 1 | 个 |
11 | 9g舵机 | 1 | 套 |
12 | T型马达 | 2 | 个 |
13 | 轮胎 | 2 | 个 |
14 | M3螺丝 | 9 | 个 |
15 | M3螺母 | 24 | 个 |
16 | M3螺栓 | 6 | 个 |
17 | M2螺丝 | 4 | 个 |
18 | M2螺母 | 1 | 个 |
19 | 5mmLED灯 | ~12 | 个 |
20 | 3mmLED灯 | ||
21 | 热缩管 | ||
22 | 锡线 | ||
23 | 热熔胶棒 | ||
24 | 环氧树脂 | ||
25 | LM2596S降压稳压器模块 | 1 | 个 |
26 | L298N双H桥直流电机驱动 | 1 | 个 |
27 | 5v蜂鸣器 | 1 | 个 |
28 | HC-05蓝牙模块 | 1 | 个 |
32 | 双串8A锂电池保护板(7.4-8.4V 8A) | 1 | 个 |
33 | 杜邦线 | ||
34 | 8.4V1A锂电池充电器(按你的设计选择电流) | ||
35 | SM2.54mm2P公母插头 | ||
36 | 毛刷 | 2 | 个 |
37 | 传动杆 | 2 | 个 |
38 | 万向联轴器 | 2 | 个 |
39 | N20电机联轴器 | 2 | 个 |
40 | 蜗轮蜗杆减速马达 | 2 | 个 |
41 | 二极管 | ||
42 | 黑胶布(寻迹识别的为黑色线) | 2 | 卷 |
注1:寻迹模块,必须为这样的而且本程序,识别的为黑色线
注1:寻迹模块
文章来源地址https://www.toymoban.com/news/detail-434159.html
二.硬件参数与电路图
因为过去好久了,而且现在有事,就不给现场的实物连接图了,不过如果人多的话,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。
文章来源:https://www.toymoban.com/news/detail-434159.html
太阳能电池板经过:LM2596S降压稳压器模块和二个储能、滤波10V220uF电容。
LM2596系列稳压器是为降压开关稳压器提供所有有效 功能的单片集成电路,能够驱动 3A 的负载,并且拥有 出色的线路和负载调节性能。这些器件可提供 3.3V、 5V、12V 固定输出电压和可调节输出电压版本。输出负载电流为 3A ,输入电压范围高达 40V。
1,太阳能板与电池
太阳能电池板:二块串联输出电压(MAX)12.1V,经过:二个储能、滤波10V220uF电容和LM2596S降压稳压器模块。
H0为电池测试端口(MAX4.2V),H1为电压输出端口(MAX8.4V), 保护板上B+、B-、BM
为电池接口,经过L298N把DC8.4V降压为+5V。
2,PWM控制舵机:
当舵机接收到一个小于1.5ms的脉冲,输出轴会以中间位置为标准,逆时针旋转一定角度。接收到的脉冲大于1.5ms情况相反。不同品牌,甚至同一品牌的不同舵机,都会有不同的最大值和最小值。一般而言,最小脉冲为1ms,最大脉冲为2ms。
舵机CTRL连接单片机的P3.7接口。
3,线路转接、控制PCB
共计二个电路板:
1.为单片机最小系统板或者使用“车辆板”,都有电路图,下载见文章末尾(EDA分享)这二个板讲解,见立创EDA分享的个人电路图与,PCB。
2.为转接板-洞洞板(集线傻瓜板),电路图见下面。
转接板-洞洞板为转接单片机输出、输入IO脚位,方便连接、控制电源开关、喇叭、状态灯(转向、照明、停车,倒车)、模块(蓝牙、寻迹)电路。
转接板-洞洞板电路定义:
J2为电源输入接口,J3、J4为电源输出接口,J5为寻迹模块接口,J6为喇叭、状态灯接口,J7为喇叭接口,J8为蓝牙接口,
其中J1到J8为一个PCB板,J9和J10为另一个PCB板。
J9、J10为电源输入输出接口。
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
5,L298N电机驱动板模块
参数我就不讲了,否则太多了!
实物图:
电路仿真:
J11为电池源输入(B+/B-),5V电源输出接口(+5V/GND),J12、J13为电机控制输出接口,J14为单片机信号电机控制的PWM接口。
该元件因为有自带的降压电路OUT(DC5V),所以也是单片机等核心模块供电电路!。
6,电打火(15KV逆变升压变压器)
控制:使用继电器!。
J15为电源输入端。【某宝有卖的】。
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有源蜂鸣器,
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 |
可以输入为DC3V-6V电源,车辆上使用的是DC5V。
三、软件
以下软件,附件的说明书可是给下载地址了(作者的怨念)
1.编程必须要的软件:
- stc-isp 程序烧录软件(附件说明书有下载,或者是去官网)
- Keil uVision4 程序编写和编译器(附件说明书有下载,或者是去官网)
2.不是必须但是推荐:
Proteus Professional 电路仿真 (附件说明书有下载,或者是去官网)
控制需要:智能设备(手机、电脑)或者单片机(忙完会发布)。
参数:
蓝牙模块:HC-05从机模式
波特率: 9600(默认),8个数据位。
STC89C516RD+单片机无线参数:
波特率: 9600(默认),8个数据位,输入即反应不用按回车。
手机推荐使用:
(以下二个附件说明书有下载,或者是去Google Pay)
Arduino bluetooth Controller,版本v1.3及以上。
蓝牙串口,版本v7.4.9及以上。
电脑版:
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.最小系统板
请使用pcb2
https://oshwhub.com/Starry_night/stc89c51-min
到了这里,关于STC89C52 小车-舵机转向/蓝牙控制/寻迹,有PCB有讲解,更新的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!