注意:虽然UDP通信没有服务器和客户端得,在这里逻辑上将8266作为服务器
一、UDP接口
- espconn_create
功能:建⽴ UDP 传输。
注意:请注意设置 remote_ip 和 remote_port 参数,请勿设置为 0。
函数定义:sin8 espconn_create(struct espconn *espconn)
参数:struct espconn *espconn
:对应⽹络连接的结构体
返回:
0:成功
其它:失败,返回错误码
• ESPCONN_ARG:未找到参数 espconn 对应的 UDP 连接
• ESPCONN_MEM:空间不⾜
• ESPCONN_ISCONN:连接已经建⽴ - espconn_sendto
功能:UDP 发包接⼝
函数定义:sin16 espconn_sendto(struct espconn *espconn, uint8 *psent, uint16 length)
参数:struct espconn *espconn
:对应⽹络连接的结构体uint8 *psent
:待发送的数据uint16 length
:发送的数据⻓度
返回:
0:成功
其它:失败,返回错误码
• ESPCONN_ARG:未找到参数 espconn 对应的 UDP 传输
• ESPCONN_MEM:空间不⾜
• ESPCONN_IF:UDP 发包失败 - espconn_igmp_join
功能:退出多播组
函数定义:sint8 espconn_igmp_leave(ip_addr_t *host_ip, ip_addr_t *multicast_ip)
参数:ip_addr_t *host_ip
:主机 IPip_addr_t *multicast_ip
:多播组 IP
返回
0:成功
其它:失败,返回错误码 ESPCONN_MEM:空间不⾜ - espconn_dns_setserver
功能:设置默认 DNS server
注意:本接口必须在 ESP8266 DHCP client 关闭wifi_station_dhcpc_stop
的情况下使⽤。
函数定义:void espconn_dns_setserver(uint8 numdns, ip_addr_t *dnsserver)
参数:uint8 numdns
:DNS server ID,⽀持设置两个 DNS server,ID 分别为 0 和 1ip_addr_t *dnsserver
:DNS server IP
返回 ⽆ - espconn_dns_getserver
功能:查询 DNS server IP
函数定义:ip_addr_t espconn_dns_getserver(uint8 numdns)
参数:uint8 numdns
:DNS server ID,⽀持传⼊ 0 或 1
返回:DNS server IP
二、例程1(8266在逻辑上作为服务器)
- 首先在user_ init函数中将ESP8266初始化为AP模式,然后执行
OS_ Timer_ 1_ Init_ _JX(1000, 1);
1秒软件定时。执行完后结束user_ init函数。在定时回调函数当中如下:
void ICACHE_ FLASH_ ATTR OS_ Timer_ 1_ cb(void)
{
struct ip_ info ST_ _ESP8266_ IP; // IP信息结构体
u8 ESP8266_ IP[4];//点分十进制形式保存IP
wifi_ get_ ip_ info (SOFTAP_ IF, &ST_ ESP8266_ IP); //查询AP模式下ESP8266的IP地址
if(ST_ ESP8266_ IP. ip. addr != 0)// ESP8266成功获取到IP地址、
{
ESP8266_ IP[0] = ST_ ESP8266_ IP. ip. addr ;//点分十进制IP的第一个数<==> addr低八位
ESP8266_ IP[1]= ST_ ESP8266_ IP. ip. addr>>8;//点分十进制IP的第二个数<==> addr次低八位
ESP8266_ IP[2]= ST_ ESP8266_ IP. ip. addr>>16;//点分十进制IP的第三个数<==> addr次高八位
ESP8266_ IP[3] = ST_ ESP8266_ IP. ip. addr>>24;//点分十进制IP的第四个数<==> addr高八位
}
//打印并显示ESP8266的IP地址
os_ printf ("ESP8266_ IP = %d. %d. %d. %d\n", ESP8266_ IP[0], ESP8266_ IP[1], ESP8266_ IP[2], ESP8266_ IP[3]) ;
OLED_ ShowIP (24, 2, ESP8266_ IP); // OLED显示ESP8266的IP地址
os_ timer_ _disarm(&OS_ Timer_ _1); // 关闭定时器
ESP8266 NetCon Init 0: // 初始化网络连接(UDP通信)
}
- 关闭定时器后,调用ESP8266 NetCon Init 0函数,初始化网络连接,开启UDP通信。
在调用函数之前,首先要定义一个网络连接结构体
//定义espconn型结构体(网络连接结构体)
struct espponn ST_ NetCon; //注:必须定义为全局变量,内核将会使用此变量(内存)
esp_ udp ST_ UDP; // UDP通信结构体
struct espconn
{
enum espconn_ type type ;//连接的类型是UDP通信还是TCP通信
enum espconn_ state state;//网络连接的状态
union
{
esp_ tcp *tcp;
esp_ udp *udp;
}proto;//共用体,TCP通信结构体指针或者是UDP通信结构体指针
espconn_ recv_ cal Iback recv_ callback;//回调函数
espconn_ sent_ call back sent_ ca I Iback;
uint8 link_ cnt;连接数量
//UDP结构体
typedef struct_ esp_ _udp
{
int remote_ port;//远端主机的端口号
int local_ port;//8266的端口号
Iuint8 local_ ip[4];//8266的IP地址
uint8 remote_ ip[4];//远端主机的IP地址
}esp udp:
- 接下来需要将网络连接结构体赋值,这里需要设置为UDP通信(注意:上面
union
{
esp_ tcp *tcp;
esp_ udp *udp;
}proto;//
是一个共用体,是TCP结构体指针,或者是UDP结构体指针。仅仅是一个指针,所以我们需要创建一个UDP通信结构体。需要将通信结构体的指针赋值给网络连接结构体中UDP通信结构体指针的成员ST_ NetCon. proto. udp = (esp_ udp_ *)os_ zalloc (sizeof(esp_ udp)); // 申请内存
(void * os_ zalloc(size_ t size)申请一块指定大小(参数决定)的内存,并返回这块内存的首地址。这块内存申请完毕后,就不能分配给其他变量。如果申请内存的操作过多,内存将不够用。使用[os_ free(指针参数) ]来释放这块内存。)
- 结构体赋值
ST_ NetCon. type = ESPCONN UDP;// 通信协议: UDP
ST_ NetCon. proto. udp = (esp_ udp *)os_ zal loc (s izeof (esp_ _udp)); // 申请内存
ST NetCon. proto. udp- >loca I port= 8266 ;//设置本地端口号
- 注册回调函数
espconn_ regist_ sentcb (&ST_ NetCon, ESP8266 WIFI Send Cb_ JX); // 注册网络数据发送成功的回调函数
espconn_ regist_ recvcb (&ST_ NetCon, ESP8266 WIFI Recv Cb JX); // 注册网络数据接收成功的回调函数
- 初始化UDP通信
espconn_ create (&ST_ NetCon); //初始化DUP通信
- 网络数据成功接收的回调函数
//[参数1:网络传输结构体espconn指针、 参数2:网络传输数据指针、参数3:数据长度】//
void ICACHE_ FLASH ATTR ESP8266_ WIFI_ Recv_ _Cb_ JX(void * arg. char * pdata, Jns i gned short len)
{
struct espconn * T_ _arg = arg;//缓存网络连接结构体指针
remot_ info_ * P_ port_ info = NULL; // 远端连接信息结构体指针
}
//根据树蕨设置LED灯的亮/灭
if (pdata[0] == 'k'|| pdata[0] == 'K') LED_ ON;//首字母为'k'/'K',灯亮
else if (pdata[0] == 'g'|l pdata[0] == 'G') LED_ _0FF;//首字母为'g'/'G',灯灭.
os_ pr intf ("\nESP8266_ Receive_ Data = %s\n", pdata) ;//串口打印接收到的数据
- 我们虽然可以接收到UDP发来的数据,如果想知道是谁发送的,我们可以调用一下API来调用远端主机的信息
if (espconn get connection info(T_ arg, &P_ port_ info, 0)--ESPCONN 0K) //获取远端信息,参数1是网络连接结构体指针、参数2是远端连接结构体指针的指针、参数3设置为0。
{
T_ arg ->proto. udp->remote_ port_ = P_ port_ info->remote_ port; // 获取对方端口号
T_ arg- >proto. udp- >r emote_ ip [0];//获取对方的IP地址
T_ arg->proto. udp->remote_ ip[1] = P_ port_ info->remote_ ip[1] ;
T_ arg- >proto. udp- >remote_ ip[2] = P_ port_ info- >remote_ ip[2];
T_ arg->proto. udp->remote_ ip[3] = P_ port_ info->remote_ ip[3];
//os_ memcpy(T_ arg- >proto. udp->remote_ ip, P_ port_ info->remote_ ip,4); // 内存拷贝。可用此句话,代替以上四句话//
OLED_ _ShowIP(24, 6, T_ _arg->proto. udp->remote_ ip); // 显示远端主机IP地址
espconn_ send(T_ arg, "ESP8266 WIFI Recv 0K", os_ str len("ESP8266_ WIFI Recv_ 0K")); // 向对方发送应答,参数1是网络连接结构体指针、参数2是一个字符串、参数3是字符串的长度//
}
- 成功发送网络函数数据后会调用一个回调函数。成功后发送一个字符串
void ICACHE_ FLASH_ ATTR ESP8266 WIFI_ Send_ Cb_ JX(void *arg)
{
os_ pr intf ("\nESP8266_ _WIFI_ Send_ _0K\n");
}
以上步骤完成后即可上电调试
网络调试助手做为客户端,ESP8266做为服务器。当客户端发送语句后,,服务器可以接收到,而且可以获取客户端的地址,并且会给客户端一个应答。当客户端发送K时,服务器可以接收K的同时LED点亮。说明以上程序可以是实现。
例程2(8266在逻辑上做为客户端)
- 在user_ init章节首先执行初始化
void ICACHE_ FLASH_ ATTR user_ init(void)
{
uart_ init (115200, 115200) ;//初始化串口波特率
os_ delay_ us (10000)
//OLED显示初始化
OLED Init() ;// OLED初始化
OLED ShowStr ing (0, 0, "ESP8266 = AP");//ESP8266模式
OLED_ ShowStr ing(0,2, "IP:"); //ESP8266 IP地址
OLED ShowStr ing(0, 4, "Remote = STA"); //远端主机模式
OLED_ ShowStr ing(0, 6, "IP"); //远端主机IP地址
LED Init JX(): // LED初始化
ESP8266_ AP_ Init_ JX() ; //初始化ESP8266_ AP模式
0S_ Timer. 1_ Init_ J030000,0); // 30秒定时(一次)(为给串口助手创建UDP通信,预留通信时间)
}
- 在定时回调函数当中
// 定时的回调函数(查询ESP8266的IP地址, 并初始化网络连接)
{
struct ip_ info ST_ ESP8266_ IP; // IP信息结构体
u8 ESP8266_ IP[4]; // 点分十进制形式保存IP
wifi_ get_ ip_ info(SOFTAP_ IF, &ST_ _ESP8266_ IP); //查询AP模式下ESP8266的IP地址
if(ST_ ESP8266_ IP. ip. addr != 0)// ESP8266成功获取到IP地址
{
ESP8266_ IP[0] = ST_ ESP8266_ IP. ip. addr //点分十进制IP的第一-个数<=> addr低八位
ESP8266_ IP[1] = ST_ ESP8266_ IP. ip. addr>>8;//点分十进制IP的第二个数<==> addr次低八位
ESP8266_ IP[2] = ST_ ESP8266_ IP. ip. addr>>16; //点分十进制P的第三个数<==> addr次高八位
ESP8266_ IP[3] = ST_ ESP8266_ IP. ip. addr>>24;//点分十进制IP的第四个数<==> addr高八位
//显示ESP8266的IP地址
os_ timer_ _disarm(&OS_ Timer_ 1); //关闭定时器
ESP8266_ NetCon_ Init_ JX() ;//初始化网络连接(UDP通信)
}
初始化UDP通信
//初始化网络连接(UDP通信)
void ICACHE FLASH_ ATTR ESP8266 NetCon Init )
{
//结构体赋值
ST_ NetCon. type = ESPCONN _UDP;//设置通信协议为UDP
ST_ NetCon. proto. udp = (esp_ udp *)os_ zalloc (sizeof (esp. _udp)) ;//开辟内存
//此处需要设置目标IP/端口(ESE8266作为CI ient,需要预先知道Server的IP/端口)
ST_ NetCon. proto. udp->local_ port = 8266 ;//设置本地端口
ST_ NetCon. proto. udp- >remote_ port_ = 8888;//设置目标端口
ST NetCon. proto. udp->remote_ ip[0] = 192; // 设置目标IP地址
ST NetCon. proto. udp- ->remote_ ip[1] = 168;
ST_ NetCon. proto. udp->remote_ ip[2]=4;
ST_ NetCon. proto. udp- >remote_ ip[3] = 2;
espconn_ regist_ sentcb (&ST_ NetCon, ESP8266_ WIFI_ Send_ Cb_ JX); // 注册网络数据发送成功的回调函数
espconn_ regist_ recvcb (&ST_ NetCon, ESP8266_ WIFI_ Recv_ Cb_ JX); // 注册网络数据接收成功的回调函数
espconn_ create (&ST_ NetCon); //初始化UDP通信
espconn send(&ST_ NetCon, "Hello, I am ESP8266", os_ strlen("Hello, I am ESP8266")); // 主动向服务器发起通信
}
如果成功接收到网络调试助手发送得数据
void ICACHE_ FLASH_ ATTR ESP8266_ WIFI_ Recv_ _Cb_ JX(void * arg,char * pdata,unsigned short len)
{
struct espconn * T_ arg = arg;//缓存网络连接结构体指针
remot_ info * P_ port_ info = NULL;//定义远端连接信息指针
//根据数据设置LED的亮/灭
if (pdata[0] == 'k' Il pdata[0] ==_ 'K') LED_ ON;//首字母为'k'/'K',灯亮
else if (pdata[0] == 'g'|l pdata[0] == 'G') LED_ 0FF ;//首字母为'g'/'G',灯灭
os_ pr intf ("\nESP8266_ Receive_ Data = %s\n" , pdata) ;//串口打印接收到的数据
//获取远端信息[UDP通信是无连接的,向远端主机回应时需获取对方的IP/端口信息]
if (espconn_ get_ connection_ info(T_ arg, &P_ port_ info, 0)==ESPCONN_ _0K) // 获取远端信息
{
T_ arg->proto. udp->remote_ port. = P. port_ info->remote_ port; // 获取对方端口号
T_ arg->proto. udp->remote_ ip[0] = P_ port_ info- >remote_ip[0];//获取对方IP地址
T_ arg- >proto. udp- >remote_ ip[1] = P_ port_ info->remote_ ip[1];
T_ arg- >proto. udp->remote_ ip[2] = P_ port_ info- >remote_ ip[2];
T_ arg- >proto. udp- >remote_ ip[3] = P port_ info- >remote_ ip[3];
}
OLED_ ShowIP(24, 6, T. _arg- >proto. udp->remote_ ip); // 显示远端主机IP地址
espconn_ send(T_ arg. "ESP8266 _WIFI_ _Recv_ _0K", os_ str len("ESP8266_ WIFI. _Recv. _0K")); // 向对方发送应答
}
- 当8266做为客户端的时候,我们需要预先赋值服务器的IP地址和端口号才能主动的向服务器发起通信。
现象
由串口可得,ESP8266的模式为AP模式,并且IP地址为192.169.4.1.接下来我们将我们的电脑连接到ESP8266创建的WIFI局域网。
由此可以看到电脑的IP地址和ESP8266的IP地址
打开网络调试助手,并且新建UDP,这个时候要保持电脑与ESP8266的连接不能断,然后将本地IP设置成电脑的IP地址。将下面的地址设置成ESP8266的IP地址。
点击发送之后,就可以看到ESP8266会发送应答到网络调试助手。并且ESP266也可以获取到电脑的IP地址。
发送K可以打开ESP8266的LED灯
发送G可以关闭LED灯
并且在串口这些也可以得到打印