百问网七天智能家居------学习记录

注意:本文只是一个初学者的学习记录,写错的地方欢迎大家评论区指正,谢谢!

实验目的:实现ESP8266与微信小程序的TCP和UDP通信。

实验效果:小程序端有一个门铃和一个台灯按键,当按下台灯按键时,开发板上的LED会跟着小程序的台灯按键亮和灭;按下开发板上的用户按键可以将小程序的门铃按键由白色变成红色。

一、实验使用的相关工具

1.硬件:

1)两块STM32F103_MINI开发板,一块用来开发,一块用百问网的烧录工具烧录成ST-LINK工具用来烧录和调试程序用,一条连接两个MINI板的灰排线(有USB拓展坞比较方便)。

2)一个ESP8266模块,和一条4Pin的杜邦线将ESP8266连接到开发板上。

连接图如下:

2.软件

        使用到的软件有Keil, STM32CubeMX, MobaXterm串口调试工具,百问网烧录ST-LINK的工具和百问网微信端TCP/UDP实验的小程序。

二、实验具体操作

1.用STM32CubeMX创建一个我们需要的Keil工程

1)打开STM32CubeMX,按原理图配置好GPIO,串口和时钟等,进入Project Manager,再点击Code Generator,将其第一项勾选上就可以生成MDK-ARM工程了。

2.需要单片机发送的创建TCP服务器的AT指令,具体步骤如下:

        注:以下为ESP8266设置为STA模式,多连接并创建TCP服务器,手机小程序为TCP客户端的设置步骤。

1)AT+RST                                //复位ESP8266

2)AT+CWMODE=1                  //设置ESP8266为STA模式

      AT+CWMODE=mode          mode=1 STA模式(做客户端,连接其他热点)

                                                  mode=2 AP模式(做服务器,自己作为热点给别人连)

                                                  mode=3 混合模式

3)AT+CWJAP="WIFI账号","WIFI密码"        //ESP8266要连接的WIFI的账号密码

4)AT+CIPMUX=1                        //设置多连接模式

      AT+CIPMUX=mode               mode=0为单连接模式       mode=1为多连接模式

      注意:1)默认是单连接;2)单连接才能开启后续的透传模式;3)必须在没有连接建立的情况下设置连接模式;4)如果建立了TCP服务器,想切换为单连接,必须关闭服务器(AT+CIPSERVER=0),服务器仅支持多连接。

5)AT+CIPSERVER=1,9999        //创建TCP服务器,端口号为9999

      AT+CIPSERVER=mode,port            mode=1表示创建服务器,mode=0表示关闭服务器

                                                                port为端口号,默认为333,此处设为了9999

       注意:1)多连接的情况下才能开启服务器;2)创建TCP服务器后,自动建立TCP服务器监听;3)当有TCP客户端接入,会自动占用一个连接ID,ID号从0开始

6)AT+CIPSEND=0,32        {"data":"doorbell","status":"1"}        //发送点亮门铃的数据到小程序端

      多连接:AT+CIPSEND=Link ID,length    

       单连接:AT+IPSEND=length

       UDP:      AT+CIPSEND = Link ID, length , remote IP , remote port

       Link ID:网络连接ID号(0-4),用于多连接情况

       length:表示发送数据的长度,最大长度为2048

       remote IP:UDP传输设置的远端IP地址

       remote port:UDP传输设置的远端端口号

AT+CIPSEND=0,32        {"data":"doorbell","status":"1"}   这条指令先发指令后发数据,先发送AT+CIPSEND=0,32 ,响应OK后再发送 {"data":"doorbell","status":"1"} ,之所以写在一起是程序里将它们封装在了一起

7)AT+CIFSR                //查询本地IP地址   

响应:

                +CIFSR:APIP,<SoftAP IP address>
                +CIFSR:APMAC,<SoftAP MAC address>
                +CIFSR:STAIP,<Station IP address>
                +CIFSR:STAMAC,<Station MAC address>
                OK
       上面我们将ESP8266设置为了STA模式,本地IP就看第三行的STAIP后面的IP          

       至此,只要程序成功实现以上步骤,硬件连接正确,小程序的远端IP地址填写第七步查询的IP地址,远端端口填写第五步设置的9999,就可以实现实验的效果了。注意手机和ESP8266要连接同一个WIFI

