发 帖  
原厂入驻New

转发:【码上评选】在润和HiSpark的WiFIIoT开发板上使用 Harmony OS,实现智能花园喷灌控制系统,并连接上云

856 HarmonyOS
分享
本帖最后由 jf_73813179 于 2020-12-28 09:44 编辑



因时间仓促,来不及配备对应的水泵、电磁阀、加药泵等外部设备。本Demo使用WIFi IoT开发板上的2号扩展板(红绿灯演示功能板),以及oled屏扩展板进行对应功能演示。

已经快到活动截止时间了,目前项目进度仅仅是实现了LED点灯、初步学习了线程的创建和复用线程函数、点亮OLED屏幕、配置好MQTT代码环境、华为IoT云端设置和初步连接调试。感觉自己在活动期间学习到很多,但是没有能按预期完成项目,非常遗憾。


智能花园喷灌控制系统后期还会再继续完成,目标实现的功能如下:
1、加入一键配网功能及OLED屏上显示wifi连接状态功能。
2、WiFi联网后自动校时、并实时在屏幕上显示时钟
3、手机端显示每天浇水量及施肥、杀虫记录功能。
4、本地定时设备完成定时浇灌及上报数据至华为云功能

项目地址 https://gitee.com/walker2048/hmos_iot


调试设备可以上报数据,但是真正完整的实现用WifiIot连上华为云,还需要攻关3个难点:
1、时间戳获取(不影响上报属性和连接,但是始终不舒服)
2、HMAC-sha256加密功能(不影响上报属性和连接)
3、pahomqtt更改为线程定时上报



我们来看一下Hi3861里,关于点灯的示范代码(applications\sample\wifi-iot\app\iothardware\led_example.c):其中点灯部分的关键内容如下:
include wifiiot_gpio.h 头文件,以wifiiot_gpio这个层面调用GPIO功能。

1
2
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"





LedTask函数就是实际执行闪烁LED功能的代码,通过检查g_ledState来设置对应IO的状态,并调用GpioSetOutputVal函数将IO状态设置好。

看到这里,很多小白朋友就会疑惑,为什么要这么麻烦,我直接调用厂商静态库的hi_gpio_set_output_val函数不可以么?当然可以,但是我们不推荐这么做。如果在app中直接调用厂商静态库函数,那假如同一个app想在另一个模组硬件中使用,是不是要改很多对应的代码呢?
这是考虑兼容性才这样封装,以下是图例说明。



代码组织架构可以参见https://gitee.com/openhARMony/docs/blob/master/readme/%E5%85%AC%E5%85%B1%E5%9F%BA%E7%A1%80README.md

=================================================================================
我们来设想一下:
案例1、假如我们在app中直接调用厂商hal库函数并调试完毕,如果想用这个app直接在另一个模组中使用,无法使用。
案例2、假如我们调用标准IoT外设控制模块接口,并在厂商目录新建adapter目录适配HAL层接口。那我们在同一个app的情况下,另一个厂商模组只需要再做一遍适配就能马上使用。同时如果更新了厂商HAL库,也只需要更新一下adapter目录适配函数即可。

这样来说,兼容性和代码的可读性不是提升了很多么?

=================================================================================
接下来,我们来完成LED部分的最终代码,首先我们创建一个hardware_config.h头文件,用来定义3个LED灯的全局变量,方便其他程序引用。




  1. <div>enum LedState {</div><div>    LED_ON = 0,</div><div>    LED_OFF,</div><div>    LED_SPARK,</div><div>};</div>
  2. <div>extern enum LedState g_ledState_R;</div><div>extern enum LedState g_ledState_G;</div><div>extern enum LedState g_ledState_Y;</div>

复制代码



接下来,我们在applications/sample/wifi-iot/app/iothardware/BUILD.gn添加刚刚定义的头文件目录




  1. <div>static_library("led_example") {</div><div>    sources = [</div><div>        "led_example.c"</div><div>    ]</div>
  2. <div>    include_dirs = [</div><div>        "//utils/native/lite/include",</div><div>        "//kernel/liteos_m/components/cmsis/2.0",</div><div>        "//base/iot_hardware/inteRFaces/kits/wifiiot_lite",</div><div>        "//applications/sample/wifi-iot/app/iothardware"</div><div>    ]</div><div>}</div>

