> 文档中心 > 《HarmonyOS开发 – OpenHarmony开发笔记(基于小型系统)》第5章 WiFi联网(STA模式)

《HarmonyOS开发 – OpenHarmony开发笔记(基于小型系统)》第5章 WiFi联网(STA模式)

开发环境:
开发系统:Ubuntu 20.04
开发板:Pegasus物联网开发板
MCU:Hi3861
OpenHarmony版本:3.0.1-LTS

HI3861默认已经初始化了WiFi,因此这里讲解如何使用WiFi联网。

5.1使用AT联网

串口终端上执行相应的AT命令,即可使Hi3861 WLAN模组联网,依次执行如下AT命令,启动STA模式,连接指定路由器,并开启DHCP功能配置IP地址。

AT+STARTSTA # 启动STA模式AT+SCAN     # 扫描周边APAT+SCANRESULT      # 显示扫描结果AT+CONN="SSID",,2,"PASSWORD"     # 连接指定AP,其中SSID/PASSWORD为待连接的热点名称和密码AT+STASTAT  # 查看连接结果AT+DHCP=wlan0,1    # 通过DHCP向AP请求wlan0的IP地址

查看Hi3861 WLAN模组与网关联通是否正常,如下所示。

AT+IFCFG    # 查看模组接口IPAT+PING=X.X.X.X    # 检查模组与网关的联通性,其中X.X.X.X需替换为实际的网关地址

下面具体演示:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

有上图可知Hi3861 WLAN模组联网成功。

当然也可在同一个局域网中ping HI3861。

在这里插入图片描述

说明网络是连通的。

关于Wifi联网的AT命令有很多,所有的AT指令都是通过函数hi_at_sys_cmd_register() 函数注册的,其中调用了hi_at_register_cmd()函数注册AT。

重点介绍三个函数。

1.启动WiFi STA模式, AT+STARTSTA

