STM32F103与ESP8266 WiFi模块结合:远程控制LED、蜂鸣器、步进电机及读取温湿度的实用应用

目录

  • 前言
  • 功能介绍:
  • 工程下载:
  • 效果图
  • STA模式 TCP服务器 控制LED1的亮灭
  • AP模式 TCP客户端 控制蜂鸣器的开关、步进电机正反转
  • AP模式 TCP服务器 读取温湿度
  • STA模式 TCP客户端 连接手机热点 与云服务器建立通信 实现云端控制
  • 1、云服务器的测试环境 搭建配置
  • 2、源程序修改 烧写
  • 3、STM32相关功能配置和测试
  • 核心代码
  • 前言

    前期准备可以参考我的这篇文章 STM32F103+ESP8266(WiFi)模块 实现AP模式下的TCP C/S 和 UDP Client,重复部分不再赘述。

    功能介绍:

    AP STA STA+AP 模式下,建立tcp/udp连接后,发送指定命令,控制LED1和蜂鸣器的开关,读取DHT11模块温湿度数据,控制步进电机正反转90度。
    命令如下:(每行都是一条命令,不要有换行等)具体实现在common.c

    LED1 ON
    LED1 OFF
    BEEP ON
    BEEP OFF
    GET T&H
    MOTOR CW
    MOTOR ACW
    

    工程下载:

    码云 GitHub

    效果图

    STA模式 TCP服务器 控制LED1的亮灭

    main.c中调用atk_8266_test();

    atk_8266_test();		//进入ATK_ESP8266测试
    

    common.c中 配置要连接wifi的信息

    //WIFI STA模式,设置要去连接的路由器无线参数,请根据你自己的路由器设置,自行修改.
    const u8* wifista_ssid="ikaros";			//路由器SSID号
    const u8* wifista_encryption="wpawpa2_aes";	//wpa/wpa2 aes加密方式
    const u8* wifista_password="12345678"; 	//连接密码
    

    准备2个手机(有WiFi的电脑,接入路由器等都可以),一个打开热点,根据配置设置ssid、加密和密码。

    串口调试打开,相关配置需要串口信息协助完成。



    手机也连上同一个wifi,打开 网络调试工具,我用的是“网络测试”,创建tcp连接

    AP模式 TCP客户端 控制蜂鸣器的开关、步进电机正反转

    复位,打开串口

    手机连接wifi,查看分配的ip

    修改代码wifiap.c中的atk_8266_wifiap_test函数中的ipbuf

    u8 ipbuf[16] = "192.168.4.2"; 	// 改为手机分配到的ip
    

    端口在common.c中,我们保持不变

    //连接端口号:8086,可自行修改为其他端口.
    const u8* portnum="8086";	
    

    重新编译烧录。打开串口,重复刚才的操作


    手机开启tcp server,监听8086端口。


    等待主动连接





    AP模式 TCP服务器 读取温湿度


    STA模式 TCP客户端 连接手机热点 与云服务器建立通信 实现云端控制

    1、云服务器的测试环境 搭建配置

    编写程序 server.c 监听 内网IP的8086端口,需要注意,此程序是一收一发的形式,程序如下:

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <string.h>
    
    int main()
    {
            printf("服务器创建socket...\n");
            int sockfd = socket(AF_INET,SOCK_STREAM,0);
            if(0 > sockfd)
            {
                    perror("socket");
                    return -1;
            }
    
            printf("准备地址...\n");
            struct sockaddr_in addr = {};
            addr.sin_family = AF_INET;
            // 你的端口
            addr.sin_port = htons(8086);
            // 你的内网IP
            addr.sin_addr.s_addr = inet_addr("10.130.4.89");
            socklen_t len = sizeof(addr);
    
            printf("绑定socket与地址...\n");
            if(bind(sockfd,(struct sockaddr*)&addr,len))
            {
                    perror("bind");
                    return -1;
            }
    
            printf("设置监听...\n");
            if(listen(sockfd,5))
            {
                    perror("listen");
                    return -1;
            }
    
            printf("等待客户端连接...\n");
            for(;;)
            {
                    struct sockaddr_in addrcli = {};
                    int clifd = accept(sockfd,(struct sockaddr*)&addrcli,&len);
                    if(0 > clifd)
                    {
                            perror("accept");
                            continue;
                    }
    
                    if(0 == fork())
                    {
                            char buf[1024] = {};
                            for(;;)
                            {
                                    printf("read:");
                                    read(clifd,buf,sizeof(buf));
                                    printf("%s\n",buf);
                                    if(0 == strcmp("quit",buf))
                                    {
                                            close(clifd);
                                            return 0;
                                    }
                                    printf(">");
                                    gets(buf);
                                    write(clifd,buf,strlen(buf)+1);
                            }
                    }
            }
            close(sockfd);
    }
    
    

    服务器安全组放行8086端口!

    运行环境,进行测试。

    2、源程序修改 烧写

    修改wifista.c中的ipbuf,改为服务器公网IP地址

    u8 ipbuf[16] = "139.198.169.41"; 	// IP缓存
    

    3、STM32相关功能配置和测试





    核心代码

    下载:码云 GitHub
    main.c调用的atk_8266_test();

    #include "sys.h"
    #include "delay.h"
    #include "usart.h"
    #include "led.h"
    #include "lcd.h"
    #include "key.h"
    #include "usmart.h"
    #include "malloc.h"
    #include "usart3.h"
    #include "common.h"
    #include "beep.h"
    #include "dht11.h"
    #include "step.h"
    
    // AP模式测试
    void ap_demo(void);
    
    int main(void)
    {
        delay_init();	    	 	//延时函数初始化
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
        uart_init(115200);	 		//串口初始化为115200
        usmart_dev.init(72);		//初始化USMART
        LED_Init();		  			//初始化与LED连接的硬件接口
        KEY_Init();					//初始化按键
    	BEEP_Init();				//初始化蜂鸣器
        //LCD_Init();			   	//初始化LCD
        usart3_init(115200);		//初始化串口3
        my_mem_init(SRAMIN);		//初始化内部内存池
    	Step_Motor_GPIO_Init();     // 步进电机初始化
        //LCD_Clear(BLACK);
    	while(DHT11_Init())			//DHT11初始化 DATA -> PG11
    	{
    		printf("DHT11 Error\r\n");
    	}
    
        delay_ms(1000);
    	
    	BEEP = 0;
    	LED1 = 0;
    	// ap_demo();
    	
        atk_8266_test();		//进入ATK_ESP8266测试
    }
    
    // AP模式测试
    void ap_demo(void)
    {
        u8 timex = 0;
    	u8 netpro = 0;	//网络模式 0,TCP服务器 1,TCP客户端 2,UDP模式
    	u8 key;
    	u8 ipbuf[16] = "192.168.4.2"; 	//IP (根据你的设备连上模块后分配到的IP填写)
    	u8 *p;
    	u16 t = 999;		//加速第一次获取链接状态
    	u16 rlen = 0;
    	u8 constate = 0;	//连接状态
        while(atk_8266_send_cmd("AT","OK",20))//检查WIFI模块是否在线
        {
            atk_8266_quit_trans();//退出透传
            atk_8266_send_cmd("AT+CIPMODE=0","OK",200);  //关闭透传模式
            printf("未检测到模块!!!\r\n");
            delay_ms(800);
            printf("尝试连接模块...\r\n");
        }
        while(atk_8266_send_cmd("ATE0","OK",20));//关闭回显
        printf("ATK_ESP8266 WIFI模块测试\r\n");
        printf("WIFI AP\r\n");
        atk_8266_msg_show(0, 0, 0);
    
        while(1)
        {
            delay_ms(10);
            atk_8266_at_response(1);//检查ATK-ESP8266模块发送过来的数据,及时上传给电脑
            printf("ATK-ESP WIFI-AP 测试\r\n");
            printf("正在配置ATK-ESP8266模块,请稍等...\r\n");
    
            p=mymalloc(SRAMIN,32);							//申请32字节内存
    
    PRESTA:
            if(netpro&0X02)   //UDP
            {
                printf("ATK-ESP WIFI-AP 测试\r\n");
                printf("正在配置ATK-ESP模块,请稍等...\r\n");
    
                sprintf((char*)p,"AT+CIPSTART=\"UDP\",\"%s\",%s",ipbuf,(u8*)portnum);    //配置目标UDP服务器
                atk_8266_send_cmd("AT+CIPMUX=0","OK",100);  //单链接模式
                while(atk_8266_send_cmd(p,"OK",500));
            }
            else     //TCP
            {
                if(netpro&0X01)     //TCP Client    透传模式测试
                {
                    printf("ATK-ESP WIFI-AP 测试\r\n");
                    printf("正在配置ATK-ESP模块,请稍等...\r\n");
                    atk_8266_send_cmd("AT+CIPMUX=0","OK",20);   //0:单连接,1:多连接
                    sprintf((char*)p,"AT+CIPSTART=\"TCP\",\"%s\",%s",ipbuf,(u8*)portnum);    //配置目标TCP服务器
                    while(atk_8266_send_cmd(p,"OK",200))
                    {
                        printf("WK_UP:返回重选");
                        printf("ATK-ESP 连接TCP Server失败"); //连接失败
                        key=KEY_Scan(0);
                        if(key==WKUP_PRES)goto PRESTA;
                    }
                    atk_8266_send_cmd("AT+CIPMODE=1","OK",200);      //传输模式为:透传
                }
                else					//TCP Server
                {
                    printf("ATK-ESP WIFI-AP 测试\r\n");
                    printf("正在配置ATK-ESP模块,请稍等...\r\n");
                    atk_8266_send_cmd("AT+CIPMUX=1","OK",20);   //0:单连接,1:多连接
                    sprintf((char*)p,"AT+CIPSERVER=1,%s",(u8*)portnum);
                    atk_8266_send_cmd(p,"OK",20);     //开启Server模式,端口号为8086
                }
            }
    
            printf("配置ATK-ESP模块成功!\r\n");
            delay_ms(200);
            printf("WK_UP:退出测试  KEY0:发送数据\r\n");
            atk_8266_get_wanip(ipbuf);//服务器模式,获取WAN IP
            sprintf((char*)p,"IP地址:%s 端口:%s",ipbuf,(u8*)portnum);
            printf("%s\r\n",p);				//显示IP地址和端口
            atk_8266_wificonf_show(30,180,"请用设备连接WIFI热点:",(u8*)wifiap_ssid,(u8*)wifiap_encryption,(u8*)wifiap_password);
            printf("状态:%s\r\n",(u8*)ATK_ESP8266_WORKMODE_TBL[netpro]); 		//连接状态
            USART3_RX_STA=0;
            while(1)
            {
                key=KEY_Scan(0);
                if(key==WKUP_PRES)			//WK_UP 退出测试
                {
                    atk_8266_quit_trans();	//退出透传
                    atk_8266_send_cmd("AT+CIPMODE=0","OK",20);   //关闭透传模式
    				myfree(SRAMIN,p);		//释放内存
                    return;
                }
                else if(key==KEY0_PRES)	//KEY0 发送数据
                {
    
                    if((netpro==3)||(netpro==2))   //UDP
                    {
                        sprintf((char*)p,"ATK-8266%s测试%02d\r\n",ATK_ESP8266_WORKMODE_TBL[netpro],t/10);//测试数据
                        printf("发送数据:%s\r\n",p);
                        atk_8266_send_cmd("AT+CIPSEND=25","OK",200);  //发送指定长度的数据
                        delay_ms(200);
                        atk_8266_send_data(p,"OK",100);  //发送指定长度的数据
                        timex=100;
                    }
                    else if((netpro==1))   //TCP Client
                    {
                        atk_8266_quit_trans();
                        atk_8266_send_cmd("AT+CIPSEND","OK",20);       //开始透传
                        sprintf((char*)p,"ATK-8266%s测试%02d\r\n",ATK_ESP8266_WORKMODE_TBL[netpro],t/10);//测试数据
                        printf("发送数据:%s\r\n",p);
                        u3_printf("%s",p);
                        timex=100;
                    }
                    else    //TCP Server
                    {
                        sprintf((char*)p,"ATK-8266%s测试%02d\r\n",ATK_ESP8266_WORKMODE_TBL[netpro],t/10);//测试数据
                        printf("发送数据:%s\r\n",p);
                        atk_8266_send_cmd("AT+CIPSEND=0,25","OK",200);  //发送指定长度的数据
                        delay_ms(200);
                        atk_8266_send_data(p,"OK",100);  //发送指定长度的数据
                        timex=100;
                    }
                }
    
                if(timex)timex--;
    
                t++;
                delay_ms(5);
                if(USART3_RX_STA&0X8000)		//接收到一次数据了
                {
                    rlen=USART3_RX_STA&0X7FFF;	//得到本次接收到的数据长度
                    USART3_RX_BUF[rlen]=0;		//添加结束符
                    sprintf((char*)p,"收到%d字节,内容如下",rlen);//接收到的字节数
                    printf("%s\r\n",p); 			//显示接收到的数据长度
                    printf("接收数据:%s\r\n",USART3_RX_BUF);//显示接收到的数据
    				USART3_RX_STA=0;
    				
    				// USART3收到的数据进行解析
    				recv_data_analysis(netpro, USART3_RX_BUF);
    				
                    if(constate!='+')t=1000;		//状态为还未连接,立即更新连接状态
                    else t=0;                   //状态为已经连接了,10秒后再检查
                }
                if(t==1000)//连续10秒钟没有收到任何数据,检查连接是不是还存在.
                {
                    constate=atk_8266_consta_check();//得到连接状态
                    if(constate=='+')printf("连接成功\r\n");  //连接状态
                    else printf("连接失败\r\n");
                    t=0;
                }
                if((t%20)==0)LED0=!LED0;
                atk_8266_at_response(1);
            }
        }
    }
    
    

    wifiap.c wifista.c apsta.c中,在收到USART3数据时,调用recv_data_analysis函数,传入当前模式和收到的数据,进行解析

    // USART3收到的数据进行解析
    recv_data_analysis(netpro, USART3_RX_BUF);
    

    common.c中,recv_data_analysis函数实现如下

    // USART3收到的数据进行解析
    void send_data_to_usart3(u8 netpro, char *data)
    {
    	u8 len = 0;
    	u8 buf[20] = {0};
    	
    	len = strlen(data);
    	
    	if((netpro==3)||(netpro==2))   //UDP
    	{
    		sprintf((char*)buf, "AT+CIPSEND=%d", len);
    		atk_8266_send_cmd(buf,"OK",200);  //发送指定长度的数据
    		delay_ms(200);
    		atk_8266_send_data((u8 *)data,"OK",100);  //发送指定长度的数据
    	}
    	else if((netpro==1))   //TCP Client
    	{
    		atk_8266_quit_trans();
    		atk_8266_send_cmd("AT+CIPSEND","OK",20);         //开始透传
    		u3_printf("%s", data);
    	}
    	else // TCP server
    	{
    		sprintf((char*)buf, "AT+CIPSEND=0,%d", len);
    		atk_8266_send_cmd(buf,"OK",200);  //发送指定长度的数据
    		delay_ms(200);
    		atk_8266_send_data((u8 *)data,"OK",100);  //发送指定长度的数据
    	}
    }
    
    // USART3收到的数据进行解析
    void recv_data_analysis(u8 netpro, u8 *USART3_RX_BUF)
    {
        char *ptr = NULL;
        char buf[100] = {0};
        u8 temperature = 0;
        u8 humidity = 0;
    
        ptr = mymalloc(SRAMIN, 600); //申请600字节内存
    
        if((netpro==1))   //TCP Client
        {
            sprintf(ptr, "%s", USART3_RX_BUF);
        }
        else    //TCP Server
        {
            ptr = strstr((char *)USART3_RX_BUF, ":");
            if(NULL != ptr)
            {
                // ptr指针后移一位
                ptr++;
    
                printf("解析后的命令为(<>内):<%s>\r\n", ptr);
            }
        }
    
        // 接收到的数据进行处理
        if(strcmp(ptr, "LED1 ON") == 0)
        {
            LED1 = 0;
            printf("打开LED1\r\n");
    
            send_data_to_usart3(netpro, "打开LED1成功\r\n");
        }
        else if(strcmp(ptr, "LED1 OFF") == 0)
        {
            LED1 = 1;
            printf("关闭LED1\r\n");
    
            send_data_to_usart3(netpro, "关闭LED1成功\r\n");
        }
        else if(strcmp(ptr, "BEEP OFF") == 0)
        {
            BEEP = 0;
            printf("关闭BEEP\r\n");
    
            send_data_to_usart3(netpro, "关闭BEEP成功\r\n");
        }
        else if(strcmp(ptr, "BEEP ON") == 0)
        {
            BEEP = 1;
            printf("开启BEEP\r\n");
    
            send_data_to_usart3(netpro, "开启BEEP成功\r\n");
        }
        else if(strcmp(ptr, "GET T&H") == 0)
        {
            DHT11_Read_Data(&temperature, &humidity);	//读取温湿度值
            sprintf(buf, "读取,温度:%d℃ 湿度:%d%%RH\r\n", temperature, humidity);
            printf("%s", buf);
    
            send_data_to_usart3(netpro, buf);
        }
    	else if(strcmp(ptr, "MOTOR ACW") == 0)
        {
            motor_circle(16, 1, 2);
            printf("步进电机正转90度\r\n");
    
            send_data_to_usart3(netpro, "步进电机正转90度成功\r\n");
        }
    	else if(strcmp(ptr, "MOTOR CW") == 0)
        {
            motor_circle(16, 2, 2);
            printf("步进电机反转90度\r\n");
    
            send_data_to_usart3(netpro, "步进电机反转90度成功\r\n");
        }
    
        myfree(SRAMIN, ptr);		// 释放内存
    }
    
    
    
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32F103与ESP8266 WiFi模块结合:远程控制LED、蜂鸣器、步进电机及读取温湿度的实用应用

    发表评论