复制代码



最后,将applications/sample/wifi-iot/app/iothardware/led_example.c文件修改成如下内容。




  1. <div>#include <stdio.h></div>
  2. <div>#include <unistd.h></div>
  3. <div>#include "ohos_init.h"</div><div>#include "cmsis_os2.h"</div><div>#include "wifiiot_gpio.h"</div><div>#include "wifiiot_gpio_ex.h"</div>
  4. <p>#include "hardware_config.h"</p><p>
  5. </p><div><div>#define LED_INTERVAL_TIME_US 300000</div><div>#define LED_TASK_STACK_SIZE 512</div><div>#define LED_TASK_PRIO 25</div></div>
  6. <div>static void *LedTask(const char *arg)</div><div>{</div><div>    (void)arg;</div><div>    while (1) {</div><div>        switch (g_ledState_R) {</div><div>            case LED_ON:</div><div>                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_10, 1);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>            case LED_OFF:</div><div>                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_10, 0);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>            case LED_SPARK:</div><div>                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_10, 1);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_10, 0);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>            default:</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>        }</div><div>        switch (g_ledState_G) {</div><div>            case LED_ON:</div><div>                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_11, 1);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>            case LED_OFF:</div><div>                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_11, 0);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>            case LED_SPARK:</div><div>                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_11, 1);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_11, 0);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>            default:</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>        }</div><div>        switch (g_ledState_Y) {</div><div>            case LED_ON:</div><div>                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_12, 1);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>            case LED_OFF:</div><div>                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_12, 0);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>            case LED_SPARK:</div><div>                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_12, 1);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_12, 0);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>            default:</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>        }</div><div>    }</div>
  7. <div>    return NULL;</div><div>}</div>
  8. <div>static void LedExampleEntry(void)</div><div>{</div><div>    osThreadAttr_t attr;</div>
  9. <div>    GpioInit();</div><div>    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_10, WIFI_IOT_IO_FUNC_GPIO_10_GPIO);</div><div>    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_10, WIFI_IOT_GPIO_DIR_OUT);</div><div>    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_FUNC_GPIO_11_GPIO);</div><div>    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_GPIO_DIR_OUT);</div><div>    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_IO_FUNC_GPIO_12_GPIO);</div><div>    GpioSetDir(WIFI_IOT_IO_NAME_GPIO_12, WIFI_IOT_GPIO_DIR_OUT);</div>
  10. <div>    attr.name = "LedTask";</div><div>    attr.attr_bits = 0U;</div><div>    attr.cb_mem = NULL;</div><div>    attr.cb_size = 0U;</div><div>    attr.stack_mem = NULL;</div><div>    attr.stack_size = LED_TASK_STACK_SIZE;</div><div>    attr.priority = LED_TASK_PRIO;</div>
  11. <div>    if (osThreadNew((osThreadFunc_t)LedTask, NULL, &attr) == NULL) {</div><div>        printf("[LedExample] Falied to create LedTask!\n");</div><div>    }</div><div>}</div>
  12. <div>SYS_RUN(LedExampleEntry);</div>

复制代码



这样一来,我们就完成了交通指示扩展板上LED的功能部署工作,其他的app需要使用LED的话,只需要引用hardware_config.h头文件,并将对应的led状态赋值就可以了。现在我们可以继续做下一步的OLED显示工作啦。

2、使用 Harmony OS 点亮 OLDE屏
首先,我们找到厂商硬件资料,OLED屏的控制芯片ssd1306。我们百度上找一个demo,或者参考(发烧友联盟上连老师的教程)。将oled.h和oled.c以及oledfont.h复制到applications\sample\wifi-iot\app\iothardware目录下。然后我们在oled.c头文件定义部分添加以下内容:




  1. <div>#include "ohos_init.h"</div><div>#include "cmsis_os2.h"</div>
  2. <div>#include "wifiiot_i2c.h"</div><div>#include "wifiiot_i2c_ex.h"</div>

复制代码


