• 小车联网—通过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 
    #include 
    #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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    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;}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    接线方式:

    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

  • 相关阅读:
    mysql开启慢查询日志及死锁排查
    什么是SRM系统,如何规范公司内部采购流程
    微信小程序之自定义导航toolbar添加home键
    Nessus已激活,New Scan按钮不可点击
    编译原理—中间代码生成、布尔表达式翻译、短路计算、控制流语句翻译、条件语句、循环语句
    [WPF]浅析资源引用(pack URI)
    Log4j和Log4j2的区别
    消息队列十连问
    SPDK/NVMe存储技术分析之初识UIO(二)
    基于springboot实现医院信管系统项目【项目源码+论文说明】
  • 原文地址:https://blog.csdn.net/weixin_46251230/article/details/126405072