当前位置: 首页 > article >正文

STM32-笔记32-ESP8266作为服务端

        esp8266作为服务器的时候,这时候网络助手以客户端的模式连接到esp8266,其中IP地址写的是esp8266作为服务器时的IP地址,可以使用AT+CIFSR查询esp8266的ip地址,端口号默认写333。

当esp8266作为服务器的时候,需要完成哪些AT指令的信息

 发现3是没有分装函数的,所以

复制36-编程实现ESP8266连接TCP服务器

重命名为37-编程实现ESP8266作为服务器

打开项目文件

main.c

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "esp8266.h"

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    led_init();//初始化led灯
    uart1_init(115200);
    esp8266_init(115200);
   // printf("hello word!\r\n");
    

    while(1)
    { 
        //接收数据
        esp8266_receive_data();
        delay_ms(10);
//        esp8266_test();
//        delay_ms(500);
    }
}

esp8266.c

#include "sys.h"
#include "esp8266.h"
#include "string.h"
#include "stdio.h"
#include "delay.h"
#include "stdarg.h"

uint8_t esp8266_rx_buf[ESP8266_RX_BUF_SIZE];//定义一个数组,用来保存接收的缓冲区
uint8_t esp8266_tx_buf[ESP8266_TX_BUF_SIZE];//定义一个数组,用来保存发送的缓冲区
uint16_t esp8266_cnt = 0,esp8266_cntPre = 0; //定义一个计数器,和保存计数器原本状态的变量


UART_HandleTypeDef esp8266_handle = {0};

void esp8266_uart_init(uint32_t baudrate)
{
    esp8266_handle.Instance = USART2;
    esp8266_handle.Init.BaudRate = baudrate;  //波特率
    esp8266_handle.Init.Mode = UART_MODE_TX_RX;//收发模式;
    esp8266_handle.Init.Parity = UART_PARITY_NONE;//无校验位
    esp8266_handle.Init.WordLength = UART_WORDLENGTH_8B;  //字长:8个字长
    esp8266_handle.Init.StopBits = UART_STOPBITS_1; //停止位:1个停止位
    esp8266_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; //无硬件流控
    
    HAL_UART_Init(&esp8266_handle);
}