接下来,我们将oled.c源程序中I2C部分调用内容替换成以下内容。(其实就是用鸿蒙定义好的标准接口函数和参数替换掉原有函数)。




  1. <div>u32 my_i2c_write(WifiIotI2cIdx id, u16 device_addr, u32 send_len)</div><div>{</div><div>    u32 status;</div><div>    WifiIotI2cData es8311_i2c_data;</div>
  2. <div>    es8311_i2c_data.sendBuf = g_send_data;</div><div>    es8311_i2c_data.sendLen = send_len;</div><div>    status = I2cWrite(id, device_addr, &es8311_i2c_data);</div><div>    if (status != 0) {</div><div>        printf("===== Error: I2C write status = 0x%x! =====\r\n", status);</div><div>        return status;</div><div>    }</div>
  3. <div>    return 0;</div><div>}</div>
  4. <div>/**********************************************</div><div>// IIC Write Command</div><div>**********************************************/</div><div>void Write_IIC_Command(unsigned char IIC_Command)</div><div>{</div><div>    g_send_data[0] = 0x00;</div><div>    g_send_data[1] = IIC_Command;</div>
  5. <div>    my_i2c_write(WIFI_IOT_I2C_IDX_0, 0x78, 2);</div><div>}</div><div>/**********************************************</div><div>// IIC Write Data</div><div>**********************************************/</div><div>void Write_IIC_Data(unsigned char IIC_Data)</div><div>{</div><div>    g_send_data[0] = 0x40;</div><div>    g_send_data[1] = IIC_Data;</div>
  6. <div>    my_i2c_write(WIFI_IOT_I2C_IDX_0, 0x78, 2);</div><div>}</div>

复制代码



以及最后初始化I2C部分,在文件最末端。




  1. <div>void my_oled_demo(void)</div><div>{</div><div>    //初始化</div><div>    I2cInit(WIFI_IOT_I2C_IDX_0, 100000); /* baudrate: 100000 */</div>
  2. <div>    led_init();</div>
  3. <div>    OLED_ColorTurn(0);   //0正常显示,1 反色显示</div><div>    OLED_displayTurn(0); //0正常显示 1 屏幕翻转显示</div>
  4. <div>    OLED_ShowString(8, 16, "hello world", 16);</div>
  5. <div>    OLED_Refresh();</div><div>}</div><div>#endif</div>
  6. <div>SYS_RUN(my_oled_demo);</div>

复制代码


===========================================================================================
除了修改源码外,我们还需要修改WiFiIoT的io初始化文件,vendor\hisi\hi3861\hi3861\app\wifiiot_app\init\app_io_init.c
将其中I2C引脚定义部分内容修改为以下内容。




  1. <div>#ifdef CONFIG_I2C_SUPPORT</div><div>    /* I2C IO复用也可以选择3/4; 9/10,根据产品设计选择 */</div><div>    hi_io_set_func(HI_IO_NAME_GPIO_13, HI_IO_FUNC_GPIO_13_I2C0_SDA);</div><div>    hi_io_set_func(HI_IO_NAME_GPIO_14, HI_IO_FUNC_GPIO_14_I2C0_SCL);</div><div>#endif</div>

复制代码


并修改makefile文件:vendor\hisi\hi3861\hi3861\build\config\usr_config.mk,启用I2C功能
添加一行I2C功能支持宏定义




  1. CONFIG_I2C_SUPPORT=y

复制代码


这样,就基本上完成OLED部分的测试功能了,我们可以编译源码后烧录到板子上看一下
显示效果如下图。

3、学习 Harmony OS 的 线程调度功能
其实我们在学习led点灯的时候,就已经使用了Harmony OS的线程功能。现在我们可以查看一下线程功能的源码,看看到底有什么。我们可以看到,在app目录的头文件区域,都包含有以下内容




  1. #include "cmsis_os2.h"

复制代码


