模块介绍
模块连接
模块连接时基于串口方式连接,其模块与电脑(服务器)之间数据的发送与接收也是基于串口。
WIFI模块的模式
- mode=1 :Station模式(连接到WIFI)
- mode=2:AP模式(自己作为WIFI源供其他连接)
- mode=3:AP+Station模式(以上两者模式的合并)
WIFI模块常用AT指令
透传模式理解
透传模式就是单片机通过串口形式与模块连接,而模块与上位机之间的数据交互的具体不用考虑。
-
如果不开启透传模式,在每次发送数据前都必须先发送指令AT+CIPSEND=
AT+CIPSEND=4 OK > //在 > 后面输入要上传的数据
-
但是开启了透传模式,我们就不需要在每次发送数据前都发送指令AT+CIPSEND=了,只需要发送一次AT+CIPSEND,之后发送的所有内容全部当成是数据了!
代码实现
代码介绍
1、对串口的配置。
串口初始化、串口中断接收数据,串口发送函数封装(模块发送数据)
2、AT指令的发送,并发送AT指令时发送相关的数据:熟练运用spprintf()函数。
实现步骤
1. 重置模组为出厂模式:AT+RESTORE 示例:AT+RESTORE OK
2. 设置工作模式:AT+CWMODE=<mode> 示例:AT+CWMODE=1 OK
3. 连接当前环境的WIFI热点:AT+CWJAP=<ssid>,< pwd >
< ssid >:字符串参数,当前WIFI的名字
< pwd >:字符串参数,连接密码
示例:AT+CWJAP="TCP_Server","12345678"
WIFI CONNECTED
WIFI GOT IP
4. 建立TCP连接通道 :AT+CIPSTART="TCP",<ip>,<port>
< ip >:字符串参数,IP地址
< port >:字符串参数,服务器端口
示例: AT+CIPSTART="TCP","192.168.4.1",333
CONNECTED
5. 开启透传模式:AT+CIPMODE=1
6. 发送数据: AT+CIPSEND=<length>
<length> 发送数据的字节长度
示例: AT+CIPSEND=10
OK
>在此处填写要发送的内容
注释:示例是在串口调试助手下的发送与返回。也是给代码编写提供示例。
.c文件
#include "delay.h"
#include "wifi.h"
#include "stdarg.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "usart.h"
#include "stm32f10x.h"
#include "sys.h"
#include "lcd.h"
//串口接收缓存区
char USART2_RX_BUF[USART2_MAX_RECV_LEN]; //接收缓冲,最大USART3_MAX_RECV_LEN个字节.
//接收到的数据状态
//[15]:0,没有接收到数据;1,接收到了一批数据.
//[14:0]:接收到的数据长度
vu16 USART2_RX_STA=0;
void USART2_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)//接收到数据
{
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
res =USART_ReceiveData(USART2);
USART2_RX_BUF[USART2_RX_STA&0X3FFF]=res; //记录接收到的值
USART2_RX_STA++;
//USART_SendData(USART1,res);
//printf("%x",res);
USART2_RX_STA|=0x8000; //标记接收完成
}
}
//初始化IO 串口2
//bound:波特率
void wifi_usart2_init(u32 bound)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // GPIOA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //串口2时钟使能
USART_DeInit(USART2); //复位串口2
//USART2_TX PA2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA2
//USART2_RX PA3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA3
//设置中断优先级
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //子优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART2, &USART_InitStructure); //初始化串口 2
//使能接收中断
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断
USART_Cmd(USART2, ENABLE); //使能串口
USART2_RX_STA=0; //清零
}
/******************************************************************************
函数说明:发送数据到串口2
入口数据:DATA_BUF 发送的数据
len 发送的长度
返回值: 无
******************************************************************************/
void esp8266_send_data(u8 *DATA_BUF,u8 len) //发送数据到串口2
{
u16 j;
if(len <= 0)
return ;
if(len>USART2_MAX_SEND_LEN) //最多只能发MAX_LEN个数据
{
for(j=0;j<USART2_MAX_SEND_LEN;j++) //循环发送数据
{
USART_SendData(USART2,DATA_BUF[j]);
while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕
}
}
else
{
for(j=0;j<len;j++) //循环发送数据
{
USART_SendData(USART2,DATA_BUF[j]);
while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕
}
}
}
/******************************************************************************
函数说明:检查是否有相应回复的数据
入口数据:str 检查的字符串
返回值: str出现的位置开始
******************************************************************************/
u8* esp8266_check_cmd(u8 *str) //检查回复是否有字符串str
{
USART2_RX_STA = 0;
return (u8*)strstr((const char*)USART2_RX_BUF,(const char*)str);
}
/******************************************************************************
函数说明:连接WIFI TCP服务器
根据电脑上连接的WIFI和IP地址,建立模块与电脑上服务器之间的连接
将模块连接与WIFI(wifi名字和密码),并确认是那台电脑上(电脑上的ip地址)的服务器
电脑与模块需要连接在同以WIFI下
使模块与电脑通过串口,连接于电脑端的服务器软件或平台
入口数据:id WIFI帐号
key WIFI密码
ip TCP服务器的IP地址
port TCP服务器的端口号
返回值: 连接成功返回0, WIFI连接失败返回-1, TCP连接失败返回-2
******************************************************************************/
int esp8266_connect_ap_tcp(u8 *ssid,u8 *password,u8 *ip,u8 *port) //发送WIFI账号,密码
{
u8 idkey_buf[64]={0};
u8 ip_server[64]={0};
u8 i;
int n;
int m;
char *ipbuf;
char *ipbuf1;
//u8 debuf[1] = """;
int datelen1,datelen2;
//将发送的数据通过sprintf存入数组
//然后发送AT指令和等待模块连接,返回相应的数据
datelen1 = sprintf((char *)idkey_buf,"AT+CWJAP=\"%s\",\"%s\"\r\n",ssid,password);//连接指令
datelen2 = sprintf((char *)ip_server,"AT+CIPSTART=\"TCP\",\"%s\",%s\r\n",ip,port);//连接指令
esp8266_send_data("AT+RSTORE\r\n",11);
delay_ms(1000); //延时3S等待重启成功
delay_ms(1000);
//设置工作模式 1:station模式 2:AP模式 3:兼容 AP+station模式
esp8266_send_data("AT+CWMODE=1\r\n",13);
delay_ms(1000);
delay_ms(1000);
esp8266_send_data(idkey_buf,datelen1); //让模块连接上自己的路由 "WIFI GOT IP"
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
if(esp8266_check_cmd("WIFI CONNECTED"))
{
delay_ms(1000);
esp8266_send_data("AT+CIFSR\r\n",10); //查询本模块IP地址
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
ipbuf = (char*)esp8266_check_cmd("+CIFSR:");
//得到IP地址最后3 位 例如:192.168.1.120 得到 120 //显示的是ESP8266模块的IP地址的后三位
for(i=0;i<3;i++)
{
ipbuf = strstr(ipbuf,".");
ipbuf ++;
}
ipbuf1 = strstr(ipbuf,"\"");
n = ipbuf1-ipbuf;
ipbuf[n] = '\0';
m = atoi(ipbuf); //将字符格式 转换为int //发送AT指令后,模块返回的是字符串,需要将后三位转化为数字
printf("clinet IP is:%d\r\n",m);
LCD_ShowString(40,0," ",RED,WHITE); //接收数据显示至lcd屏
LCD_ShowString(40,0,(u8 *)ipbuf,RED,WHITE); //接收数据显示至lcd屏
esp8266_send_data(ip_server,datelen2); //建立TCP连接 这四项分别代表了 要连接的ID号0~4 连接类型 远程服务器IP地址 远程服务器端口号
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
if(esp8266_check_cmd("CONNECT")) //判断是否连接成功
{
return m;
}
else
return -2;
}
return -1;
}
/******************************************************************************
函数说明:发送数据到服务器
模块建立TCP连接到服务器,并发送数据
入口数据:data 发送的数据
len 发送的长度
返回值: 若无TCP连接返回0,有返回1
******************************************************************************/
u8 esp8266_send_serverdata(u8 *data,u8 len) //给服务器发数据,检查若无连接TCP 则return 0;连上则发送
{
//检查TCP连接状态 AT+CIPSTATUS STATUS:3
u8 Send_ServerBuf[32] = {0};
u8 len2=0;
esp8266_send_data("AT+CIPSTATUS\r\n",14);
delay_ms(10);
if(esp8266_check_cmd("STATUS:3")) //检查回复
{
len2=sprintf((char *)Send_ServerBuf,"AT+CIPSEND=%d\r\n",(int)len);
esp8266_send_data(Send_ServerBuf,len2);//发送len个字节的数据到服务器端
delay_ms(10);
esp8266_send_data(data,len);
return 1;
}
else
return 0;
}
/******************************************************************************
函数说明:解析服务器发送的有效数据
参数:recv_buf 接收数组指针
返回值: 有效数据的长度
******************************************************************************/
u16 esp8266_rev_serverdata(u8 *recv_buf)
{
u8 i,j;
int len;
char *USART_RX_BUF1;
char *USART_RX_BUF2;
u8 lens[3]={0};
delay_ms(20);
if(USART2_RX_STA&0X8000) //接收到一次数据了
{
//"\r\n+IPD,20:http://www.baidu.com"
if(strstr((const char*)USART2_RX_BUF,"+IPD"))
{
USART_RX_BUF1=strstr(USART2_RX_BUF,","); //查找第一个 ","所在位置 返回指针
USART_RX_BUF2=strstr(USART2_RX_BUF,":"); //查找第一个 ":"所在位置 返回指针
j=USART_RX_BUF2-USART_RX_BUF1; //数据长度计算 指针相减
if (j>3) j=3;
for(i=0;i<j;i++)
{
lens[i]=USART_RX_BUF1[i+1];
}
len = atoi((const char *)lens); //字符串转整数
for(i=0;i<len;i++)
{
recv_buf[i] = USART_RX_BUF2[i+1];
}
recv_buf[len]='\0';
USART2_RX_STA = 0;
return len;
}
}
USART2_RX_STA = 0;
return 0;
}
.h文件
#ifndef __WIFI_H
#define __WIFI_H
#include "sys.h"
#define USART2_MAX_RECV_LEN 200 //最大接收缓存字节数
#define USART2_MAX_SEND_LEN 200 //最大发送缓存字节数
extern char USART2_RX_BUF[USART2_MAX_RECV_LEN]; //接收缓冲,最大USART2_MAX_RECV_LEN字节
extern u8 USART2_TX_BUF[USART2_MAX_SEND_LEN]; //发送缓冲,最大USART2_MAX_SEND_LEN字节
extern vu16 USART2_RX_STA; //接收数据状态
void wifi_usart2_init(u32 bound); //串口2初始化
int esp8266_connect_ap_tcp(u8 *ssid,u8 *password,u8 *ip,u8 *port); //发送WIFI账号,密码/TCP服务器的IP,接口
u16 esp8266_rev_serverdata(u8 *USART_RX_buf);//解析服务器发送的有效数据
u8 esp8266_send_serverdata(u8 *data,u8 len);
#endif
main.c文件
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "lcd.h"
#include "wifi.h"
#include "key.h"
#include "timer.h"
#include "beep.h"
#include "lcd_init.h"
//技术支持:
int main(void)
{
u16 rlen=0;
int add;
u8 key;
u16 led0pwmval=0; //PWM用变量
u8 dir=1; //PWM初始递增
u8 revbuf[200] = {0}; //接收buffer
u8 heartbeat[5]={0x55,0x00,0x00,0x00,0xaa}; //心跳包格式
u8 ledflag = 1; //LED处理变量
u8 beepflag = 0;//蜂鸣器处理变量
u8 picflag = 0;//图片处理变量
u8 pwmflag = 1;//PWM处理变量
u8 beepfirst=1;//定义此变量来解决蜂鸣器上电后默认响的问题
u8 picjif=0;//定义此变量解决PWM时刷新图片导致PWM观察不明显的问题
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
delay_init(); //延时函数初始化
uart_init(115200); //串口1初始化为115200
wifi_usart2_init(115200);
LED_Init(); //初始化LED
LCD_Init(); //初始化LCD
KEY_Init(); //初始化KEY
BEEP_Init(); //初始化BEEP
TIM1_PWM_Init(899,0);//初始化TIM1
LCD_Fill(0,0,LCD_W,LCD_H,WHITE);//进行清屏
LCD_ShowString(0,0,(u8*)"地址: LED: ",RED,WHITE);
LCD_ShowString(0,16,(u8*)"蜂鸣器: PWM: ",RED,WHITE);
add=esp8266_connect_ap_tcp("TZH-WiFi","88888888","192.168.0.25","8234");
if(add)
{
heartbeat[1] = add&0xff;
esp8266_send_serverdata(heartbeat,5);
}
LCD_ShowPicture(0,32,128,128,gImage_ta);
while(1)
{
key=KEY_Scan(0); //进行按键扫描 不检测连按
if( key == KEYLEFT_PRES ) //KEYLEFT按下,连接服务器
{
//连接wifi ap ssid ="TZHXXKJ" password = "1105_tzh" tcp server ip="192.168.1.147" port="8234"
add=esp8266_connect_ap_tcp((u8*)"TZH-WiFi","88888888","192.168.0.25","8234");
if(add)
{
heartbeat[1] = add&0xff;
esp8266_send_serverdata(heartbeat,5);
}
}
//-------------------------------------------------------------------------------------------------------
if(key==KEYRIGHT_PRES) //KEYRIGHT按下,往服务器发送数据
{
esp8266_send_serverdata((u8*)"123456789",9);
}
//-------------------------------------------------------------------------------------------------------
if(!ledflag) //LED 相关处理
{
LED1=0;
LCD_ShowString(112,0,(u8*)"开",RED,WHITE);
}
else
{
LED1=1;
LCD_ShowString(112,0,(u8*)"关",RED,WHITE);
}
if(!beepflag) //蜂鸣器 相关处理
{
if(beepfirst) //第一次上电时蜂鸣器不响
{
BEEP=0;
LCD_ShowString(56,16,(u8*)"关",RED,WHITE);
}
else
{
BEEP=1;
LCD_ShowString(56,15,(u8*)"开",RED,WHITE);
}
}
else
{
BEEP=0;
LCD_ShowString(56,16,(u8*)"关",RED,WHITE);
}
//-------------------------------------------------------------------------------------------------------
if(picflag) //动态图片相关处理
{
LCD_ShowPicture(0,32,128,128,gImage_gif1);
LCD_ShowPicture(0,32,128,128,gImage_gif2);
}
//-------------------------------------------------------------------------------------------------------
if(!pwmflag)//PWM 相关处理
{
if(picflag)//如果动态图片刷新为真
{
picjif=1;//记录该状态
picflag=0;//先禁止动态图片刷新 否则影响PWM观察
}
if(dir)led0pwmval += 15;
else led0pwmval -= 15;
if(led0pwmval>800)dir=0;
if(led0pwmval==0)dir=1;
TIM_SetCompare1(TIM1,led0pwmval);
LCD_ShowString(112,16,(u8*)"开",RED,WHITE);
}
else//PWM关闭
{
if(picjif)//如果记录状态为真,说明动态图片刷新被禁止
{
picjif=0;//清除该状态变量
picflag=1;//恢复动态图片刷新
}
TIM_SetCompare1(TIM1,0);
LCD_ShowString(112,16,(u8*)"关",RED,WHITE);
}
//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------
delay_ms(10);
rlen=esp8266_rev_serverdata(revbuf); //接收服务器发过来的数据
if(rlen)
{
if(revbuf[2] == 1) //LED 相关处理
{
ledflag=revbuf[3];
}
if(revbuf[2] == 2)//蜂鸣器 相关处理
{
beepfirst=0;
beepflag=revbuf[3];
}
if(revbuf[2] == 3)//图片显示 相关处理
{
switch(revbuf[3])
{
case 0x01:picflag=0;picjif=0;LCD_ShowPicture(0,32,128,128,gImage_ta);break;
case 0x02:picflag=0;picjif=0;LCD_ShowPicture(0,32,128,128,gImage_yun);break;
case 0x03:picflag=1;picjif=0;break;
default:
LCD_ShowPicture(0,32,128,128,gImage_ta);
}
}
if(revbuf[2] == 4) //PWM 相关处理
{
pwmflag=revbuf[3];
}
}
} //end while(1)
}
数据接收讲解
主要部分:
rlen=esp8266_rev_serverdata(revbuf); //接收服务器发过来的数据
if(rlen)
{
if(revbuf[2] == 1) //LED 相关处理
{
ledflag=revbuf[3];
}
if(revbuf[2] == 2)//蜂鸣器 相关处理
{
beepfirst=0;
beepflag=revbuf[3];
}
if(revbuf[2] == 3)//图片显示 相关处理
{
switch(revbuf[3])
{
case 0x01:picflag=0;picjif=0;LCD_ShowPicture(0,32,128,128,gImage_ta);break;
case 0x02:picflag=0;picjif=0;LCD_ShowPicture(0,32,128,128,gImage_yun);break;
case 0x03:picflag=1;picjif=0;break;
default:
LCD_ShowPicture(0,32,128,128,gImage_ta);
}
}
if(revbuf[2] == 4) //PWM 相关处理
{
pwmflag=revbuf[3];
}
}
上位机发送的数据文章来源:https://www.toymoban.com/news/detail-768999.html
> [1,OnAccept] -> PASS(192.168.1.177:18323)
> [1,OnReceive] -> 192.168.1.177:18323 (5 bytes)
-> HEX: 55 B1 00 00 AA
-> ASCII: U?
其中最主要看HEX十六进制数据
根据代码和接受的数据,可知,其最后在物理层连接部分,只是串口的应用。文章来源地址https://www.toymoban.com/news/detail-768999.html
到了这里,关于STM32---WIFI模块ESP8266的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!