本文参与极术社区的《基于安谋科技STAR-MC1的XR806开发板试用》活动。
一、例程编译、烧录确认
首先按照全志在线文档平台的点灯教程确保能正常编译、烧录和点灯:https://xr806.docs.aw-ol.com/study/soft_led/
确保例程没问题后,我们再改造例程,实现我们想要的功能
二、代码编写
我们将led工程复制一份改文件夹名为mydemo,目录结构如下
mydemo
├── BUILD.gn
└── src
└── main.c
然后BUILD.gn内容增加头文件引用,部分配置如下:
static_library("app_mydemo") {
...
include_dirs += [
"//kernel/liteos_m/kernel/arch/include",
"//base/iot_hardware/peripheral/interfaces/kits",
".",
"//utils/native/lite/include",
"//foundation/communication/wifi_lite/interfaces/wifiservice",
"//device/xradio/xr806/xr_skylark/project"
]
}
接下来是main.c,内容如下:
#include <stdio.h>
#include <string.h>
#include "ohos_init.h"
#include "kernel/os/os.h"
#include "iot_gpio.h"
#include "wifi_device.h"
#include "common/framework/net_ctrl.h"
#include "net/mqtt/MQTTClient-C/MQTTClient.h"
#include "driver/chip/hal_pwm.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 "ssid"//这里填你家路由器的SSID
#define WIFI_DEVICE_CONNECT_AP_PSK "pwm"//这里填你家路由器的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/master/light" //手机发出来的TOPIC
#define MQTT_RECV_TOPIC "/to/slave/light" //设备发出来的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) ;
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, "/to/slave/light", 15) && data->message->payloadlen) {
char *payload = data->message->payload;
char str[8] = "";
int max_len = data->message->payloadlen > 3 ? 3 : data->message->payloadlen;
strncpy(str, payload, max_len);
int duty = atoi(str);
HAL_Status status = HAL_PWM_ChSetDutyRatio(PWM_OUTPUT_CHL, duty * max_duty_ratio / 100);
if (status != HAL_OK)
printf("%s(): %d, PWM set duty ratio error\n", __func__, __LINE__);
if(duty) {
mqtt_demo_publish(MQTT_RESP_TOPIC, "light on");
} else {
mqtt_demo_publish(MQTT_RESP_TOPIC, "light off");
}
}
}
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, "light 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("MainThread start\r\n");
HAL_Status status = HAL_ERROR;
PWM_ClkParam clk_param;
PWM_ChInitParam ch_param;
clk_param.clk = PWM_CLK_HOSC;
clk_param.div = PWM_SRC_CLK_DIV_1;
status = HAL_PWM_GroupClkCfg(PWM_OUTPUT_CHL, &clk_param);
if (status != HAL_OK)
printf("%s(): %d, PWM group clk config error\n", __func__, __LINE__);
ch_param.hz = 1000;
ch_param.mode = PWM_OUTPUT_MODE;
ch_param.polarity = PWM_HIGHLEVE;
max_duty_ratio = HAL_PWM_ChInit(PWM_OUTPUT_CHL, &ch_param);
if (max_duty_ratio == -1)
printf("%s(): %d, PWM ch init error\n", __func__, __LINE__);
printf("max_duty_ratio=%d\n", max_duty_ratio);
status = HAL_PWM_ChSetDutyRatio(PWM_OUTPUT_CHL, 0);
if (status != HAL_OK)
printf("%s(): %d, PWM set duty ratio error\n", __func__, __LINE__);
status = HAL_PWM_EnableCh(PWM_OUTPUT_CHL, PWM_OUTPUT_MODE, 1);
if (status != HAL_OK)
printf("%s(): %d, PWM ch enable error\n", __func__, __LINE__);
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");
}
}
SYS_RUN(LEDMain);
三、配置上层的BUILD.gn,并编译
部分内容如下:
group("ohosdemo") {
deps = [
#"hello_demo:app_hello",
#"iot_peripheral:app_peripheral",
#"wlan_demo:app_WlanTest",
"mydemo:app_mydemo",
]
}
然后执行hb build -f,编译成功(若编译失败见论坛有解决方案)
然后烧录到开发板上
四、运行实例
烧录完成后,开发板重新上电,输出如下日志
====================================================================
Hello! OpenHarmony!
System tag : OpenHarmony 1.1.2_LTS
====================================================================
use default flash chip mJedec 0x0
[FD I]: mode: 0x10, freq: 96000000Hz, drv: 0
[FD I]: jedec: 0x0, suspend_support: 1
mode select:e
wlan information ===================================================
firmware:
version : R0-XR_C07.08.52.65_02.84 May 27 2021 11:41:33-Y02.84
buffer : 8
driver:
version : XR_V02.05
mac address:
in use : 1c:98:c9:bc:50:01
in use : 1c:98:c9:bc:50:02
====================================================================
wlan mode:a
[VFS INF] LittleFS mount success.
platform information ===============================================
XR806 SDK v1.2.0 Dec 13 2021 13:06:05
heap space [0x2238d0, 0x24bc00), size 164656
cpu clock 160000000 Hz
HF clock 40000000 Hz
sdk option:
XIP : enable
INT LF OSC : enable
SIP flash : enable
mac address:
efuse : 80:74:84:21:38:8e
in use : 1c:98:c9:bc:50:01
====================================================================
hiview init success.MainThread start
max_duty_ratio=40000
console init success
[net INF] no need to switch wlan mode 0
[net INF] msg <wlan scan success>
ssid: TP-LINK_A668 securityType: 2
Config Success
[net INF] no need to switch wlan mode 0
en1: Trying to associate with a4:c7:4b:71:f9:84 (SSID='XXXXXX' freq=2462 MHz)
en1: Associated with a4:c7:4b:71:f9:84
en1: WPA: Key negotiation completed with a4:c7:4b:71:f9:84 [PTK=CCMP GTK=CCMP]
en1: CTRL-EVENT-CONNECTED - Connection to a4:c7:4b:71:f9:84 completed [id=0 id_str=]
[net INF] msg <wlan connected>
[net INF] netif is link up
[net INF] start DHCP...
[net INF] IPv6 addr state change: 0x0 --> 0x1
[net INF] msg <>
[net INF] netif (IPv4) is up
[net INF] address: 192.168.3.48
[net INF] gateway: 192.168.3.1
[net INF] netmask: 255.255.255.0
[net INF] msg <network IPv6 state>
NET_CTRL_MSG_NETWORK_UP
WAR drop=1117, fctl=0x00d0.
mqtt connected
get a message, topic: /to/slave/light, msg: 0
可以看到,开发板成功连接路由器,并接入了MQTT服务器
五、手机测试
本人的手机是Iphone,也不会手机APP开发,于是我们下载了一个叫MQTTTool的第三方APP验证点灯,其界面如下:
Host和Port填对,由于是免费开放的MQTT服务器,其他参数任意,设置好以后点Connect即可连接上MQTT服务器。然后底部切换至Subscribe栏,订阅主题:
若手机比设备先连接服务器并订阅相关主题,那么你会在订阅栏收到topic为/to/master/light的消息:light ready,这是因为设备连上服务器就会发布该topic。
接下来是发布主题,我们往/to/slave/light主题发送一个0~100的数字,就会让设备以这个数字为占空比控制LED灯亮灭,如0表示灭灯,50表示50%的占空比驱动LED灯,100表示100%的占空比驱动LED灯。同时设备收到LED控制指令后,若占空比不为0,则发送消息light on,否则发送消息light off
部分日志如下:
WAR drop=1117, fctl=0x00d0.
mqtt connected
get a message, topic: /to/slave/light, msg: 0
[net INF] IPv6 addr state change: 0x0 --> 0x1
[net INF] msg <>
get a message, topic: /to/slave/light, msg: 100
get a message, topic: /to/slave/light, msg: 100
get a message, topic: /to/slave/light, msg: 50
以上就是一个手机远程给LED进行PWM调光的应用实例