当前位置:   article > 正文

ESP8266与手机App通信(STM32)_esp8266手机端app开发

esp8266手机端app开发

认识模块

        ESP8266是一种低成本的Wi-Fi模块,可用于连接物联网设备,控制器和传感器等。它具有小巧、高度集成和低功耗的特点,因此在物联网应用中被广泛使用。ESP8266模块由Espressif Systems开发,具有单芯片的封装和多种功能,包括Wi-Fi网络连接、GPIO控制、PWM控制和模拟输入/输出等。ESP8266模块支持多种编程语言和开发工具,包括C语言、Lua脚本和Arduino开发环境。ESP8266模块的一个优点是它的成本相对较低,因此可以用于低成本的物联网项目。另外,由于它具有小巧的封装和低功耗的特性,因此它可以在嵌入式系统和移动设备中使用。

        总之,ESP8266模块是一种功能强大、低成本、小巧、低功耗的Wi-Fi模块,非常适合用于物联网和其他嵌入式应用中。

模块与单片机的连接

        我在本次开发中选择的是模块型号为ESP8266-01S,与ESP8266一样,他们都有8个引脚,我们只用得到其中的4个引脚,分别是:

  1. VCC:电源引脚,接收3.3V的直流电源。(也可以接5V)

  2. VCC:电源引脚,接收3.3V的直流电源。

  3. TXD:串行传输引脚,用于发送串行数据。

  4. RXD:串行接收引脚,用于接收串行数据。

        而唯一与ESP8266不同的是,esp8266需要接第5个引脚EN,接在高电平上。

        在与STM32连接时,VCC接3.3V或5V,GND接地,TX接在32单片机的RX上,RX接在32单片机的TX上。我使用的32单片机型号为STM32F407ze,通过查找资料可知,其内部的电路图大致如下图所示:

大致电路图

         我选择把WiFi模块连接到P6上,以下是我的实物连接图(下面那个是我连接的OLED模块,不用理会):

实物连接图

        接下来就是敲代码让他运行起来了。

