前一章已经搭建了ESP8266的编译环境,接下来就是编写控制代码啦~
写在编写程序的前面
1、ESP8266作为一款物联网模块,必定是要联网的,所以,首先把微软的防火墙关掉!
2、下载程序的时候注意,如果提示“错误”,那么请查看,下载的波特率是不是过高了!
3、在编译前,一定要先保存,再clean project,最后再build project !
4、编写执行周期很长(>500ms)的用户程序时,记得经常喂狗!
如果注意以上几点的话,相信,码代码的过程是会很顺利滴!好了,切入正题。
导入工程后,首先进入application文件夹,双击user后打开user_main.c,从上到下,,并没有熟悉的while大循环,没错,这是一种“内核回调”的机制,即一个方法的指针传递给事件源,当某一事件发生时用来调用这个方法。
因为我用的板子是不带有外围电路的,所以调试的时候都需要串口打印一些东西来辅助我调试,晶振26MHz,芯片上电初始化会自动打印到串口一些信息,注意,此时的波特率是74880;如果我们用的串口是115200的话,在调试信息出来之前会有一段乱码,这是正常的!
一切准备妥当之后,我们就可以写程序了,记住,用户入口在这里:
void ICACHE_FLASH_ATTR
user_init(void)
{
uart_init(115200,115200);//初始化串口0和串口1的波特率
os_delay_us(1000);//等待稳定
os_printf("\r\n-----------------------------\r\n");
os_printf("SDK version:%s\r\n",system_get_sdk_version());//打印SDK版本
os_printf("I am a coder\r\n");
uart0_sendStr("\r\nHello world\r\n");
os_printf("\r\n-----------------------------\r\n");
ESP8266_STA_Init();
OS_Timer_1_Init(1000,1);//1s重复定时
//输入输出配置函数
/*PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U,FUNC_GPIO4);//GPIO4设为IO口
GPIO_OUTPUT_SET(GPIO_ID_PIN(4),1);//IO4 = 1
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U,FUNC_GPIO0);
GPIO_DIS_OUTPUT(GPIO_ID_PIN(0));//失能输出
PIN_PULLUP_DIS(PERIPHS_IO_MUX_GPIO0_U);//失能内部上拉
PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO0_U);//使能内部上拉
if(GPIO_INPUT_GET(GPIO_ID_PIN(0)) == 0)
{
;
}*/
//GPIO中断设置
/*
ETS_GPIO_INTR_DISABLE();//关闭GPIO中断功能
WTS_GPIO_INTR_ATTACH((ets_isr_t)GPIO_INTERRUPT,NULL);//注册中断回调函数
gpio_pin_intr_state_set(GPIO_ID_PIN(0),GPIO_PIN_INTR_NEGEDGE);//GPIO下降沿中断
ETS_GPIO_INTR_ENABLE();//打开GPIO中断功能
*/
/*while(1)//测试用
{
system_soft_wdt_feed();//喂狗
os_printf("Please think\r\n");
delay_ms(1000);
}*/
}
我们只调用库函数就可以啦,记住,在写回调函数之前,要注册回调函数(下文再叙)!
上文中的毫秒延时函数,是要自己编写的,不过要注意,这里的延时,并不是非常精准:
void ICACHE_FLASH_ATTR delay_ms(u32 C_time)
{
for(;C_time >0;C_time--)
{
os_delay_us(1000);
}
}
因为这个例程是要将esp8266作为是sta连接路由器作为客户端,所以ESP8266_STA_Init()这个函数就是功能初始化函数了(ctrl键+鼠标左键能直接跳转到函数定义的位置哦~):
void ICACHE_FLASH_ATTR ESP8266_STA_Init()
{
struct station_config STA_Config;//STA参数结构体
struct ip_info ST_ESP8266_IP; //STA信息结构体
wifi_set_opmode(0x01);//设置为station模式并保存到flash
/*
wifi_station_dhcp_stop();
IP4_ADDR(&ST_ESP8266_IP.ip,192.168.1.2);
IP4_ADDR(&ST_ESP8266_IP.netmask,255.255.255.0);
IP4_ADDR(&ST_ESP8266_IP.gw,192.168.1.1);
wifi_set_ip_info(STATION_IF,&ST_ESP8266_IP);
*/
os_memset(&STA_Config,0,sizeof(struct station_config));//ap参数结构体初始化为0
os_strcpy(STA_Config.ssid,ESP8266_STA_SSID);
os_strcpy(STA_Config.password,ESP8266_STA_PASS);
wifi_station_set_config(&STA_Config);
}
因为这里设置了dhcp,所以就不用指定IP地址了,ESP8266_STA_PASS和ESP8266_STA_SSID都是需要用字符串宏定义的!两行代码,这里就不写啦。wifi_station_set_config()是初始化以上参数,在1s的重复定时函数里:
void ICACHE_FLASH_ATTR OS_Timer_1_Init(u32 time_ms,u8 time_repetitive)
{
os_timer_disarm(&OS_Timer_1);//关闭软件定时器
os_timer_setfn(&OS_Timer_1,(os_timer_func_t *)OS_Timer_1_cb,NULL);//设置回调函数
os_timer_arm(&OS_Timer_1,time_ms,time_repetitive);//设置定时器参数并使能
}
打开定时器回调函数,即在定时时间到达后要执行的函数:
void ICACHE_FLASH_ATTR OS_Timer_1_cb(void)//回调函数
{
u8 S_WIFI_STA_Connect;
struct ip_info ST_ESP8266_IP;//IP信息结构体
u8 ESP8266_IP[4];
S_WIFI_STA_Connect = wifi_station_get_connect_status();
switch(S_WIFI_STA_Connect)
{
case 0: os_printf("\r\nStation_Idle\r\n"); break;
case 1: os_printf("\r\nStation_Connecting\r\n"); break;
case 2: os_printf("\r\nStation_Wrong_Password\r\n"); break;
case 3: os_printf("\r\nStation_No_Ap_Found\r\n"); break;
case 4: os_printf("\r\nStation_Connect_Fail\r\n"); break;
case 5: os_printf("\r\nStation_Got_IP\r\n"); break;
}
if(S_WIFI_STA_Connect == STATION_GOT_IP)
{
wifi_get_ip_info(STATION_IF,&ST_ESP8266_IP);
ESP8266_IP[0] = ST_ESP8266_IP.ip.addr;//点分表示
ESP8266_IP[1] = ST_ESP8266_IP.ip.addr>>8;
ESP8266_IP[2] = ST_ESP8266_IP.ip.addr>>16;
ESP8266_IP[3] = ST_ESP8266_IP.ip.addr>>24;
os_printf("ESP8266_IP = %d.%d.%d.%d.\r\n",ESP8266_IP[0],ESP8266_IP[1],ESP8266_IP[2],ESP8266_IP[3]);
os_timer_disarm(&OS_Timer_1);
ESP8266_NetCon_Init();
}
}
以上,获取模块的地址并打印到串口,然后,进入这个函数:
void ICACHE_FLASH_ATTR ESP8266_NetCon_Init()
{
ST_NetCon.type = ESPCONN_TCP;//设置为TCP协议
ST_NetCon.proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));//开辟内存
ST_NetCon.proto.tcp ->local_port = 8266;//设置socket
ST_NetCon.proto.tcp ->remote_port = 8888;
ST_NetCon.proto.tcp ->remote_ip[0] = 192;
ST_NetCon.proto.tcp ->remote_ip[1] = 168;
ST_NetCon.proto.tcp ->remote_ip[2] = 1;
ST_NetCon.proto.tcp ->remote_ip[3] = 10;
espconn_regist_connectcb(&ST_NetCon,ESP8266_TCP_Connect_Cb);//注册回调函数
espconn_regist_reconcb(&ST_NetCon,ESP8266_TCP_Break_Cb);
espconn_connect(&ST_NetCon);//连接TCP-Server
}
以上就是连接服务器啦,设置协议,本地通信端口和服务的的IP+Port,设置完成后就进入连接请求函数,这里,就直接调用啦,在这个函数中还注册了异常断开和正常断开的回调函数,这样,再编写指定的函数,就可以建立断线重连机制了!
这是文件头:
#include "ets_sys.h"
#include "c_types.h"//变量类型
#include "user_config.h"//用户配置
#include "osapi.h"//os_xxx、软件定时器
#include "user_interface.h"//系统接口、system_param_xxx接口、WIFI等
#include "eagle_soc.h"//GPIO函数、宏定义
#include "driver/uart.h"//串口初始化文件
#include "ets_sys.h"//回调函数
#include "os_type.h"//os_xxx
#include "ip_addr.h"
#include "espconn.h"
#include "mem.h"
struct espconn ST_NetCon;
os_timer_t OS_Timer_1;//定义软件定时器
至此,保存,清理工程,编译工程,就可以上手啦!