LV01-01-AliOSThings-12-任务间通信-03-信号量使用实例

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

点击查看使用工具及版本
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. 功能分析

要实现的功能如下:

信号量之按键点灯

有两个任务:

(1)按键任务检测按键是否按下,并释放信号量;

(2)LED任务获取信号量进行LED的翻转。

2. 功能实现

2.1 esp8266

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
/*
* Copyright (C) 2015-2020 Alibaba Group Holding Limited
*/

#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 LED_PORT 16
#define KEY_PORT 0

#define TASK_KEY_NAME "task_key"
#define TASK_LED_NAME "task_led"
#define MOUDLE_NAME "key_led_sem"

aos_sem_t key_led_sem;
gpio_dev_t led_gpio_dev;
gpio_dev_t key_gpio_dev;
uint32_t key_value;

void task_key_entry(void *arg)
{
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)
{
printf("key is down signal \r\n");
aos_sem_signal(&key_led_sem);
//等待按键松开
do{
hal_gpio_input_get(&key_gpio_dev, &key_value);
aos_msleep(10);
}while(!key_value);
}

}
//10ms 读取一次按键状态
aos_msleep(10);
}

}

void task_led_entry(void *arg)
{

int ret;
while(1)
{
ret = aos_sem_wait(&key_led_sem, AOS_WAIT_FOREVER);
printf("led is toggle \r\n");
hal_gpio_output_toggle(&led_gpio_dev);
}

}



int application_start(int argc, char *argv[])
{
int ret;
led_gpio_dev.port = LED_PORT;
led_gpio_dev.config = OUTPUT_PUSH_PULL;
led_gpio_dev.priv = NULL;
//led 初始化
hal_gpio_init(&led_gpio_dev);

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

aos_set_log_level(AOS_LL_INFO);
//创建任务
ret = aos_task_new(TASK_KEY_NAME, task_key_entry, NULL, 4*128);
if(ret != 0)
{

LOGE(MOUDLE_NAME, "task key new error\r\n");

}
ret = aos_task_new(TASK_LED_NAME, task_led_entry, NULL, 4*128);
if(ret != 0)
{

LOGE(MOUDLE_NAME, "task led new error\r\n");

}
//创建信号量
aos_sem_new(&key_led_sem,0);

while(1)
{
aos_msleep(1000);
}

}

2.2 mk3080

这个mk3080的实例可以直接看gitee仓库代码:helloworld_mk3080/example/01_sem_demo.c · sumumm/AliOS-Things-Prj - 码云 - 开源中国 (gitee.com)

2.3 测试结果

然后当我们按下按键的时候,串口就会打印对应的内容,LED也会进行翻转:

image-20231205190844076

二、共享任务池

课程中叫共享线程池,但是在RTOS中,似乎用线程的概念不太合适,感觉叫任务池应该更贴切,但是笔记还是都写的线程池了。

1. 线程池的概念 

线程池

如上图,现在5个任务分别运行着5个app程序,但是这个号死后又来了一个app6,此时线程池中没有空闲的线程来运行这个app6,那么app6就只能处于阻塞状态,当app1运行完毕后,task1空闲,此时可以运行app6,后续再有app7的话,也是一样的流程。

线程池 (1)

2. 线程池功能需求

用户点击一次按键吗,就会有一个任务被唤醒,去处理对应的按键事情。

线程池实现功能需求

当之前的任务未退出的时候,就会唤醒任务池中的空闲任务去执行新的按键时间事件:

线程池实现功能需求 (1)

3. 线程池实现

4. 功能实现

4.1 信号量创建

image-20200806162910412

4.2 任务创建

image-20200806163747761

4.3 线程池管理

image-20200806163415580

4.4 线程池的任务执行

image-20200806163720795

5. 源码实例

5.1 esp8266

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
201
202
203
204
205
/*
* Copyright (C) 2015-2020 Alibaba Group Holding Limited
*/

#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 LED_PORT 16
#define KEY_PORT 0
#define TASK_EXEC_NUMBER 5
#define TASK_KEY_NAME "task_key"
#define TASK_POOL_NAME "task_pool"
#define APP_MOUDLE_NAME "task_pool"

