物联网应用是Hi3863及其系统中最主要的功能。

我分步来实现一个 MQTT 设备通信的应用。

首先在我的代码目录下 \application\samples\hi3863\ 下建一个 “mqtt_test”子文件夹,我将我要写的代码放在这个子文件夹下。

文件目录是这样的:

先写通单独功能,最后综合在一起,组成一个完整应用。

先设置编译配置

修改 \application\samples\hi3863\Kconfig 

添加 编译菜单 MQTT_TEST 项

config MQTT_TEST
    bool
    prompt "Enable the mqtt test app."
    default n
    help
        This option means enable the mqtt test app.

if MQTT_TEST
    osource "application/samples/hi3863/mqtt_test/Kconfig"
endif

修改 \application\samples\hi3863\CMakeLists.txt

添加 编译 MQTT_TEST 目录

if(DEFINED CONFIG_MQTT_TEST)
    add_subdirectory_if_exist(mqtt_test)
endif()

在 \application\samples\hi3863\mqtt_test\ 目录下 添加 CMakeLists.txt , Kconfig 文件

Kconfig 修改为

# wifi sta 站点模式 t1 
config WIFI_STA_T1
    bool
    prompt "Enable the mqtt app wifi sta t1 "
    default n
    help
        This option means enable the mqtt app wifi sta t1.

# mqtt client 客户端实现 t2
config MQTT_CLIENT_T2
    bool
    prompt "Enable the mqtt app mqtt client t2"
    default n
    help
        This option means enable the mqtt t2.

# cjson data 格式数据 t3
config CJSON_DATA_T3
    bool
    prompt "Enable the mqtt app cjson data t3."
    default n
    help
        This option means enable the mqtt app cjson data t3.

# crypt cjson 数据加密 t4
config CRYPT_CJSON_T4
    bool
    prompt "Enable the mqtt app crypt cjson t4."
    default n
    help
        This option means enable the mqtt app crypt cjson t4.

# all in 全部 t5
config ALL_IN_T5
    bool
    prompt "Enable the mqtt app all in t5."
    default n
    help
        This option means enable the mqtt app all in t5.

CMakeLists.txt  修改为

if(DEFINED CONFIG_WIFI_STA_T1)
    add_subdirectory_if_exist(wifi_sta_t1)
endif()

if(DEFINED CONFIG_MQTT_CLIENT_T2)
    add_subdirectory_if_exist(mqtt_client_t2)
endif()

if(DEFINED CONFIG_CJSON_DATA_T3)
    add_subdirectory_if_exist(cjson_data_t3)
endif()

if(DEFINED CONFIG_CRYPT_CJSON_T4)
    add_subdirectory_if_exist(crypt_cjson_t4)
endif()

if(DEFINED CONFIG_ALL_IN_T5)
    add_subdirectory_if_exist(all_in_t5)
endif()

set(SOURCES "${SOURCES}" PARENT_SCOPE)

首先实现连WiFi的功能。

在源码目录 \application\samples\wifi\sta_sample 下有官方的例子,根据对这个例子的学习理解,我根据自己的需要,整理简化了一下。

在 \application\samples\hi3863\mqtt_test\wifi_sta_t1 目录下建这几个文件

然后 先修 CMakeLists.txt 

set(SOURCES_LIST
    ${CMAKE_CURRENT_SOURCE_DIR}/entry.c
    ${CMAKE_CURRENT_SOURCE_DIR}/wifi_sta.c
)

set(PUBLIC_HEADER_LIST
    ${CMAKE_CURRENT_SOURCE_DIR}
)

set(SOURCES "${SOURCES_LIST}" PARENT_SCOPE)
set(PUBLIC_HEADER "${PUBLIC_HEADER_LIST}" PARENT_SCOPE)

添加2个要编译的文件

wifi_sta.c 代码


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "common_def.h"
#include "soc_osal.h"
#include "app_init.h"
#include "osal_addr.h"
#include "cmsis_os2.h"

#include "lwip/netifapi.h"
#include "wifi_hotspot.h"
#include "wifi_hotspot_config.h"

#include "wifi_sta.h"

static uint8_t conn_stat = 0;       // 连接 状态
static uint8_t scan_stat = 0;       // 扫描 状态

struct netif *net_if = NULL;        // 网络接口信息

// 连接状态改变 回调
static void WiFi_Conn_State_Changed_Callback(int32_t state, const wifi_linked_info_stru *info, int32_t reason_code)
{
    (void)info;
    (void)reason_code;

    if(state != 0)
    {
        conn_stat = 1;
    }

    return;
}

// 扫描状态改变 回调
static void WiFi_Scan_State_Changed_Callback(int32_t state, int32_t size)
{
    (void)state;
    (void)size;

    scan_stat = 1;

    return;
}