查找了一下源码(在命令行运行 find -name cmsis_os2.h),我们找到一个有意思的文件。





  1. <p>kernel\liteos_m\components\cmsis\2.0\cmsis_liteos2.c</p><div><div>osThreadId_t osThreadNew(osThreadFunc_t func, void *argument, const osThreadAttr_t *attr)</div><div>{</div><div>    UINT32 uwTid;</div><div>    UINT32 uwRet;</div><div>    LosTaskCB *pstTaskCB = NULL;</div><div>    TSK_INIT_PARAM_S stTskInitParam;</div>
  2. <div>    if (OS_INT_ACTIVE) {</div><div>        return NULL;</div><div>    }</div>
  3. <div>    if ((attr == NULL) || (func == NULL) || (attr->priority < osPriorityLow1) ||</div><div>        (attr->priority > osPriorityAboveNormal6)) {</div><div>        return (osThreadId_t)NULL;</div><div>    }</div>
  4. <div>    (void)memset_s(&stTskInitParam, sizeof(TSK_INIT_PARAM_S), 0, sizeof(TSK_INIT_PARAM_S));</div><div>    stTskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)func;</div><div>#ifndef LITEOS_WIFI_IOT_VERSION</div><div>    stTskInitParam.uwArg = (UINT32)argument;</div><div>#else</div><div>    stTskInitParam.auwArgs[0] = (UINT32)argument;</div><div>#endif</div><div>    stTskInitParam.uwStackSize = attr->stack_size;</div><div>    stTskInitParam.pcName = (CHAR *)attr->name;</div><div>    stTskInitParam.usTaskPrio = OS_TASK_PRIORITY_LOWEST - ((UINT16)(attr->priority) - LOS_PRIORITY_WIN); /* 0~31 */</div>
  5. <div>    uwRet = LOS_TaskCreate(&uwTid, &stTskInitParam);</div>
  6. <div>    if (LOS_OK != uwRet) {</div><div>        return (osThreadId_t)NULL;</div><div>    }</div>
  7. <div>    pstTaskCB = OS_TCB_FROM_TID(uwTid);</div>
  8. <div>    return (osThreadId_t)pstTaskCB;</div><div>}</div></div>

复制代码

在这段代码里,我们不难看出,其实最终调用的还是LiteOS的标准LOS_TaskCreate函数,并且仔细看一下函数,是可以传递参数的。我们在LiteOS官网可以找到对应线程部分的教程代码,并依葫芦画瓢,把Led模块的代码优化一下,通过传递LedSet结构体的形式,复用线程定义函数,这样我们的代码可以更简洁,更简单一些。




  1. <div><div>typedef struct LedSet</div><div>{</div><div>    /* data */</div><div>    enum LedState state;</div><div>    enum WifiIotIoName pin;</div><div>};</div>

  2. <div>static void *LedTask(const struct LedSet* arg)</div><div>{</div><div>    while (1) {</div><div>        switch (arg->state) {</div><div>            case LED_ON:</div><div>                GpioSetOutputVal(arg->pin, 1);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>            case LED_OFF:</div><div>                GpioSetOutputVal(arg->pin, 0);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>            case LED_SPARK:</div><div>                GpioSetOutputVal(arg->pin, 1);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                GpioSetOutputVal(arg->pin, 0);</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>            default:</div><div>                usleep(LED_INTERVAL_TIME_US);</div><div>                break;</div><div>        }</div><div>    }</div><div>    return NULL;</div><div>}</div></div><p></p>

复制代码




然后在创建线程的时候,就可以通过传递不同的结构体,点亮不同的Led灯了。




  1. <div>    green_led.state = LED_OFF;</div><div>    green_led.pin = WIFI_IOT_IO_NAME_GPIO_10;</div>
  2. <div>    if (osThreadNew((osThreadFunc_t)LedTask, &green_led, &attr) == NULL) {</div><div>        printf("[LedExample] Falied to create LedTask!\n");</div><div>    }</div>

复制代码


=================================================================================

虽然我们调整了结构体定义,但是这样创建3个线程,在物联网MCU的贫乏资源上浪费CPU和RAM,其实并不大好。led模块还可以通过消息队列来进行控制。我们再来学习一下消息队列的使用吧。





4、上云基础知识学习,并使用MQTT接入华为云
WiFi连接部分以及MQTT部分代码参考连老师的代码。我们现在先学习一下上云的一些理论知识。首先、设备上云并不会将完整的业务模型发布到云上,仅需要将重要的关键控制属性发布到云上。其次、可以利用物模型的服务和事件获取到更多的有用信息。



属性是通过设备影子保存在华为云上,同时应用端app(如手机端)中同步的也是设备影子上的数据。另外在设备离线时,应用端修改设备影子后,设备上线时应同步设备影子数据,与云端保持一致。