void USART2_IRQHandler(void)
{
    uint8_t receive_data = 0;
    //这个函数是用来检查特定的UART接口(在这个例子中是esp8266_handle所代表的UART接口)是否有数据可读
    if(__HAL_UART_GET_FLAG(&esp8266_handle,UART_FLAG_RXNE) != RESET)//关注RXNE这个标志位的值是不是不为reset(0)
    {
        if(esp8266_cnt >= sizeof(esp8266_rx_buf))//如果接收的字符长度大于字符缓冲区的长度,则把缓冲区长度置0
            esp8266_cnt = 0;
        //如果RXNE的值为1,证明有数据,所以需要接收数据
        HAL_UART_Receive(&esp8266_handle,&receive_data,1,1000);//句柄,接收的数据存放在哪?接收数据的个数,超时时间
        esp8266_rx_buf[esp8266_cnt++] = receive_data;//将接收的数据存放在esp8266rx_buf数组中
        
        //HAL_UART_Transmit(&esp8266_handle,&receive_data,1,1000);//发送数据:句柄,要发送的数据,发送数据的长度,超时
    }
}
//这个函数主要用来判断esp8266cnt有没有动,如果没有动证明接收完成了
uint8_t esp8266_wait_receive(void)
{
    if(esp8266_cnt == 0)//如果cnt为0证明,出现了错误
        return ESP8266_ERROR;//出现错误
    if(esp8266_cnt == esp8266_cntPre)//判断当前cnt和上一个cnt是否一致,如果是一致的证明数据不动了,传输完成
    {
        esp8266_cnt = 0;//cnt清0
        return ESP8266_EOK;//数据接收完成
    }
    esp8266_cntPre = esp8266_cnt;//把当前计数器cnt的值赋给之前计数器
    return ESP8266_ERROR;//
     
}
//把接收寄存器的内容清空
void esp8266_rx_clear(void)
{
    //把接收缓冲器清空
    memset(esp8266_rx_buf,0,sizeof(esp8266_rx_buf));
    //清空长度
    esp8266_cnt = 0;
}
//测试函数-这个函数在while循环里,来一直判断当前数据是否接收完
void esp8266_receive_data(void)
{
    if(esp8266_wait_receive() == ESP8266_EOK)//判断数据是否接受完整
    {
        printf("esp8266 recv: %s\r\n",esp8266_rx_buf);//接收完整,打印数据
        esp8266_rx_clear();//清除当前接收
    }
}
//发送数据的函数
void esp8266_send_data(char *fmt,...)
{
    va_list ap;
    uint16_t len;
    va_start(ap,fmt);
    vsprintf((char *)esp8266_tx_buf,fmt,ap);
    va_end(ap);
    
    len = strlen((const char *)esp8266_tx_buf);
    HAL_UART_Transmit(&esp8266_handle,esp8266_tx_buf,len,100);
}
//定义一个发送指令函数,cmd是发送的指令,res是期待的返回值,对应指令接收的日志
uint8_t esp8266_send_command(char *cmd,char *res)
{
    uint8_t time_out = 250;
    esp8266_rx_clear();//把接收缓冲区的内容清空
    HAL_UART_Transmit(&esp8266_handle,(uint8_t *)cmd,strlen(cmd),100);//发送的库函数:句柄,要发生的内容,内容的长度,阻塞的值
    
    //一共等待2.5s的时间,每一次等待10ms
    while(time_out--)
    {
        if(esp8266_wait_receive() == ESP8266_EOK)//表示已经接收到数据
        {
            if(strstr((const char*)esp8266_rx_buf,res) != NULL)//判断接收到的数据里面有没有我们想要的数据
                return ESP8266_EOK;
        }
        delay_ms(10);
    }
    return ESP8266_ERROR;
}
//AT指令
uint8_t esp8266_at_test(void)
{
    return esp8266_send_command("AT\r\n","OK");
}
//工作模式:1. 是station(设备)模式 2.是AP(路由)模式 3.是双模
uint8_t esp8266_set_mode(uint8_t mode)
{
    switch(mode)
    {
        case ESP8266_STA_MODE:
            return esp8266_send_command("AT+CWMODE=1\r\n","OK");
        case ESP8266_AP_MODE:
            return esp8266_send_command("AT+CWMODE=2\r\n","OK");
        case ESP8266_STA_AP_MODE:
            return esp8266_send_command("AT+CWMODE=3\r\n","OK");
        default:
            return ESP8266_EINVAL;//数据非法
    }
}
//以设备模式接入家中路由器,账号和密码
uint8_t esp8266_join_ap(char *ssid,char *pwd)
{
    char cmd[64];
    sprintf(cmd,"AT+CWJAP=\"%s\",\"%s\"",ssid,pwd);//使用sprintf构造字符串
    return esp8266_send_command(cmd,"WIFI GOT IP");
}
//模式:设置单路链接模式(透传只能使用此模式)
uint8_t esp8266_connection_mode(uint8_t mode)
{
    char cmd[64];
    sprintf(cmd,"AT+CIPMUX=%d\r\n",mode);//使用sprintf构造字符串
    return esp8266_send_command(cmd,"OK");
}
//连接服务器
uint8_t esp8266_connect_tcp_server(char *server_ip,char *server_port)
{
    char cmd[64];
    sprintf(cmd,"AT+CIPSTART=\"TCP\",\"%s\",%d\r\n",server_ip,server_port);//使用sprintf构造字符串
    return esp8266_send_command(cmd,"CONNECT");
}
//透传模式
uint8_t esp8266_enter_unvarnished(void)
{
    uint8_t ret;
    ret = esp8266_send_command("AT+CIPMODE=1\r\n","OK"); //如果数据正常传输结果为0
    ret += esp8266_send_command("AT+CIPSEND\r\n",">");   //如果数据正常传输结果为0
    if(ret == ESP8266_EOK)
        return ESP8266_EOK;
    else
        return ESP8266_ERROR;
}
//建立TCPserver
uint8_t esp8266_build_tcp_server(void)
{
    return esp8266_send_command("AT+CIPSERVER=1\r\n","OK");
}
void esp8266_init(uint32_t baudrate)
{
    printf("esp8266初始化开始...\r\n");
    //esp8266串口初始化
    esp8266_uart_init(baudrate);
    
    //esp8266的其他初始化 
    printf("1、测试esp8266是否存在...\r\n");
    while(esp8266_at_test())
        delay_ms(500);
    
    printf("2、设置工作模式为AP...\r\n");
    while(esp8266_set_mode(ESP8266_AP_MODE))
        delay_ms(500);
    printf("3、设置多路链接模式...\r\n"); 
    while(esp8266_connection_mode(ESP8266_MULTI_CONNECTION))
        delay_ms(500);
    printf("4、建立TCP服务器...\r\n");
    while(esp8266_build_tcp_server())
        delay_ms(500);
    printf("esp8266已连接到TCP服务器,并且进入到透传模式\r\n");
    printf("esp8266初始化完成\r\n");
}

