LV01-01-AliOSThings-12-任务间通信-09-消息队列使用实例

本文主要是任务之间的通信——消息队列使用实例的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows版本 windows11
Ubuntu版本 Ubuntu22.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license))
点击查看本文参考资料
分类 网址 说明
官方网站 阿里云 阿里云官网主页
阿里生活物联平台 生活物联网平台(飞燕平台)主页
AliGenie 天猫精灵开放平台AliGenie主页
阿里物联网平台 阿里物联网平台主页
Bluetooth 技术网站 蓝牙协议规范什么的可以来这里找
Telink Telink | Chips for a Smarter IoT (telink-semi.com)
Telink中文官网
开发手册 AliOS Things开发指南 AliOS Things开发指南,这里是最新版本,可以直接从官网找到
AliOS Things开发指南 AliOS Things应用开发指南,这里应该是3.3版本的完整开发文档
AliOS Things开发指南(3.0) AliOS Things应用开发指南,这里应该是3.0版本的完整开发文档
生活物联网平台开发文档 生活物联网平台(飞燕平台)开发文档
《设备端开发指南》
Wi-Fi IoT品类定义与功能开发 天猫精灵IoT开放平台——Wi-Fi IoT品类定义与功能开发
硬件平台 mk3080 WiFi开发板 WiFi开发板使用指南-阿里云开发者社区
esp8266开发板 一个教程:ESP8266-NodeMCU开发板详解-太极创客 (taichi-maker.com)
TLSR8258 Datasheet Datasheet for Telink BLE + IEEE802.15.4 MultiStandard Wireless SoC TLSR8258
参考资料 AliOS Things 3.0 应用开发指南 这个只是一篇参考文章,里面是一些环境搭建相关的,可以参考
IP知识百科 - 华为 (huawei.com) IP的一些相关知识点
点击查看相关文件下载
分类 网址 说明
蓝牙规范相关文档 Core Specification 5.2 核心规格 5.2,该规范定义了创建可互操作的Bluetooth 设备所需的技术。
《Core_v5.2.pdf》
Mesh Model(v1.1) 本Bluetooth 规范定义了模型(以及它们所需的状态和消息),这些模型用于在mesh 网络中的节点上执行基本功能,超出了Bluetooth Mesh 配置文件 规范中定义的基础模型。
本规范包括定义跨设备类型标准功能的通用模型,以及支持关键mesh 场景的模型,如照明控制、传感器、时间和场景。
《MshMDL_v1.1.pdf》
Mesh Profile(v1.0.1) 该Bluetooth 规范定义了基本要求,以实现可互操作的mesh 网络解决方案,用于Bluetooth 低能量无线技术。
《MshPRFv1.0.1.pdf》
Mesh Device Properties 本规范包含Bluetooth Mesh 配置文件 和Bluetooth Mesh 模型规范所要求的设备属性的定义。
但是跟之前的有些区别,我主要看的之前的版本:《MMeshDeviceProperties_v1.2.pdf》
GATT Specification Supplement GATT Specification Supplement | Bluetooth® Technology Website。
好像可以在线看:《GATT Specification Supplement》
Assigned Numbers GATT的一些类型定义可以在这里找。
AliOS Things alios-things/AliOS-Things Gitee上的AliOSThings SDK源码仓库
alibaba/AliOS-Things GitHub上的AliOSThings SDK源码仓库
天猫精灵蓝牙Mesh协议栈 alibaba-archive/genie-bt-mesh-stack GitHub上的天猫精灵蓝牙Mesh协议栈源码仓库。
之前是在alibaba/genie-bt-mesh-stack这个仓库。
写笔记的时候最新提交为faf523618a6a2560090fc423222b9db80984bb7a
蓝牙Mesh设备开发指南 阿里云生活服务平台开发手册——蓝牙设备开发一节中的内容

一、按键状态识别功能

1. 需求分析

我们现在想要通过消息队列来实现按键的单击、双击和长按的识别。该怎么做?

