一、前言
- U8G2移植参见之前写的文章 https://aijishu.com/a/1060000...
- 本次增加MQTT+JSON是站在大佬的肩膀上,参见 https://aijishu.com/a/1060000...
- CJSON的使用,参见 https://blog.csdn.net/fengxin...
二、成果
- 目录结构:
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"); } }
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);
- 这里说明一个很奇怪的现象,u8g2_t u8g2;这个变量我改为全局静态变量后,LCD显示内容不对,会出现硬件错误并重启MCU,所以我把u8g2部分代码移动到main.c,通过全局的标志来刷新显示,这一点有待完善,应该使用系统队列来完成此操作。
效果展示,不知道怎么把图片旋转,知道的留言告诉我,谢谢。
三、结束语
文章只是初次尝试,实际项目还需要很多的优化,不过使用这个芯片开发感觉还是很迅速,并且有大佬在前方引路还是很奈斯的。