设备鉴权注意内容(以TypeScript代码为示范,代码地址https://gitee.com/walker2048/mqttclient/tree/master)



成功上报后的截图:


mqtt.h内容,将服务器信息,设备端信息等独立出来





  1. <div>#define publish_message "{\"publish\":{\"services\":[{\"service_id\":\"SmartPumpServer\",\"properties\":{\"walterPumpSwitch\":\"on\",\"pesticidePumpSwitch\":\"on\",\"manurePumpSwitch\":\"on\",\"manureLevels\":600,\"pesticideLevel\":1000},\"event_time\":\"\"}]}}"</div><div>#define Hi_cloudHost "a15fbdc9af.iot-mqtts.cn-north-4.myhuaweicloud.com"</div><div>#define Hi_deviceId "5fc9a576b4ec2202e9a32615_testDevice"                                   //设备ID</div><div>#define Hi_deviceSecret ""                                                                  //设备secret</div><div>#define Hi_clientId "5fc9a576b4ec2202e9a32615_testDevice_0_0_2020120512"                    //鉴权用ClientID</div><div>#define Hi_password "1ded5f4731ab1b097edfac633a3f1cea21ab2d14ef02e1c5643fb4e08cd9415e"      //鉴权用password</div>
  2. <div>#define publishTopic "$oc/devices/5fc9a576b4ec2202e9a32615_testDevice/sys/messages/up"</div>
  3. <div>void mqtt_test(void);</div>
  4. <div>#endif /* __MQTT_TEST_H__ */</div>

复制代码


mqtt.c实现内容




  1. <div>#include <stdio.h></div>
  2. <div>#include <unistd.h></div>
  3. <div>#include "ohos_init.h"</div><div>#include "cmsis_os2.h"</div>
  4. <div>#include <unistd.h></div><div>#include "hi_wifi_api.h"</div><div>//#include "wifi_sta.h"</div><div>#include "lwip/ip_addr.h"</div><div>#include "lwip/netifapi.h"</div>
  5. <div>#include "lwip/sockets.h"</div>
  6. <div>#include "MQTTPacket.h"</div><div>#include "transport.h"</div><div>#include "mqtt.h"</div>
  7. <div>int toStop = 0;</div>
  8. <div>int mqtt_connect(void)</div><div>{</div>
  9. <div>    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;</div><div>    int rc = 0;</div><div>    int mysock = 0;</div><div>    unsigned char buf[200];</div><div>    int buflen = sizeof(buf);</div><div>    int msgid = 1;</div><div>    MQTTString topicString = MQTTString_initializer;</div><div>    int req_qos = 0;</div><div>    char *payload = "";</div><div>    int payloadlen = strlen(payload);</div><div>    int len = 0;</div><div>    char *host = Hi_cloudHost;</div><div>    int port = 1883;</div>
  10. <div>    mysock = transport_open(host, port);</div><div>    if (mysock < 0)</div><div>        return mysock;</div>
  11. <div>    printf("Sending to hostname %s port %d\n", host, port);</div>
  12. <div>    data.clientID.cstring = Hi_clientId;</div><div>    data.keepAliveInterval = 20;</div><div>    data.cleansession = 1;</div><div>    data.username.cstring = Hi_deviceId;</div><div>    data.password.cstring = Hi_password;</div>
  13. <div>    len = MQTTSerialize_connect(buf, buflen, &data);</div><div>    rc = transport_sendPacketBuffer(mysock, buf, len);</div>
  14. <div>    /* wait for connack */</div><div>    if (MQTTPacket_read(buf, buflen, transport_getdata) == CONNACK)</div><div>    {</div><div>        unsigned char sessionPresent, connack_rc;</div>
  15. <div>        if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0)</div><div>        {</div><div>            printf("Unable to connect, return code %d\n", connack_rc);</div><div>            goto exit;</div><div>        }</div><div>    }</div><div>    else</div><div>        goto exit;</div><div>    </div><div>    /* loop getting msgs on subscribed topic */</div><div>    topicString.cstring = "$oc/devices/5fc9a576b4ec2202e9a32615_testDevice/sys/properties/report";</div><div>    /* transport_getdata() has a built-in 1 second timeout,</div><div>        your mileage will vary */</div><div>    if (MQTTPacket_read(buf, buflen, transport_getdata) == PUBLISH)</div><div>    {</div><div>        unsigned char dup;</div><div>        int qos;</div><div>        unsigned char retained;</div><div>        unsigned short msgid;</div><div>        int payloadlen_in;</div><div>        unsigned char *payload_in;</div><div>        int rc;</div><div>        MQTTString receivedTopic;</div><div>        rc = MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic,</div><div>                                     &payload_in, &payloadlen_in, buf, buflen);</div><div>        printf("message arrived %.*s\n", payloadlen_in, payload_in);</div>
  16. <div>        rc = rc;</div><div>    }</div>
  17. <div>    printf("publishing device message\n");</div><div>    len = MQTTSerialize_publish(buf, buflen, 0, 0, 0, 0, topicString, (unsigned char *)payload, payloadlen);</div><div>    rc = transport_sendPacketBuffer(mysock, buf, len);</div>
  18. <div>    printf("disconnecting\n");</div><div>    len = MQTTSerialize_disconnect(buf, buflen);</div><div>    rc = transport_sendPacketBuffer(mysock, buf, len);</div><div>exit:</div><div>    transport_close(mysock);</div>
  19. <div>    rc = rc;</div>
  20. <div>    return 0;</div><div>}</div>
  21. <div>void mqtt_test(void)</div><div>{</div><div>    mqtt_connect();</div><div>}</div>

