当前位置:   article > 正文

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

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

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

实验目的:实现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
  1. static char rx_data[256] = {0};//定义一个用来接收数据的数组
  2. static char wifi_data[100] = {0};//定义一个用来接收WIFI指令的数组
  3. USART2_Receive_Start(); //启动串口的中断接收方式
  4. Key_UpdataWIFI(wifi_data,2000); //延时两秒判断是否需要更改WIFI信息
  5. ESP8266_SendCommand("AT+RST","OK",1000); //复位ESP8266
  6. HAL_Delay(1000);
  7. ESP8266_SendCommand("AT+CWMODE=1","OK",500); //ESP8266设置为STA模式
  8. ESP8266_SendCommand(wifi_data,"OK",4000); //设置ESP8266连接的WIFI
  9. ESP8266_SendCommand("AT+CIPMUX=0","OK",500); //设置为单连接模式,这一步也可以省略
  10. //设置为UDP方式,远端IP随意设置,远端端口和本地端口也随意设置,2表示远端可变
  11. ESP8266_SendCommand("AT+CIPSTART=\"UDP\",\"192.168.1.1\",1234,5678,2","OK",500);
  12. //ESP8266_SendCommand("AT+CIPMUX=1","OK",500);
  13. //ESP8266_SendCommand("AT+CIPSERVER=1,8886","OK",500);
  14. ESP8266_SendCommand("AT+CIFSR","OK",500); //查询ESP8266的IP地址
  15. while (1)
  16. {
  17. if(Get_Key_flag())//用户按键按下则返回1,进入if,发送门铃为1指令
  18. {
  19. //ESP8266_SendTCP("{\"data\":\"doorbell\",\"status\":\"1\"}");
  20. ESP8266_SendUDP("{\"data\":\"doorbell\",\"status\":\"1\"}");
  21. }
  22. if(USART2_Receive(rx_data))//串口收到数据则进入if
  23. {
  24. if(strstr(rx_data,"\"led\",\"status\":\"0\""))//收到LED status 0则熄灭灯
  25. {
  26. printf("LED OFF\r\n");
  27. HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
  28. USART2_Clearbuf();
  29. memset(rx_data,0,256);
  30. }
  31. else if(strstr(rx_data,"\"led\",\"status\":\"1\""))//收到LED status 1则点亮灯
  32. {
  33. printf("LED ON\r\n");
  34. HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
  35. USART2_Clearbuf();
  36. memset(rx_data,0,256);
  37. }
  38. }
  39. }
2)usart.c

        串口接收程序

  1. /****使用printf打印就需要复写以下两个打印函数****/
  2. int fputc(int ch, FILE *f)
  3. {
  4. HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 10);
  5. return ch;
  6. }
  7. int fgetc(FILE *f)
  8. {
  9. uint8_t ch = 0;
  10. HAL_UART_Receive(&huart1, (uint8_t*)&ch, 1, 10);
  11. return (int)ch;
  12. }
  13. static uint8_t pdata = 0;
  14. static uint8_t rx_buf[256] = {0};
  15. static uint8_t rx_len = 0;
  16. //串口2中断方式启动接收函数
  17. void USART2_Receive_Start(void)
  18. {
  19. HAL_UART_Receive_IT(&huart2, &pdata, 1);
  20. }
  21. //串口2接收中断回调函数
  22. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  23. {
  24. if(huart == &huart2)
  25. {
  26. rx_buf[rx_len%256] = pdata;
  27. rx_len++;
  28. HAL_UART_Receive_IT(&huart2, &pdata, 1);//开启下一次的接收中断
  29. }
  30. }
  31. //串口2接收数据函数
  32. uint8_t USART2_Receive(char *pData)//返回值len不是0则有接收到数据
  33. {
  34. memcpy(pData,(char *)rx_buf,rx_len);
  35. return rx_len;
  36. }
  37. //串口2发送数据函数
  38. void USART2_Transmit(uint8_t *pData, uint16_t Size, uint32_t Timeout)
  39. {
  40. HAL_UART_Transmit(&huart2, pData, Size, Timeout);
  41. }
  42. //串口2清空接收数据的数组
  43. void USART2_Clearbuf(void)
  44. {
  45. memset(rx_buf,0,256);
  46. rx_len = 0;
  47. }

        向ESP8266发送指令程序

  1. //向ESP8266发送指令
  2. uint8_t ESP8266_SendCommand(char *cmd,char *reply,uint16_t timeout)
  3. {
  4. char *ipofset;
  5. char ip_buf[20] = {0};
  6. char buf[100] = {0};//定义一个数组用来接收要发送的数据
  7. uint8_t len = 0;
  8. memcpy(buf,cmd,strlen(cmd));
  9. if(strstr(buf,"\r\n") == 0)
  10. {
  11. strcat(buf,"\r\n");
  12. }
  13. USART2_Clearbuf();//发之前清除上一次接收到的数据,不然会接收错误
  14. USART2_Transmit((uint8_t *)buf,strlen(buf),500);
  15. memset(buf,0,100);//清空buf用来接收数据
  16. while(timeout != 0)
  17. {
  18. USART2_Receive(buf);
  19. if(strstr(buf,reply))//如果接收到的数据与设置的回复一致则打印指令发送成功
  20. {
  21. printf("%s Send OK\r\n",cmd);
  22. ipofset = strstr(buf,"STAIP");
  23. if(ipofset) //判断是否返回正确的查询WIFI指令的指针
  24. {
  25. //memset(buf,0,100);
  26. memcpy(buf,ipofset+6,strlen(ipofset));
  27. while(buf[len] != '\r')
  28. {
  29. ip_buf[len] = buf[len];
  30. len++;
  31. }
  32. printf("ESP8266 IP: %s",ip_buf);
  33. }
  34. return 1;
  35. }
  36. HAL_Delay(1);
  37. timeout--;
  38. }
  39. printf("%s Send error\r\n",cmd);
  40. return 1;
  41. }
  42. //发送TCP数据函数
  43. void ESP8266_SendTCP(char *cmd)
  44. {
  45. char Buf[100] = {0};
  46. uint8_t len = 0;
  47. len = strlen(cmd);
  48. sprintf(Buf,"AT+CIPSEND=0,%d",len);
  49. if(ESP8266_SendCommand(Buf,"OK",500))
  50. {
  51. memset(Buf,0,100);
  52. memcpy(Buf,cmd,len);
  53. ESP8266_SendCommand(Buf,"OK",500);
  54. }
  55. }
  56. //发送UDP数据函数
  57. void ESP8266_SendUDP(char *cmd)
  58. {
  59. char Buf[100] = {0};
  60. uint8_t len = 0;
  61. len = strlen(cmd);
  62. sprintf(Buf,"AT+CIPSEND=%d",len);
  63. if(ESP8266_SendCommand(Buf,"OK",500))
  64. {
  65. memset(Buf,0,100);
  66. memcpy(Buf,cmd,len);
  67. ESP8266_SendCommand(Buf,"OK",500);
  68. }
  69. }

