一、硬件采购与安装
1.1 采购
-
TB:清翔电子直售店
1.2 安装
二、基础理论学习
2.1 H桥电机控制电路
当ENA=0时,无论IN1与IN2值为多少,T1=0与T2=0与T3=0与T4=0;
当ENA=1时,IN1=1与IN2=0,T1=1与T2=0与T3=0与T4=0,电机顺时针选旋转/逆时针旋转;
当ENA=1时,IN1=0与IN2=1,T1=0与T2=1与T3=1与T4=0,电机逆时针选旋转/顺时针旋转;
当ENA=1时,IN1=1与IN2=1,T1=0与T2=1与T3=0与T4=1,电机停;
当ENA=1时,IN1=0与IN2=0,T1=1与T2=0与T3=1与T4=0,电机停;
2.2 串行通信
-
计算机通信:计算机与计算机之间或计算机月外部设备信息交换
-
并行通信:将数据字节各位用多条数据线同时传送
-
特点:控制简单,传输速度快;传输线多,长距离传输成本高,接收方同时接收各位难度高
-
串行通信:使用一条数据线,数据一位一位传输,数据占用一个固定时间长度
-
特点:传输线少,长距离传送时成本低,但数据的传送控制较复杂
-
分类:
-
同步通信:同步通信时要建立发送方时钟对接收方时钟的直接控制,使双方达到 完全同步。此时,传输数据的位之间的距离均为“位间隔”的整数倍,同时传送的字符间不留间隙,即保持位同步关系,也保持字符同步关系。发送方对接收方的同步可以通过两种方法实现。
-
异步通信:异步通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程 为使双方的收发协调,要求发送和接收设备的时钟尽可能一致。异步通信是以字符(构成的帧)为单位进行 传输,字符与字符之间的间隙(时间间隔)是任意的,但每个字符中的各位是以固定的时间传送的。
-
设备简单便宜,传输效率低
-
传输方向:
-
单工:单向的
-
半双工:收/发不能同时进行
-
全双工:收/发能同时进行
-
传输速率:比特率是每秒钟传输二进制代码位数,单位:位/秒
-
接口标准:RS-232C接口
-
串行接口结构:
-
初始化串行口: 1.设置T1的工作方式(编程TMOD寄存器) 2.计算T1的初值,装载TH1、TL1; 3.启动T1(编程TCON中的TR1位) 4.确定串行口控制(编程SCON寄存器); 5.如需串行口在中断方式工作时,要进行中断设置编程寄存器。
-
相关寄存器:
-
比特率计算
2.3 直流有刷马达
-
结构图
-
工作原理
-
优点:
-
体积小
-
运行平稳,启动制动效果好
-
结构简单
-
控制精度高
-
缺点:
-
电刷与换向器间有摩擦,增加噪音,容易发热,产生电火花,干扰大
-
维修麻烦
-
电阻大,效率低
2.4 系统中断
-
中断系统:中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件 处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。
-
查询中断请求次序:
-
C语言编程:中断查询次序号就是中断号
-
void Int0_Routine(void) interrupt 0; void Timer0_Rountine(void) interrupt 1; void Int1_Routine(void) interrupt 2; void Timer1_Rountine(void) interrupt 3; void UART_Routine(void) interrupt 4; void Timer2_Routine(void) interrupt 5; void Int2_Routine(void) interrupt 6; void Int3_Routine(void) interrupt 7;
-
中断结构:
-
中断触发:
-
中断寄存器:
-
中断控制寄存器
-
中断优先级寄存器
当高位=0且低位=0时,外部中断0为最低优先级中断(优先级0) 当高位=0且低位=1时,外部中断0为较低优先级中断(优先级1) 当高位=1且低位=0时,外部中断0为较高优先级中断(优先级2) 当高位=1且低位=1时,外部中断0为最高优先级中断(优先级3)
-
定时器/计数器控制寄存器
-
中断处理
-
当前正被执行的指令全部执行完毕;
-
PC值被压入栈;
-
现场保护;
-
阻止同级别其他中断;
-
将中断向量地址装载到程序计数器PC;
-
执行相应的中断服务程序。
2.5 面向寄存器编程 Eg. *((unsigned int *) 0x0400 0001) ; //定义指针再解指针
2.6 GPIO GPIO(通用IO高级称呼)= IO(输入输出端口) P1.0~P1.1,P3.0~P3.7端口复用
-
端口介绍
-
CMOS电平与TTL电平标准
-
普通IO口(驱动电路)
2.7 I2C总线协议
-
简介:I2C总线是一种串行、半双工的总线,主要用于近距离、低速的芯片之间的通信;I2C总线有两根双向的信号线,一根数据线SDA用于收发数据,一根时钟线SCL用于通信双方时钟的同步 I2C总线是一种多主机总线,连接在 I2C总线上的器件分为主机和从机。主机有权发起和结束一次通信,从机只能被动呼叫
-
通信过程:
-
主机发送起始信号启用总线
-
主机发送一个字节数据指明从机地址和后续字节的传送方向
-
被寻址的从机发送应答信号回应主机
-
发送器发送一个字节数据
-
接收器发送应答信号回应发送器
-
........ (循环步骤4、5)
-
通信完成后主机发送停止信号释放总线
-
寻址方式:I2C总线上传送的数据是广义的,既包括地址,又包括真正的数据。 主机在发送起始信号后必须先发送一个字节的数据,该数据的高7位为从机地址,最低位表示后续字节的传送方向,‘0’表示主机发送数据给->从机,‘1’表示从机发送数据给->主机。 总线上所有的从机接收到该字节数据后都将这7位地址与自己的地址进行比较,如果相同,则认为自己被主机寻址,然后再根据第8位将自己定为发送器或接收器。
-
起始信号与停止信号: SCL为高电平时,SDA由高变低表示起始信号; SCL为高电平时,SDA由低变高表示停止信号; 起始信号和停止信号都是由主机发出,起始信号产生后总线处于占用状态,停止信号产生后总线被释放,处于空闲状态。 空闲时,SCL与SDA都是高电平。
-
字节传送与应答:
-
同步数据信号:
-
1)时钟同步 时钟同步是通过I2C总线上的SCL之间的线“与”(wire-AND)来完成的,即如果有多个主机同时产生时钟,那么只有所有master都发送高电平时,SCL上才表现为高电平,否则SCL都表现为低电平。
线“与”特性由开漏电路实现。如果控制开漏输出INT为0,低电平,则VGS >0,N-MOS管导通,使输出接地,若控制开漏输出INT为1 (它无法直接输出高电平) 时,则N-MOS 管关闭,所以引脚既不输出高电平,也不输出低电平,为高阻态。正常使用时必须外部接上拉电阻。也就是说,若有很多个开漏模式引脚(C1、C2....)连接到一起时,只有当所有引脚都输出高阻态,才由上拉电阻提供高电平,此高电平的电压为外部上拉电阻所接的电源的电压。若其中一个引脚为低电平,那线路就相当于短路接地,使得整条线路都为低电平,0 伏。 (2)仲裁 总线仲裁与时钟同步类似,当所有主机在SDA上都写1时,SDA的数据才是1,只要有一个主机写0,那此时SDA上的数据就是0. 一个主机每发送一个bit数据,在SCL为高电平时,就检查SDA的电平是否和发送的数据一致,如果不一致,这个主机便知道自己输掉了仲裁,然后停止向SDA写数据。也就是说,如果主机一致检查到总线上数据和自己发送的数据一致,则继续传输,这样在仲裁过程中就保证了赢得仲裁的master不会丢失数据。 输掉仲裁的主机在检测到自己输了之后也就不再产生时钟脉冲,并且要在总线空闲时才能重新传输。 仲裁的过程可能要经过多个bit的发送和检查,实际上两个主机如果发送的时序和数据完全一样,则两个主机都能正常完成整个数据传输。
注意:多个主机仲裁时,因为线“与”特性,谁低谁能强制SDA为低,也就是跟自己匹配,所以先高(高电平1)的那个就会仲裁失败。
-
典型I2C时序 (1)主机向从机发送数据
(2)从机向主机发送数据
(3)主机先向从机发送数据,然后从机再向主机发送数据
注:S:起始信号,A:应答信号,A非表示非应答,P:终止信号, 2.8 蓝牙模块
-
电路图:
-
管脚功能描述
-
主从设置——28脚——硬件主从设置口:3.3V高水平设置主机透传模式、接地或悬空从机透传
-
LED指示——24脚状态指示LED:主模式均匀闪烁——搜索及连接,长亮——建立连接;从模式均匀慢速闪烁——等待配对,长亮——建立连接;
-
25脚——连接状态指示LED:建立连接高电平,未连接低电平
-
唤醒模块设置:
-
系统按键管脚P1_3:
三、软件环境和程序烧写配置
3.1 软件安装:
-
先将CH340模块连接至电脑USB接口
-
管理员身份安装CH340驱动
-
点击安装
-
在此电脑->管理中查看端口号
-
打开程序烧录软件->选择单片机型号->选择端口->选择程序文件->下载程序->重新上电->烧录成功
2.9 SPI通信协议
-
连接方式1对1
-
连接方式1对多
-
首先拉低对应SS信号线,表示与该设备进行通信
-
主机通过发送SCLK时钟信号,来告诉从机写数据或者读数据这里要注意. SCLK时钟信号可能是低电平有效,也可能是高电平有效,因为SPI有四种模式:
-
主机(Master)将要发送的数据通过MOSI信号线将字节一位一位的移出去传送给从机,同时MISO接 口接收到的数据经过移位寄存器一位一位的移到接收缓存区
-
从机(Slave)也将自己的数据通过MISO信号线返回给主机:同时通过MOSI信号线接收主机发送的数 据。如下图:
SPI只有主模式和从模式之分,没有读和写的说法,外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输。也就是说,你发一个数据必然会收到一个数据;你要收一个数据必须也要先发一个数据。
-
SPI模式
-
Mode0:CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采样是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在上升沿(准备数据),(发送数据)数据发送是在下降沿。 Mode1:CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,数据发送是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿。 Mode2:CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,数据采集是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在下降沿,数据发送是在上升沿。 Mode3:CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,数据发送是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿。
2.10 USB-HID协议
3.2 硬件安装
-
CH340模块连接方式
-
硬件连接
四、程序编写
4.1 小车前进、后退、左转、右转、停止
-
车轮尺寸
-
电机参数:
-
驱动原理图:
-
左电机:
右电机
-
前后左右综合实验
-
代码:
#include "reg52.h"
#define LeftMotorStop IN1=0,IN2=0; //左电机停止
#define RightMotorStop IN3=0,IN4=0; //右电机停止
#define LeftMotorGo IN1=0,IN2=1; //左电机正转
#define RightMotorGo IN3=1,IN4=0; //右电机正转
#define LeftMotorBack IN1=1,IN2=0; //左电机反转
#define RightMotorBack IN3=0,IN4=1; //右电机反转
#define uint unsigned int;
//定义双H桥电机控制电路端口变量
//左电机使能端
sbit ENA = P1^5;
//左电机输入口1
sbit IN1 = P1^4;
//左电机输入口2
sbit IN2 = P1^3;
//右电机输入口1
sbit IN3 = P1^2;
//右电机输入口2
sbit IN4 = P1^1;
//右电机使能端
sbit ENB = P1^0;
//声明函数
//控制小车前进
void SmartCarForward();
//控制小车后退
void SmartCarBack();
//控制小车左转
void SmartCarLeft();
//控制小车右转
void SmartCarRight();
//延迟函数
void delay(uint n);
void main()
{
while(1)
{
SmartCarForward();
delay(2000);
SmartCarBack();
delay(2000);
SmartCarLeft();
delay(2000);
SmartCarRight();
delay(2000);
while(1);
}
}
//控制小车前进
void SmartCarForward(){
ENA=1;
ENB=1;
LeftMotorGo;
RightMotorGo;
}
//控制小车后退
void SmartCarBack(){
ENA=1;
ENB=1;
LeftMotorBack;
RightMotorBack;
}
//控制小车左转
void SmartCarLeft(){
ENA=1;
ENB=1;
LeftMotorStop;
RightMotorGo;
}
//控制小车右转
void SmartCarRight(){
ENA=1;
ENB=1;
LeftMotorGo;
RightMotorStop;
}
//延迟函数
void delay(uint n){
uint i=0,j=0;
for(i=0;i<n;i++)
{
for(j=0;j<120;j++);
}
}
4.2 小车花式动作
-
前进,后退,间歇式前进,间歇式后退,坦克掉头,转圈,蜂鸣器鸣笛
-
蜂鸣器原理:
-
代码:
`#include "reg52.h"` `#define LeftMotorStop IN1=0,IN2=0; //左电机停止` `#define RightMotorStop IN3=0,IN4=0; //右电机停止` `#define LeftMotorGo IN1=0,IN2=1; //左电机正转` `#define RightMotorGo IN3=1,IN4=0; //右电机正转` `#define LeftMotorBack IN1=1,IN2=0; //左电机反转` `#define RightMotorBack IN3=0,IN4=1; //右电机反转` `#define uint unsigned int;` `//定义双H桥电机控制电路端口变量` `//左电机使能端` `sbit ENA = P1^5;` `//左电机输入口1` `sbit IN1 = P1^4;` `//左电机输入口2` `sbit IN2 = P1^3;` `//右电机输入口1` `sbit IN3 = P1^2;` `//右电机输入口2` `sbit IN4 = P1^1;` `//右电机使能端` `sbit ENB = P1^0;` `//声明函数` `//控制小车前进` `void SmartCarForward();` `//控制小车后退` `void SmartCarBack();` `//控制小车左转` `void SmartCarLeft();` `//控制小车右转` `void SmartCarRight();` `//控制小车左掉头` `void SmartCarLeftTurn();` `//控制小车右掉头` `void SmartCarRightTurn();` `//控制小车停止` `void SmartCarStop();` `//延迟函数` `void delay1ms(uint n);` `//初始化定时器0` `void Timer0_Init();` `void main()` `{` `uint i = 0;` `Timer0_Init;` `//前进` `SmartCarForward();` `delay1ms(2000);` `//后退` `SmartCarBack();` `delay1ms(2000);` `//间歇式前进` `for(i=0;i<8;i++)` `{` `SmartCarForward();` `delay1ms(200);` `SmartCarStop();` `delay1ms(200);` `}` `//间歇式后退` `for(i=0;i<8;i++)` `{` `SmartCarBack();` `delay1ms(200);` `SmartCarStop();` `delay1ms(200);` `}` `//左转与坦克掉头` `for(i=0;i<8;i++)` `{` `SmartCarLeft();` `delay1ms(400);` `SmartCarStop();` `delay1ms(200);` `SmartCarRightTurn();` `delay1ms(200);` `SmartCarStop();` `delay1ms(200);` `}` `//右转与坦克掉头` `for(i=0;i<8;i++)` `{` `SmartCarRight();` `delay1ms(400);` `SmartCarStop();` `delay1ms(200);` `SmartCarLeftTurn();` `delay1ms(200);` `SmartCarStop();` `delay1ms(200);` `}` `SmartCarStop();` `//BUZZER = 0;` `delay1ms(1000);` `//BUZZER = 1;` `while(1);` `}` `//控制小车前进` `void SmartCarForward(){` `ENA=1;` `ENB=1;` `LeftMotorGo;` `RightMotorGo;` `}` `//控制小车后退` `void SmartCarBack(){` `ENA=1;` `ENB=1;` `LeftMotorBack;` `RightMotorBack;` `}` `//控制小车左转` `void SmartCarLeft(){` `ENA=1;` `ENB=1;` `LeftMotorStop;` `RightMotorGo;` `}` `//控制小车右转` `void SmartCarRight(){` `ENA=1;` `ENB=1;` `LeftMotorGo;` `RightMotorStop;` `}` `//控制小车左转` `void SmartCarLeftTurn(){` `ENA=1;` `ENB=1;` `LeftMotorBack;` `RightMotorGo;` `}` `//控制小车右转` `void SmartCarRightTurn(){` `ENA=1;` `ENB=1;` `LeftMotorGo;` `RightMotorBack;` `}` `//控制小车停止` `void SmartCarStop()` `{` `LeftMotorStop;` `RightMotorStop;` `}` `//延迟函数` `void delay1ms(uint n){` `uint i=0,j=0,k=0;` `for(k=0;k<n;k++)` `{` `for(i=0;i<2;i++)` `{` `for(j=0;j<248;j++);` `}` `}` `}` `void Timer0_Init(){` `TMOD |=0x02;` `TH0 = 164;` `TL0 = 164;` `TR0 = 1;` `ET0 = 1;` `EA = 1;` `}`
4.3 PWM调速
-
PWM脉宽调制,靠脉冲宽度来控制输出电压,通过改变周期来控制其输出频率
-
IO口输出一个脉冲,指IO发生一次高低电平的变化
-
占空比:一个脉冲时间内,高电平时间与整个脉冲持续时间的比值
-
频率:1S内完成周期性变化的次数,常用f表示
代码:
`#include "reg52.h"`
`#define uint unsigned int`
`#define uchar unsigned char`
`//定义双H桥电机控制电路端口变量`
`//左电机使能端`
`sbit ENA = P1^5;`
`//左电机输入口1`
`sbit IN1 = P1^4;`
`//左电机输入口2`
`sbit IN2 = P1^3;`
`//右电机输入口1`
`sbit IN3 = P1^2;`
`//右电机输入口2`
`sbit IN4 = P1^1;`
`//右电机使能端`
`sbit ENB = P1^0;`
`//PWM周期`
`uchar PWM_T = 0;`
`//左电机速度`
`uchar LeftMotorSpeed = 0;`
`//右电机速度`
`uchar RightMotorSpeed = 0;`
`#define LeftMotorStop IN1=0,IN2=0 //左电机停止`
`#define RightMotorStop IN3=0,IN4=0 //右电机停止`
`#define LeftMotorGo IN1=0,IN2=1 //左电机正转`
`#define RightMotorGo IN3=1,IN4=0 //右电机正转`
`#define LeftMotorBack IN1=1,IN2=0 //左电机反转`
`#define RightMotorBack IN3=0,IN4=1 //右电机反转`
`//声明函数`
`//控制小车前进`
`void SmartCarForward(uchar LeftSpeed,uchar RightSpeed);`
`//控制小车后退`
`void SmartCarBack(uchar LeftSpeed,uchar RightSpeed);`
`//控制小车左转`
`void SmartCarLeft(uchar LeftSpeed,uchar RightSpeed);`
`//控制小车右转`
`void SmartCarRight(uchar LeftSpeed,uchar RightSpeed);`
`//控制小车左掉头`
`void SmartCarLeftTurn(uchar LeftSpeed,uchar RightSpeed);`
`//控制小车右掉头`
`void SmartCarRightTurn(uchar LeftSpeed,uchar RightSpeed);`
`//控制小车停止`
`void SmartCarStop();`
`//延迟函数`
`void delay1ms(uint n);`
`//初始化定时器0`
`void Timer0_Init();`
`void main()`
`{`
`uint i = 0;`
`Timer0_Init();`
`while(1)`
`{`
`for(i=0;i<255;i++)`
`{`
`SmartCarForward(i,i);`
`delay1ms(5);`
`}`
`}`
`/*`
`//前进`
`SmartCarForward();`
`delay1ms(2000);`
`//后退`
`SmartCarBack();`
`delay1ms(2000);`
`//间歇式前进`
`for(i=0;i<8;i++)`
`{`
`SmartCarForward();`
`delay1ms(200);`
`SmartCarStop();`
`delay1ms(200);`
`}`
`//间歇式后退`
`for(i=0;i<8;i++)`
`{`
`SmartCarBack();`
`delay1ms(200);`
`SmartCarStop();`
`delay1ms(200);`
`}`
`//左转与坦克掉头`
`for(i=0;i<8;i++)`
`{`
`SmartCarLeft();`
`delay1ms(400);`
`SmartCarStop();`
`delay1ms(200);`
`SmartCarRightTurn();`
`delay1ms(200);`
`SmartCarStop();`
`delay1ms(200);`
`}`
`//右转与坦克掉头`
`for(i=0;i<8;i++)`
`{`
`SmartCarRight();`
`delay1ms(400);`
`SmartCarStop();`
`delay1ms(200);`
`SmartCarLeftTurn();`
`delay1ms(200);`
`SmartCarStop();`
`delay1ms(200);`
`}`
`SmartCarStop();`
`//BUZZER = 0;`
`delay1ms(1000);`
`//BUZZER = 1;`
`while(1);`
`*/`
`}`
`//控制小车前进`
`void SmartCarForward(uchar LeftSpeed,uchar RightSpeed){`
`LeftMotorSpeed = LeftSpeed;`
`RightMotorSpeed = RightSpeed;`
`ENA=1;`
`ENB=1;`
`LeftMotorGo;`
`RightMotorGo;`
`}`
`//控制小车后退`
`void SmartCarBack(uchar LeftSpeed,uchar RightSpeed){`
`LeftMotorSpeed = LeftSpeed;`
`RightMotorSpeed = RightSpeed;`
`ENA=1;`
`ENB=1;`
`LeftMotorBack;`
`RightMotorBack;`
`}`
`//控制小车左转`
`void SmartCarLeft(uchar LeftSpeed,uchar RightSpeed){`
`LeftMotorSpeed = LeftSpeed;`
`RightMotorSpeed = RightSpeed;`
`ENA=1;`
`ENB=1;`
`LeftMotorStop;`
`RightMotorGo;`
`}`
`//控制小车右转`
`void SmartCarRight(uchar LeftSpeed,uchar RightSpeed){`
`LeftMotorSpeed = LeftSpeed;`
`RightMotorSpeed = RightSpeed;`
`ENA=1;`
`ENB=1;`
`LeftMotorGo;`
`RightMotorStop;`
`}`
`//控制小车掉头`
`void SmartCarLeftTurn(uchar LeftSpeed,uchar RightSpeed){`
`LeftMotorSpeed = LeftSpeed;`
`RightMotorSpeed = RightSpeed;`
`ENA=1;`
`ENB=1;`
`LeftMotorBack;`
`RightMotorGo;`
`}`
`//控制小车右掉头`
`void SmartCarRightTurn(uchar LeftSpeed,uchar RightSpeed){`
`LeftMotorSpeed = LeftSpeed;`
`RightMotorSpeed = RightSpeed;`
`ENA=1;`
`ENB=1;`
`LeftMotorGo;`
`RightMotorBack;`
`}`
`//控制小车停止`
`void SmartCarStop()`
`{`
`LeftMotorStop;`
`RightMotorStop;`
`}`
`//延迟函数`
`void delay1ms(uint n){`
`uint i=0,j=0,k=0;`
`for(k=0;k<n;k++)`
`{`
`for(i=0;i<2;i++)`
`{`
`for(j=0;j<248;j++);`
`}`
`}`
`}`
`void Timer0_Init(){`
`TMOD |=0x02; //定时器0,8位自动重装模块`
`TH0 = 164; //11.0592M晶振,12T溢出时间约等于100微秒`
`TL0 = 164; //256-N/(12/11.0592)`
`TR0 = 1; //启动定时器0`
`ET0 = 1; //允许定时器0中断`
`EA = 1; //总中断允许`
`}`
`void tm0_isr() interrupt 1`
`{`
`PWM_T++;`
`if(PWM_T == 255)`
`{`
`PWM_T = 0;`
`}`
`if(LeftMotorSpeed >= PWM_T)`
`{`
`LeftMotorGo;`
`}`
`if(LeftMotorSpeed < PWM_T)`
`{`
`LeftMotorStop;`
`}`
`if(RightMotorSpeed >= PWM_T)`
`{`
`RightMotorGo;`
`}`
`if(RightMotorSpeed < PWM_T)`
`{`
`RightMotorStop;`
`}`
`}`
4.3 小车黑线循迹
-
硬件工作原理 两个反射型光电探测器RPR220,电压比较芯片LM358
-
PRP220 内部由一个红外发射管和一个光电三极管组成,当红外发射管发射的红外光被反射后,根据反射回来接收到的红外光强度不同,内部光电三极管的阻抗会发生对应的变化,当接收到的红外光强时光电三极管阻抗低,反之则高。
-
R25是用来给红外发射管限流的
-
RP3是10K电位器,调节输出电压,提供参考电压
-
LM358比较器,如果输出低电压LED7点亮,如果输出高电压LED7熄灭
-
R22用来给LED7限流
-
R19的上拉电阻,不输出低电平则输出高电平
-
循迹原理:
-
右侧未检测到黑线,向左转;左侧未检测到黑线,向右转;两侧都检测到黑线,直行
-
防出线:
-
当左右循迹探头都未检测到黑线时,证明小车已经驶离黑线,这时调用小车后退命令即可回到黑线上。
-
防出轨:
-
当小车出轨时,小车倒退回到轨道
代码:
- #include "reg52.h"
#define uint unsigned int
#define uchar unsigned char
//定义双H桥电机控制电路端口变量
//左电机使能端
sbit ENA = P1^5;
//左电机输入口1
sbit IN1 = P1^4;
//左电机输入口2
sbit IN2 = P1^3;
//右电机输入口1
sbit IN3 = P1^2;
//右电机输入口2
sbit IN4 = P1^1;
//右电机使能端
sbit ENB = P1^0;
//左循迹信号 为0没有识别到黑线,为1识别到黑线
sbit L_TrackSensorPin = P3^5;
//右循迹信号 为0没有识别到黑线,为1识别到黑线
sbit R_TrackSensorPin = P3^4;
//PWM周期
uchar PWM_T = 0;
//左电机速度
uchar LeftMotorSpeed = 0;
//右电机速度
uchar RightMotorSpeed = 0;
#define LeftMotorStop IN1=0,IN2=0 //左电机停止
#define RightMotorStop IN3=0,IN4=0 //右电机停止
#define LeftMotorGo IN1=1,IN2=0 //左电机正转
#define RightMotorGo IN3=0,IN4=1 //右电机正转
#define LeftMotorBack IN1=0,IN2=1 //左电机反转
#define RightMotorBack IN3=1,IN4=0 //右电机反转
#define PWM_HIGH_MIN 60 //限制PWM输出的最小占空比。用户请勿修改。
#define PWM_HIGH_MAX 200 //限制PWM输出的最大占空比。用户请勿修改。
//声明函数
//控制小车前进
void SmartCarForward(uchar LeftSpeed,uchar RightSpeed);
//控制小车后退
void SmartCarBack(uchar LeftSpeed,uchar RightSpeed);
//控制小车左转
void SmartCarLeft(uchar LeftSpeed,uchar RightSpeed);
//控制小车右转
void SmartCarRight(uchar LeftSpeed,uchar RightSpeed);
//控制小车左掉头
void SmartCarLeftTurn(uchar LeftSpeed,uchar RightSpeed);
//控制小车右掉头
void SmartCarRightTurn(uchar LeftSpeed,uchar RightSpeed);
//控制小车停止
void SmartCarStop();
//延迟函数
void delay1ms(uint n);
//初始化定时器0
void Timer0_Init();
//小车循迹
void Tracking();
//小车变速
void LoadPWM();
void main()
{
//循迹
Timer0_Init();
while(1){
Tracking();
}
}
//控制小车前进
void SmartCarForward(uchar LeftSpeed,uchar RightSpeed){
LeftMotorSpeed = LeftSpeed;
RightMotorSpeed = RightSpeed;
ENA=1;
ENB=1;
LeftMotorGo;
RightMotorGo;
}
//控制小车后退
void SmartCarBack(uchar LeftSpeed,uchar RightSpeed){
LeftMotorSpeed = LeftSpeed;
RightMotorSpeed = RightSpeed;
LeftMotorBack;
RightMotorBack;
}
//控制小车左转
void SmartCarLeft(uchar LeftSpeed,uchar RightSpeed){
LeftMotorSpeed = LeftSpeed;
RightMotorSpeed = RightSpeed;
LeftMotorStop;
RightMotorGo;
}
//控制小车右转
void SmartCarRight(uchar LeftSpeed,uchar RightSpeed){
LeftMotorSpeed = LeftSpeed;
RightMotorSpeed = RightSpeed;
LeftMotorGo;
RightMotorStop;
}
//控制小车左掉头
void SmartCarLeftTurn(uchar LeftSpeed,uchar RightSpeed){
LeftMotorSpeed = LeftSpeed;
RightMotorSpeed = RightSpeed;
LeftMotorBack;
RightMotorGo;
}
//控制小车右掉头
void SmartCarRightTurn(uchar LeftSpeed,uchar RightSpeed){
LeftMotorSpeed = LeftSpeed;
RightMotorSpeed = RightSpeed;
LeftMotorGo;
RightMotorBack;
}
//控制小车停止
void SmartCarStop()
{
LeftMotorStop;
RightMotorStop;
}
//延迟函数
void delay1ms(uint n){
uint i=0,j=0,k=0;
for(k=0;k<n;k++)
{
for(i=0;i<2;i++)
{
for(j=0;j<248;j++);
}
}
}
void Timer0_Init(){
TMOD |=0x02; //定时器0,8位自动重装模块
TH0 = 164; //11.0592M晶振,12T溢出时间约等于100微秒
TL0 = 164; //256-N/(12/11.0592)
TR0 = 1; //启动定时器0
ET0 = 1; //允许定时器0中断
EA = 1; //总中断允许
}
void Tracking(){
if((L_TrackSensorPin == 1) && (R_TrackSensorPin ==1)){
SmartCarForward(100,100);
}else{
if((L_TrackSensorPin == 1) && (R_TrackSensorPin ==0)){
SmartCarLeftTurn(60,140);
}else if((L_TrackSensorPin == 0) && (R_TrackSensorPin ==1)){
SmartCarRightTurn(140,60);
}else{
delay1ms(10);
SmartCarStop();
delay1ms(1);
SmartCarBack(80,80);
}
}
}
//小车变速
void LoadPWM(){
if(LeftMotorSpeed > PWM_HIGH_MAX) LeftMotorSpeed = PWM_HIGH_MAX; //如果左输出写入大于最大占空比数据,则强制为最大占空比。
if(LeftMotorSpeed < PWM_HIGH_MIN) LeftMotorSpeed = PWM_HIGH_MIN; //如果左输出写入小于最小占空比数据,则强制为最小占空比。
if(RightMotorSpeed > PWM_HIGH_MAX) RightMotorSpeed = PWM_HIGH_MAX; //如果右输出写入大于最大占空比数据,则强制为最大占空比。
if(RightMotorSpeed < PWM_HIGH_MIN) RightMotorSpeed = PWM_HIGH_MIN; //如果右输出写入小于最小占空比数据,则强制为最小占空比。
if(LeftMotorSpeed >= PWM_T)
{
ENA=1;
}
if(LeftMotorSpeed < PWM_T)
{
ENA=0;
}
if(RightMotorSpeed >= PWM_T)
{
ENB=1;
}
if(RightMotorSpeed < PWM_T)
{
ENB=0;
}
}
void tm0_isr() interrupt 1
{
PWM_T++;
if(PWM_T == 255){
PWM_T = 0;
}
LoadPWM();
}`
4.4 蓝牙控制模块
APP:
代码模块
#include "reg52.h"
#define uint unsigned int
#define uchar unsigned char
//定义双H桥电机控制电路端口变量
//左电机使能端
sbit ENA = P1^5;
//左电机输入口1
sbit IN1 = P1^4;
//左电机输入口2
sbit IN2 = P1^3;
//右电机输入口1
sbit IN3 = P1^2;
//右电机输入口2
sbit IN4 = P1^1;
//右电机使能端
sbit ENB = P1^0;
//左循迹信号 为0没有识别到黑线,为1识别到黑线
sbit L_TrackSensorPin = P3^5;
//右循迹信号 为0没有识别到黑线,为1识别到黑线
sbit R_TrackSensorPin = P3^4;
//蜂鸣器
sbit Buzzer = P2^2;
//左电机速度
uchar LeftMotorSpeed = 100;
//右电机速度
uchar RightMotorSpeed = 100;
// 当前命令状态
uchar currentCmd = 0;
#define LeftMotorStop IN1=0,IN2=0 //左电机停止
#define RightMotorStop IN3=0,IN4=0 //右电机停止
#define LeftMotorGo IN1=1,IN2=0 //左电机正转
#define RightMotorGo IN3=0,IN4=1 //右电机正转
#define LeftMotorBack IN1=0,IN2=1 //左电机反转
#define RightMotorBack IN3=1,IN4=0 //右电机反转
#define PWM_HIGH_MIN 0 //限制PWM输出的最小占空比。用户请勿修改。
#define PWM_HIGH_MAX 255 //限制PWM输出的最大占空比。用户请勿修改。
#define MAIN_Fosc 11059200L //定义主时钟
#define Main_Fosc_KHZ (MAIN_Fosc / 1000)
#define BAUD 9600 //UART 波特率
//声明函数
//控制小车前进
void SmartCarForward(uchar LeftSpeed,uchar RightSpeed);
//控制小车后退
void SmartCarBack(uchar LeftSpeed,uchar RightSpeed);
//控制小车左转
void SmartCarLeft(uchar LeftSpeed,uchar RightSpeed);
//控制小车右转
void SmartCarRight(uchar LeftSpeed,uchar RightSpeed);
//控制小车左掉头
void SmartCarLeftTurn(uchar LeftSpeed,uchar RightSpeed);
//控制小车右掉头
void SmartCarRightTurn(uchar LeftSpeed,uchar RightSpeed);
//控制小车停止
void SmartCarStop();
//延迟函数
void delay1ms(uint n);
//初始化定时器0
void Timer0_Init();
//小车循迹
void Tracking();
//小车变速
void LoadPWM();
//串口初始化
void UartInit();
//发送单字节
void sendByte(char data_msg);
//发送字符串
void sendString(char* str);
void main()
{
//蓝牙串口通信
char cmd;
Buzzer = 1;
Timer0_Init();
UartInit();
while(1){
if(RI==1){
RI=0;
cmd = SBUF;
if(cmd != currentCmd) { // 只有在接收到新的命令时才更新状态
switch(cmd)
{
case 0x01: Tracking(); sendString("Tracking"); break;
case 0x02: SmartCarForward(80,80); sendString("SmartCarForward"); break;
case 0x03: SmartCarBack(80,80); sendString("SmartCarBack"); break;
case 0x04: SmartCarLeft(50,100); sendString("SmartCarLeft"); break;
case 0x05: SmartCarRight(100,50); sendString("SmartCarRight"); break;
case 0X06: SmartCarLeftTurn(0,100); sendString("SmartCarLeftTurn"); break;
case 0X07: SmartCarRightTurn(100,0); sendString("SmartCarRightTurn"); break;
case 0X08: Buzzer = 0; sendString("open"); break;
case 0X09: Buzzer = 1; sendString("close"); break;
case 0X0A: SmartCarStop(); sendString("stop"); break;
default: SmartCarStop(); sendString("stop"); break;
}
currentCmd = cmd; // 更新当前命令状态
}
}else{
cmd = currentCmd; // 更新当前命令状态
switch(cmd)
{
case 0x01: Tracking(); sendString("Tracking"); break;
case 0x02: SmartCarForward(80,80); sendString("SmartCarForward"); break;
case 0x03: SmartCarBack(80,80); sendString("SmartCarBack"); break;
case 0x04: SmartCarLeft(50,100); sendString("SmartCarLeft"); break;
case 0x05: SmartCarRight(100,50); sendString("SmartCarRight"); break;
case 0X06: SmartCarLeftTurn(0,100); sendString("SmartCarLeftTurn"); break;
case 0X07: SmartCarRightTurn(100,0); sendString("SmartCarRightTurn"); break;
case 0X08: Buzzer = 0; sendString("open"); break;
case 0X09: Buzzer = 1; sendString("close"); break;
case 0X0A: SmartCarStop(); sendString("stop"); break;
default: SmartCarStop(); sendString("stop"); break;
}
}
}
}
//控制小车前进
void SmartCarForward(uchar LeftSpeed,uchar RightSpeed){
LeftMotorSpeed = LeftSpeed;
RightMotorSpeed = RightSpeed;
LeftMotorGo;
RightMotorGo;
}
//控制小车后退
void SmartCarBack(uchar LeftSpeed,uchar RightSpeed){
LeftMotorSpeed = LeftSpeed;
RightMotorSpeed = RightSpeed;
LeftMotorBack;
RightMotorBack;
}
//控制小车左转
void SmartCarLeft(uchar LeftSpeed,uchar RightSpeed){
LeftMotorSpeed = LeftSpeed;
RightMotorSpeed = RightSpeed;
LeftMotorStop;
RightMotorGo;
}
//控制小车右转
void SmartCarRight(uchar LeftSpeed,uchar RightSpeed){
LeftMotorSpeed = LeftSpeed;
RightMotorSpeed = RightSpeed;
LeftMotorGo;
RightMotorStop;
}
//控制小车左掉头
void SmartCarLeftTurn(uchar LeftSpeed,uchar RightSpeed){
LeftMotorSpeed = LeftSpeed;
RightMotorSpeed = RightSpeed;
LeftMotorBack;
RightMotorGo;
}
//控制小车右掉头
void SmartCarRightTurn(uchar LeftSpeed,uchar RightSpeed){
LeftMotorSpeed = LeftSpeed;
RightMotorSpeed = RightSpeed;
LeftMotorGo;
RightMotorBack;
}
//控制小车停止
void SmartCarStop()
{
LeftMotorStop;
RightMotorStop;
}
//延迟函数
void delay1ms(uint n){
uint i=0,j=0,k=0;
for(k=0;k<n;k++)
{
for(i=0;i<2;i++)
{
for(j=0;j<248;j++);
}
}
}
void Timer0_Init(){
TMOD |= 0x02;//定时器0,8位自动重装模块
TH0 = 164;
TL0 = 164;//11.0592M晶振,12T溢出时间约等于100微秒
TR0 = 1;//启动定时器0
ET0 = 1;//允许定时器0中断
EA = 1;//总中断允许
}
void Tracking(){
if((L_TrackSensorPin == 1) && (R_TrackSensorPin ==1)){
SmartCarForward(100,100);
}else{
if((L_TrackSensorPin == 1) && (R_TrackSensorPin ==0)){
SmartCarLeftTurn(60,140);
}else if((L_TrackSensorPin == 0) && (R_TrackSensorPin ==1)){
SmartCarRightTurn(140,60);
}else{
delay1ms(10);
SmartCarStop();
delay1ms(1);
SmartCarBack(80,80);
}
}
}
//小车变速
void LoadPWM(){
//PWM周期
static uchar PWM_T = 0;
PWM_T++;
if(PWM_T == 255){
PWM_T = 0;
}
// 设置左电机的PWM输出
ENA = (PWM_T < LeftMotorSpeed);
// 设置右电机的PWM输出
ENB = (PWM_T < RightMotorSpeed);
}
//发送单字节
void sendByte(char data_msg)
{
SBUF = data_msg;
while(!TI);
TI = 0;
}
//发送字符串
void sendString(char* str)
{
while( *str != '\0'){
sendByte(*str);
str++;
}
}
void UartInit(){
SCON |= 0x50; // SCON: 模式1, 8-bit UART, 使能接收
T2CON |= 0x34; //设置定时器2为串口波特率发生器并启动定时器2
TL2 = RCAP2L = (65536-(MAIN_Fosc/32/BAUD)); //设置波特率
TH2 = RCAP2H = (65536-(MAIN_Fosc/32/BAUD)) >> 8;
ES= 1; //打开串口中断
sendString("A11-J Ready!\r\n"); //UART1发送一个字符串
}
void tm0_isr() interrupt 1
{
LoadPWM();
}