CC3200使用MQTT协议连接Onenet平台实践

代码仓库地址:https://github.com/idrey/CC3200_Onenet

0x01 介绍

CC3200是TI公司推出的一款WIFI MCU,支持多种网络协议。信息物理系统课程中使用的是CC3200 Launchpad,上面还带有tmp006温度传感器和加速度传感器,通过I2C可以和这两个传感器通信,获取对应的数据。

Onenet是中国移动推出的物联网云平台,支持主流的物联网协议,本次实验将使用CC3200通过MQTT协议与Onenet平台完成基本的连接。

0x02 实验环境

  1. CCS 6.1
  2. MobaXterm(串口调试)
  3. CC3200 SDK 1.3

0x03 场景设置

CC3200实时上传温度信息至Onenet,应用端显示温度信息并控制CC3200工作。

0x04 Onenet侧配置

选择MQTT物联网套件(新版)创建产品及设备,这里创建产品的是iottest,设备命名为CC3200
在这里插入图片描述在这里插入图片描述

0x05 CC3200 MQTT_CLIENT例程

在CC3200SDK中有mqtt_client的例程,使用CCS导入该工程。为了连接上Onenet云平台,我们需要修改其中一些配置。

首先,根据开发指南,需要把服务器地址修改为mqtts.heclouds.com,把端口号修改为1883,为了操作简便,这里使用的是非加密端口。
在这里插入图片描述
根据协议规范,我们使用的是MQTT 3.1.1版本,需要修改原定义为#define SERVER_MODE MQTT_3_1_1。Onenet不支持Retain特性,需要修改原定义为#define RETAIN 0

接下来,配置user_connect_config[]。其中,ClientID字段为cc3200,是在Onenet里创建的设备名称,UserName字段为439074,是在Onenet里创建的产品ID,在平台中获取该ID并替换该字段。紧随其后的是用于认证的Password,参见token生成示例 - python,在代码里需要替换为自己的ID和access_key。
在这里插入图片描述

定义topic: 在这里我们需要用到两个topic,一个用于发布消息,一个用于订阅消息。在原来的例程中定义了两个用于发布消息的topic,我们只需要使用一个,为了方便,把PUB_TOPIC_FOR_SW2设置为$sys/439074/cc3200/dp/post/json,参见数据点topic簇,使用时请替换为对应的pid和device_name。
在这里插入图片描述
此外,我们还需要订阅topic用于接受命令,这里把TOPIC1设置为$sys/439074/cc3200/cmd/request/##是通配符,参见设备命令topic簇
在这里插入图片描述
定义好topic后,我们需要进一步配置user_connect_config[]。由于我们只订阅了1个topic,我们需要修改#define TOPIC_COUNT为1。
在这里插入图片描述
然后把user_connect_config[]中的{QOS2, QOS2, QOS2}改为{QOS1}{QOS0},并把will的参数设置为NULL。完整的user_connect_config[]如下所示:
在这里插入图片描述
接下来我们需要实现发布消息的功能,发布消息前首先需要获取温度信息。

0x06 获取温度传感器信息

CC3200上面使用的是tmp006温度传感器,DatasheetUser’s Guide。使用I2C前,我们还得配置好管脚,需要修改原来的pinmux.c
根据I2C的例程文档,温度传感器的地址为0x41,储存环境温度的寄存器地址为0x01。在这里我们只需要读取温度传感器的数据,把I2C里面的函数ProcessReadRegCommand修改为

unsigned int ProcessReadRegCommand(char *regStr)
{
    unsigned char ucDevAddr, ucRegOffset, ucRdLen;
    unsigned char aucRdDataBuf[256];
    char *pcErrPtr;

    ucDevAddr = (unsigned char)strtoul(devStr, &pcErrPtr, 16);

    ucRegOffset = (unsigned char)strtoul(regStr, &pcErrPtr, 16);

    ucRdLen = (unsigned char)2;
    //RETERR_IF_TRUE(ucLen > sizeof(aucDataBuf));

    //
    // Write the register address to be read from.
    // Stop bit implicitly assumed to be 0.
    //
    RET_IF_ERR(I2C_IF_Write(ucDevAddr,&ucRegOffset,1,0));

    //
    // Read the specified length of data
    //
    RET_IF_ERR(I2C_IF_Read(ucDevAddr, &aucRdDataBuf[0], ucRdLen));

//    UART_PRINT("I2C Read From address complete\n\r");

    //
    // Display the buffer over UART on successful readreg
    //
    unsigned int f = (unsigned int)aucRdDataBuf[0]; // Byte 1
    unsigned int s = (unsigned int)aucRdDataBuf[1]; // Byte 2
    unsigned int ans = f;
    ans = ans << 8;
    ans = ans + s;
//    UART_PRINT("%d   %x\n\r", ans, ans);

    return ans;
}

