小车联网—通过ESP8266将速度发送到客户端

小车联网-通过ESP8266将速度发送到客户端

实现目标:

客户端通过网络发送启动信息控制小车启动,小车将速度实时地发送给客户端查看,同时也能在OLED屏上显示速度信息

基于小车测速并通过OLED显示的代码进行修改

程序

程序文件

1.main.c:定时器0、定时器2、串口初始化函数的调用,自动发送AT指令函数,外部中断初始化函数,OLED屏初始化函数,while循环内根据标志位将速度数据通过串口发送到客户端,在OLED上显示

2.Motor.c:小车前进、后退、左转、右转和停止的函数

3.Delay.c:延时函数

4.Timer0.c:定时器0初始化,中断处理函数PWM控制小车前进

5.Timer2.c:定时器2初始化,中断处理函数定义1秒,接收外部中断的变量,然后置0,开启下一次计算

6.Int0.c:外部中断0初始化,测速模块有下降沿来,则中断处理函数变量++

7.IIC.c:IIC协议,供OLED屏使用

8.OLED.c:OLED写命令、写数据、初始化、清屏、显示等函数

9.WIFI.c:AT指令数组,设置为AP模式,以及根据应答调用串口发送函数发送AT指令的函数,和发送指定通道和数据长度的AT指令

在这里插入图片描述

1.添加WIFI.c文件

将之前ESP8266当AP模式的代码模块化后,整理出WIFI.c源文件,并将源文件复制到本次代码的工程目录下,然后在keil中添加进来,

主要是用来设置AP模式的AT指令数组,需要加code,将数组放到ROM中,不然代码太大编译不通过,然后是应答的标志位,两个通过串口发送AT指令的函数

相应的在WIFI.h头文件中添加函数的声明

#include <REGX52.H>
#include <string.h>
#include "Usart.h"
#include "Delay.h"

//AP模式AT指令
code char CWMODE[] = "AT+CWMODE=2\r\n";
code char CIPMUX[] = "AT+CIPMUX=1\r\n";
code char CIPSERVER[] = "AT+CIPSERVER=1\r\n";
code char CIPSEND[] = "AT+CIPSEND=0,13\r\n";

unsigned char AT_OK_Flag = 0;					//收到OK应答标志
unsigned char Client_Connect_Flag = 0;			//收到客户端连接标志
unsigned char Client_Disconnect_Flag = 0;		//客户端断开连接标志
/**
  * @brief 自动发送AT指令
  * @param 无
  * @retval无
  */
void Automatic_connection()
{
	//设置为AP模式,防止自动连接WIFI干扰应答
	Uart_SendString(CWMODE);
	while(!AT_OK_Flag);
	AT_OK_Flag = 0;
	
	//使能多连接
	Uart_SendString(CIPMUX);
	while(!AT_OK_Flag);
	AT_OK_Flag = 0;
	
	Delay1ms(2000);
	
	//开启TCP Server
	Uart_SendString(CIPSERVER);
	while(!AT_OK_Flag);
	AT_OK_Flag = 0;
	
	//等待客户端连接
	while(!Client_Connect_Flag);
}

/**
  * @brief 自动发送数据
  * @param 无
  * @retval无
  */
void Automatic_send_data()
{
	Uart_SendString(CIPSEND);
}

2.Usart.c头文件的中断处理函数中添加AT应答的判断语句

结合之前ESP8266的串口通信,在小车的串口中断中直接添加判断语句即可

/**
  * @brief 串口中断处理函数
  * @param 无
  * @retval无
  */
void Uart_Rountine() interrupt 4
{
	static unsigned int i = 0;
	unsigned char temp;
	if(RI)
	{
		RI = 0;
		temp = SBUF;
		//0和O是ESP8266的应答信号
		if(temp == 'F' || temp == 'B' || temp == 'L' || temp == 'R' || temp == 'S'||temp == 'Q'
			||temp == 'M' || temp == '0' || temp == 'O')
		{
			i = 0;
		}
		rec[i++] = temp;
		/*收到客户端连接成功,返回0,CONNECT应答信号*/
		if(rec[0] == '0' && rec[2] == 'C')
		{
			Client_Connect_Flag = 1;	//客户端连接标志位置1
			memset(rec,'\0',SIZE);
		}
		/*如果收到OK应答,则rec数组内存放的是OK,所以直接判断下标0位和1位就行*/
		if(rec[0] == 'O' && rec[1] == 'K')
		{
			AT_OK_Flag = 1;				//OK应答标志位置1
			memset(rec,'\0',SIZE);
		}
		/*如果客户端自己断开,则8266会返回0,CLOSED应答,标志位置1让main函数中停止发送数据
		因为ESP8266应答信息多了判断会出错,尽量跟其他判断区分开,搞清楚一个应答中哪几个
		字母会放在数组的第0位*/
		if(rec[1] == 'E' && rec[2] == 'D')
		{
			Client_Disconnect_Flag = 1;
			memset(rec,'\0',SIZE);
		}
		//前进信号Forward
		if(rec[0] == 'F' && rec[1] == 'o')
		{
			GoForward();
			//收到前进信号后延时400ms,再被main函数停止,延时时间越小,就越接近点动模式
			Delay1ms(400);			
			i = 0;
			memset(rec,'\0',SIZE);
		}
		//后退信号Back
		if(rec[0] == 'B' && rec[1] == 'a')
		{
			GoBack();
			Delay1ms(400);		//延时
			i = 0;
			memset(rec,'\0',SIZE);
		}
		//左转信号Left
		if(rec[0] == 'L' && rec[1] == 'e')
		{
			GoLeft();
			/*左转的延时少一点,可通过点动方式一点一点地调方向,
			如果延时大的话,按一下就转动很大,不便调方向*/
			Delay1ms(200);		
			i = 0;
			memset(rec,'\0',SIZE);
		}
		//右转信号Right
		if(rec[0] == 'R' && rec[1] == 'i')
		{
			GoRight();
			Delay1ms(200);		//右转的延时跟左转同理
			i = 0;
			memset(rec,'\0',SIZE);
		}
		//收到停止信号,speed记得要清零
		if(rec[0] == 'S' && rec[1] == 't')
		{
			speed = 0;			
			Stop();
			i = 0;
			memset(rec,'\0',SIZE);
		}
		//快速
		if(rec[0] == 'Q' && rec[1] == 'u')
		{
			speed = 35;
			i = 0;
			memset(rec,'\0',SIZE);
		}
		//中速
		if(rec[0] == 'M' && rec[1] == 'i')
		{
			speed = 25;
			i = 0;
			memset(rec,'\0',SIZE);
		}
		//慢速
		if(rec[0] == 'S' && rec[1] == 'l')
		{
			speed = 15;
			i = 0;
			memset(rec,'\0',SIZE);
		}
		//没收到信号,小车停止
		if(rec[0] == '\0' && rec[1] == '\0')
		{
			Stop();
			i = 0;
			memset(rec,'\0',SIZE);
		}
		if(i == SIZE){i = 0;}
	}
}

