这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【E103-W12C-TB测评】3.使用MQTT指令实现传感器数据的上传

共1条 1/1 1 跳转至

【E103-W12C-TB测评】3.使用MQTT指令实现传感器数据的上传

高工
2025-05-10 11:05:45     打赏

上一篇通过AT调试工具实现MQTT推送开发板状态的功能。在程序中添加响应的代码,实现消息的自动推送。

1.1添加AT指令

由于AT指令没有统一的格式,对不同的模块,需要根据AT指令的格式编写对应的驱动。通过手动测试AT指令,可以实现MQTT发布信息,通过MQTT服务器转发,在手机的MQTT客户端订阅对应的信息,监控开发板的状态。

既然该开发板是基于瑞萨DA16200开发的,参考瑞萨官网上给出的AT示例程序。移植示例程序中的AT指令部分的代码。

官方IOTDemo.png

在示例程序的源码中,AT指令相关的代码在da16200_AT.cda16200_AT.h中。

官方DemoAT代码.png

由于亿佰特的模块中的AT接口定义和示例程序中对应的DA16200模块的AT接口定义有差别,移植过程中需要对指令部分进行修改。修改后的AT指令集如下:

 

/** AT Command sets */
/*LDRA_INSPECTED 27 D This structure must be accessible in user code. It cannot be static. */
da16200_at_cmd_set_t g_da16200_cmd_set[] =
{
    /** Intial AT command */
    [DA16200_AT_CMD_INDEX_ATZ] =
    {
        .p_cmd = (uint8_t *) "ATZ",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_10,
        .retry_delay = DA16200_DELAY_500MS
    },
    /** Echo on/off */
    [DA16200_AT_CMD_INDEX_ATE] =
    {
        .p_cmd = (uint8_t *) "ATE",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_32,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* All profiles in NVRAM are removed and set up in Soft-AP mode with the default configuration. */
    [DA16200_AT_CMD_INDEX_AT_CWDEFAP] =
    {
        .p_cmd = (uint8_t *) "AT+CWDEFAP",
        .p_success_resp[0] = (uint8_t *) "OK",
        .p_success_resp[1] = (uint8_t *) "+INIT:DONE,1",
        .max_resp_length = DA16200_STR_LEN_128,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* Set AP mode, here is station */
    [DA16200_AT_CMD_INDEX_AT_CWMODE] =
    {
        .p_cmd = (uint8_t *) "AT+CWMODE=0",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_32,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* Set Country Code */
    [DA16200_AT_CMD_INDEX_AT_CWCOUNTRY] =
    {
        .p_cmd = (uint8_t *) "AT+CWCOUNTRY=",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_32,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },

    /* System restart */
    [ DA16200_AT_CMD_INDEX_AT_RESTART] =
    {
        .p_cmd = (uint8_t *) "AT+RESTART",
        .p_success_resp[0] = (uint8_t *) "OK",
        .p_success_resp[1] = (uint8_t *) "+INIT:DONE,0",
        .max_resp_length = DA16200_STR_LEN_128,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_1000MS
    },
    /* Connect to an AP */
    [ DA16200_AT_CMD_INDEX_AT_CWJAPA] =
    {
        .p_cmd = (uint8_t *) ("AT+CWJAPA="),
        .p_success_resp[0] = (uint8_t *) "OK",
        .p_success_resp[1] = (uint8_t *) "+CWJAP:1",
        .max_resp_length = DA16200_STR_LEN_128,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_1000MS
    },
    /* Start the DHCP Client */
    [ DA16200_AT_CMD_INDEX_AT_CWDHCPC] =
    {
        .p_cmd = (uint8_t *) "AT+CWDHCPC=1",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* Start the DHCP Client */
    [ DA16200_AT_CMD_INDEX_AT_CWDHCPC_READ] =
    {
        .p_cmd = (uint8_t *) "AT+CWDHCPC=?",
        .p_success_resp[0] = (uint8_t *) "+CWDHCPC:1",
        .p_success_resp[1] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* Set the IP address and the port number of the MQTT Broker */
    [ DA16200_AT_CMD_INDEX_AT_MQTTBR] =
    {
        .p_cmd = (uint8_t *) "AT+MQTTBR=",
//        .p_cmd = (uint8_t *) "AT+NWMQBR="+MQTT_SERVER_IP+","+MQTT_PORT+"\r\n",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* Set the MQTT QoS level */
    [ DA16200_AT_CMD_INDEX_AT_MQTTQOS] =
    {
        .p_cmd = (uint8_t *) "AT+MQTTQOS=0",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* MQTT login information */
    [ DA16200_AT_CMD_INDEX_AT_MQTTLI] =
    {
        .p_cmd = (uint8_t *) "AT+MQTTLI=",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_32,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* Set the MQTT Client ID */
    [ DA16200_AT_CMD_INDEX_AT_MQTTCID] =
    {
        .p_cmd = (uint8_t *) "AT+MQTTCID=",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_32,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* Enable the MQTT client, 1 enable, 0 disable */
    [ DA16200_AT_CMD_INDEX_AT_MQTTCL] =
    {
        .p_cmd = (uint8_t *) "AT+MQTTCL=1",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_32,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    /* Publish an MQTT message with <msg>,<topic> */
/*    [ DA16200_AT_CMD_INDEX_AT_NWMQMSG] =
    {
        .p_cmd = (uint8_t *) "AT+NWMQMSG=open,door\r\n",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_32,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    }*/
    [ DA16200_AT_CMD_INDEX_AT_MQTTMSG_BUTTON_PRESSED] =
    {
        .p_cmd = (uint8_t *) "AT+MQTTMSG=button is pressed,button",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    [ DA16200_AT_CMD_INDEX_AT_MQTTMSG_BUTTON_RELEASED] =
    {
        .p_cmd = (uint8_t *) "AT+MQTTMSG=button is released,button",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    [ DA16200_AT_CMD_INDEX_AT_MQTTMSG_TEMP_READ] =
    {
        .p_cmd = (uint8_t *) "AT+MQTTMSG=",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    },
    [ DA16200_AT_CMD_INDEX_AT_MQTTMSG_HUMI_READ] =
    {
        .p_cmd = (uint8_t *) "AT+MQTTMSG=",
        .p_success_resp[0] = (uint8_t *) "OK",
        .max_resp_length = DA16200_STR_LEN_64,
        .retry = DA16200_RETRY_VALUE_5,
        .retry_delay = DA16200_DELAY_200MS
    }


};

 

1.2 MQTT应用程序实现

上一篇中通过RT-ThreadAT指令调试工具对MQTT客户端连接服务器和发布消息的流程进行验证,确认过程可以实现。在NUCLEO-F411开发板上连接E103-W12C-TB通讯模块和HS3003温湿度传感器,将开发板按键事件和温湿度传感器数据发布到MQTT网络中,在手机APP上查看相应的结果。硬件连接如下图。

开发板连接图.jpg

应用程序的流程如下,检测到按键状态发生变化后,发布按键的信息。对温湿度传感器数据的发布采用周期发布的方式。

程序流程.png

发布温湿度数据的MQTT消息函数如下。

rt_err_t AT_cmd_send_temp(rt_int32_t temp)
{
    rt_err_t status = RT_EOK;
    static char tempc[AT_CMD_LENGTH];

    sprintf(tempc,"AT+MQTTMSG=%3d.%d,temperature",temp / 10,temp % 10);

    g_da16200_cmd_set[DA16200_AT_CMD_INDEX_AT_MQTTMSG_TEMP_READ].p_cmd = (uint8_t *)tempc;
    status = AT_cmd_send_ok(DA16200_AT_CMD_INDEX_AT_MQTTMSG_TEMP_READ);

    return status;
}


rt_err_t AT_cmd_send_humi(rt_int32_t humi)
{
    rt_err_t status = RT_EOK;
    static char humic[AT_CMD_LENGTH];

    sprintf(humic,"AT+MQTTMSG=%3d.%d,humidity",humi / 10,humi % 10);
//    LOG_D("%s",humic);

    g_da16200_cmd_set[DA16200_AT_CMD_INDEX_AT_MQTTMSG_HUMI_READ].p_cmd = (uint8_t *)humic;
//    LOG_D("%s",g_da16200_cmd_set[DA16200_AT_CMD_INDEX_AT_MQTTMSG_HUMI_READ].p_cmd);
    status = AT_cmd_send_ok(DA16200_AT_CMD_INDEX_AT_MQTTMSG_HUMI_READ);

    return status;
}


通过sprintf函数和格式化字符串,将整型的温湿度数据添加到MQTT消息中,发布到MQTT网络。

主程序的代码如下

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

#include <at.h>   /* AT 组件头文件 */
#define LOG_TAG              "mqtt_app"
#define LOG_LVL              LOG_LVL_DBG
#include <ulog.h>

#include <agile_button.h>
#include "da16200_AT.h"

#include "sensor_renesas_hs300x.h"
#define HS300X_I2C_BUS  "i2c1"


/* defined the LED0 pin: PA5 */
#define LED0_PIN               GET_PIN(A, 5)
#define BUTTON_PIN             GET_PIN(C, 13)

static agile_btn_t *_dbtn = RT_NULL;


static void read_temp_entry(void *parameter);
static void read_humi_entry(void *parameter);
static rt_int32_t temp_10,humi_10;

static void btn_click_event_cb(agile_btn_t *btn)
{
    rt_kprintf("[button click event] pin:%d   repeat:%d, hold_time:%d\r\n", btn->pin, btn->repeat_cnt, btn->hold_time);
    send_message(1);
}

int main(void)
{
    int count = 1;
    rt_uint8_t msg;
    rt_uint8_t mode=1;

    int pin = BUTTON_PIN;
    int active = 0;

    if (active == PIN_HIGH)
        _dbtn = agile_btn_create(pin, active, PIN_MODE_INPUT_PULLDOWN);
    else
        _dbtn = agile_btn_create(pin, active, PIN_MODE_INPUT_PULLUP);

    agile_btn_set_event_cb(_dbtn, BTN_CLICK_EVENT, btn_click_event_cb);
    agile_btn_start(_dbtn);

    /* set LED0 pin mode to output */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);

    rt_thread_t hs3003temp_thread,hs3003humi_thread;

    at_client_init("uart6", 512);

    LOG_D("button pin  %d!",BUTTON_PIN);
    //AT_cmd_send_data(DA16200_AT_CMD_INDEX_AT_CWDEFAP, 4000);

    wifi_con_routine();

    mqtt_con_routine();

    rt_thread_mdelay(3000);

    hs3003temp_thread = rt_thread_create("hs3003tem",
                                      read_temp_entry,
                                      "temp_hs3",
                                      2048,
                                      RT_THREAD_PRIORITY_MAX / 2,
                                      20);
    if (hs3003temp_thread != RT_NULL)
    {
        rt_thread_startup(hs3003temp_thread);
    }


    while (count++)
    {
        msg=get_message();
        switch(msg){
        case 1:{
            switch(mode)
            {
            case 1:
                mode =2;
                AT_cmd_send_ok(DA16200_AT_CMD_INDEX_AT_MQTTMSG_BUTTON_PRESSED);
                break;
            case 2:
                AT_cmd_send_ok(DA16200_AT_CMD_INDEX_AT_MQTTMSG_BUTTON_RELEASED);
                mode =1;
                break;
            }
            break;
        }
        case 2:
            AT_cmd_send_temp(temp_10);
            rt_thread_mdelay(1000);
            AT_cmd_send_humi(humi_10);
            break;
        }
    }

    return RT_EOK;
}


/* Notice: PB8 --> 24 SCL; PB9 --> 25 SDA*/
int rt_hw_hs300x_port(void)
{
    struct rt_sensor_config cfg;
    cfg.intf.dev_name  = HS300X_I2C_BUS;
    cfg.intf.user_data = (void *)HS300X_I2C_ADDR;
    rt_hw_hs300x_init("hs300x", &cfg);
    return RT_EOK;
}
INIT_ENV_EXPORT(rt_hw_hs300x_port);


static void read_temp_entry(void *parameter)
{
    rt_device_t dev_t = RT_NULL;
    rt_device_t dev_h = RT_NULL;
    struct rt_sensor_data sensor_data,sensor_datah;
    rt_size_t res;

    dev_t = rt_device_find(parameter);
    dev_h = rt_device_find("humi_hs3");

    if (dev_t == RT_NULL)
    {
        rt_kprintf("Can't find device:%s\n", parameter);
        return;
    }

    if (rt_device_open(dev_t, RT_DEVICE_FLAG_RDWR) != RT_EOK)
    {
        rt_kprintf("open device failed!\n");
        return;
    }
    if (rt_device_open(dev_h, RT_DEVICE_FLAG_RDWR) != RT_EOK)
    {
        rt_kprintf("open device failed!\n");
        return;
    }
    rt_device_control(dev_t, RT_SENSOR_CTRL_SET_ODR, (void *)100);
    rt_device_control(dev_h, RT_SENSOR_CTRL_SET_ODR, (void *)100);

    while (1)
    {
        res = rt_device_read(dev_h, 0, &sensor_datah, 1);
        res = rt_device_read(dev_t, 0, &sensor_data, 1);
        if (res != 1)
        {
            rt_kprintf("read data failed!size is %d\n", res);
            rt_device_close(dev_t);
            return;
        }
        else
        {
            temp_10=sensor_data.data.temp;
            humi_10=sensor_datah.data.humi;
            send_message(2);
        }

        rt_thread_mdelay(5000);
    }
}


       代码的运行流程和图中一样,注册按键的回调函数、创建温湿度传感器数据读取任务,进入主循环等待接收信号队列数据,接收到信号后,根据接收到的信号类型,发布对应MQTT消息。

应用程序逻辑如上所述,在程序开发时,借助RT-Thread丰富的组件,比如程序中的alige-buttonsensor框架等,可以快速完成原型程序的搭建,只需要在工程的RT-Thread Settings界面配置相应的组件,即可使用已有的代码创建应用程序,完成功能验证。

 

image.png

image.png

1.3 功能演示

参考上一篇中搭建MQTT服务器和App客户端订阅消息的设置,在APP上订阅传感器发布的按键和温湿度消息。可以看到数据更新到了手机端。

 app.gif


1.4 总结

AT指令由于各家的协议不同,在开发时需要根据协议要求编写通讯程序,借助RT-Thread已有的代码,可以快速进行原型验证,并在此基础上对代码进行优化,开发应用程序。





关键词: 传感器     数据    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]