复制代码

5、使用 Harmony OS  的 KV 组件实现本地数据存储
6、使用 Harmony OS  的 RTC 实时时钟功能实现定时管理
使用lwip的精简校时功能third_party\lwip\src\apps\sntp\sntp.c
功能未经测试,udp_recv函数未实现




  1. <div>#include <stdio.h></div><div>#include <string.h></div><div>#include "ohos_init.h"</div><div>#include "cmsis_os2.h"</div>
  2. <div>#include "sntp.h"</div><div>#include "sntp_opts.h"</div><div>#include "hi_time.h"</div>
  3. <div>uint32_t sntp_time;</div>
  4. <div>void init_sntp(void)</div><div>{</div><div>    uint32_t time = hi_get_real_time();</div>
  5. <div>    //加入授时中心的IP信息</div><div>    sntp_setservername(0, "ntp1.aliyun.com");</div><div>    //设置 SNTP 的获取方式 -> 使用向服务器获取方式</div><div>    sntp_setoperatingmode(SNTP_OPMODE_POLL);</div><div>    //SNTP 初始化</div><div>    sntp_init();</div><div>}</div>
  6. <div>void sntp_init(void)</div><div>{</div><div>    SNTP_RESET_RETRY_TIMEOUT();</div>
  7. <div>    //创建udp,用于接收udp包,时间数据</div><div>    int sntp_PCB = udp_new();</div><div>    LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL);</div><div>    if (sntp_pcb != NULL)</div><div>    {</div>
  8. <div>        //有数据,处理接收数据,同步到本地,由sntp_recv处理。</div><div>        udp_recv(sntp_pcb, sntp_set_time, NULL);</div><div>        sntp_request(NULL);</div><div>    }</div><div>}</div>
  9. <div>void sntp_set_time()</div><div>{</div><div>    if (sntp_time == 0)</div><div>    {</div><div>        print_log("sntp_set_time: wrong!@@\n");</div><div>        return;</div><div>    }</div>
  10. <div>    print_log("sntp_set_time: c00, enter!\n");</div><div>    print_log("sntp_set_time: c01, get time = %u\n", sntp_time);</div>
  11. <div>    struct tm *time;</div><div>    struct tm *sTime;</div>
  12. <div>    sntp_time += (8 * 60 * 60); ///北京时间是东8区需偏移8小时</div>
  13. <div>    time = localtime(&sntp_time);</div><div>    /*</div><div>     * 设置 RTC 的 时间</div><div>     */</div>
  14. <div>    hi_set_real_time(time);</div>
  15. <div>    print_log("sntp_set_time: c02, decode time: 20%d-%02d-%02d %d:%d:%d\n",</div><div>              time->tm_year, time->tm_mon, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec);</div>
  16. <div>    print_log("sntp_set_time: c03, test get = %u\n", get_timestamp());</div><div>    print_log("sntp_set_time: c04, set rtc time done\n");</div><div>}</div>

复制代码

作者:忙碌的死龙







0
2020-12-25 18:35:52   评论 分享淘帖 邀请回答

只有小组成员才能发言,加入小组>>

1160个成员聚集在这个小组

加入小组

创建小组步骤

关闭

站长推荐 上一条 /8 下一条

快速回复 返回顶部 返回列表