其中devStr为在外面定义的函数常量,在这里定义为0x41,也即温度传感器的地址。这里得到的为原始字节数据,需要做进一步转换,转换公式为temp = (float)(temp_die >> 2)*0.03125;
在这里插入图片描述除此之外,在读取温度前,还得使用下列代码检查传感器是否配置好。

    do {
        config = ProcessReadRegCommand(regStr);
    }while((config & 0x0080) != 0x0080);

0x07 上传温度信息至Onenet

配置好后,即可与平台进行连接并发布消息。Onenet要求上传的消息格式为JSON格式,所以这里我们引入cJSON。书写下列函数把温度信息写入JSON。

char *getJson(char* temp) {
    cJSON* cjson_test = NULL;
    cJSON* cjson_dp = NULL;
    cJSON* cjson_temp = NULL;
    cJSON* cjson_v = NULL;

    /* 创建一个JSON数据对象(链表头结点) */
    cjson_test = cJSON_CreateObject();

    /* 添加一条字符串类型的JSON数据(添加一个链表节点) */
    cJSON_AddNumberToObject(cjson_test, "id", 123);


    cjson_dp = cJSON_CreateObject();

    cjson_v = cJSON_CreateObject();
    cJSON_AddStringToObject(cjson_v, "v", temp);

    cjson_temp = cJSON_CreateArray();
    cJSON_AddItemToArray(cjson_temp, cjson_v);
    cJSON_AddItemToObject(cjson_dp, "temp", cjson_temp);

    cJSON_AddItemToObject(cjson_test, "dp", cjson_dp);

    return cJSON_Print(cjson_test);
}

例如,生成的JSON消息为:

{
    "id": 123,        
    "dp": {             
        "tmp": 25
    }
}

然后便可Publish出去

data_sw2 = (unsigned char*)getJson(temp_str);
sl_ExtLib_MqttClientSend((void*)local_con_conf[iCount].clt_ctx,
pub_topic_sw2,data_sw2,strlen((char*)data_sw2),QOS1,RETAIN);
UART_PRINT("\n\r CC3200 Publishes the following message \n\r");
UART_PRINT("Topic: %s\n\r",pub_topic_sw2);
UART_PRINT("Data: %s\n\r",data_sw2);

0x08 接收消息与处理

接下来我们修改Mqtt_Recv函数,该函数是收到消息的回调函数,在里面可以书写收到下发命令的处理逻辑。在这里,我们打算收到平台下发的命令后,改变工作状态,并翻转LED的亮灭。首先我们需要修改前面几行为:

    char *output_str=(char*)malloc(pay_len+1);
    memset(output_str,'\0',pay_len+1);
    strncpy(output_str, (char*)payload, pay_len);
    output_str[pay_len]='\0';

原来的代码是提取订阅的topic字符串,这里我们修改后,提取的是下发设备收到的消息。然后书写处理逻辑

    if(strncmp(output_str,RECV_MSG, pay_len) == 0)
    {
    	flag_red = 1 - flag_red;
    	ToggleLedState(LED1);
        UART_PRINT("OK\n\r");
    }

在这其中我们使用了RECV_MSG宏定义,比如#define RECV_MSG "1234",当收到的消息为1234时,会对flag_red取反,该变量的值指示了板子的工作状态。然后调用ToggleLedState(LED1)翻转LED,并在串口输出"OK"。接下来的代码复用例程中的即可。

0x09 应用端(APP)

  • 数据获取
  • 下发命令

0x0A 应用端(Web)

  • 加入百度地图
  • 前端
  • 后端
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值