系统任务
1.系统任务原理
以下资料来自《ESP8266 Non-OS SDK API参考》第2.2章节与第3.3章节。
Non-OS SDK 不像基于 RTOS 的应⽤程序⽀持任务调度。 Non-OS SDK 使⽤四种类型的函数:
- 应用函数
- 回调函数
- 用户任务
- 中断服务函数
1.1 应用函数
应用函数类似于嵌入式C编程中常用的C函数。这些函数必须由另一个函数调用。应用函数在定义时建议添加ICACHE_FLASH_ATTR宏,相应程序将存放在flash中,被调用时才会加载到cache运行。而如果添加了IRAM_ATTR宏的函数,则会在上电启动时加载到iRAM中。
1.2 回调函数
回调函数是指不直接从用户程序调用的函数。而是当某系统事件发送时,相应的回调函数由non-OS SDK内核调用执行。这使得开发者能够在不使用RTOS或者轮询事件的情况下响应实时事件。
要编写回调函数,用户首先需要使用相应的register_cb API注册回调函数。回调函数的示例代码包括定时器回调函数和网络事件回调函数。
1.3 中断服务函数
中断服务函数(ISR)是一种特殊类型的回调函数。发生硬件中断时会调用这些函数。当时能中断时,必须注册相应的中断处理函数。请注意,ISR必须添加IRAM_ATTR。
1.4 用户任务
用户任务可以分为三个优先级:0、1、2.任务优先级为2 > 1 > 0。即Non-OS SDK最多只支持3个用户任务,优先级分别为0、1、2。
用户任务一般用于函数不能被调用的情况下。要创建用户任务,请参阅本文档中的system_os_task()的API描述。例如espconn_disconnect() API不能直接在espconn的回调函数中调用,因此建议开发者在espconn回调中创建用户任务来执行espconn_disconnect()。
2. 硬件中断定时器相关API函数
系统接⼝位于 /ESP8266_NONOS_SDK/include/user_interface.h。
os_XXX 系列接⼝位于 /ESP8266_NONOS_SDK/include/osapi.h。
2.1 system_os_task ()函数
函数原型:bool system_os_task(os_task_t task,uint8 prio,os_event_t *queue,uint8 qlen)
函数功能:创建系统任务,最多支持创建3个任务,优先级分别为0/1/2
函数形参:
os_task_t task:函数任务
uint8 prio:任务优先级,可分为0/1/2;0为最低优先级。这表示最多只支持建立3个任务。
可填形参:
enum {
USER_TASK_PRIO_0 = 0,
USER_TASK_PRIO_1,
USER_TASK_PRIO_2,
USER_TASK_PRIO_MAX
};
os_event_t *queue:消息队列指针
uint8 qlen:消息队列深度
返回值:
ture :成功
false:失败
==============================================================
官方参考示例代码:
#define SIG_RX 0
#define TEST_QUEUE_LEN 4
os_event_t *testQueue;
void test_task(os_event_t *e)
{
switch (e->sig)
{
case SIG_RX:
os_printf(sig_rx %c / n, (char)e->par);
break;
default:
break;
}
}
void task_init(void)
{
testQueue = (os_event_t*)os_malloc(sizeof(os_event_t)*TEST_QUEUE_LEN);
system_os_task(test_task, USER_TASK_PRIO_0, testQueue, TEST_QUEUE_LEN);
}
2.2 system_os_post()函数
函数原型:bool system_os_post(uint8 prio,os_signal_t sig,os_param_t par)
函数功能:向任务发送消息
函数形参:
uint8 prio:任务优先级,与建立时的任务优先级对应
os_signal_t sig:消息类型
os_param_t par:消息参数
返回值:
ture :成功
false:失败
3. 参考代码
3.1 系统任务调用顺序
① 创建任务指针
② 分配任务指针空间
③ 创建任务函数
④ 创建任务
⑤ 给系统安排任务
⑥ 编写任务函数(根据消息类型/消息参数实现相应功能)
3.2 参考驱动源码
//user_main.c
#include "ets_sys.h"
#include "osapi.h"
#include "user_interface.h"
#include "driver/uart.h"
#include "gpio.h"
#include "eagle_soc.h"
#include "driver/delay.h"
#include "driver/led.h"
#include "driver/key.h"
#include "driver/HwTimer.h"
#include "osapi.h"
#include "mem.h" // 内存申请等函数
/*
* ① 创建任务指针
* ② 分配任务指针空间
* ③ 创建任务
* ④ 创建任务函数
* ⑤ 给系统安排任务
* ⑥ 编写任务函数(根据消息类型/消息参数实现相应功能)
* */
#define TEST_QUEUE_LEN 4 //消息队列深度
os_event_t *testQueue; //① 创建任务指针
//④ 创建任务 形参必须为s_event_t *类型
void test_task(os_event_t * Task_message)
{
//⑤ 给系统安排任务
os_printf("消息类型=%d,消息参数=%c\r\n", Task_message->sig, Task_message->par);
}
void ICACHE_FLASH_ATTR user_init(void)
{
int i;
char data = 0;
char ch = 'a';
uart_init(115200, 115200);//设置串口波特率
DelayMs(1000); // 延时1秒
// LedInitConfig();//LED灯初始化函数
// KeyInitConfig();//按键初始化函数
// KeyExtiInitConfig();//配置按键外部中断
// TimerInitConfig(500,1);
// hw_timer_set_func();
// HwTimerInitConfig();
os_printf("=============================================\r\n");
os_printf("\t SDK version:\t%s", system_get_sdk_version());
os_printf("\r\n嵌入式陈工个人编辑资料\r\n未经本人同意请勿私自传播\r\n");
os_printf("\r\n系统任务调度代码\r\n");
os_printf("\r\n带看门狗\r\n");
os_printf("=============================================\r\n");
//② 分配任务指针空间
testQueue = (os_event_t*)os_malloc(sizeof(os_event_t)*TEST_QUEUE_LEN);
//③ 创建任务函数
system_os_task(test_task, USER_TASK_PRIO_0, testQueue, TEST_QUEUE_LEN);
for (i = 0; i < 5; i++)
{
system_soft_wdt_feed();//喂软件看门狗,防止程序跑偏
os_DelayMs(1000); // 延时1秒 系统延时函数
os_printf("安排任务:Task = %d\r\n", i);
// 调用任务(参数1=任务等级 / 参数2=消息类型 / 参数3=消息参数)
// 注意:参数3必须为无符号整数,否则需要强制类型转换
//---------------------------------------------------------------
system_os_post(USER_TASK_PRIO_0, data ++, ch ++);
}
os_printf("任务创建完成\r\n");
}