3.需要单片机发送的创建UDP远端可变的AT指令,具体步骤如下:

        注:以下为ESP8266设置为STA模式,单连接,UDP貌似不存在客户端和服务器的说法,前面三步与TCP的是一样的。

1)AT+RST                                //复位ESP8266

2)AT+CWMODE=1                  //设置ESP8266为STA模式

      AT+CWMODE=mode          mode=1 STA模式(做客户端,连接其他热点)

                                                  mode=2 AP模式(做服务器,自己作为热点给别人连)

                                                  mode=3 混合模式

3)AT+CWJAP="WIFI账号","WIFI密码"        //ESP8266要连接的WIFI的账号密码

4)AT+CIPMUX=0                        //设置单连接模式

      AT+CIPMUX=mode               mode=0为单连接模式       mode=1为多连接模式

      注意:1)默认是单连接;2)单连接才能开启后续的透传模式;3)必须在没有连接建立的情况下设置连接模式;4)如果建立了TCP服务器,想切换为单连接,必须关闭服务器(AT+CIPSERVER=0),服务器仅支持多连接。

        因为默认就是单连接,第四步也可以省略

5)AT+CIPSTART="UDP","192.168.1.103",1234,5678,2       //连接类型为UDP,远端IP地址为 192.168.1.103,远端端口号为1234,本地端口号为5678,2表示收到数据后,改变远端目标。远端IP地址可以先随便填写一个,因为ESP8266的远端可以变成上一次发数据给它的那个远端,所以只要我们的手机中途给ESP8266发送一次数据,ESP8266收到数据后,ESP8266的远端目标就变成了我们的手机端,这就是远端可变。

      AT+CIPSTART="type","remote IP",remote port,UDP local port,UDP mode

      UDP mode=0 :收到数据后,不更改远端⽬标,默认值为 0

      UDP mode=1 :收到数据后,改变⼀次远端⽬标

       UDP mode=2 :收到数据后,改变远端⽬标

6)AT+CIPSEND=32        {"data":"doorbell","status":"1"}        //发送点亮门铃的数据到小程序端

       单连接:AT+IPSEND=length

       多连接:AT+CIPSEND=Link ID,length    

       UDP:      AT+CIPSEND = Link ID, length , remote IP , remote port

       length:表示发送数据的长度,最大长度为2048

       Link ID:网络连接ID号(0-4),用于多连接情况

       remote IP:UDP传输设置的远端IP地址

       remote port:UDP传输设置的远端端口号

       AT+CIPSEND=32        {"data":"doorbell","status":"1"}   这条指令先发指令后发数据,先发送AT+CIPSEND=32 ,响应OK后再发送 {"data":"doorbell","status":"1"} ,之所以写在一起是程序里将它们封装在了一起

7)AT+CIFSR                //查询本地IP地址   

响应:

                +CIFSR:APIP,<SoftAP IP address>
                +CIFSR:APMAC,<SoftAP MAC address>
                +CIFSR:STAIP,<Station IP address>
                +CIFSR:STAMAC,<Station MAC address>
                OK
       上面我们将ESP8266设置为了STA模式,本地IP就看第三行的STAIP后面的IP   
        至此,只要程序成功实现以上步骤,硬件连接正确,小程序的远端IP地址填写第七步查询的IP地址,小程序的远端端口填写第五步设置的本地端口5678,就可以实现实验的效果了。 注意手机和ESP8266要连接同一个WIFI。

4.程序