代码部分

      串口的定义

        首先是定义串口,定义串口1是为了将串口3的收到数据发给电脑看。定义串口3用于WiFi模块的使用。

        uart1.c

        这段代码是用于配置STM32芯片上的UART1串口,并定义了一个函数 send_sring 用于通过UART1发送字符串。

  1. #include "uart.h"
  2. void UART1_Config(void)
  3. {
  4. GPIO_InitTypeDef GPIO_InitStructure;
  5. USART_InitTypeDef USART_InitStructure;
  6. NVIC_InitTypeDef NVIC_InitStructure;
  7. //初始化GPIOA的时钟
  8. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  9. //初始化串口1的时钟
  10. RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
  11. //通过结构体初始化串口引脚
  12. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //配置的引脚
  13. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式
  14. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽模式
  15. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度为100MHz
  16. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //上下拉电阻:无上下拉电阻
  17. GPIO_Init(GPIOA, &GPIO_InitStructure);
  18. //选择引脚复用功能
  19. GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
  20. GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
  21. //配置串口相关属性
  22. USART_InitStructure.USART_BaudRate = 115200; //波特率
  23. USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位
  24. USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位
  25. USART_InitStructure.USART_Parity = USART_Parity_No; //校验位
  26. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无流控
  27. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //接收发送模式
  28. USART_Init(USART1, &USART_InitStructure);
  29. //配置串口的中断(数据接收触发中断)
  30. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  31. NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  32. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  33. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  34. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  35. NVIC_Init(&NVIC_InitStructure);
  36. //串口1工作
  37. USART_Cmd(USART1,ENABLE);
  38. }
  39. /* 参数:要发送的字符串,要求字符串末尾以 \0 结尾 */
  40. void send_string(char *arr)
  41. {
  42. while(*arr) //判断字符串是否结束
  43. {
  44. //通过串口1发送数据到PC
  45. USART_SendData(USART1, *arr++);
  46. while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);//等待发送数据完毕
  47. }
  48. }

        uart3.c与接受数据

        这里面定义了串口3的定义函数,中断函数和数据发送函数。在中断函数获取串口3收到的数据,其中包含单片机发给串口3的,也含括WiFi模块接收到消息并回传给串口3的。32单片机发给串口3的数据不需要我们获取,关键是如何获取WiFi模块收到手机的数据后回传给串口3的数据

        要知道如何获取WiFi模块收到手机的数据后回传给串口3的数据,首先要知道WiFi模块要如何工作。WiFi模块的配置工作在下面,可以先去看看。

        在多次调试与测试时我发现,WiFi模块在接收手机发来的数据时,会以“数据来源:数据”的格式将数据发给串口,所以我们只要在串口中断中,获取数据,然后在数据里找到带有“:”的数据,“:”往后几个字节就是手机发来的数据。

        在函数中,我定义了 USART3_RX_BUF [USART3_MAX_RECV_LEN] 用于保存所有串口接收到的数据,然后在 USART3_RX_BUF 中查询是否含有 “:”,如果有,就说明是手机发来的数据,我将 “:” 后面的11个字节保存到 get_data[11] 中(这个数组大小可变,因为我设定的是手机发送9个字节给WiFi模块,所以才定义了个大小为 11 的数组变量 get_data)。因为我手机发送的数据是以空格为间隔的三个数值,比如“ 40 50 20”,为了从 u8 类型的数组变量中获取这三个数值,我把 u8 类型的  get_data 转化为字符类型的 str_get_data[11],利用 strtok 函数把字符串  str_get_data[11] 以空格拆分,再把拆下来的部分转化为整型赋值给阈值参数。

  1. #include "uart3.h"
  2. #include "delay.h"
  3. #include "stdarg.h"
  4. #include "stdio.h"
  5. #include "string.h"
  6. #include "tim.h"
  7. int i=0;
  8. extern u8 Temperature_yu,Smog_yu,CO_yu;
  9. //串口发送缓存区
  10. __align(8) u8 USART3_TX_BUF[USART3_MAX_SEND_LEN]; //发送缓冲,最大USART3_MAX_SEND_LEN字节
  11. #ifdef USART3_RX_EN //如果使能了接收
  12. //串口接收缓存区
  13. u8 USART3_RX_BUF [USART3_MAX_RECV_LEN]; //接收缓冲,最大USART3_MAX_RECV_LEN个字节.
  14. //通过判断接收连续2个字符之间的时间差不大于100ms来决定是不是一次连续的数据.
  15. //如果2个字符接收间隔超过100ms,则认为不是1次连续数据.也就是超过100ms没有接收到
  16. //任何数据,则表示此次接收完毕.
  17. //接收到的数据状态
  18. //[15]:0,没有接收到数据;1,接收到了一批数据.
  19. //[14:0]:接收到的数据长度
  20. u16 USART3_RX_STA=0;
  21. void USART3_IRQHandler(void)
  22. {
  23. u8 res;
  24. int j,k,find;
  25. u8 get_data[11];//用于保存手机发送的数据
  26. char str_get_data[11];//用于把手机发送的数据转换为字符类型
  27. char* token;
  28. if(USART_GetITStatus(USART3,USART_IT_RXNE) != RESET)//接收到数据
  29. {
  30. res =USART_ReceiveData(USART3);
  31. if((USART3_RX_STA&(1<<15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据
  32. {
  33. if(USART3_RX_STA<USART3_MAX_RECV_LEN)//还可以接收数据
  34. {
  35. USART3_RX_BUF[USART3_RX_STA++]=res;
  36. // 判断接收到的数据是否为esp8266发送的数据
  37. if(res == '\n' && USART3_RX_BUF[USART3_RX_STA - 2] == '\r')
  38. {
  39. // 提取接收缓存区中的数据并进行处理
  40. if(USART3_RX_BUF[0] == '\n' || USART3_RX_BUF[0] == '\r' ){} //舍弃换行符,以免输出空行
  41. else{
  42. if(i<47){ //过滤掉重置wifi模块时传给串口3的返回值
  43. i++;
  44. }
  45. else{
  46. printf("串口3收到%s",USART3_RX_BUF);
  47. /*寻找 USART3_RX_BUF 中的冒号*/
  48. for(j=0;j<20;j++){
  49. find = 0;
  50. if(USART3_RX_BUF[j] == ':')
  51. {
  52. find = 1;//找到后find = 1,退出循环
  53. break;
  54. }
  55. }
  56. if(find==1){
  57. for(k=0;k<10;k++){
  58. get_data[k] = USART3_RX_BUF[k+j];
  59. }
  60. printf("get_data%s\n",get_data);
  61. snprintf(str_get_data, sizeof(str_get_data), "%s", get_data);
  62. // 按空格分割字符串
  63. token = strtok(str_get_data, " ");
  64. if (token != NULL) {
  65. // 第一个数值
  66. token = strtok(NULL, " ");
  67. if (token != NULL) {
  68. Temperature_yu = atoi(token);
  69. // 第二个数值
  70. token = strtok(NULL, " ");
  71. if (token != NULL) {
  72. Smog_yu = atoi(token);
  73. // 第三个数值
  74. token = strtok(NULL, " ");
  75. if (token != NULL){
  76. CO_yu = atoi(token);
  77. } else {
  78. // 如果没有第三个数值,可以给它赋一个默认值
  79. CO_yu = 20;
  80. }
  81. } else {
  82. // 如果没有第二个数值,可以给它赋一个默认值
  83. CO_yu = 20;
  84. }
  85. } else {
  86. // 如果没有任何数值,可以给它们都赋一个默认值
  87. Temperature_yu = 40;
  88. Smog_yu = 20;
  89. CO_yu = 20;
  90. }
  91. } else {
  92. // 如果没有任何数值,可以给它们都赋一个默认值
  93. Temperature_yu = 40;
  94. Smog_yu = 20;
  95. CO_yu = 20;
  96. }
  97. }
  98. }
  99. }
  100. // 清空接收缓存区
  101. USART3_RX_STA = 0;
  102. memset(USART3_RX_BUF, 0, sizeof(USART3_RX_BUF));//用于清空接收缓存区USART3_RX_BUF,将其中的所有元素都设置为0
  103. }
  104. }
  105. else
  106. {
  107. USART3_RX_STA|=1<<15;
  108. }
  109. }
  110. }
  111. }
  112. #endif
  113. void UART3_Config(void)
  114. {
  115. NVIC_InitTypeDef NVIC_InitStructure;
  116. GPIO_InitTypeDef GPIO_InitStructure;
  117. USART_InitTypeDef USART_InitStructure;
  118. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);//使能GPIOB时钟
  119. RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//使能USART3时钟
  120. USART_DeInit(USART3);
  121. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_10;//GPIOB11和GPIOB10初始化
  122. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF ;//复用功能
  123. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//速度50MHz
  124. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽复用输出
  125. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  126. GPIO_Init(GPIOB,&GPIO_InitStructure);//初始化GPIOB11,和GPIOB10
  127. GPIO_PinAFConfig(GPIOB,GPIO_PinSource11,GPIO_AF_USART3);//GPIOB11复用为USART3
  128. GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_USART3);//GPIOB10复用为USART3
  129. USART_InitStructure. USART_BaudRate = 115200;//波特率
  130. USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
  131. USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
  132. USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
  133. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  134. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
  135. USART_Init(USART3, &USART_InitStructure);//初始化串口3
  136. USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//开启中断
  137. NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
  138. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级2
  139. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//子优先级3
  140. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
  141. NVIC_Init(&NVIC_InitStructure);//根据指定的参数初始化VIC寄存器
  142. // TIM7_Config(1000-1,8400-1); //100ms中断
  143. USART3_RX_STA=0;//清零
  144. TIM_Cmd(TIM7,DISABLE);//关闭定时器7
  145. USART_Cmd (USART3,ENABLE);//使能串口
  146. }
  147. //串口3,printf 函数
  148. //确保一次发送数据不超过USART3_MAX_SEND_LEN字节
  149. void u3_printf(char* fmt, ...)
  150. {
  151. u16 i,j;
  152. va_list ap;
  153. va_start(ap,fmt);
  154. vsprintf((char*)USART3_TX_BUF,fmt,ap);
  155. va_end(ap);
  156. i=strlen((const char*)USART3_TX_BUF);//此次发送数据的长度
  157. for(j=0;j<i;j++)//循环发送数据
  158. {
  159. while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET);//等待上次数据传输完成
  160. USART_SendData(USART3,(uint8_t)USART3_TX_BUF[j]);
  161. }
  162. }

        uart3.h

  1. #ifndef _UART3_H
  2. #define _UART3_H
  3. //C文件中需要的其他的头文件
  4. #include "sys.h"
  5. #include <stm32f4xx.h>
  6. #define USART3_MAX_RECV_LEN 500
  7. #define USART3_MAX_SEND_LEN 500
  8. #define USART3_RX_EN 1
  9. extern u8 USART3_RX_BUF[USART3_MAX_RECV_LEN];
  10. extern u8 USART3_TX_BUF[USART3_MAX_SEND_LEN];
  11. extern u16 USART3_RX_STA;
  12. void UART3_Config(void);
  13. void TIM7_Int_Init(u16 arr,u16 psc);
  14. void u3_printf(char* fmt, ...);
  15. #endif

        esp8266.c

        要使WiFi模块与手机通信,我的做法是让WiFi模块开启热点并作为TCP服务器,手机作为TCP客户端连接服务器,实现数据的传输。

        这里的代码使用 atk_8266_start_trans() 函数初始化WiFi模块,让其工作,这段代码主要作用是给WiFi模块发送各种AT指令。如“AT”用来确认模块是否可正常工作,“AT+RST” 用来重置模块,“AT+CWMODE=2” 用来让模块进入AP模式,就是开启热点,“AT+CWSAP=\"ESP8266-ly\",\"123456789\",11,0” 用于配置热点,“AT+CIPMUX=1” 用于开启多路连接模式,最后“AT+CIPSERVER=1” 用于开启TCP服务器,这样就可以通过WiFi使用TCP协议与TCP客户端也就是手机通信了。

  1. #include "esp8266.h"
  2. void atk_8266_start_trans(void)
  3. {
  4. u8 ret = 0;
  5. delay_ms(1000);
  6. delay_ms(1000);
  7. ret = atk_8266_send_cmd("AT","OK", 100);
  8. if(ret == 0 ) printf("AT成功\n");
  9. else printf("AT fail\n");
  10. delay_ms(1000);
  11. ret = atk_8266_send_cmd ("AT+RST" , NULL ,100);
  12. if(ret == 0 ) printf("AT+RST成功\n");
  13. else printf("AT+RST fail\n");
  14. delay_ms(2000);
  15. ret = atk_8266_send_cmd("AT+CWMODE=2","OK",200);//开启热点
  16. if(ret == 0 ) printf("AT+CWMODE=2\n");
  17. else printf("AT+CWMODE fail\n");
  18. delay_ms(1000);
  19. ret = atk_8266_send_cmd("AT+CWSAP=\"ESP8266-ly\",\"123456789\",11,0","OK",100);//设置热点
  20. if(ret == 0 ) printf("AT+CWSAP成功\n");
  21. else printf("AT+CWSAP fail\n");
  22. delay_ms(1000);
  23. ret = atk_8266_send_cmd("AT+CIPMUX=1","OK",20);//=0:单路连接模式=1:多路连接模式
  24. if(ret == 0 ) printf("AT+CIPMUX=1\n");
  25. else printf("AT+CIPMUX=1 fail\n");
  26. delay_ms(1000);
  27. ret = atk_8266_send_cmd("AT+CIPSERVER=1","OK",200);//启动TCP服务器
  28. if(ret == 0 ) printf("AT+CIPSERVER=1\n");
  29. else printf("AT+CIPSERVER fail\n");
  30. delay_ms(1000);
  31. }
  32. u8 atk_8266_check_cmd(char *str)
  33. {
  34. if(USART3_RX_STA&0x8000)//接收到一次数据
  35. {
  36. USART3_RX_BUF[USART3_RX_STA&0x7fff]=0;//添加结束符
  37. if(strstr((const char*)USART3_RX_BUF,(const char*)str))
  38. return 1;
  39. else
  40. return 0;
  41. }
  42. return 0;
  43. }
  44. //向atk_8266发送命令
  45. //cmd:发送的命令字符串; ack:期待的应答结果,如果为空,则表示不需要等待应答;waittime:等待时间(单位:10ms)
  46. //返回值:0,发送成功(得到了期待的应答结果);1,发送失败
  47. u8 atk_8266_send_cmd(char *cmd, char *ack,u16 waittime)
  48. {
  49. u8 res=0;
  50. USART3_RX_STA=0;
  51. u3_printf("%s\r\n",cmd);//发送命令
  52. if(ack && waittime)//需要等待应答
  53. {
  54. while(--waittime)//等待倒计时
  55. {
  56. delay_ms(100);
  57. if(USART3_RX_STA&0x8000)//接收到期待的应答结果
  58. {
  59. if(atk_8266_check_cmd(ack))
  60. {
  61. printf("ack:%s\r\n",(u8*)ack);
  62. break;//得到有效数据
  63. }
  64. }
  65. USART3_RX_STA=0;
  66. }
  67. if(waittime==0)res=1;
  68. }
  69. return res;
  70. }
  71. //向atk_8266发送数据
  72. //cmd:发送的命令字符串;waittime:等待时间(单位:10ms)
  73. //返回值:发送数据后,服务器的返回验证码
  74. u8* atk_8266_send_data(char *cmd,u16 waittime)
  75. {
  76. char temp[5];
  77. char *ack=temp;
  78. USART3_RX_STA=0;
  79. u3_printf("%s\r\n",cmd);//发送命令
  80. if(waittime)//需要等待应答
  81. {
  82. while(--waittime)//等待倒计时
  83. {
  84. delay_ms(10);
  85. if(USART3_RX_STA&0X8000)//接收到期待的应答结果
  86. {
  87. USART3_RX_BUF[USART3_RX_STA&0X7fff]=0;//添加结束符
  88. ack=(char*)USART3_RX_BUF;
  89. printf("ack:%s\r\n",(u8*)ack);
  90. USART3_RX_STA=0;
  91. break;
  92. }
  93. }
  94. }
  95. return (u8*)ack;
  96. }

        esp8266.h

  1. #ifndef _ESP8266_H
  2. #define _ESP8266_H
  3. //C文件中需要的其他的头文件
  4. #include <stm32f4xx.h>
  5. #include "sys.h"
  6. #include "delay.h"
  7. #include "uart3.h"
  8. #include "uart.h"
  9. #include "string.h"
  10. #include <stdio.h>
  11. extern char restart[];
  12. extern char cwmode[];
  13. extern char cwlap[];
  14. extern char cwjap[];
  15. extern char cifsr[];
  16. extern char cipmux[];
  17. extern char cipstart[];
  18. extern char cipsend[];
  19. extern char cipserver[];
  20. extern char cwlif[];
  21. extern char cipstatus[];
  22. extern char cipsto[];
  23. extern char cipmode[];
  24. extern char test[];
  25. u8 atk_8266_send_cmd(char *cmd,char *ack,u16 waittime);
  26. u8* atk_8266_send_data(char *cmd,u16 waittime);
  27. u8 atk_8266_check_cmd(char *str);
  28. void atk_8266_start_trans(void);
  29. u8 atk_8266_quit_trans(void);
  30. #endif

       发送数据

        使用WiFi模块发送数据,其AT指令为“AT+CIPSEND=0,21”(其中0表示第0个客户端,21表示发送21个字节,所以这句话意思为向第0个客户端发送21个字节的数据),当配置好WiFi模块并发送这一串指令后,WiFi模块便会做出应答,并将我们接下来传给他的数据中的前21个字节发送给第0个客户端。具体代码可以写入主函数,其代码如下:

  1. ret = atk_8266_send_cmd("AT+CIPSEND=0,21",NULL,200);
  2. if(ret == 0 )
  3. {
  4. delay_ms(1000);
  5. ret1 = atk_8266_send_cmd(str, NULL, 200);//str即为要发送给App的数据
  6. if(ret1 == 0 ) printf("SEND OK\n");
  7. else printf("SEND fail\n");
  8. }
  9. else printf("AT+CIPSEND fail\n");

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/531625
推荐阅读
相关标签
  

闽ICP备14008679号