Link SDK支持跨平台跨系统运行,默认支持Linux(POSIX接口)设备,其它环境的设备都需要移植。无操作系统的设备资源较少,移植难度较大。本文介绍无操作系统的单片机设备,使用C Link SDK接入物联网平台的流程和示例。
前提条件
步骤一:接口移植
无操作系统设备可以理解为只有一个任务或线程,该任务的栈大小需要足够支撑SDK运行。
实现Link SDK运行依赖的底层接口后,设备才可以正常运行,下文介绍不同接口实现方案。
接口类型 | 接口列表 | 实现方案 |
内存管理 | core_sysdep_malloc |
|
core_sysdep_free | ||
系统时间 | core_sysdep_time | 建议使用单片机的系统嘀嗒实现,获取系统运行时间,单位:ms。 |
系统睡眠 | core_sysdep_sleep | 裸单片机环境没有睡眠接口,也不会存在多任务并发处理,所以不用让出MCU的运行权限,可以使用轮询的方式模拟睡眠。 |
随机值 | core_sysdep_rand | 以系统时间为随机因子,使用 |
互斥锁 | core_sysdep_mutex_init |
|
core_sysdep_mutex_lock | ||
core_sysdep_mutex_unlock | ||
core_sysdep_mutex_deinit | ||
网络连接 | core_sysdep_network_*** | 阻塞式接口,有、无操作系统实现相同。 |
步骤二:应用开发
对于有操作系统的设备,应用开发建议多任务处理,因为接口会阻塞,单任务处理会影响其他的业务处理。但对于无操作系统设备,只有一个任务,解决Link SDK接口阻塞的方案是降低阻塞的时间,尽量不影响业务的处理流程。
MQTT模块涉及到阻塞的接口
接口类 | 接口名 | 说明 |
MQTT建连 | aiot_mqtt_connect | 执行建连会阻塞,通过设置建连和接收超时处理,示例值:2s。 |
MQTT接收 | aiot_mqtt_recv | 执行MQTT的消息接收、回调执行、心跳超时重连会阻塞,通过设置网络接收超时处理,示例值:1s。 |
MQTT处理 | aiot_mqtt_process | 执行MQTT的心跳、QoS 1消息会阻塞。 |
配置超时时间
/* 配置MQTT超时时间 */
int32_t recv_timeout = 1000, connect_timeout = 2000;
aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_RECV_TIMEOUT_MS, (void *)&recv_timeout);
aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_CONNECT_TIMEOUT_MS, (void *)&connect_timeout);
示例
环境说明
环境配置 | 说明 |
操作系统 | 无。 |
硬件设备 | STM32L476 + 移远EC200S模组。 |
接口连接 | STM32串口1连接模组串口,串口波特率为115200。 |
开发环境 | |
参数配置 | 堆大小为80 KB、栈大小为1.5 KB。 |
移植实现示例
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "os_net_interface.h"
#include "stm32l4xx_hal.h"
/**
* @brief 获取当前的时间戳,SDK用于差值计算
*/
uint64_t __time(void) {
return (uint64_t)HAL_GetTick();
}
/**
* @brief 睡眠指定的毫秒数
*/
void __sleep(uint64_t time_ms) {
uint64_t start = __time();
while(__time() - start < time_ms) {
;
}
}
/**
* @brief 随机数生成方法
*/
void __rand(uint8_t *output, uint32_t output_len) {
uint32_t idx = 0, bytes = 0, rand_num = 0;
srand(__time());
for (idx = 0; idx < output_len;) {
if (output_len - idx < 4) {
bytes = output_len - idx;
} else {
bytes = 4;
}
rand_num = rand();
while (bytes-- > 0) {
output[idx++] = (uint8_t)(rand_num >> bytes * 8);
}
}
}
/**
* @brief 创建互斥锁
*/
void* __mutex_init(void) {
return (void *)0xFFFFFFFF;
}
/**
* @brief 申请互斥锁
*/
void __mutex_lock(void *mutex) {
}
/**
* @brief 释放互斥锁
*/
void __mutex_unlock(void *mutex) {
}
/**
* @brief 销毁互斥锁
*/
void __mutex_deinit(void **mutex) {
if (mutex == NULL || *mutex == NULL) {
return;
}
*mutex = NULL;
}
aiot_os_al_t g_aiot_freertos_api = {
.malloc = malloc,
.free = free,
.time = __time,
.sleep = __sleep,
.rand = __rand,
.mutex_init = __mutex_init,
.mutex_lock = __mutex_lock,
.mutex_unlock = __mutex_unlock,
.mutex_deinit = __mutex_deinit,
};
示例工程
使用MDK-Arm,打开工程
./LinkSDK/portfiles/aiot_port/project/stm32_noneos/MDK-ARM/L476.uvprojx
。MDK-Arm的使用说明,请参见MDK-Arm。
如果需要适配不同环境接口,修改文件
./LinkSDK/portfiles/aiot-port/project/stm32_noneos/Core/os_none_impl.c
。修改方法,请参见步骤一:接口移植。
打开
./LinkSDK/portfiles/aiot-port/project/stm32_noneos/Core/mqtt_at_basic_demo.c
,配置设备认证信息。参数
示例
说明
product_key
a18wP******
设备认证信息。开发准备时,您获取的设备证书。
您也可以在物联网平台控制台的设备详情页面查看设备的认证信息。
device_name
LightSwitch
device_secret
uwMTmVA**********DY6cHxxB******
mqtt_host
a18wP******.iot-as-mqtt.cn-shanghai.aliyuncs.com
设备的MQTT接入域名。
新旧版公共实例和企业版实例的接入域名信息,请参见查看实例终端节点。
编译工程文件,然后下载可执行文件到开发板运行。
成功运行后,您可以在设备端查看日志。
模组初始化:
>>> AT >>> AT <<< RDY >>> AT <<< AT OK >>> AT+QIACT=1 <<< OK >>> AT+QIACT? <<< +QIACT: 1,1,1,"10.13.***.***" OK
建立连接:
[22.400][LK-0313] MQTT user calls aiot_mqtt_connect api, connect [22.433][LK-0317] LightSwitch&a18wP****** [22.444][LK-0318] B4C45425D73E24B2935D73C1E98B6079A630FBE03F61E2A2031CEE7867D4D0D7 >>> AT+QIOPEN=1,1,"TCP","a18wP******.iot-as-mqtt.cn-shanghai.aliyuncs.com",443,0,1 <<< OK <<< +QIOPEN: 1,0 >>> AT+QISEND=1,286 <<< > >>> <<< SEND OK <<< +QIURC: "recv",1,4 id 0, len 4, res 20 [22.744][LK-0313] MQTT connect success in 341 ms AIOT_MQTTEVT_CONNECT
数据上报:
[27.766][LK-0309] pub: /sys/a18wP******/LightSwitch/thing/event/property/post [LK-030A] > 7B 22 69 64 22 3A 22 31 22 2C 22 76 65 72 73 69 | {"id":"1","versi [LK-030A] > 6F 6E 22 3A 22 31 2E 30 22 2C 22 70 61 72 61 6D | on":"1.0","param [LK-030A] > 73 22 3A 7B 22 4C 69 67 68 74 53 77 69 74 63 68 | s":{"LightSwitch [LK-030A] > 22 3A 30 7D 7D | ":0}} >>> AT+QISEND=1,120 <<< > >>> 0v<<< SEND OK <<< +QIURC: "recv",1,178 0?id 0, len 178, res 22
数据接收:
[27.933][LK-0309] pub: /sys/a18wP******/LightSwitch/thing/event/property/post_reply [LK-030A] < 7B 22 63 6F 64 65 22 3A 32 30 30 2C 22 64 61 74 | {"code":200,"dat [LK-030A] < 61 22 3A 7B 7D 2C 22 69 64 22 3A 22 31 22 2C 22 | a":{},"id":"1"," [LK-030A] < 6D 65 73 73 61 67 65 22 3A 22 73 75 63 63 65 73 | message":"succes [LK-030A] < 73 22 2C 22 6D 65 74 68 6F 64 22 3A 22 74 68 69 | s","method":"thi [LK-030A] < 6E 67 2E 65 76 65 6E 74 2E 70 72 6F 70 65 72 74 | ng.event.propert [LK-030A] < 79 2E 70 6F 73 74 22 2C 22 76 65 72 73 69 6F 6E | y.post","version [LK-030A] < 22 3A 22 31 2E 30 22 7D | ":"1.0"} pub, qos: 0, topic: /sys/a18wP******/LightSwitch/thing/event/property/post_reply
- 您也可以在物联网平台查看日志,具体操作,请参见云端运行日志。