//定义一个临时的函数,用来测试,判断发送一个指令回应的函数是否正确
void esp8266_test(void)
{
    esp8266_send_data("this is from esp8266\r\n");//发送数据
    esp8266_receive_data();//接收数据
}

esp8266.h

#ifndef __ESP8266_H__
#define __ESP8266_H__

#include "sys.h"

#define ESP8266_RX_BUF_SIZE         128 //接收的长度
#define ESP8266_TX_BUF_SIZE         64  //发送的长度

#define ESP8266_EOK                  0  //宏定义错误代码 ok
#define ESP8266_ERROR                1  //错误
#define ESP8266_ETIMEOUT             2  //超时
#define ESP8266_EINVAL               3  //数据非法

#define ESP8266_STA_MODE             1  //STA模式
#define ESP8266_AP_MODE              2  //AP模式
#define ESP8266_STA_AP_MODE          3  //双模
           
#define ESP8266_SINGLE_CONNECTION    0  //单链接
#define ESP8266_MULTI_CONNECTION     1  //多链接

#define WIFI_SSID                    "ChinaUnicom-FXL6NZ"  //wifi账号
#define WIFI_PWD                     "13555305181ljf"      //wifi密码

#define TCP_SERVER_IP                 "192.168.101.26"  //TCP IP
#define TCP_SERVER_PORT               "8080"            //端口号

void esp8266_init(uint32_t baudrate);
void esp8266_receive_data(void);
void esp8266_test(void);

#endif

结果实现:

        我们将代码烧录到开发板中,使用usb转ttl连接串口1,与电脑相连接,打印出esp8266的日志信息。使用杜邦线连接esp8266在串口2中。

        网络调试助手连接的信息是esp8266中的,它是作为客户端与服务端的esp8266进行通信的。

        这样当代码烧录到开发板中的时候,给开发板上电,开发板就会通过杜邦线传递AT指令信息给ESP8266,ESP8266收到指令,执行命令,返回指令信息给开发板,开发板收到ESP8266传递的信息,发送到串口2中,串口2连接电脑的串口助手,将信息打印出来。

百度安全验证

出现的问题

当,把所有东西准备就绪之后,出现错误

网络助手连接不上,并且报上面的错误

串口助手停留在这里

可能是:

没有写\r\n

加上就好了,当然如果出现上面网络助手中出现的错误,那么串口助手中起码会把指令完成

在这里,指令都没有完全完成,所有大概率是你代码的事。


http://www.kler.cn/a/470861.html

相关文章:

  • CS·GO搬砖流程详细版
  • 【Cesium】自定义材质,添加带有方向的滚动路线
  • 30分钟学会HTML
  • sunrays-framework(太阳射线框架搭建)
  • JVM vs JDK vs JRE
  • 【网络安全技术与应用】(选修)实验8 入侵检测
  • 设计模式七大设计原则Java 实践
  • 没有图形界面,如何快速部署一个Ubuntu 24.10的Server虚拟机
  • AICMP,开启智能挖矿新时代!
  • Elasticsearch 创建索引 Mapping映射属性 索引库操作 增删改查
  • C++:const和constexpr两个关键字
  • 【C++数据结构——线性表】顺序表的基本运算(头歌实践教学平台习题)【合集】
  • springboot+vue实现SSE服务器发送事件
  • 【OceanBase】利用 OceanBase 向量检索能力构建文档智能问答小助手
  • 6 网络编程
  • 小程序组件 —— 26 组件案例 - 跳转到商品列表
  • Unity-Mirror网络框架-从入门到精通 总目录
  • C# delegate 委托使用教程
  • 【Linux】sed编辑器
  • 周记-Repeater中的children和item区别
  • Go语言的 的抽象类(Abstract Classes)核心知识
  • 图数据库 | 17、高可用分布式设计(上)
  • Elixir语言的学习路线
  • 像素越多越好?像元的面积越小越好?
  • QT ---------------数据库编程概要
  • 自组织映射 (Self-Organizing Map, SOM) 算法详解与PyTorch实现