ESP8266 SDDC 设备开发
本章将介绍如何在 ESP8266 上使用 FreeRTOS 和 libsddc 开发一个能接入到 EdgerOS 的 Wi-Fi 物联网设备。
硬件准备
ESP8266 开发板
ESP8266 是乐鑫科技推出的一款面向物联网应用的高性价比、高度集成的 Wi-Fi MCU。
ESP8266 内置超低功耗 Tensilica L106 32 位 RISC 处理器,CPU 时钟速度最高可达 160 MHz,支持实时操作系统(RTOS)和 Wi-Fi 协议栈,可将高达 80% 的处理能力留给应用编程和开发。
本实验使用的是一块 ESP8266 开发板,它带有两个按键,一个 RESET 复位按键和一个 FLASH 编程按键,如下图所示:
软件准备
开发 ESP8266 需要使用安信可科技 AI-Thinker 开发 IDE。
下载 IDE 软件包并安装
网盘链接:https://pan.baidu.com/s/1bk_mc-X9Aol9MgiU0gZA0A 提取码:shm3
下载 AiThinkerIDE_V1.5.2.exe 即可,双击 AiThinkerIDE_V1.5.2.exe,完成安装。
调整 IDE PATH
将 AiThinkerIDE 相关的 4 个环境变量上移到最前面:
下载 ESP8266 SDK
在一个路径不带空格的目录下,执行以下命令下载:
git clone --recursive https://github.com/ms-rtos/AiThinkerProjectForESP.git
如果 github 下载速度慢,可以试试 gitee:
git clone --recursive https://gitee.com/ms-rtos/AiThinkerProjectForESP.git
该 ESP8266 SDK 为翼辉信息工程师在安信可科技开源项目 AiThinkerProjectForESP 的基础上,二次开发而来,特此鸣谢安信可科技。
导入 ESP8266 SDK
双击桌面的 AiThinkerIDE_V1.5.2 图标,打开 AiThinkerIDE,点击 File > Import 菜单,将弹出 Import 向导:
选择 C/C++ 下的 Existing code as Makefile Project 类型,然后点击 Next 按钮:
点击 Browse 按钮选择刚刚下载的 ESP8266 SDK 的路径,Toolchain for indexer Settings 选择 Cross GCC,最后点击 Finish 按钮完成导入:
配置 SDK 工程
配置 IDF_PATH 变量
鼠标选中 AiThinkerProjectForESP 工程,点击右键,在右键菜单中选择 Properties,选择 C/C++ Build->Environment,点击 Add 按钮添加一个 IDF_PATH
变量,值为 ESP8266 SDK 的路径,注意需要将路径修改为 unix 风格,如 /D/AiThinkerWorkspace/AiThinkerProjectForESP
,最后点击 OK 按钮:
配置构建路径
鼠标选中 AiThinkerProjectForESP 工程,点击右键,在右键菜单中选择 Properties,选择 C/C++ Build,修改 Build directory 为需要编译的例程路径,如${workspace_loc:/AiThinkerProjectForESP}/examples/protocols/sddc
,最后点击 OK 按钮:
配置 menuconfig 目标
鼠标选中 AiThinkerProjectForESP 工程,点击右键,在右键菜单中选择 Make Targets > Create,在弹出的对话框中取消勾选 Same as the target name 与 User builder settings 这 2 个选项,将 Target name 修改为 menuconfig
,并且在 Build command 中输入 mintty.exe -e make menuconfig
,最后点击 OK 按钮:
鼠标选中 AiThinkerProjectForESP 工程,点击右键,在右键菜单中选择 Make Targets > Build,在弹出的对话框中选中 menuconfig 项,然后点击 Build 按钮:
修改连接 Wi-Fi AP 的配置,将 Wi-Fi SSID 和 Password 修改为智能边缘计算机 Spirit 1 的 Wi-Fi AP SSID 和密码,最后选中 Exit 回车后退出配置,等待配置完成。
连接 Wi-Fi 的方式还支持 SmartConfig,具体连接方式可见后文。
编译 SDK 和例程
鼠标选中 AiThinkerProjectForESP 工程,点击右键,在右键菜单中选择 Build project,等待编译完成。
烧写镜像
配置 FLASH 编程目标
将 ESP8266 开发板接入电脑,打开设备管理,查看操作系统为 ESP8266 开发板分配的 COM 号。
鼠标选中 AiThinkerProjectForESP 工程,点击右键,在右键菜单中选择 Make Targets > Create ,在弹出的对话框中取消勾选 Same as the target name 与 User builder settings 这 2 个选项,将 Target name 修改为 flash
,并且在 Build command 中输入 make flash ESPPORT=COM11
,最后点击 OK 按钮,注意 COM 号为 ESP8266 开发板插入电脑后分配出来的 COM 号:
烧写镜像
在右键菜单中选择 Make Targets > Build,在弹出的对话框中选中 flash 项,然后点击 Build 按钮:
验证功能
ESP8266 开发板连接 EdgerOS
使用 PuTTY 作为串口调试工具,新建一个 Serial 类型的 Session,按如下图所示配置串口,注意 Speed 为 74880,点击 Save 按钮保存 Session 方便以后直接打开,最后点击 Open 按钮:
按下 ESP8266 开发板的 RESET 按键,将看到 SDDC 程序运行起来:
如果在前面 make menuconfig
时配置了正确的 Spirit 1 的 Wi-Fi AP SSID 和密码,ESP8266 开发板将能成功连接 Spirit 1 的 Wi-Fi 网络,接下来请参考《SDDC introduction》章节的“添加设备流程”去添加 ESP8266 开发板。
注意 ESP8266 开发板的设备密码为 1234567890
ESP8266 开发板 SmartConfig
如果在前面 make menuconfig
时没有配置了正确的 Spirit 1 的 Wi-Fi AP SSID 和密码或在后续使用过程中修改了 Spirit 1 的 Wi-Fi AP SSID 或密码,则可以通过 SmartConfig 方式令 ESP8266 开发板重新加入 Spirit 1 的 Wi-Fi 网络,操作方式请参考《SDDC introduction》章节的“SmartConfig 流程”。
注意 长按 ESP8266 开发板的 FLASH 按键 3 秒进入 SmartConfig 模式。
ESP8266 SDDC 代码解析
SDDC demo 代码位于 examples/protocols/sddc/main/sddc_esp8266_example.c
,在 void app_main()
函数中调用 xTaskCreate(sddc_example_task, "sddc_example_task", 4096, NULL, 5, NULL);
来创建 SDDC 的工作任务 ,具体 SDDC 协议细节可参考《SDDC introduction》章节。
// 应用入口函数
void app_main(void)
{
// 初始化 FLASH
ESP_ERROR_CHECK(nvs_flash_init());
// 初始化 NETIF
ESP_ERROR_CHECK(esp_netif_init());
// 创建缺省的事件循环
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
// 创建 SDDC task
xTaskCreate(esp_sddc_task, "sddc_task", ESP_SDDC_TASK_STACK_SIZE, NULL, ESP_SDDC_TASK_PRIO, NULL);
}
// SDDC 工作任务
static void esp_sddc_task(void *arg)
{
sddc_t *sddc;
char *data;
uint8_t mac[6];
char ip[sizeof("255.255.255.255")];
tcpip_adapter_ip_info_t ip_info = { 0 };
// 创建 SDDC 协议对象
sddc = sddc_create(SDDC_CFG_PORT);
// 设置事件响应函数
sddc_set_on_message(sddc, esp8266_on_message); // 设置接收消息请求时的回调函数
sddc_set_on_message_ack(sddc, esp8266_on_message_ack); // 设置接收消息确认时的回调函数
sddc_set_on_message_lost(sddc, esp8266_on_message_lost); // 设置丢失消息时的回调函数
sddc_set_on_invite(sddc, esp8266_on_invite); // 设置接受邀请请求时的回调函数
sddc_set_on_invite_end(sddc, esp8266_on_invite_end); // 设置发送邀请后的回调函数
sddc_set_on_update(sddc, esp8266_on_update); // 设置接收更新请求时的回调函数
sddc_set_on_edgeros_lost(sddc, esp8266_on_edgeros_lost); // 设置 EdgerOS 断连时的回调函数
// 设置设备密码
#if SDDC_CFG_SECURITY_EN > 0
sddc_set_token(sddc, "1234567890");
#endif
// 创建并设置 Report 报文数据
data = esp_report_data_create();
sddc_set_report_data(sddc, data, strlen(data));
// 创建并设置 Invite 报文数据
data = esp_invite_data_create();
sddc_set_invite_data(sddc, data, strlen(data));
// 获取网卡 mac 地址
esp_wifi_get_mac(ESP_IF_WIFI_STA, mac);
// 使用网卡 mac 地址设置设备唯一标识 UID
sddc_set_uid(sddc, mac);
// 获取并打印 IP 地址
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info);
inet_ntoa_r(ip_info.ip, ip, sizeof(ip));
sddc_printf("IP addr: %s\n", ip);
// 创建 Wi-Fi 事件组
wifi_event_group = xEventGroupCreate();
// 创建 FLASH 按键检测 task
xTaskCreate(esp_flash_key_task, "flash_key_task", ESP_KEY_TASK_STACK_SIZE, sddc, ESP_KEY_TASK_PRIO, NULL);
// 运行 SDDC 协议循环
while (1) {
sddc_printf("SDDC running...\n");
sddc_run(sddc);
sddc_printf("SDDC quit!\n");
}
// 销毁 SDDC 协议对象
sddc_destroy(sddc);
// 删除 SmartConfig 任务
vTaskDelete(NULL);
}
// FLASH 按键检测任务
static void esp_flash_key_task(void *arg)
{
sddc_t *sddc = arg;
gpio_config_t io_conf;
int i = 0;
(void)sddc;
// 配置 GPIO 禁能中断
io_conf.intr_type = GPIO_INTR_DISABLE;
// 配置 GPIO 为输入模式
io_conf.mode = GPIO_MODE_INPUT;
// 配置 GPIO 引脚
io_conf.pin_bit_mask = 1ULL << GPIO_INPUT_IO_SMARTCOFNIG;
// 禁能下拉
io_conf.pull_down_en = 0;
// 使能上拉
io_conf.pull_up_en = 1;
// 配置 GPIO
gpio_config(&io_conf);
while (1) {
vTaskDelay(1000 / portTICK_RATE_MS);
// 检测 FLASH 按键按下
if (!gpio_get_level(GPIO_INPUT_IO_SMARTCOFNIG)) {
i++;
// FLASH 按键按下超过三秒
if (i > 3) {
i = 0;
sddc_printf("Start SmartConfig....\n");
esp_wifi_disconnect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT);
// 注册 Wi-Fi 断开连接回调函数
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &on_wifi_disconnect, NULL));
// 注册 Wi-Fi 获取 IP 回调函数
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_got_ip, NULL));
// 设置 SmartConfig 类型
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH_AIRKISS) );
// 开始 SmartConfig
ESP_ERROR_CHECK( esp_smartconfig_start(sc_callback) );
while (1) {
// 等待连接上 Wi-Fi AP 和 ESPTOUCH 结束
EventBits_t uxBits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT,
true, false, portMAX_DELAY);
if (uxBits & CONNECTED_BIT) {
// 连接上 Wi-Fi AP
ESP_LOGI(TAG, "Wi-Fi Connected to AP");
}
if (uxBits & ESPTOUCH_DONE_BIT) {
// ESPTOUCH 结束
ESP_LOGI(TAG, "SmartConfig over");
// 停止 SmartConfig
esp_smartconfig_stop();
break;
}
}
// 取消注册 Wi-Fi 断开连接回调函数
ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &on_wifi_disconnect));
// 取消注册 Wi-Fi 获取 IP 回调函数
ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_got_ip));
}
} else {
i = 0;
}
}
}