hi_u32 cmd_sta_start_adv(hi_s32 argc, const hi_char *argv[]){    hi_s32  ret;    hi_wifi_bw bw = HI_WIFI_BW_LEGACY_20M;    if (argc != 3) { /* "+STARTSTA" command fix 3 parameters */ return HI_ERR_FAILURE;    }    ret = (hi_s32)sta_start_adv_param(argc, argv, &bw);    if (ret != HI_ERR_SUCCESS) { return HI_ERR_FAILURE;    }#ifndef CONFIG_FACTORY_TEST_MODE    hi_char ifname[WIFI_IFNAME_MAX_SIZE + 1] = {0};    hi_s32  len = sizeof(ifname);    ret = hi_wifi_sta_start(ifname, &len);    if (ret != HISI_OK) { return HI_ERR_FAILURE;    }#endif    ret = hi_wifi_set_bandwidth(DEFAULT_IFNAME_STA, strlen(DEFAULT_IFNAME_STA) + 1, bw);    if (ret != HI_ERR_SUCCESS) {#ifndef CONFIG_FACTORY_TEST_MODE hi_wifi_sta_stop();#endif return HI_ERR_FAILURE;    }    hi_at_printf("OK\r\n");    return HI_ERR_SUCCESS;}

该函数的核心就是hi_wifi_sta_start()函数。

2.连接WiFi ,AT+CONN

/****************************************************************************** Func description: station connect network* example: AT+CONN="hisilicon",,3,"123456789"*****************************************************************************/hi_u32 cmd_sta_connect(hi_s32 argc, const hi_char *argv[]){    hi_wifi_assoc_request assoc_req = {0};    if ((argc < 3) || (argc > 4)) {     /* argc 3/4 */ return HI_ERR_FAILURE;    }    /* get ssid */    if ((argv[0] != HI_NULL) && (cmd_sta_connect_get_ssid(argv, &assoc_req, HI_NULL, 0) != HI_ERR_SUCCESS)) { return HI_ERR_FAILURE;    }    /* get bssid */    if (argv[1] == HI_NULL) { memset_s(assoc_req.bssid, sizeof(assoc_req.bssid), 0, sizeof(assoc_req.bssid));    } else if (strlen(argv[1]) == HI_WIFI_TXT_ADDR_LEN) { if (cmd_strtoaddr(argv[1], assoc_req.bssid, HI_WIFI_MAC_LEN) != HISI_OK) {     return HI_ERR_FAILURE; }    } else { return HI_ERR_FAILURE;    }    /* get auth_type */    if ((integer_check(argv[2]) != HI_ERR_SUCCESS) || (atoi(argv[2]) < HI_WIFI_SECURITY_OPEN) ||    /* argc 2 */ (atoi(argv[2]) == HI_WIFI_SECURITY_WPA) || (atoi(argv[2]) == HI_WIFI_SECURITY_WPA2) || /* argc 2 */ (atoi(argv[2]) == HI_WIFI_SECURITY_WPAPSK) || (atoi(argv[2]) >= HI_WIFI_SECURITY_UNKNOWN) || /* argc 2 */ ((atoi(argv[2]) == HI_WIFI_SECURITY_OPEN) && (argc != 3)) || /* argc 2/3/4 */ ((atoi(argv[2]) != HI_WIFI_SECURITY_OPEN) && (argc != 4))) { /* argc 2/3/4 */ return HI_ERR_FAILURE;    }    assoc_req.auth = (hi_wifi_auth_mode)atoi(argv[2]); /* 2 */    assoc_req.pairwise = HI_WIFI_PARIWISE_UNKNOWN;    /* get key */    if (argc == 4) {    /* argc 4 */ const hi_char *buf = argv[3];   /* argc 3 */ if (buf == HI_NULL) {     return HI_ERR_FAILURE; } size_t len = strlen(argv[3]); /* 3:key */ if ((atoi(argv[2]) == HI_WIFI_SECURITY_WEP) && (len != 9) && (len != 17) && /* argc 2, len 9/17 */     (len != 12) && (len != 28))  { /* 12 28: password len */     return HI_ERR_FAILURE; } else if ((atoi(argv[2]) != HI_WIFI_SECURITY_WEP) && ((len > HI_WIFI_AP_KEY_LEN_MAX + 2) ||    /* argc 2 */     (len < HI_WIFI_AP_KEY_LEN_MIN + 2))) {  /* len plus 2 */     return HI_ERR_FAILURE; } if ((*buf != '\"') || (*(buf + strlen(argv[3]) - 1) != '\"') || /* argc 3 */     (memcpy_s(assoc_req.key, HI_WIFI_MAX_KEY_LEN + 1, buf + 1, strlen(argv[3]) - 2) != EOK)) { /* 3 2 */     return HI_ERR_FAILURE; }    }    if (hi_wifi_sta_connect(&assoc_req) != HISI_OK) { return HI_ERR_FAILURE;    }    hi_at_printf("OK\r\n");    return HI_ERR_SUCCESS;}

该函数主要用于解析AT+CONN指令,核心是hi_wifi_sta_connect()函数。

3.获取IP地址, AT+DHCP

hi_u32 at_setup_dhcp(hi_s32 argc, const hi_char **argv){    hi_s32 ret = 0;    if (at_param_null_check(argc, argv) == HI_ERR_FAILURE) { return HI_ERR_FAILURE;    }    if (argc != 2) { /* at+dhcp cmd length equl 2 */ return HI_ERR_FAILURE;    }#ifndef CONFIG_FACTORY_TEST_MODE    struct netif *netif_p = netifapi_netif_find(argv[0]);    if (netif_p == NULL) { return HI_ERR_FAILURE;    }    if (strcmp(argv[1], "1") == 0) { ret = netifapi_dhcp_start(netif_p);    } else if (strcmp(argv[1], "0") == 0) { ret = netifapi_dhcp_stop(netif_p);    } else if (strcmp(argv[1], "2") == 0) { ret = netifapi_netif_common(netif_p, dhcp_clients_info_show, NULL);    } else { return HI_ERR_FAILURE;    }#endif    if (ret == LOS_OK) { hi_at_printf("OK\r\n");    }    return ret;}

其中netifapi_netif_find()函数通过DHCP向AP请求wlan0的IP地址,然后就调用netifapi_dhcp_start()函数获取IP。

以上函数在device/hisilicon/hispark_pegasus/sdk_liteos/components/at/src目录下。

使用AT比较麻烦,接下来笔者将通过程序来联网。

5.2 Hi3861自动联网

编程自动联网,其本质和使用AT指令一样,最终都是调用了相同的API,只是通过加载应用的方式去实现了,联网流程和使用AP一样的,编写应用的方式参看上一章内容,本文将在wifi-iot目录下新建应用,这样可以简化步骤。

5.2.1新建目录

在./applications/sample/wifi-iot/app路径下新建一个目录,用于存放WiFi应用的源码文件。

在app下新增业务wifi_connect,其中wifi_app.c为应用代码,BUILD.gn为编译脚本,目录结构如下:

在这里插入图片描述

5.2.2编写应用代码

新建./applications/sample/wifi-iot/app/wifi_app下的wifi_app.c文件,在wifi_app.c中新建入口函数wifi_task,并实现业务逻辑。并在代码最下方,使用OpenHarmony启动模块接口SYS_RUN()启动业务。

从上一节内容得到,连接WiFi核心就三个:启动STA模式,连接WiFi,设置IP。

因此,最终的wifi_app.c的函数代码如下:

/**  ******************************************************************************  * @file  wifi_app.c  * @authorBruceOu  * @version      V1.0  * @date  2022-06-18  * @blog  https://blog.bruceou.cn/  * @Official Accounts   嵌入式实验楼  * @brief    ******************************************************************************  */#include #include #include "ohos_init.h"#include "cmsis_os2.h"#include #include "hi_wifi_api.h"#include "lwip/ip_addr.h"#include "lwip/netifapi.h"#define SSID      "media"#define PASSWORD  "12345678"static struct netif *g_lwip_netif = NULL;/**  * @brief  Set netif's ip, gateway and netmask  * @param  pst_lwip_netif  * @retval None  */void hi_sta_set_addr(struct netif *pst_lwip_netif){    ip4_addr_t st_gw;    ip4_addr_t st_ipaddr;    ip4_addr_t st_netmask;    if (pst_lwip_netif == NULL)    { printf("hisi_reset_addr::Null param of netdev\r\n"); return;    }    IP4_ADDR(&st_gw, 192, 168, 101, 1);    IP4_ADDR(&st_ipaddr, 192, 168, 101, 100);    IP4_ADDR(&st_netmask, 255, 255, 255, 0);    netifapi_netif_set_addr(pst_lwip_netif, &st_ipaddr, &st_netmask, &st_gw);}/**  * @brief  Wifi connect  * @param  None  * @retval None  */int hi_wifi_start_connect(void){    int ret;    errno_t rc;    hi_wifi_assoc_request assoc_req = {0};    // Copy SSID to assoc_req    rc = memcpy_s(assoc_req.ssid, HI_WIFI_MAX_SSID_LEN + 1, SSID, strlen(PASSWORD));    if (rc != EOK)    { printf("[Wifi Connnect] hi_wifi_sta_connect fail"); printf("%s %d \r\n", __FILE__, __LINE__); return -1;    }    //Set encryption method    assoc_req.auth = HI_WIFI_SECURITY_WPA2PSK;    // Wifi password    memcpy(assoc_req.key, PASSWORD, strlen(PASSWORD));    ret = hi_wifi_sta_connect(&assoc_req);    if (ret != HISI_OK)    {printf("[Wifi Connnect] hi_wifi_sta_connect fail"); printf("%s %d \r\n", __FILE__, __LINE__); return -1;    }return 0;}/**  * @brief  wifi task  * @param  None  * @retval None  */void wifi_task(void){    int ret;    char ifname[WIFI_IFNAME_MAX_SIZE + 1] = {0};    int len = sizeof(ifname);    unsigned int  num = WIFI_SCAN_AP_LIMIT;// Step 1: Start STA mode, AT+STARTSTA     ret = hi_wifi_sta_start(ifname, &len);    if (ret != HISI_OK)    { printf("[Wifi Connnect] hi_wifi_sta_start fail"); printf("%s %d \r\n", __FILE__, __LINE__); return;    }    // Step 2: Connect to the specified AP:, AT+CONN="SSID", ,2,"PASSWORD"    ret = hi_wifi_start_connect();    if (ret != 0)    { printf("[Wifi Connnect] hi_wifi_start_connect fail"); printf("%s %d \r\n", __FILE__, __LINE__); return ;    }    // Step 3: DHCP requests the IP address of wlan0 from the AP, AT+DHCP=wlan0,1      g_lwip_netif = netifapi_netif_find(ifname);    if(NULL == g_lwip_netif)     { printf("[Wifi Connnect] netifapi_netif_find fail"); printf("%s %d \r\n", __FILE__, __LINE__); return;    }    //DHCP automatically assigns IP    if(ret != netifapi_dhcp_start(g_lwip_netif))     { printf("[Wifi Connnect] netifapi_dhcp_start fail"); return;    }    printf("[Wifi Connnect] Connect to wifi successfully\n");}SYS_RUN(wifi_task);

5.2.3新建编译组织文件

新建./applications/sample/wifi-iot/app/wifi_connect/BUILD.gn文件,内容如下所示:

static_library(wifiapp") {    sources = [ "wifi_app.c"    ]    include_dirs = [ "//utils/native/lite/include"    ]}
  • static_library中指定业务模块的编译结果,为静态库文件libwifiapp.a,开发者根据实际情况完成填写。

  • sources中指定静态库.a所依赖的.c文件及其路径,若路径中包含"//“则表示绝对路径(此处为代码根路径),若不包含”//"则表示相对路径。

  • include_dirs中指定source所需要依赖的.h文件路径。

5.2.4新增组件

将wifiapp添加到组件中。即修改applications/sample/wifi-iot/app/BUILD.gn文件,修改后如下所示。
import(“//build/lite/config/component/lite_component.gni”)

lite_component("app") {    features = [ "wifi_connect:wifiapp"    ]}
  • wifi_connect是相对路径,指向applications/sample/wifi-iot/app/wifi_connect。
  • wifiapp是目标,指向applications/sample/wifi-iot/app/wifi_connect/BUILD.gn中的static_library(“wifiapp”)。

5.2.5编译下载测试

最后,编译下载固件,我们就可以自动连接Wifi了。

在这里插入图片描述

接下来ping下网络:

在这里插入图片描述

说明自动连接网络成功。

官网手册


欢迎访问我的网站

BruceOu的哔哩哔哩
BruceOu的主页
BruceOu的博客
BruceOu的CSDN博客
BruceOu的简书
BruceOu的知乎


欢迎订阅我的微信公众号

关注公众号[嵌入式实验楼]获取更多资讯

K歌软件