1)main.c
    static char rx_data[256] = {0};//定义一个用来接收数据的数组
	static char wifi_data[100] = {0};//定义一个用来接收WIFI指令的数组
	USART2_Receive_Start();			 //启动串口的中断接收方式
	Key_UpdataWIFI(wifi_data,2000);  //延时两秒判断是否需要更改WIFI信息
	ESP8266_SendCommand("AT+RST","OK",1000);		//复位ESP8266
	HAL_Delay(1000);
	ESP8266_SendCommand("AT+CWMODE=1","OK",500);	//ESP8266设置为STA模式
	ESP8266_SendCommand(wifi_data,"OK",4000);		//设置ESP8266连接的WIFI
	ESP8266_SendCommand("AT+CIPMUX=0","OK",500);	//设置为单连接模式,这一步也可以省略
	//设置为UDP方式,远端IP随意设置,远端端口和本地端口也随意设置,2表示远端可变
	ESP8266_SendCommand("AT+CIPSTART=\"UDP\",\"192.168.1.1\",1234,5678,2","OK",500);	
	//ESP8266_SendCommand("AT+CIPMUX=1","OK",500);
	//ESP8266_SendCommand("AT+CIPSERVER=1,8886","OK",500);
	ESP8266_SendCommand("AT+CIFSR","OK",500);		//查询ESP8266的IP地址

  while (1)
  {
	  if(Get_Key_flag())//用户按键按下则返回1,进入if,发送门铃为1指令
	  {
		  //ESP8266_SendTCP("{\"data\":\"doorbell\",\"status\":\"1\"}");
		  ESP8266_SendUDP("{\"data\":\"doorbell\",\"status\":\"1\"}");
	  }
	  
	  if(USART2_Receive(rx_data))//串口收到数据则进入if
	  {
		  if(strstr(rx_data,"\"led\",\"status\":\"0\""))//收到LED status 0则熄灭灯
		  {
			  printf("LED OFF\r\n");
			  HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
			  USART2_Clearbuf();
			  memset(rx_data,0,256);
		  }
		  else if(strstr(rx_data,"\"led\",\"status\":\"1\""))//收到LED status 1则点亮灯
		  {
			  printf("LED ON\r\n");
			  HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
			  USART2_Clearbuf();
			  memset(rx_data,0,256);
		  }
	  }  
  }


2)usart.c

        串口接收程序

/****使用printf打印就需要复写以下两个打印函数****/
int fputc(int ch, FILE *f)
{
	HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 10);
	return ch;
}
	
int fgetc(FILE *f)
{ 
	 uint8_t ch = 0; 
	 HAL_UART_Receive(&huart1, (uint8_t*)&ch, 1, 10); 
	 return (int)ch;
}

static uint8_t pdata = 0;
static uint8_t rx_buf[256] = {0};
static uint8_t rx_len = 0;

//串口2中断方式启动接收函数
void USART2_Receive_Start(void)
{
	HAL_UART_Receive_IT(&huart2, &pdata, 1);
}

//串口2接收中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart == &huart2)
	{
		rx_buf[rx_len%256] = pdata;
		rx_len++;
		HAL_UART_Receive_IT(&huart2, &pdata, 1);//开启下一次的接收中断
	}
}

//串口2接收数据函数
uint8_t USART2_Receive(char *pData)//返回值len不是0则有接收到数据
{
	memcpy(pData,(char *)rx_buf,rx_len);
	return rx_len;
}

//串口2发送数据函数
void USART2_Transmit(uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
	HAL_UART_Transmit(&huart2, pData, Size, Timeout);
}

//串口2清空接收数据的数组
void USART2_Clearbuf(void)
{
	memset(rx_buf,0,256);
	rx_len = 0;
}

        向ESP8266发送指令程序