const char * task_exec_names[TASK_EXEC_NUMBER] =
{
"task_exec1",
"task_exec2",
"task_exec3",
"task_exec4",
"task_exec5",
};

gpio_dev_t led_gpio_dev;
gpio_dev_t key_gpio_dev;
uint32_t key_value;
aos_sem_t key_sem;
aos_sem_t pool_sem;
aos_sem_t exec_sem;
void task_exec_entry(void *arg)
{
int ret;
const char * task_name;
task_name = aos_task_name();
while(1)
{
//等待任务执行命令
ret = aos_sem_wait(&exec_sem, AOS_WAIT_FOREVER);
if(ret != 0)
{
LOGE(APP_MOUDLE_NAME,"task key sem wait err\r\n");

}else
{
//打印任务执行信息
LOGI(APP_MOUDLE_NAME, "%s is run\r\n",task_name);
aos_msleep(10000);
LOGI(APP_MOUDLE_NAME, "%s is stop\r\n",task_name);
//释放任务池资源
aos_sem_signal(&pool_sem);
}


}
}


void task_pool_entry(void *pool)
{
int ret;

while(1){
//等待按键按下
ret = aos_sem_wait(&key_sem, AOS_WAIT_FOREVER);
if(ret != 0)
{
LOGE(APP_MOUDLE_NAME,"task key sem wait err\r\n");

}
else
{
//获取线程池
ret = aos_sem_wait(&pool_sem, AOS_WAIT_FOREVER);
if(ret != 0)
{
LOGE(APP_MOUDLE_NAME,"task pool sem wait err\r\n");

}
else
{
//让任务执行
aos_sem_signal(&exec_sem);
}


}

}


}



void task_key_entry(void *arg)
{


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)
{
printf("key is down sem signal\r\n");
aos_sem_signal(&key_sem);
//等待按键松开
do{
hal_gpio_input_get(&key_gpio_dev, &key_value);
aos_msleep(10);
}while(!key_value);
}

}
//10ms 读取一次按键状态
aos_msleep(10);
}



}


int application_start(int argc, char *argv[])
{
int ret;
int index;
led_gpio_dev.port = LED_PORT;
led_gpio_dev.config = OUTPUT_PUSH_PULL;
led_gpio_dev.priv = NULL;
//led 初始化
hal_gpio_init(&led_gpio_dev);

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

aos_set_log_level(AOS_LL_INFO);
//创建按键同步信号量
ret = aos_sem_new(&key_sem, 0);

if(ret != 0)
{
LOGE(APP_MOUDLE_NAME,"task key sem create err\r\n");

}
//创建任务池资源共享信号量
ret = aos_sem_new(&pool_sem, 5);

if(ret != 0)
{
LOGE(APP_MOUDLE_NAME,"task pool sem create err\r\n");

}
//创建任务池同步信号量
ret = aos_sem_new(&exec_sem, 0);

if(ret != 0)
{
LOGE(APP_MOUDLE_NAME,"task pool sem create err\r\n");

}
//创建5个任务数量的任务池
for(index = 0; index < TASK_EXEC_NUMBER; index++)
{

ret = aos_task_new(task_exec_names[index], task_exec_entry, NULL, 8*128);
if(ret != 0)
{
LOGE(APP_MOUDLE_NAME,"%s create err\r\n", task_exec_names[index]);

}

}
//创建按键检测任务
ret = aos_task_new(TASK_KEY_NAME, task_key_entry, NULL, 8*128);
if(ret != 0)
{
LOGE(APP_MOUDLE_NAME,"task key create err\r\n");

}
//创建任务池分配任务
ret = aos_task_new(TASK_POOL_NAME, task_pool_entry, NULL, 8*128);
if(ret != 0)
{
LOGE(APP_MOUDLE_NAME,"task led create err\r\n");
}
while(1) {
aos_msleep(1000);
}
}

5.2 mk3080

mk3080的工程可以看这里:helloworld_mk3080/example/02_sem_task_pool.c · sumumm/AliOS-Things-Prj - 码云 - 开源中国 (gitee.com)

6. 测试现象

我们按下按键,任务就会开始执行,我们连续按下7次,则会有如下现象:

image-20231205194537090