Java教程

极客领航 ( 51、STM32、智能小车项目、ESP8266、远程控制系统 )

本文主要是介绍极客领航 ( 51、STM32、智能小车项目、ESP8266、远程控制系统 ),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章记录:极客领航

该项目是极客领航教程中嵌入式项目,智能小车远程控制系统
代码开源(文末)。

设计体系主要包括(如图所示)

  • 小车主体(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

这篇关于极客领航 ( 51、STM32、智能小车项目、ESP8266、远程控制系统 )的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!