因时间仓促,来不及配备对应的水泵、电磁阀、加药泵等外部设备。本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里,关于点灯的示范代码(applicationssamplewifi-iotappiothardwareled_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灯的全局变量,方便其他程序引用。
- <div>enum LedState {</div><div> LED_ON = 0,</div><div> LED_OFF,</div><div> LED_SPARK,</div><div>};</div>
- <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添加刚刚定义的头文件目录
- <div>static_library("led_example") {</div><div> sources = [</div><div> "led_example.c"</div><div> ]</div>
- <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文件修改成如下内容。
- <div>#include <stdio.h></div>
- <div>#include <unistd.h></div>
- <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>
- <p>#include "hardware_config.h"</p><p>
- </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>
- <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>
- <div> return NULL;</div><div>}</div>
- <div>static void LedExampleEntry(void)</div><div>{</div><div> osThreadAttr_t attr;</div>
- <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>
- <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>
- <div> if (osThreadNew((osThreadFunc_t)LedTask, NULL, &attr) == NULL) {</div><div> printf("[LedExample] Falied to create LedTask!n");</div><div> }</div><div>}</div>
- <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复制到applicationssamplewifi-iotappiothardware目录下。然后我们在oled.c头文件定义部分添加以下内容:
- <div>#include "ohos_init.h"</div><div>#include "cmsis_os2.h"</div>
- <div>#include "wifiiot_i2c.h"</div><div>#include "wifiiot_i2c_ex.h"</div>
复制代码
接下来,我们将oled.c源程序中I2C部分调用内容替换成以下内容。(其实就是用鸿蒙定义好的标准接口函数和参数替换掉原有函数)。
- <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>
- <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! =====rn", status);</div><div> return status;</div><div> }</div>
- <div> return 0;</div><div>}</div>
- <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>
- <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>
- <div> my_i2c_write(WIFI_IOT_I2C_IDX_0, 0x78, 2);</div><div>}</div>
复制代码
以及最后初始化I2C部分,在文件最末端。
- <div>void my_oled_demo(void)</div><div>{</div><div> //初始化</div><div> I2cInit(WIFI_IOT_I2C_IDX_0, 100000); /* baudrate: 100000 */</div>
- <div> led_init();</div>
- <div> OLED_ColorTurn(0); //0正常显示,1 反色显示</div><div> OLED_DisplayTurn(0); //0正常显示 1 屏幕翻转显示</div>
- <div> OLED_ShowString(8, 16, "hello world", 16);</div>
- <div> OLED_Refresh();</div><div>}</div><div>#endif</div>
- <div>SYS_RUN(my_oled_demo);</div>
复制代码
===========================================================================================
除了修改源码外,我们还需要修改WiFiIoT的io初始化文件,vendorhisihi3861hi3861appwifiiot_appinitapp_io_init.c
将其中I2C引脚定义部分内容修改为以下内容。
- <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文件:vendorhisihi3861hi3861buildconfigusr_config.mk,启用I2C功能
添加一行I2C功能支持宏定义
这样,就基本上完成OLED部分的测试功能了,我们可以编译源码后烧录到板子上看一下
显示效果如下图。
3、学习 Harmony OS 的 线程调度功能
其实我们在学习led点灯的时候,就已经使用了Harmony OS的线程功能。现在我们可以查看一下线程功能的源码,看看到底有什么。我们可以看到,在app目录的头文件区域,都包含有以下内容
查找了一下源码(在命令行运行 find -name cmsis_os2.h),我们找到一个有意思的文件。
- <p>kernelliteos_mcomponentscmsis2.0cmsis_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>
- <div> if (OS_INT_ACTIVE) {</div><div> return NULL;</div><div> }</div>
- <div> if ((attr == NULL) || (func == NULL) || (attr->priority < osPriorityLow1) ||</div><div> (attr->priority > osPriorityAboveNormal6)) {</div><div> return (osThreadId_t)NULL;</div><div> }</div>
- <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>
- <div> uwRet = LOS_TaskCreate(&uwTid, &stTskInitParam);</div>
- <div> if (LOS_OK != uwRet) {</div><div> return (osThreadId_t)NULL;</div><div> }</div>
- <div> pstTaskCB = OS_TCB_FROM_TID(uwTid);</div>
- <div> return (osThreadId_t)pstTaskCB;</div><div>}</div></div>
复制代码在这段代码里,我们不难看出,其实最终调用的还是LiteOS的标准LOS_TaskCreate函数,并且仔细看一下函数,是可以传递参数的。我们在LiteOS官网可以找到对应线程部分的教程代码,并依葫芦画瓢,把Led模块的代码优化一下,通过传递LedSet结构体的形式,复用线程定义函数,这样我们的代码可以更简洁,更简单一些。
- <div><div>typedef struct LedSet</div><div>{</div><div> /* data */</div><div> enum LedState state;</div><div> enum WifiIotIoName pin;</div><div>};</div>
- <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灯了。
- <div> green_led.state = LED_OFF;</div><div> green_led.pin = WIFI_IOT_IO_NAME_GPIO_10;</div>
- <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内容,将服务器信息,设备端信息等独立出来
- <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>
- <div>#define publishTopic "$oc/devices/5fc9a576b4ec2202e9a32615_testDevice/sys/messages/up"</div>
- <div>void mqtt_test(void);</div>
- <div>#endif /* __MQTT_TEST_H__ */</div>
复制代码
mqtt.c实现内容
- <div>#include <stdio.h></div>
- <div>#include <unistd.h></div>
- <div>#include "ohos_init.h"</div><div>#include "cmsis_os2.h"</div>
- <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>
- <div>#include "lwip/sockets.h"</div>
- <div>#include "MQTTPacket.h"</div><div>#include "transport.h"</div><div>#include "mqtt.h"</div>
- <div>int toStop = 0;</div>
- <div>int mqtt_connect(void)</div><div>{</div>
- <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>
- <div> mysock = transport_open(host, port);</div><div> if (mysock < 0)</div><div> return mysock;</div>
- <div> printf("Sending to hostname %s port %dn", host, port);</div>
- <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>
- <div> len = MQTTSerialize_connect(buf, buflen, &data);</div><div> rc = transport_sendPacketBuffer(mysock, buf, len);</div>
- <div> /* wait for connack */</div><div> if (MQTTPacket_read(buf, buflen, transport_getdata) == CONNACK)</div><div> {</div><div> unsigned char sessionPresent, connack_rc;</div>
- <div> if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) != 1 || connack_rc != 0)</div><div> {</div><div> printf("Unable to connect, return code %dn", 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 %.*sn", payloadlen_in, payload_in);</div>
- <div> rc = rc;</div><div> }</div>
- <div> printf("publishing device messagen");</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>
- <div> printf("disconnectingn");</div><div> len = MQTTSerialize_disconnect(buf, buflen);</div><div> rc = transport_sendPacketBuffer(mysock, buf, len);</div><div>exit:</div><div> transport_close(mysock);</div>
- <div> rc = rc;</div>
- <div> return 0;</div><div>}</div>
- <div>void mqtt_test(void)</div><div>{</div><div> mqtt_connect();</div><div>}</div>
复制代码5、使用 Harmony OS 的 KV 组件实现本地数据存储
6、使用 Harmony OS 的 RTC 实时时钟功能实现定时管理
使用lwip的精简校时功能third_partylwipsrcappssntpsntp.c
功能未经测试,udp_recv函数未实现
- <div>#include <stdio.h></div><div>#include <string.h></div><div>#include "ohos_init.h"</div><div>#include "cmsis_os2.h"</div>
- <div>#include "sntp.h"</div><div>#include "sntp_opts.h"</div><div>#include "hi_time.h"</div>
- <div>uint32_t sntp_time;</div>
- <div>void init_sntp(void)</div><div>{</div><div> uint32_t time = hi_get_real_time();</div>
- <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>
- <div>void sntp_init(void)</div><div>{</div><div> SNTP_RESET_RETRY_TIMEOUT();</div>
- <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>
- <div> //有数据,处理接收数据,同步到本地,由sntp_recv处理。</div><div> udp_recv(sntp_pcb, sntp_set_time, NULL);</div><div> sntp_request(NULL);</div><div> }</div><div>}</div>
- <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>
- <div> print_log("sntp_set_time: c00, enter!n");</div><div> print_log("sntp_set_time: c01, get time = %un", sntp_time);</div>
- <div> struct tm *time;</div><div> struct tm *sTime;</div>
- <div> sntp_time += (8 * 60 * 60); ///北京时间是东8区需偏移8小时</div>
- <div> time = localtime(&sntp_time);</div><div> /*</div><div> * 设置 RTC 的 时间</div><div> */</div>
- <div> hi_set_real_time(time);</div>
- <div> print_log("sntp_set_time: c02, decode time: 20%d-%02d-%02d %d:%d:%dn",</div><div> time->tm_year, time->tm_mon, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec);</div>
- <div> print_log("sntp_set_time: c03, test get = %un", get_timestamp());</div><div> print_log("sntp_set_time: c04, set rtc time donen");</div><div>}</div>
复制代码作者:忙碌的死龙