莱莱 发表于 2025-4-17 21:10:29

STM32驱动esp8266wife模块毗连TCP服务器(极其详细的教程)

     这次我要讲一下怎样使用STM32进行驱动esp8266模块去毗连TCP服务器进行通讯。后面我打算写一篇使用MQTTfx毗连阿里云的教程,然后再写一篇使用STM32进行驱动esp8266使用mqtt毗连阿里云,并实现智能云APP控制单片机,单片机控制智能云APP的教程。
一:硬件准备

    准备好STM32f407单片机和esp8266模块。esp8266模块如图:
https://i-blog.csdnimg.cn/direct/ceea8dab89b24723b102118325f7923a.jpeg
拍的不太好,请见谅。
二:软件准备

准备串口调试助手软件和网络调试助手软件。串口调试助手是使用来观察运行情况,将毗连情况展示出来。网络调试助手是用来以你电脑来搭一个小型服务器以供esp8266毗连。(这两个软件我都放在我的资源里面去了,自己去下就可以了)
串口调试助手软件如图:
https://i-blog.csdnimg.cn/direct/5d4cfa972f7840d8831bbf328c8fbd72.png
网络调试助手软件如图:
https://i-blog.csdnimg.cn/direct/1f7996dcac1948b4aff6632f7441272b.png
三:准备esp8266所需指令

  硬件和软件准备好后,我们还需要准备esp8266所需相干下令,和具体步骤。
1:起首我们要确认esp8266模块有没有坏,使用测试指令AT来测试模块是否能正常响应
2:使用AT+CWMODE=1指令设置ESP8266,进入station模式,使其能链接电脑、手机、 路由器热点
3: 使用 AT+CWJAP_CUR="账号名","密码"指令来链接电脑、手机、 路由器热点。(指令样式为:AT+CWJAP_CUR="cx","12345678")不要用希奇字符和中文。
4:使用 AT+CIPMUX=0指令设置ESP8266毗连服务器的模式为单链接模式(同一个时候只能链接一个服务器)
5:使用 AT+CIPMODE=1指令设置ESP8266的数据传输模式-透传模式(发送数据的时候不需要指定命据长度)
6:使用 AT+CIPSTART="服务器类型",“服务器IP”,服务器端标语 指令设置ESP8266链接服务器服务器类型: TCP/UDP/SSL(指令样式为:AT+CIPSTART="TCP",“192.168.53.12”,8080)端标语那里没有双引号。到这里你就已经连上服务器了。但需要与服务器通讯还需要几步。
7:使用 AT+CIPSEND指令设置ESP8266进入数据透传模式(使用这个指令后,你在发消息就都会传个服务器)
8: 如果不需要与服务器通讯,可以使用+++指令(该指令不需要发送换行)退出数据透传模式
以上除了+++指令都需要换行后发送才有效。全部指令如果实行乐成,esp8266都会传送OK回来,出了+++。
另有一些其他的指令如:AT+CWQAP(断开热点),AT+CIPCLOSE(断开服务器)。
步骤图如图:
https://i-blog.csdnimg.cn/direct/f39ea804a0d14e38bf3cc634ad940672.png
四:写代码

         如今我们已经把全部要准备的东西都准备好了,只差写代码了。起首整理一下思路,我们要初始化esp8266,所以我们要写指令给esp8266,且我们还要检查esp8266是否返回了OK。要完成这些,我们起首要能向esp8266接发信息,所以我们需要一个串口来接发信息,这里我选择的是USART3串口。然后我们先来写底子的接收和发送信息函数。
   发送信息函数:    

        我们发送信息根本都是发字符串,所以我们要写一个发送字符串函数。代码如下:          
   void USART_Sendstr(USART_TypeDef* USARTx,char *str)
{
        char *i=str;
        while((*i)!='\0')
        {               
        USART_SendData( USARTx, *i++);
        while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE)==RESET);
        }
}https://blog.csdn.net/data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==因为字符串的末尾是 \0 符,所以我们可以检测*i是否为\0来确认是否传输完毕,再通过while循环和*i++来实现指针 i 指向的位置不断向字符串末尾移动,直到字符串全部传输完毕。(USART_SendData函数是库自带的传输数据函数,只能一字节一字节的传输)
接收函数:

         我们需要在接受到信息的时候再去处理,我们不大概时时候刻都去检查信息有没有传过来,所以我需要使用串口制止函数进行接收函数。代码如图:                                                                   
   void USART3_IRQHandler(void)
{
        uint8_t ch=0;
//判断一下,触发中断服务函数的中断类型是否为接受中断
        if(USART_GetITStatus(USART3,USART_IT_RXNE))
        {
               
                ch=USART_ReceiveData(USART3);//接收数据
                usart3_recev_data=ch;//将接收到的数据放在数组里
                if((usart3_recev_data_index>=USART3_RX_SIZE-2))
                {
                   usart3_recev_flag=1;//接收信息标志位
                   usart3_recev_data_index=0;//接收信息数组的下标
                       
                }
               
                //清空中断触发
                USART_ClearITPendingBit(USART3, USART_IT_RXNE);
        }       
}https://blog.csdn.net/data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw== usart3_recev_data[]数组是专门存放串口3接收的数据的,usart3_recev_flag是是否接收完数据的的标记位,接收完数据或数组满了后置一。 usart3_recev_data_index是数组的下标,它代表你接收的数据大小为几字节。USART3_RX_SIZE是我宏界说的数组大小。
写指令函数:

       我们可以通过发送字符串函数将指令发给esp8266,但光发送可不行,我们还需要检查esp8266有没有返回数据,返回的数据有没有OK字符。
       既然我们知道只要esp8266实行乐成,那它返回的数据里就肯定会有OK,那我们就可以通过strstr函数来检测数据里有没有OK字符。可以通过while(strstr(usart3_recev_data,"OK")==NULL)来不绝不断检测数据,检测到再实行后面的代码。但我们也不能不绝卡在这里,如果esp8266实行失败了,返回的数据没有OK怎么办?我们可以while((strstr(usart3_recev_data,"OK")==NULL)&&timeout){timeout--;delayms(1)}。这样就算esp8266实行失败了,返回的数据没有OK,我们也可以在肯定时间后跳出循环。具体代码如下:
   uint32_t ESP8266_send_cmd(char *cmd,char *rtdata,int timeout)
{
        //清空
        ESP8266_rxbuf_clear();
        //串口3发送数据
        USART_Sendstr(USART3,cmd);
        /* 查找接收数据包中的字符串 */
        while((strstr((const char*)usart3_recev_data,(const char*)rtdata)==NULL)&&timeout)//等待串口接收完毕或超时退出
        {
                timeout--;
                delay_ms(1);
        }
        printf("返回%s\n",usart3_recev_data);
        if(timeout)
        {
                return 0;//找到匹配的响应字符串, 返回0
        }
        else
        {
                printf("超时\n");
                return 1;//没有找到匹配的字符串
        }       
}https://blog.csdn.net/data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==ESP8266_rxbuf_clear函数是清空数组用的,在代码里我们通过判断timeout的值是否大于0来判断是时间耗尽退出循环还是找到匹配的字符退出循环。
配置函数:

        有了上面三个函数,我们就可以正式写配置esp8266的函数了。代码如下:
void ESP8266_rxbuf_clear(void){        memset((void*)usart3_recev_data,0,4096);        usart3_recev_data_index=0;                usart3_recev_flag=0;}uint32_t ESP8266_send_cmd(char *cmd,char *rtdata,int timeout)
{
        //清空
        ESP8266_rxbuf_clear();
        //串口3发送数据
        USART_Sendstr(USART3,cmd);
        /* 查找接收数据包中的字符串 */
        while((strstr((const char*)usart3_recev_data,(const char*)rtdata)==NULL)&&timeout)//等待串口接收完毕或超时退出
        {
                timeout--;
                delay_ms(1);
        }
        printf("返回%s\n",usart3_recev_data);
        if(timeout)
        {
                return 0;//找到匹配的响应字符串, 返回0
        }
        else
        {
                printf("超时\n");
                return 1;//没有找到匹配的字符串
        }       
}uint32_t ESP8266_test(void){        if(ESP8266_send_cmd("AT\r\n","OK",3000)==0)        {                printf("测试正常\n");                return 0;        }        else        {                printf("测试失败\n");                return 1;        }}uint32_t ESP8266_set_station(void){        if(ESP8266_send_cmd("AT+CWMODE=1\r\n","OK",3000)==0)        {                printf("设置station乐成\n");                return 0;        }        else        {                printf("设置station失败\n");                return 1;        }}uint32_t ESP8266_connect_wife(char *name,char *password){        char buf={0};        sprintf(buf,"AT+CWJAP_CUR=\"%s\",\"%s\"\r\n",name,password);        if(ESP8266_send_cmd(buf,"OK",10000)==0)        {                printf("毗连热点乐成\n");                return 0;        }        else        {                printf("毗连热点失败\n");                return 1;        }}uint32_t ESP8266_disconnect_wife(void){        if(ESP8266_send_cmd("AT+CWQAP\r\n","OK",3000)==0)        {                printf("断开热点乐成\n");                return 0;        }        else        {                printf("断开热点失败\n");                return 1;        }}uint32_t ESP8266_set_connectmode(char *s){        char buf={0};        sprintf(buf,"AT+CIPMUX=%s\r\n",s);        if(ESP8266_send_cmd(buf,"OK",3000)==0)        {                printf("设置毗连模式乐成\n");                return 0;        }        else        {                printf("设置毗连模式失败\n");                return 1;        }}uint32_t ESP8266_set_transparentmode(char *s){        char buf={0};        sprintf(buf,"AT+CIPMODE=%s\r\n",s);        if(ESP8266_send_cmd(buf,"OK",3000)==0)        {                printf("设置传输模式乐成\n");                return 0;        }        else        {                printf("设置传输模式失败\n");                return 1;        }}uint32_t ESP8266_connect_server(char *ip,char *port){        char buf={0};        sprintf(buf,"AT+CIPSTART=\"TCP\",\"%s\",%s\r\n",ip,port);        if(ESP8266_send_cmd(buf,"OK",10000)==0)        {                printf("毗连服务器乐成\n");                return 0;        }        else        {                printf("毗连服务器失败\n");                return 1;        }}uint32_t ESP8266_disconnect_server(void){        if(ESP8266_send_cmd("AT+CIPCLOSE\r\n","OK",4000)==0)        {                printf("断开服务器乐成\n");                return 0;        }        else        {                printf("断开服务器失败\n");                return 1;        }}uint32_t ESP8266_set_transparent_transmission(void){        if(ESP8266_send_cmd("AT+CIPSEND\r\n","OK",3000)==0)        {                printf("设置透传模式乐成\n");                return 0;        }        else        {                printf("设置透传模式失败\n");                return 1;        }}uint32_t ESP8266_exit_transparent_transmission(void){        USART_Sendstr(USART3,"+++");        delay_ms(1000);        ESP8266_send_cmd("+++","+++",100);        delay_ms(2000);        return 0;        }uint32_t esp8266_reset(void){        if(ESP8266_send_cmd("AT+RST\r\n","OK",10000)==0)        {                printf("复位乐成\n");                return 0;        }        else        {                printf("复位失败\n");                return 1;        }        }/* 回显打开或关闭 */int32_t esp8266_enable_echo(uint32_t b){                if(b)                {if(ESP8266_send_cmd("ATE1\r\n","OK",5000)!=0)                {printf("回显打开失败\n");                }}        else        {if(ESP8266_send_cmd("ATE0\r\n","OK",5000)!=0)          { printf("回显关闭失败\n");                }}        return 0;} 这些配置函数都只是调用写指令函数,换一换输入的下令字符而已。
怎样判断数据接收完毕:

        我们可以初始化一个定时器,使它200ms触发一次定时制止,在制止函数内对  usart3_recev_data_index进行比较,如果usart3_recev_data_index>0且与上一次制止函数的它一样大,那么就说明接收了数据且已经接收完毕。如果不一样大,则大概其还在接收数据,如果=0,则代表且没接收数据。代码如下:
void TIM6_DAC_IRQHandler()
{
        IWDG_ReloadCounter();
        static uint32_t usart3_recev_data_preindex=0;
       
        if(TIM_GetITStatus(TIM6,TIM_IT_Update))//判断是否是TIM6的中断
        {                
                if(usart3_recev_data_index==0)
                {
                       
                }
                else if(usart3_recev_data_index==usart3_recev_data_preindex)
                {
                        usart3_recev_flag=1;
                       
                }
                usart3_recev_data_preindex=usart3_recev_data_index;
               
                //清除中断标志位
                TIM_ClearITPendingBit(TIM6,TIM_IT_Update);
        }
}
main函数:

代码如下:
int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
        USART3_Init(115200);
        USART1_PA9_10(9600);

    ESP8266_exit_transparent_transmission();
        delay_ms(2000);       
    esp8266_reset();
        delay_ms(2000);       
        esp8266_enable_echo(0);
        delay_s(2);
        ESP8266_set_station();       
        ESP8266_connect_wife("Redmicx","123456qwe");
        delay_ms(2000);       
        ESP8266_set_transparentmode("1");
//连接服务器       
        delay_s(3);
        ESP8266_connect_server(192.168.184.1,"8080");
    delay_ms(2000);
        ESP8266_set_transparent_transmission();       
    TIM6_Init();
while(1)
{
        if((usart3_recev_flag)
        {
   ESP8266_rxbuf_clear();
      GPIO_ToggleBits( GPIOE, GPIO_Pin_14);
   
   }
delay_ms(100);
} 五:结果视频

   WeChat_20250223225924


六:一些留意点

       如果你连不上电脑的热点,那你有大概是因为电脑的网络波段不对,调成2.4GHZ就行了。如果服务器连不上,你可以看一下电脑的ip地点,网络调试助手的地点调成你电脑的ip地点就行了。这些信息去网络和Internet里面的设置里看。发下令没反应的话,可以把esp8266拔了重插,或者看一下你发的下令有带换行吗。另有大概是因为你没退出透传模式,stm32下载程序的时候并没有完全断电,所以esp8266大概没有被重置。
        另有什么不懂得话,可以在评论区问我。如果文章哪里写的不太好,不太对可以指正我一下,究竟我才写博客没多久,欢迎指正。









































            


     
           

  
                

             

  

             





      

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: STM32驱动esp8266wife模块毗连TCP服务器(极其详细的教程)