赞
踩
注意:本文只是一个初学者的学习记录,写错的地方欢迎大家评论区指正,谢谢!
实验目的:实现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,按原理图配置好GPIO,串口和时钟等,进入Project Manager,再点击Code Generator,将其第一项勾选上就可以生成MDK-ARM工程了。
注:以下为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地址
响应:
至此,只要程序成功实现以上步骤,硬件连接正确,小程序的远端IP地址填写第七步查询的IP地址,远端端口填写第五步设置的9999,就可以实现实验的效果了。注意手机和ESP8266要连接同一个WIFI
注:以下为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地址
响应:
- 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);
- }
- }
- }
-
-
串口接收程序
- /****使用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;
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。