.ACE彭洪权 · 2022年01月14日

【XR806开发板试用】XR806在U8G2上增加MQTT+JSON控制

一、前言

  1. U8G2移植参见之前写的文章 https://aijishu.com/a/1060000...
  2. 本次增加MQTT+JSON是站在大佬的肩膀上,参见 https://aijishu.com/a/1060000...
  3. CJSON的使用,参见 https://blog.csdn.net/fengxin...

二、成果

  1. 目录结构:目录2.png
  2. test_mqtt.c 基本上照搬大佬的代码,内容如下:

    #include <stdio.h>
    #include <string.h>
    #include "ohos_init.h"
    #include "kernel/os/os.h"
    
    #include "wifi_device.h"
    #include "common/framework/net_ctrl.h"
    #include "net/mqtt/MQTTClient-C/MQTTClient.h"
    #include "cjson/cJSON.h"
    
    static OS_Thread_t g_main_thread;
    static OS_Thread_t g_mqtt_thread;
    
    #define PWM_OUTPUT_CHL        PWM_GROUP1_CH2
    #define PWM_OUTPUT_MODE       PWM_CYCLE_MODE
    
    #define WIFI_DEVICE_CONNECT_AP_SSID "TP-LINK_EEF3" /* 这里填你家路由器的SSID */
    #define WIFI_DEVICE_CONNECT_AP_PSK "13677668125"  /* 这里填你家路由器的PWD */
    
    
    #define MQTT_DEMO_CLIENT_ID "12345"
    #define MQTT_DEMO_HOST_NAME "broker-cn.emqx.io" /* 这个是免费调试用的MQTT服务器地址 */
    #define MQTT_DEMO_PORT      "1883"
    #define MQTT_DEMO_USERNAME  "12345678"
    #define MQTT_DEMO_PASSWORD  "12345678"
    #define MQTT_RESP_TOPIC "/to/weixin/display" /* 设备发出来的TOPIC */
    #define MQTT_RECV_TOPIC  "/to/xr806/display" /* 手机发出来的TOPIC */
    #define MQTT_DEMO_BUF_SIZE (2*1024)
    
    static MQTTPacket_connectData mqtt_demo_connectData = MQTTPacket_connectData_initializer;
    static Client mqtt_demo_client;
    static Network mqtt_demo_network;
    static int max_duty_ratio = 0;
    
    static int mqtt_demo_publish(char *topic, char *msg) ;
    
    void test_set_str(uint8_t *pstr, uint8_t plen);
    
    static int mqtt_demo_init(void)
    {
     char *send_buf;
     char *recv_buf;
    
     mqtt_demo_connectData.clientID.cstring = MQTT_DEMO_CLIENT_ID;
     mqtt_demo_connectData.keepAliveInterval = 30; /* 30s */
     mqtt_demo_connectData.cleansession = 0;
     mqtt_demo_connectData.MQTTVersion = 4; /* Version of MQTT 3.1.1 */
    
     send_buf = malloc(MQTT_DEMO_BUF_SIZE);
     if (send_buf == NULL)
     {
         printf("no memory\n");
         return -1;
     }
     recv_buf = malloc(MQTT_DEMO_BUF_SIZE);
     if (recv_buf == NULL)
     {
         free(send_buf);
         printf("no memory\n");
         return -1;
     }
    
     /* init network */
     NewNetwork(&mqtt_demo_network);
     /* init mqtt client object */
     MQTTClient(&mqtt_demo_client, &mqtt_demo_network, 6000,
                (unsigned char *)send_buf, MQTT_DEMO_BUF_SIZE,
                (unsigned char *)recv_buf, MQTT_DEMO_BUF_SIZE);
    
     /* set username and password */
     mqtt_demo_connectData.username.cstring = MQTT_DEMO_USERNAME;
     mqtt_demo_connectData.password.cstring = MQTT_DEMO_PASSWORD;
     return 0;
    }
    
    static int mqtt_demo_connect(char *host_name, char *host_port)
    {
     int ret = -1;
    
     ret = ConnectNetwork(&mqtt_demo_network, host_name, atoi(host_port));
     if (ret != 0) {
         printf("mqtt connect faild, ret:%d, host:%s, port:%s\n", ret, host_name, host_port);
         goto exit;
     }
    
     ret = MQTTConnect(&mqtt_demo_client, &mqtt_demo_connectData);
     if (ret != 0) {
         printf("mqtt connect faild, ret:%d\n", ret);
         mqtt_demo_network.disconnect(&mqtt_demo_network);
         goto exit;
     }
     printf("mqtt connected\n");
    exit:
     return ret;
    }
    
    static void mqtt_demo_msg_cb(MessageData *data)
    {
     printf("get a message, topic: %.*s, msg: %.*s\n", data->topicName->lenstring.len,
            data->topicName->lenstring.data, data->message->payloadlen,
            (char *)data->message->payload);
     if(!strncmp(data->topicName->lenstring.data, MQTT_RECV_TOPIC, 15) && data->message->payloadlen)
     {
         char *payload = data->message->payload;
    
         cJSON *root;
         cJSON *json_display;
         root = cJSON_Parse(payload);
         if (root)
         {
             json_display = cJSON_GetObjectItem(root, "display");
    
             if (json_display)
             {
                 printf("mqtt display!\r\n");
                 test_set_str(json_display->valuestring, strlen(json_display->valuestring));
    
                 cJSON * usr;
    
                 usr  = cJSON_CreateObject();   /* 创建根数据对象 */
                 cJSON_AddStringToObject(usr, "msg", "success");  /* 加入键值,加字符串 */
    
                 char *out = cJSON_Print(usr);   //将json形式打印成正常字符串形 */
                 printf("%s\n", out);
    
                 mqtt_demo_publish(MQTT_RESP_TOPIC, out);
    
                 /* 释放内存 */
                 cJSON_Delete(usr);
             }
    
             cJSON_Delete(root);  /* 释放内存 */
         }
     }
    }
    
    static int mqtt_demo_subscribe(char *topic)
    {
     int ret = -1;
     if (mqtt_demo_client.isconnected) {
         ret = MQTTSubscribe(&mqtt_demo_client, topic, 0, mqtt_demo_msg_cb);
         if (ret != 0)
             printf("mqtt subscribe faild ret:%d\n", ret);
     }
     return ret;
    }
    
    static int mqtt_demo_unsubscribe(char *topic)
    {
     int ret = -1;
     if (mqtt_demo_client.isconnected)
     {
         ret = MQTTUnsubscribe(&mqtt_demo_client, topic);
         if (ret != 0)
             printf("mqtt unsubscribe faild, ret:%d\n", ret);
     }
     return ret;
    }
    
    static int mqtt_demo_publish(char *topic, char *msg)
    {
     int ret = -1;
    
     MQTTMessage message;
     memset(&message, 0, sizeof(message));
     message.qos = 0;
     message.retained = 0; /* disable retain the message in server */
     message.payload = msg;
     message.payloadlen = strlen(msg);
     ret = MQTTPublish(&mqtt_demo_client, topic, &message);
     if (ret != 0)
         printf("mqtt publish faild, ret:%d\n", ret);
     return ret;
    }
    
    static int mqtt_demo_disconnect(void)
    {
     int ret = -1;
    
     if (mqtt_demo_client.isconnected) {
         ret = MQTTDisconnect(&mqtt_demo_client);
         if (ret != 0)
             printf("mqtt disconnect fail, ret:%d\n", ret);
         mqtt_demo_network.disconnect(&mqtt_demo_network);
     }
     return ret;
    }
    
    static void mqtt_demo_deinit(void)
    {
     if (mqtt_demo_client.buf) {
         free(mqtt_demo_client.buf);
         mqtt_demo_client.buf = NULL;
     }
     if (mqtt_demo_client.readbuf) {
         free(mqtt_demo_client.readbuf);
         mqtt_demo_client.readbuf = NULL;
     }
    }
    
    static void mqtt_task(void *arg)
    {
     int ret;
     int reconnect_times = 0;
    
     mqtt_demo_init();
    
     ret = mqtt_demo_connect(MQTT_DEMO_HOST_NAME, MQTT_DEMO_PORT);
     if (ret != 0)
         goto exit;
    
     ret = mqtt_demo_subscribe(MQTT_RECV_TOPIC);
     if (ret != 0)
         goto exit;
    
     mqtt_demo_publish(MQTT_RESP_TOPIC, "mqtt ready");
    
     while (1)
     {
         ret = MQTTYield(&mqtt_demo_client, 300);
         if (ret != 0)
         {
             printf("mqtt yield err, ret:%d\n", ret);
    reconnect:
             printf("mqtt reconnect\n");
             mqtt_demo_disconnect();
             ret = mqtt_demo_connect(MQTT_DEMO_HOST_NAME, MQTT_DEMO_PORT);
             if (ret != 0)
             {
                 reconnect_times++;
                 if (reconnect_times > 5)
                     goto exit;
                 OS_MSleep(5000); //5s
                 goto reconnect;
             }
         }
     }
    
    exit:
     mqtt_demo_unsubscribe(MQTT_RECV_TOPIC);
     mqtt_demo_disconnect();
     mqtt_demo_deinit();
     OS_ThreadDelete(&g_mqtt_thread);
    }
    
    static void net_cb(uint32_t event, uint32_t data, void *arg)
    {
     uint16_t type = EVENT_SUBTYPE(event);
     switch (type)
     {
     case NET_CTRL_MSG_NETWORK_UP:
         printf("NET_CTRL_MSG_NETWORK_UP\n");
         if (!OS_ThreadIsValid(&g_mqtt_thread))
         {
             OS_ThreadCreate(&g_mqtt_thread, "connect_to_server_task",
                                 mqtt_task, (void *)NULL,  OS_THREAD_PRIO_APP, (8 * 1024));
         }
         break;
     case NET_CTRL_MSG_NETWORK_DOWN:
         break;
     default:
         break;
     }
    }
    
    static void MainThread(void *arg)
    {
     printf("Mqtt start\r\n");
    
     if (WIFI_SUCCESS != EnableWifi())
     {
         printf("Error: EnableWifi fail\n");
         return;
     }
    
     OS_Sleep(1);
    
     if (WIFI_SUCCESS != Scan())
     {
         printf("Error: Scan fail.\n");
         return;
     }
    
     OS_Sleep(3); /* 这里为了方便用延时,实际用回调更好,否则3秒可能不够 */
    
     const char ssid_want_connect[] = WIFI_DEVICE_CONNECT_AP_SSID;
     const char psk[] = WIFI_DEVICE_CONNECT_AP_PSK;
     WifiScanInfo scan_results[30];
     unsigned int scan_num = 30;
    
     if (WIFI_SUCCESS != GetScanInfoList(scan_results, &scan_num))
     {
         printf("Error: GetScanInfoList fail.\n");
         return;
     }
    
     WifiDeviceConfig config = { 0 };
     int netId = 0;
    
     int i;
     for (i = 0; i < scan_num; i++)
     {
         printf("ssid: %s    ", scan_results[i].ssid);
         printf("securityType: %d\n", scan_results[i].securityType);
         if (0 == strcmp(scan_results[i].ssid, ssid_want_connect))
         {
             memcpy(config.ssid, scan_results[i].ssid,
                    WIFI_MAX_SSID_LEN);
             memcpy(config.bssid, scan_results[i].bssid,
                    WIFI_MAC_LEN);
             strcpy(config.preSharedKey, psk);
             config.securityType = scan_results[i].securityType;
             config.wapiPskType = WIFI_PSK_TYPE_ASCII;
             config.freq = scan_results[i].frequency;
             break;
         }
     }
    
     if (i >= scan_num)
     {
         printf("Error: No found ssid in scan_results\n");
         return;
     }
    
     if (WIFI_SUCCESS != AddDeviceConfig(&config, &netId))
     {
         printf("Error: AddDeviceConfig Fail\n");
         return;
     }
     printf("Config Success\n");
    
     if (WIFI_SUCCESS != ConnectTo(netId))
     {
         printf("Error: ConnectTo Fail\n");
         return;
     }
    
     observer_base *net_ob;
     net_ob = sys_callback_observer_create(CTRL_MSG_TYPE_NETWORK, NET_CTRL_MSG_ALL, net_cb, NULL);
     if (net_ob == NULL)
         return;
    
     if (sys_ctrl_attach(net_ob) != 0)
         return;
    
     while (1)
     {
         OS_MSleep(500);
     }
    }
    
    void LEDMain(void)
    {
     if (OS_ThreadCreate(&g_main_thread, "MainThread", MainThread, NULL, OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK) {
         printf("[ERR] Create MainThread Failed\n");
     }
    }
  3. main.c内容如下:

    #include <stdio.h>
    #include "ohos_init.h"
    #include "kernel/os/os.h"
    #include "test_i2c.h"
    #include  "test_mqtt.h"
    #include "iot_i2c.h"
    #include "oled.h"
    #include "u8g2.h"
    
    static OS_Thread_t g_main_thread;
    static uint8_t status=  0;
    static uint8_t str[8] = {0};
    
    uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
    uint8_t u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr);
    void delay_ms(uint32_t ms);
    
    void test_set_str(uint8_t *pstr, uint8_t plen)
    {
     uint8_t vi;
    
     status = 1;
    
     for (vi = 0; vi < plen; vi++)
     {
         str[vi] = pstr[vi];
     }
     str[vi] = 0;
    }
    
    static void MainThread(void *arg)
    {
     u8g2_t u8g2;
    
     IotI2CTest();
    
     u8g2_Setup_sh1106_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_hw_i2c, u8g2_gpio_and_delay_stm32);
     //u8g2_InitDisplay(&u8g2);
     u8g2_SetPowerSave(&u8g2, 0);
     u8g2_ClearDisplay(&u8g2);
     u8g2_SetFont(&u8g2, u8g2_font_wqy16_t_chinese1);
     u8g2_DrawCircle(&u8g2, 55, 30,  5,  U8G2_DRAW_ALL);
     u8g2_DrawCircle(&u8g2, 65, 30,  5,  U8G2_DRAW_ALL);
     u8g2_DrawCircle(&u8g2, 75, 30,  5,  U8G2_DRAW_ALL);
     u8g2_DrawUTF8(&u8g2, 20, 50, "你好, XR806!");
     u8g2_SendBuffer(&u8g2);
    
     while (1)
     {
         if (status == 1)
         {
             status = 0;
             printf("u8g2 display:%s\r\n", str);
             memset(u8g2.tile_buf_ptr, 0, 128*24/8);
             u8g2_DrawUTF8(&u8g2, 20, 20, str);
             u8g2_SendBuffer(&u8g2);
         }
    
         printf("hello world!\n");
         LOS_Msleep(1000);
     }
    }
    
    uint8_t u8g2_gpio_and_delay_stm32(U8X8_UNUSED u8x8_t *u8x8, U8X8_UNUSED uint8_t msg, U8X8_UNUSED uint8_t arg_int, U8X8_UNUSED void *arg_ptr)
    {
     switch(msg)
     {
     case U8X8_MSG_GPIO_AND_DELAY_INIT:
     break;
    
     case U8X8_MSG_DELAY_MILLI:
         delay_ms(arg_int);
     break;
    
     default:
         return 0;
     }
     return 1;
    }
    
    uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
    {
     static uint8_t buffer[131];        /* u8g2/u8x8 will never send more than 32 bytes between START_TRANSFER and END_TRANSFER */
     static uint8_t buf_idx;
     uint8_t *data;
    
     switch(msg)
     {
     case U8X8_MSG_BYTE_SEND:
         data = (uint8_t *)arg_ptr;
         while( arg_int > 0 )
         {
         buffer[buf_idx++] = *data;
         data++;
         arg_int--;
         }
     break;
    
     case U8X8_MSG_BYTE_INIT:
         /* add your custom code to init i2c subsystem */
     break;
    
     case U8X8_MSG_BYTE_START_TRANSFER:
         buf_idx = 0;
     break;
    
     case U8X8_MSG_BYTE_END_TRANSFER:
         if (buf_idx != 132)
         {
             for (uint8_t i = 0; i < buf_idx; i++)
             {
                 OLED_WR_Byte(buffer[i], OLED_CMD);
             }
         }
         else
         {
             for (uint8_t i = 1; i < 4; i++)
             {
                 OLED_WR_Byte(buffer[i], OLED_CMD);
             }
    
             for (uint8_t i = 4; i < buf_idx; i++)
             {
                 OLED_WR_Byte(buffer[i], OLED_DATA);
             }
         }
     break;
    
     default:
         return 0;
     }
     return 1;
    }
    
    void delay_ms(uint32_t ms)
    {
     uint16_t i,  j;
    
     for (i = 0; i < ms; i++)
     {
         for (j = 0; j < 10; j++)
         {
             __asm("nop");
         }
     }
    }
    
    void HelloTestMain(void)
    {
     if (OS_ThreadCreate(&g_main_thread, "MainThread", MainThread, NULL,
                 OS_THREAD_PRIO_APP, 4 * 1024) != OS_OK) {
         printf("[ERR] Create MainThread Failed\n");
     }
    
     LEDMain();
    }
    
    SYS_RUN(HelloTestMain);
  4. 这里说明一个很奇怪的现象,u8g2_t u8g2;这个变量我改为全局静态变量后,LCD显示内容不对,会出现硬件错误并重启MCU,所以我把u8g2部分代码移动到main.c,通过全局的标志来刷新显示,这一点有待完善,应该使用系统队列来完成此操作。
  5. 效果展示,不知道怎么把图片旋转,知道的留言告诉我,谢谢。效果3.jpg效果2.jpg

    三、结束语

    文章只是初次尝试,实际项目还需要很多的优化,不过使用这个芯片开发感觉还是很迅速,并且有大佬在前方引路还是很奈斯的。

推荐阅读
关注数
13823
内容数
139
全志XR806开发板相关的知识介绍以及应用专栏。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息