//向ESP8266发送指令
uint8_t ESP8266_SendCommand(char *cmd,char *reply,uint16_t timeout)
{
	char *ipofset;
	char ip_buf[20] = {0};
	char buf[100] = {0};//定义一个数组用来接收要发送的数据
	uint8_t len = 0;
	memcpy(buf,cmd,strlen(cmd));
	if(strstr(buf,"\r\n") == 0)
	{
		strcat(buf,"\r\n");
	}
	USART2_Clearbuf();//发之前清除上一次接收到的数据,不然会接收错误
	USART2_Transmit((uint8_t *)buf,strlen(buf),500);
	memset(buf,0,100);//清空buf用来接收数据
	while(timeout != 0)
	{
		USART2_Receive(buf);
		if(strstr(buf,reply))//如果接收到的数据与设置的回复一致则打印指令发送成功
		{
			printf("%s Send OK\r\n",cmd);
			ipofset = strstr(buf,"STAIP");
			if(ipofset)		//判断是否返回正确的查询WIFI指令的指针
			{
				//memset(buf,0,100);
				memcpy(buf,ipofset+6,strlen(ipofset));
				while(buf[len] != '\r')
				{
					ip_buf[len] = buf[len];
					len++;
				}
				printf("ESP8266 IP: %s",ip_buf);
			}
			return 1;
		}
		HAL_Delay(1);
		timeout--;
	}
	printf("%s Send error\r\n",cmd);
	return 1;
}

//发送TCP数据函数
void ESP8266_SendTCP(char *cmd)
{
	char Buf[100] = {0};
	uint8_t len = 0;
	len = strlen(cmd);
	sprintf(Buf,"AT+CIPSEND=0,%d",len);
	if(ESP8266_SendCommand(Buf,"OK",500))
	{
		memset(Buf,0,100);
		memcpy(Buf,cmd,len);
		ESP8266_SendCommand(Buf,"OK",500);
	}
}

//发送UDP数据函数
void ESP8266_SendUDP(char *cmd)
{
	char Buf[100] = {0};
	uint8_t len = 0;
	len = strlen(cmd);
	sprintf(Buf,"AT+CIPSEND=%d",len);
	if(ESP8266_SendCommand(Buf,"OK",500))
	{
		memset(Buf,0,100);
		memcpy(Buf,cmd,len);
		ESP8266_SendCommand(Buf,"OK",500);
	}
}

修改WIFI程序

//修改WIFI信息
void Key_UpdataWIFI(char *wifidata,uint16_t time)
{
	char ch = 0;
	uint8_t len = 0;
	char ssid_buf[20] = "Xiaomi";
	char pwd_buf[20] = "aabbccdd";
	char wifi_buf[100] = "AT+CWJAP=\"";		//WIFI指令的前半段
	
	HAL_Delay(time);						//延时等待按键输入
	if(Get_Key_flag())
	{
		memset(ssid_buf,0,20);				//有按键输入先清空WIFI账号数组
		printf("Please enter IIID: ");
		while(ch != '\r')					//没有按下回车键则一直可以输入WIFI账号
		{
			ch = getchar();
			if(ch > ' ')					//键值大于空格的按键才是有效按键
			{
				printf("%c",ch);			//将按键键值打印到串口
				ssid_buf[len] = ch;			//将按键值存进WIFI账号数组
				len++;						//按键值存入数组的位置往后移一位
			}
		}
		ch = 0;								//先将按键值清空,不然下个while一判断就退出了
		len = 0;							//WIFI密码也是从数组0开始存
		memset(pwd_buf,0,20);				//将WIFI密码数组内容清空,从而接收新的WIFI密码
		printf("\r\nPlease enter Password: ");
		while(ch != '\r')
		{
			ch = getchar();
			if(ch > ' ')
			{
				printf("%c",ch);
				pwd_buf[len] = ch;
				len++;
			}
		}
		
	}
	strcat(wifi_buf,ssid_buf);				//四步strcat将WIFI指令拼接完整
	strcat(wifi_buf,"\",\"");
	strcat(wifi_buf,pwd_buf);
	strcat(wifi_buf,"\"");
	memcpy(wifidata,wifi_buf,strlen(wifi_buf));	//将wifi_buf的内容传给wifidata
	//printf("c\r\n");
}

3)gpio.c

static uint8_t Key_flag = 0;    //定义一个按键标志位

//获取按键标志位
uint8_t Get_Key_flag(void)//用户按键按下返回1
{
	if(Key_flag)
	{
		Key_flag = 0;
		return 1;
	}
	else 
		return 0;
}

//外部中断0回调函数,下降沿中断
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin == KEY_Pin)
	{
		Key_flag =~ Key_flag;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值