3.main函数中调用WIFI.c的自动发送AT指令函数以及发送数据的前提AT指令

extern unsigned int ResultSpeed;		//速度变量
extern unsigned char signal;			//发送标志,当定时器2将其改为1时串口发送数据
char recspeed[24];

extern unsigned char Client_Disconnect_Flag;	//客户端断开连接标志
extern code char CIPSEND[];				//AT指令,往0通道发送13个字节
void main()
{
	Timer0Init();
	Timer2Init();
	UartInit();
	Delay1ms(1000);			//给ESP8266模块上电时间
	Automatic_connection();	//自动发送AT指令,最后等待客户端连接
	Int0_Init();
	OLED_Init();	//OLED初始化
	OLED_Clear();	//先清屏
	OLED_P8x16Str(1,0,"******BMW******");		//显示一个字符串
	
	while(1)
	{
		//定时器2那边如果将标志位改为1,则进行数组格式组装并发送
		if(signal == 1)
		{
			//sprintf将ResultSpeed按格式组建好后放到数组中去
			sprintf(recspeed,"speed:%d cm/s ",ResultSpeed);
			/*当客户端断开连接标志位为0则继续发送数据,检测到断开应答时置1,则不再发送数据*/
			if(Client_Disconnect_Flag == 0)
			{
				Uart_SendString(CIPSEND);		//开启发送数据到客户端的AT指令
				Delay1ms(1000);
				Uart_SendString(recspeed);		//通过串口发送速度,得到AT指令则发送到客户端上
				OLED_P8x16Str(3,3,recspeed);	//通过OLED显示速度
				signal = 0;
			}
		}
	}
}

接线方式:

1.查看通信情况

如果是想通过串口查看通信情况的,可以将CH340接上,ESP8266的TX通过分线接单片机的RX和CH340的RX,ESP8266的RX通过分线接单片机的TX和CH340的RX,因为小车的电源由两节18650电池供电,经过降压模块得到5V,要给单片机、电机驱动、测速模块供电,所以ESP8266的电源需要额外供给,把模块的地全接在面包板上

在这里插入图片描述

2.不查看通信情况

查看通信情况一般是前期测试代码正确性所用的方法,真正使用ESP8266时是不用查看通信情况的,若小车上有3.3V电源,则直接把ESP8266接上去,小车电源也由板载的18650电池供电,此时小车就完全是独立的状态,通过发送AT指令给ESP8266设置为AP模式,则此时小车就相当于一个服务器,当用客户端连接上服务器时,就能通过网络控制小车了

在这里插入图片描述

最终实现:

不用串口助手查看通信情况,小车上电后,发送AT指令给ESP8266开启服务器模式,等待一两秒客户端点击连接,成功连上服务器,小车的速度通过网络发送到客户端上,客户端也能通过网络发送前进后退等指令控制小车启动

需要注意的地方:

如果小车本身的接线没改变,ESP8266按之前的接线方式,即用分线将ESP8266的应答信息通过TX分别发送到单片机和电脑串口助手上,分线的部分没有问题,问题出在了单片机使用的数据线供电上,还记得之前说用充电宝给单片机供电,是无法通过电脑串口查看到ESP8266的应答信息的,这是因为:单片机用电脑USB供电是通过电脑与CH340和ESP8266共地了,因为共地才能进行通信,所以能在电脑串口上查看到ESP8266的应答信息,如果用充电宝给单片机供电,则单片机与CH340、ESP8266是不共地的,通信基准不同,所以是无法通信的

只要抓住一个准则,就是共地,想办法解决ESP8266 3.3V供电问题,其实就能实现远程客户端控制小车

效果演示:【基于ESP8266的网络控制小车】 https://www.bilibili.com/video/BV1aB4y1m7xG?share_source=copy_web&vd_source=d6b62ea36d09d5899101585761eec921

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值