// WiFi 事件 回调
wifi_event_stru WiFi_Event_Callback = {

    .wifi_event_connection_changed = WiFi_Conn_State_Changed_Callback,              // 连接状态改变
    .wifi_event_scan_state_changed = WiFi_Scan_State_Changed_Callback,              // 扫描状态改变

};

// WiFi STA 模式 连接 AP :输入 AP 名 , AP 密码 , 空 IP 地址
uint8_t WiFi_STA_Conn_AP(char *ap_name, char *ap_pass, char *ip_str)
{
    // 注册事件回调
    if(wifi_register_event_cb(&WiFi_Event_Callback) != ERRCODE_SUCC)
    {
        return 1;
    }

    // 获取 WiFi 设备初始化状态
    while(wifi_is_wifi_inited() != 1)
    {
        (void)osDelay(20);
    }

    // 开启 STA
    if(wifi_sta_enable() != ERRCODE_SUCC)
    {
        return 2;
    }

    // 进行全信道基础扫描
    if(wifi_sta_scan() != ERRCODE_SUCC)
    {
        return 3;
    }

    // 等待 扫描状态改变
    while(scan_stat != 1)
    {
        (void)osDelay(20);
    }

    // 最大扫描数
    uint32_t ap_num = 16;

    // 扫描信息大小
    uint32_t scan_info_size = sizeof(wifi_scan_info_stru) * ap_num;

    // 分配存储空间
    wifi_scan_info_stru *result = osal_kmalloc(scan_info_size, OSAL_GFP_ATOMIC);

    // 分配 失败
    if(result == NULL)
    {
        return 4;
    }

    // 空间清零
    memset_s(result, scan_info_size, 0, scan_info_size);

    // 获取sta扫描结果
    if(wifi_sta_get_scan_info(result, &ap_num) != ERRCODE_SUCC)
    {
        osal_kfree(result);
        return 5;
    }

    uint8_t ap_find = 0;    // ap 查找 结果 
    uint8_t idx;            // 序号

    // 检索 热点名
    for(idx = 0; idx < ap_num; idx++)
    {
        if(strlen(ap_name) == strlen(result[idx].ssid))
        {
            if(memcmp(ap_name, result[idx].ssid, strlen(ap_name)) == 0)
            {
                ap_find = 1;
                break;
            }
        }
    }

    // 未检索到 热点
    if(ap_find == 0)
    {
        osal_kfree(result);
        return 6;
    }

    // 连接到 WiFi AP

    // 连接 AP 的配置信息
    wifi_sta_config_stru sta_config = {0};

    memcpy_s(sta_config.ssid, WIFI_MAX_SSID_LEN, ap_name, strlen(ap_name));
    memcpy_s(sta_config.bssid, WIFI_MAC_LEN, result[idx].bssid, WIFI_MAC_LEN);
    memcpy_s(sta_config.pre_shared_key, WIFI_MAX_KEY_LEN, ap_pass, strlen(ap_pass));
    sta_config.security_type = result[idx].security_type;
    sta_config.ip_type = DHCP;

    osal_kfree(result);

    // 连接到 WiFi AP 热点
    if(wifi_sta_connect(&sta_config) != ERRCODE_SUCC)
    {
        return 7;
    }

    // 等待 连接状态改变
    while(conn_stat != 1)
    {
        (void)osDelay(20);
    }

    // dhcp 分配 IP

    // 网络 接口 名
    char if_name[WIFI_IFNAME_MAX_SIZE + 1] = "wlan0";

    // 获取 网络接口信息
    net_if = netifapi_netif_find(if_name);

    // 网络接口信息 为空
    if(net_if == NULL)
    {
        return 8;
    }

    // 开启 DHCP
    if(netifapi_dhcp_start(net_if) != ERR_OK)
    {
        return 9;
    }

    // 等待协商完成
    while(netifapi_dhcp_is_bound(net_if) != ERR_OK)
    {
        (void)osDelay(20);
    }

    // 保存 IP 地址
    if(net_if->ip_addr.u_addr.ip4.addr != 0)
    {
        sprintf(ip_str, "%u.%u.%u.%u",  (net_if->ip_addr.u_addr.ip4.addr & 0x000000ff),
                                        (net_if->ip_addr.u_addr.ip4.addr & 0x0000ff00) >> 8,
                                        (net_if->ip_addr.u_addr.ip4.addr & 0x00ff0000) >> 16,
                                        (net_if->ip_addr.u_addr.ip4.addr & 0xff000000) >> 24);
    }

    return 0;
}

