文章记录:极客领航
该项目是极客领航教程中嵌入式项目,智能小车远程控制系统
代码开源(文末)。
设计体系主要包括(如图所示)
- 小车主体(51与STM32实现)
- 硬件遥控器(主控STM32)
- 手机遥控软件(Android设计)
- 电脑控制软件(QT设计)
该设计在小车上未加太多传感器,先主要实现小车的主要功能,就是遥控。对于测距、显示屏、陀螺仪、循迹等等都可以在基础功能实现后添加。在教程的后续会写循迹小车、平衡小车、玲珑机器人等文章,可参考极客领航教程体系。
下面是以前制作的小车,现在看来是有点丑,小车和遥控器可以画PCB和3D建模,这样会好看很多,感兴趣的可以看该教程的辅助设计篇。
以前设计的海报,现在看起来感觉也还行。
在这里我先不多说了,感兴趣的可以支持下,后续我也会录制作教程视频,如果觉得文章枯燥的可以看视频学。
小车主体(51)
小车主体主要模块是L298N电机驱动模块与ESP8266WiFi模块.
L298N电机驱动
核心知识点
- 通道A和通道B是接两个电机,不分正负极。
- 5V输入是给L298N芯片供电的,有的接主电源正极过后,芯片就会通电,不用外接,然后可以利用这个电压去给其他单片机供电。
- 主电源正极的给电机输出的电压,最大不超过12V
- 输入1,2,3,4是控制电机正反转的,比如1给高电平,2给低电平,电机就会转动,反接电机就会反转。12控制一个电机,34控制一个电机。
- A相使能端与B相使能端是给电机使能的,如果我们不进行调速,就直接接高电平,在L298N上面就是接旁边引脚,速度快慢是根据电机电压大小判断。如果我们需要进行调速,那么这两个引脚需要接单片机引脚,通过程序设计,进行PWM输出。
51代码设置,我们如何定义就如何接线。
//使能端,利用PWM波实现调速
sbit ENA = P1^4;
sbit ENB = P1^5;
sbit IN1 = P1^0; //定义右边控制引脚
sbit IN2 = P1^1;
sbit IN3 = P1^2; //定义左边控制引脚
sbit IN4 = P1^3;
如何控制电机转动呢?
上面我们设置好引脚了,可以先让使能端接高电平,或者让使能端引脚等于高电平。
如果想让右边的电机转动,那么可以IN1 = 1,IN2 = 0,电机就会转动,如果IN1 = 0,IN2 = 1,电机就会反转。如果IN1 = 1,IN2 = 1;IN1 = 0,IN2 = 0,电机都会停止。
如何对电机进行调速呢?
电机调速,就会涉及PWM输出,在51中就会涉及定时器,占空比。
那么我们就先说下定时器的配置,主要包括初始化与中断函数。
定时器基本寄存器
- 没有基础看寄存器比较费劲,在这里我也不深究,需要哪些内容就提出来,不想了解的可以跳过,看应用就好。
中断系统图
TMOD寄存器
TCON 定时器控制寄存器
TR0 :TR0=1表示T0开始运行。(单片机中T1引脚,需要高低电平的驱动)
TR1 :TR1=1表示T1开始运行。(单片机中T0引脚,需要高低电平的驱动)
中断源优先级及中断号
在这里需要哪些内容我就列举出来,至于寄存器具体知识,可以自己去查阅,我不想文章太冗杂。
定时器初始化流程
- 1、选择定时器的模式,设置TMOD,比如我们设置TMOD=0X01;由上图可知,M1 = 0,M0 = 1;选择了方式一。要记住后四位是定时器0,前四位是定时器1。选择模式,就是确定了定时和计数的寄存器是多少位。
- 2、给定时器送入初值,确定每次寄存器溢出的时间
送入初值的具体原理:
由TMOD模式选择可知,方式1为16位定时器/计数器
16位寄存器容量为65535
定时器一旦开始,寄存器就会在原来的数值上加 1,每次加1的时间为1个机器周期
一个机器周期等于12个时钟周期,时钟周期与晶振的频率有关
如果晶振频率为12HZ,那么一个时钟周期的时间为1/12us
所以一个机器周期就为 1us
就说明,寄存器每一次计数都需要1us的时间
10000us == 10ms
如果我们将寄存器的初值设置为 65535 - 10000 = 55535
那么从55535开始计数,当达到65535时,需要计数10000次,就是10ms
我们可以控制寄存器溢出的次数,来得到准确的时间
假如我们设置每次溢出要10ms,那么100次就是 1s
又怎么设置寄存器的初值呢?
假如我们要设置初值为55535
1、对55535 / 256 = 216; 216对应的十六进制就是 1101 1000 = 0xd8
写成 TH0=0Xd8;
2、再对55535 % 256 = 239; 239对应十六进制为 1110 1111 = 0xef
写成 TL0=0Xf0;
- 3、打开中断允许,就是ET0,EA
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
- 4、开始计时 TR0=1;
根据中断系统图分享逻辑就比较清晰,后续录视频教程,文章主要是总结。
由上面分析可知,我们可以写出
定时器0的初始化函数
//定时器0初始化函数
void Timer0Config()
{
TMOD &= 0xF0; //清除定时器0的模式
TMOD |= 0x01; //设置定时器0模式
TH0 = 0xFF; //送入初值 (65536 - 130) / 256 65536 - 65406
TL0 = 0x7E; //(65536 - 130) % 256
EA = 1; //打开总中断
ET0 = 1; //打开定时器0中断允许
TR0 = 1; //定时器0允许控制位
}
定时器0中断函数
//定时器0 中断函数 中断号为 1
void InterruptTimer0() interrupt 1
{
//每次溢出过后,都需要重新设置初值
TH0 = 0xFF; //给定时器赋初值,定时130us
TL0 = 0x7E;
cnt++; //每次溢出cnt自加1,130us自加一次
if(cnt >= 100) //当cnt大于等于100时,就清0
{
cnt = 0;
}
//在这里是定义一个周期为 130 * 100 = 13000us,13ms
}
定时器初始化函数和中断函数都写了,又如何控制电机呢?
目前还不行,因为我们还有写PWM函数。
我们通过一段代码来分析
IN3 = 1;
if(cnt <= DutyCycle) //DutyCycle是占空比
{
IN4 = 0;
}
else
{
IN4 = 1;
}
因为由定时器中断函数,cnt变量在0 - 100进行循环,一个周期溢出100次;分析上面代码,当占空比DutyCycle = 60时,我们执行一百次上面的程序,cnt递增。会发现在IN3一百次都是1,IN4六十次为0,四十次为1,速度是全速的%60;当空比DutyCycle = 100时,一个周期内IN3全是1,IN4全是0,速度为全速。所以我们可以通过修改占空比来调节速度。
上面分析可能比较模糊,因为没有主观的认识,可以利用单片机和电机驱动进行测试,去修改占空比,看速度的变化,在视频教程中我也会演示。
我们将调节占空比的函数封装一下。
/*
参数定义:
ReverOrCoro 传递正反转,1为正转,0为反转
DutyCycle 占空比参数
*/
void Motor_Right(bit ReverOrCoro, unsigned char DutyCycle)
{
if(ReverOrCoro == 1)
{
IN3 = 1;
if(cnt <= DutyCycle)
{
IN4 = 0;
}
else
{
IN4 = 1;
}
}
else
{
IN4 = 1;
if(cnt <= DutyCycle)
{
IN3 = 0;
}
else
{
IN3 = 1;
}
}
}
在程序中我们如何调用的呢?
Motor_Right(0, 0); //占空比为0,停止
Motor_Right(0, 50); //占空比为50,中速
Motor_Right(0, 100); //占空比为100,全速
上面是控制右边电机的函数,左边也是一样,只是修改为IN1,IN2。
通过定时器的初始化,中断函数,PWM电机调速函数。我们已经可以控制电机的转向和转速了。如果我们要实现遥控小车,就是接收遥控器传过来的数据,进行判断。可以看下程序中的写法,下文会分析程序。
if(receiveTable[9]==0x31) //当送入字符1时,前进
{
Motor_Left(1, number), Motor_Right(0, number);
}
if(receiveTable[9]==0x32) //当送入字符2时,后退
{
Motor_Left(0, number), Motor_Right(1, number);
}
if(receiveTable[9]==0x33) //当送入字符3时,左转
{
Motor_Left(1, number), Motor_Right(0, 0);
}
到这里电机驱动的部分就完了,回顾一下,我们需要掌握哪些知识。
- 1、L298N电机驱动芯片的引脚含义,要区分控制电机,控制电机转向、供电、使能各个部分。
- 2、定时器相关的寄存器,TMON,TCON,还有中断系统图。
- 3、定时器0初始化的步骤,设置模式、送入初值、开启定时。
- 4、定时器中断函数,每次溢出的时间我们可以控制,每次溢出做什么是需要我们考虑的。
- 5、PWM输出函数,通过定时器0的配置,要知道我们怎么设置占空比,进行调速。
ESP8266
上面是两种WiFi模块,第一种是ESP8266 -01s,下面是Esp8266(NodeMCU),我们这里只是用来进行数据传输,效果相同。
ESP8266原理
ESP8266模式:
AP模式 服务器
STA模式 客户端
AP + STA模式
测试ESP8266
可以利用串口助手进行AT指令测试。
通信结构图
51和STM32原理都一样。
配置思路
- 如果单片机当作服务器,那么ESP8266就是AP模式,开放热点,拥有IP地址与端口号。其他TCP客户端想要连接服务器时,需要先连接热点,然后再绑定IP地址与端口号,进行连接
- 如果是STA模式,就需要连接服务器的热点,绑定IP地址与端口号,进行连接
连接范围
- 因为是利用WIFI局部通信,只是在局部网内有效,想要实现广域网通信,可以连接到云服务器,需要利用WIFI或者流量配置
ESP8266配置成服务器(指令)
ESP8266配置成服务器(PC或单片机发指令):
(1) 测试AT指令:AT
(2) 更改模块波特率:
AT+CIOBAUD=9600 (波特率设置成功后要更改后再进行设置其它波特率)
(3) 复位重启模块:AT+RST
(4) 设置为AP模式:AT+CWMODE=2
(5) 设置name password,加密方式:
AT+CWSAP="esp8266","123456789",11,4
(6) 查看主机端的ip地址:
AT+CIFSR(此处的IP地址是模块本身的IP,不是ST模式中加入路由器后分配的IP)
(7) 设置模块传输模式为TCP模式:AT+CIPMODE=0
(8) 设置为多连接模式,启动模块:AT+CIPMUX=1
(9) 服务器的设置端口:
AT+CIPSERVER=1,8090 (TCP client连接server时端口号要保持一致)
指令测试
设置AP模式、账号密码,然后就能搜索到WIFI模块了。
TCP客服端数据传输测试。
自己写的TCP客户端进行通信,成功。
通过串口助手我们可以测试相关指令,我上面测试了一遍,设置AP模式过后,再设置账号密码,然后利用TCP客户端进行连接,进行数据传输测试。
上面是在串口助手上面测试ESP8266,而我们是要把ESP8266运用到单片机上面。通过AT指令的测试,我们也发现,在串口助手上面,我们也是发送相关的指令到串口助手上面,然后通过串口发送到ESP8266上面。
如下图,我们也需要利用单片机的串口,发送指令到ESP8266上面进行配置。
所以下面我们介绍51串口的配置与使用。
串口初始化函数
//串口初始化函数
void UartInit(void) //串口初始化函数
{
TMOD &= 0x0F; //清除定时器1的配置
TMOD |= 0x20; //定时器工作方式2,8位自动重载(0010 0000)
TL1 = 0xfd; //装入初值
TH1 = 0xfd; //装入初值
IP = 0; //中断优先级相同
TR1 = 1; //启动定时器1
REN=1; //允许串行口接收数据
SM0=0; //工作方式1,10位异步收发
SM1=1;
EA = 1; //打开全局中断控制
ES=1; //打开串行口中断
}
串口发送数据(单个字节)
//串口发送数据 单个字节
void Sent_ZF(u8 dat) //发送一个字节
{
ES = 0; //不允许串行口接受、发送中断
TI=0; //循环等待发送结束,当发送结束时,TI=1了
SBUF = dat; //将dat数据存入SBUF中,为一字节
while(!TI); //当发送完成,TI = 1,那么!TI为假,结束循环
TI = 0; //TI复位
ES = 1; //允许串行口接受、发送中断
}
串口发送数据(字符串)
//串口发送数据,字符串
void AT_Send_String(u8 *string) //发送字符串
{
while(*string) //当到字符尾时,'\0' 会结束循环
{
Sent_ZF(*string++);//调用发送单个字节函数
Delay_ms(5);
}
}
串口中断函数
//串口中断函数 接收数据
void uart() interrupt 4
{
if(RI == 1) //说明接收到了数据
{
RI = 0; //清除串口接收标志位,只有清除了,下一次才能接收数据
receiveTable[i] = SBUF; //将数据存入数组中
if(receiveTable[0] == '+')
//判断是否为无效数据,由于WiFi模块会自动加上“+PID. ”开头的字符串
//有效的数据是第十位
//假如外部通过ESP8266发送数据 5 到51上
//那么51串口接收到"+PID...5" 5是第十位
//所以receiveTable[9]才是我们真正的数据
{
i++;
}
else
{
i = 0;
}
if(i == 10)
{
i = 0;
}
}
}
ESP8266初始化函数
//ESP8266 初始化函数
void ESP8266_Init() //esp8266 9600波特率
{
Delay_ms(1000);
// = 2 为AP模式,= 1 为客户端模式
AT_Send_String("AT+CWMODE=2\r\n");
Delay_ms(1000);
//建立WiFi热点
AT_Send_String("AT+CWSAP=esp8266,0123456789,11,4\r\n");
Delay_ms(1000);
AT_Send_String("AT+RST\r\n"); //重启模块
Delay_ms(1000);
//设置为多连接模式,启动模块
AT_Send_String("AT+CIPMUX=1\r\n");
Delay_ms(1000);
//服务器的设置端口
AT_Send_String("AT+CIPSERVER=1,8090\r\n");
}
ESP8266配置客户端
配置服务器指令(STA模式)
1、AT+CWMODE=1 配置STA模式
2、AT+RST 重启生效
3、AT+CWJAP="wifi名称","WiFi密码" 连接WIFI
4、AT+CIPSTART="TCP","192.168.4.1",8090 连接服务器
5、AT+CIPSEND=4 发送指令
6、AT+CIPMODE=1 开启透传模式
7、AT+CIPSEND 开始透传
代码链接
链接:代码链接
提取码:1314