修改WIFI程序

  1. //修改WIFI信息
  2. void Key_UpdataWIFI(char *wifidata,uint16_t time)
  3. {
  4. char ch = 0;
  5. uint8_t len = 0;
  6. char ssid_buf[20] = "Xiaomi";
  7. char pwd_buf[20] = "aabbccdd";
  8. char wifi_buf[100] = "AT+CWJAP=\""; //WIFI指令的前半段
  9. HAL_Delay(time); //延时等待按键输入
  10. if(Get_Key_flag())
  11. {
  12. memset(ssid_buf,0,20); //有按键输入先清空WIFI账号数组
  13. printf("Please enter IIID: ");
  14. while(ch != '\r') //没有按下回车键则一直可以输入WIFI账号
  15. {
  16. ch = getchar();
  17. if(ch > ' ') //键值大于空格的按键才是有效按键
  18. {
  19. printf("%c",ch); //将按键键值打印到串口
  20. ssid_buf[len] = ch; //将按键值存进WIFI账号数组
  21. len++; //按键值存入数组的位置往后移一位
  22. }
  23. }
  24. ch = 0; //先将按键值清空,不然下个while一判断就退出了
  25. len = 0; //WIFI密码也是从数组0开始存
  26. memset(pwd_buf,0,20); //将WIFI密码数组内容清空,从而接收新的WIFI密码
  27. printf("\r\nPlease enter Password: ");
  28. while(ch != '\r')
  29. {
  30. ch = getchar();
  31. if(ch > ' ')
  32. {
  33. printf("%c",ch);
  34. pwd_buf[len] = ch;
  35. len++;
  36. }
  37. }
  38. }
  39. strcat(wifi_buf,ssid_buf); //四步strcat将WIFI指令拼接完整
  40. strcat(wifi_buf,"\",\"");
  41. strcat(wifi_buf,pwd_buf);
  42. strcat(wifi_buf,"\"");
  43. memcpy(wifidata,wifi_buf,strlen(wifi_buf)); //将wifi_buf的内容传给wifidata
  44. //printf("c\r\n");
  45. }

3)gpio.c

  1. static uint8_t Key_flag = 0; //定义一个按键标志位
  2. //获取按键标志位
  3. uint8_t Get_Key_flag(void)//用户按键按下返回1
  4. {
  5. if(Key_flag)
  6. {
  7. Key_flag = 0;
  8. return 1;
  9. }
  10. else
  11. return 0;
  12. }
  13. //外部中断0回调函数,下降沿中断
  14. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
  15. {
  16. if(GPIO_Pin == KEY_Pin)
  17. {
  18. Key_flag =~ Key_flag;
  19. }
  20. }

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号