// wifi sta 关闭
void WiFi_STA_Close(void)
{
    // 停止 DHCP
    netifapi_dhcp_stop(net_if);

    // 清空
    net_if = NULL;

    // 断开连接
    wifi_sta_disconnect();

    // 关闭 wifi sta 
    wifi_sta_disable();
}


// 打印 错误信息
void Print_Error(uint8_t error)
{
    switch (error)
    {
        case 1:
            // 注册 事件 回调 失败
            osal_printk(" [wifi_register_event_cb] FAILURE! \n");            
            break;
        case 2:
            // 开启 STA 模式 失败
            osal_printk(" [wifi_sta_enable] FAILURE! \n");            
            break;
        case 3:
            // 进行全信道基础扫描 失败
            osal_printk(" [wifi_sta_scan] FAILURE! \n");            
            break;
        case 4:
            // 分配存储空间 失败
            osal_printk(" [osal_kmalloc] FAILURE! \n");            
            break;
        case 5:
            // 获取 sta 扫描结果 失败
            osal_printk(" [wifi_sta_get_scan_info] FAILURE! \n");            
            break;
        case 6:
            // 未检索到 WiFi ap 失败
            osal_printk(" [ap_find == 0] FAILURE! \n");            
            break;
        case 7:
            // 连接 WiFi AP 失败
            osal_printk(" [wifi_sta_connect] FAILURE! \n");            
            break;
        case 8:
            // 获取 网口 信息 失败
            osal_printk(" [netifapi_netif_find] FAILURE! \n");            
            break;
        case 9:
            // 开启 DHCP 失败
            osal_printk(" [netifapi_dhcp_start] FAILURE! \n");            
            break;        
        default:
            break;
    }
}

wifi_sta.h 


#ifndef __WIFI_STA_H__
#define __WIFI_STA_H__

// WiFi STA 模式 连接 AP :输入 AP 名 , AP 密码 , 空 IP 地址
uint8_t WiFi_STA_Conn_AP(char *ap_name, char *ap_pass, char *ip_str);

// WiFi STA 关闭
void WiFi_STA_Close(void);

// 打印 错误信息
void Print_Error(uint8_t error);

#endif

entry.c 

#include "common_def.h"
#include "soc_osal.h"
#include "app_init.h"

#include "wifi_sta.h"

#define TASK_PRIO   6               // 任务 优先级 OSAL_TASK_PRIORITY_MIDDLE
#define TASK_SIZE   0x2000          // 任务 大小

#define AP_NAME     "WiFi名"        // wifi ap 名
#define AP_PASS     "WiFi密码"      // wifi ap 连接密码

static char ip_str[16] = {0};       // IP 地址 

// 任务
static void *wifi_sta_task(const char *arg)
{
    unused(arg);

    // 开始
    osal_printk(" [wifi sta t1] start \n");

    uint8_t ret;

    // 连接 热点
    ret = WiFi_STA_Conn_AP(AP_NAME, AP_PASS, ip_str);

    if(ret == 0)
    {
        osal_printk(" [WiFi_STA_Conn_AP] SUCCESS. \n");
        osal_printk(" ip addr : %s \n", ip_str);
    }
    else
    {
        Print_Error(ret);
    }

    uint8_t num = 0;

    while (num < 5)
    {
        osal_msleep(500);
        num++;
        osal_printk(" connect... %d ms \n", num * 500);
    }

    osal_printk(" [WiFi_STA_Close] \n");

    // 关闭 sta
    WiFi_STA_Close();

    // 结束 退出
    osal_printk(" [wifi sta t1] end \n");

    return NULL;
}

// 线程
static void wifi_sta_entry(void)
{
    osal_task *task_handle = NULL;

    // 锁定任务
    osal_kthread_lock();
    
    // 创建线程
    task_handle = osal_kthread_create((osal_kthread_handler)wifi_sta_task, 0, "APPTask", TASK_SIZE);

    // 创建成功
    if (task_handle != NULL)
    {
        // 优先级
        osal_kthread_set_priority(task_handle, TASK_PRIO);

        // 释放
        osal_kfree(task_handle);
    }

    // 解锁任务
    osal_kthread_unlock();
}

// 加载
app_run(wifi_sta_entry);

然后 打开 系统配置

点 “save", 关闭

点编译。

编译成功后,烧录,运行。上一篇幅都有讲。

显示 连接成功,间隔一段时间,关闭连接,退出程序。

具体功能过程看源码库里的文档吧,我再重复也没有文档说的详细。代码都做了注释。

相关代码我写完在gitee.com上开个仓,有些都是新手入门,没有vip也没有百度网盘,我的代码都是基础的,我也是给自己做个记录,不值得你们消费,以后放gitee上下吧。

陆续再更。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