2. 怎么判断按键的信息的种类

判断按键信息的种类

总的来说就是根据按下的时间长短来区分长按还是短按,在一定时间内再检测按键次数来判断是单击还是双击。

3. 检测按键延时

写代码检测按键延时

如何检测按键各个时间?我们可以通过ulog组件的打印来实现。

4. 按键时间检测

4.1 使用实例

以下是源码,也可以看这里:helloworld_mk3080/example/04_queue_key_test.c · sumumm/AliOS-Things-Prj - 码云 - 开源中国 (gitee.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/** =====================================================
* Copyright © hk. 2022-2025. All rights reserved.
* File name : 04_queue_key.c
* Author : 上上签
* Date : 2023-12-06
* Version :
* Description:
* ======================================================
*/

#include <stdio.h>
#include <stdlib.h>
#include <aos/kernel.h>
#include "aos/init.h"
#include "board.h"
#include <k_api.h>
#include "aos/hal/gpio.h"
#include "ulog/ulog.h"

#define RED_LED 0 // PA14
#define GRE_LED 1 // PA15

#define KEY1_PORT 8 // PA5
#define KEY2_PORT 2 // PA22
#define KEY3_PORT 4 // PA23

#define TASK_KEY_NAME "task_key"
#define TASK_QUEUE_NAME "task_queue"
#define MOUDLE_NAME "key_led_queue"

#define MAX_QUEUE_LEN 10
static uint32_t key_queue_arr[MAX_QUEUE_LEN] = {0};
static aos_queue_t key_queue;

aos_task_t task1_handle;
aos_task_t task2_handle;

gpio_dev_t led_gpio_dev[2] = {0};
gpio_dev_t key_gpio_dev;
uint32_t key_value;

void task_key_entry(void *arg)
{
int ret = 0;
const char * task_name;
task_name = aos_task_name();
while(1)
{
hal_gpio_input_get(&key_gpio_dev, &key_value);
if(!key_value)
{
//延时去抖动
aos_msleep(10);
//再次判断是否按下
hal_gpio_input_get(&key_gpio_dev, &key_value);
if(!key_value)
{
LOGI(MOUDLE_NAME, "[%s]key is down!send key down message", task_name);
ret = aos_queue_send(&key_queue, &key_value, sizeof(key_value));
if(ret != 0)
{
LOGE(MOUDLE_NAME, "queue send error");
}
//等待按键松开
do{
hal_gpio_input_get(&key_gpio_dev, &key_value);
aos_msleep(10);
}while(!key_value);
LOGI(MOUDLE_NAME, "[%s]key is up!send key up message", task_name);
ret = aos_queue_send(&key_queue, &key_value, sizeof(key_value));
if(ret != 0)
{
LOGE(MOUDLE_NAME, "queue send error");
}
}
}
//10ms 读取一次按键状态
aos_msleep(10);
}

}

void task_queue_entry(void *arg)
{
int ret = 0;
uint32_t message[MAX_QUEUE_LEN] = {0};
int size = 0;
const char * task_name;
task_name = aos_task_name();
while(1)
{
ret = aos_queue_recv(&key_queue, AOS_WAIT_FOREVER, message, &size);
if(ret == 0)
{
LOGI(MOUDLE_NAME, "[%s]recv message is %d", task_name, message[0]);
}
}

}
int led_init(void)
{
//由于PA14时rtl8710的jtag接口,我要使用GPIO功能,必须先关闭jtag借口
sys_jtag_off();
led_gpio_dev[0].port = RED_LED;
led_gpio_dev[0].config = OUTPUT_PUSH_PULL;
led_gpio_dev[0].priv = NULL;
//gpio PA14初始化
hal_gpio_init(&led_gpio_dev[0]);

led_gpio_dev[1].port = GRE_LED;
led_gpio_dev[1].config = OUTPUT_PUSH_PULL;
led_gpio_dev[1].priv = NULL;
//gpio PA14初始化
hal_gpio_init(&led_gpio_dev[1]);

return 0;
}

int key_init(void)
{
key_gpio_dev.port = KEY1_PORT;
//根据原理图分析配置位输入上拉模式
key_gpio_dev.config = INPUT_PULL_UP;
key_gpio_dev.priv = NULL;
//key 初始化
hal_gpio_init(&key_gpio_dev);

return 0;
}

int application_start(int argc, char *argv[])
{
int ret = 0;
int index = 0;

led_init();
key_init();
aos_set_log_level(AOS_LL_INFO);

//创建任务
ret = aos_task_new(TASK_KEY_NAME, task_key_entry, NULL, 8*128);
if(ret != 0)
{
LOGE(MOUDLE_NAME, "task key new error");
}
ret = aos_task_new(TASK_QUEUE_NAME, task_queue_entry, NULL, 8*128);
if(ret != 0)
{
LOGE(MOUDLE_NAME, "task queue new error");
}

//创建消息队列
ret = aos_queue_new(&key_queue, key_queue_arr, sizeof(key_queue_arr), sizeof(uint32_t));
if(ret != 0)
{
LOGE(MOUDLE_NAME, "queue new error");
}

while(1)
{
aos_msleep(1000);
hal_gpio_output_toggle(&led_gpio_dev[1]);
}

}

4.2 测试结果

下面的打印信息跟代码可能有些不同,因为代码我改过了,但是原理是一样的。但是和双击或者长按之间的时间间隔对于不同的按键可能是不同的,我们测试一下就知道了,灵活调整即可。

4.2.1 单击

image-20200812155447754

4.2.2 双击

image-20200812155639807

4.2.3 长按

image-20200812155806460

5. 短按长按区分?

检测短击还是长按

那我们如何获取CPU的时间?其实AliOSThings为我们提供了一个接口:

image-20200812164210616

6. 双击检测?

5

二、功能实现

1. 使用实例

完整源码如下,也可以看这里:helloworld_mk3080/example/04_queue_key.c · sumumm/AliOS-Things-Prj - 码云 - 开源中国 (gitee.com)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/** =====================================================
* Copyright © hk. 2022-2025. All rights reserved.
* File name : 04_queue_key.c
* Author : 上上签
* Date : 2023-12-06
* Version :
* Description:
* ======================================================
*/

#include <stdio.h>
#include <stdlib.h>
#include <aos/kernel.h>
#include "aos/init.h"
#include "board.h"
#include <k_api.h>
#include "aos/hal/gpio.h"
#include "ulog/ulog.h"

#define RED_LED 0 // PA14
#define GRE_LED 1 // PA15

#define KEY1_PORT 8 // PA5
#define KEY2_PORT 2 // PA22
#define KEY3_PORT 4 // PA23

#define TASK_KEY_NAME "task_key"
#define TASK_QUEUE_NAME "task_queue"
#define MOUDLE_NAME "key_led_queue"

#define MAX_QUEUE_LEN 10
static uint32_t key_queue_arr[MAX_QUEUE_LEN] = {0};
static aos_queue_t key_queue;
const uint32_t key_short = 1;
const uint32_t key_long = 2;

aos_task_t task1_handle;
aos_task_t task2_handle;

gpio_dev_t led_gpio_dev[2] = {0};
gpio_dev_t key_gpio_dev;
uint32_t key_value;

void task_key_entry(void *arg)
{
int ret = 0;
const char * task_name;
long long cpu_ms_value1, cpu_ms_value2;
task_name = aos_task_name();

while(1)
{
hal_gpio_input_get(&key_gpio_dev, &key_value);
if(!key_value)
{
//延时去抖动
aos_msleep(10);
//再次判断是否按下
hal_gpio_input_get(&key_gpio_dev, &key_value);
if(!key_value)
{
//获取按下时cpu的当前时间
cpu_ms_value1 = aos_now_ms();
//等待按键松开
do{

hal_gpio_input_get(&key_gpio_dev, &key_value);
aos_msleep(10);
}while(!key_value);
//获取松开时cpu的当前时间
cpu_ms_value2 = aos_now_ms();
LOGE(MOUDLE_NAME, "[%s]key down --> up time is %ld ms!", task_name, cpu_ms_value2 - cpu_ms_value1);
//是否大于2S
if ((cpu_ms_value2 - cpu_ms_value1) > 2000)
{
ret = aos_queue_send(&key_queue, (void *)&key_long, sizeof(key_long));
if (ret != 0)
{
LOGE(MOUDLE_NAME, "queue send key_long error");
}
}
else
{
ret = aos_queue_send(&key_queue, (void *)&key_short, sizeof(key_short));
if (ret != 0)
{
LOGE(MOUDLE_NAME, "queue send key_short error");
}
}
}
}
//10ms 读取一次按键状态
aos_msleep(10);
}

}

void task_queue_entry(void *arg)
{
int ret = 0;
uint32_t message[MAX_QUEUE_LEN] = {0};
int size = 0;
const char * task_name;
int index = 0;
task_name = aos_task_name();
while (1)
{
index = 0;
ret = aos_queue_recv(&key_queue, AOS_WAIT_FOREVER, &message[index], &size);
if (ret == 0)
{
//短击
if(message[index] == key_short)
{
LOGI(MOUDLE_NAME, "[%s]key is short!", task_name);
index++;
ret = aos_queue_recv(&key_queue, 300, &message[index], &size);
if(ret == 0)
{
if(message[index] == key_short)
{
LOGI(MOUDLE_NAME, "[%s]key is double!", task_name);
}
}
}
//长按
else if(message[index] == key_long)
{
LOGI(MOUDLE_NAME, "[%s]key is long!", task_name);
}
}
}
}
int led_init(void)
{
//由于PA14时rtl8710的jtag接口,我要使用GPIO功能,必须先关闭jtag借口
sys_jtag_off();
led_gpio_dev[0].port = RED_LED;
led_gpio_dev[0].config = OUTPUT_PUSH_PULL;
led_gpio_dev[0].priv = NULL;
//gpio PA14初始化
hal_gpio_init(&led_gpio_dev[0]);

led_gpio_dev[1].port = GRE_LED;
led_gpio_dev[1].config = OUTPUT_PUSH_PULL;
led_gpio_dev[1].priv = NULL;
//gpio PA14初始化
hal_gpio_init(&led_gpio_dev[1]);

return 0;
}

int key_init(void)
{
key_gpio_dev.port = KEY1_PORT;
//根据原理图分析配置位输入上拉模式
key_gpio_dev.config = INPUT_PULL_UP;
key_gpio_dev.priv = NULL;
//key 初始化
hal_gpio_init(&key_gpio_dev);

return 0;
}

int application_start(int argc, char *argv[])
{
int ret = 0;
int index = 0;

led_init();
key_init();
aos_set_log_level(AOS_LL_INFO);

//创建任务
ret = aos_task_new(TASK_KEY_NAME, task_key_entry, NULL, 8*128);
if(ret != 0)
{
LOGE(MOUDLE_NAME, "task key new error");
}
ret = aos_task_new(TASK_QUEUE_NAME, task_queue_entry, NULL, 8*128);
if(ret != 0)
{
LOGE(MOUDLE_NAME, "task queue new error");
}

//创建消息队列
ret = aos_queue_new(&key_queue, key_queue_arr, sizeof(key_queue_arr), sizeof(uint32_t));
if(ret != 0)
{
LOGE(MOUDLE_NAME, "queue new error");
}

while(1)
{
aos_msleep(1000);
hal_gpio_output_toggle(&led_gpio_dev[1]);
}

}

2. 测试结果

我们更新代码后,长按、短按按键,会有以下打印信息:

image-20231206232344404