文章目录
- RT-Thread
- 一、线程
- 1. 线程定义
- 2. 线程栈
- 3. 线程函数 rt_thread_entry()
- 4. 线程控制块 struct rt_thread
- 5. 线程初始化 rt_thread_init()
- 6. 就绪列表
- 7. 调度器
- 二、对象容器
- 1. 对象:所有的数据结构都是对象
- 2. 容器:每当创建一个对象,就会将这个对象放到容器中。
- 三、空闲线程与阻塞延时
- 四、创建线程
- 创建线程-静态内存
- 创建线程-动态内存
- 五、RT-Thread移植到STM32F407
- 六、消息队列
- 七、信号量
- 八、互斥量
- 九、临界区
- 十、事件
- 十一、邮箱
- 十二、定时器
RT-Thread
一、线程
1. 线程定义
在裸机系统中所有代码都运行在一个main函数中,只能按照顺序运行程序,当遇到中断时才会打断当前程序,用以提高系统的实时性。如果遇到软件延时等情况,CPU只能在那空转,大大浪费了CPU的性能。而多线程是多个独立且无法返回的函数,就好比有多个裸机系统的main函数同时运行。如果把裸机系统比做单车道,那么多线程就是多车道。
2. 线程栈
在学习C语言的时候,里面有一个内存分区模型如下:
-
代码区:存放函数体的二进制代码
-
全局区:存放全局变量,静态变量,以及常量
-
栈区:由编译器自动分配释放,存放函数的参数值,局部变量
-
堆区:用new操作符由程序员分配和释放,若程序员不释放,程序结束时操作系统回收
在裸机系统中,全局变量,局部变量等都放在栈区,而我们为了实现多线程,相当于多个main函数,我们必须将栈区划分成一个个独立的、互不干扰的区域
/* 定义线程栈 */
rt_uint8_t rt_flag1_thread_stack[512];
线程栈其实就是一个数组
3. 线程函数 rt_thread_entry()
线程函数是一个线程实现功能的函数,比如点亮一个LED。一般将其称为入口函数
rt_err_t flag1_thread_entry(void *p_arg)
{
for(;;)
{
//一个线程所需执行的功能的代码
}
rt_schedule();//线程手动切换
}
4. 线程控制块 struct rt_thread
线程控制块本质是一个C语言的结构体,里面存放了一个线程的属性,用于控制一个线程。
struct rt_thread// (1)
{
void *sp; /* 线程栈指针 */
void *entry; /* 线程入口地址 */
void *parameter; /* 线程形参 */
void *stack_addr; /* 线程起始地址 */
rt_uint32_t stack_size; /* 线程栈大小,单位为字节 */
rt_list_t tlist; /* 线程链表节点 */
};
typedef struct rt_thread *rt_thread_t;// (2)
5. 线程初始化 rt_thread_init()
当我们定义好线程栈、线程函数、线程控制块后需要将其联系起来,通过**rt_thread__init()**函数
rt_err_t rt_thread_init(struct rt_thread *thread,
void (*entry)(void *parameter),
void *parameter,
void *stack_start,
rt_uint32_t stack_size)
{
rt_list_init(&(thread->tlist));
thread->entry = (void *)entry;
thread->parameter = parameter;
thread->stack_addr = stack_start;
thread->stack_size = stack_size;
/* 初始化线程栈,并返回线程栈指针 */ )
thread->sp = (void *)rt_hw_stack_init( thread->entry,
thread->parameter,
(void *)((char *)thread->stack_addr +␣thread->stack_size - 4) );
return RT_EOK;
}
6. 就绪列表
线程创建好后,需要将线程添加到就绪列表,表示线程已经就绪,系统可以随时调度
/* 线程就绪列表 */
rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];
就绪列表本质是一个数组,大小为RT_THREAD_PRIORITY_MAX,这个宏用于表示最大有多少个优先级。有多少个优先级这个数组就有多少个元素。数值越小优先级越高。每个元素的类型为rt_list_t,定义如下
struct rt_list_node
{
struct rt_list_node *next; /* 指向后一个节点 */
struct rt_list_node *prev; /* 指向前一个节点 */
};
typedef struct rt_list_node rt_list_t;
定义为链表的一个节点,当同一优先级下有多个线程时,可以通过插入链表的方式插入该优先级下
下面是几个链表相关函数
-
rt_list_init
rt_inline void rt_list_init(rt_list_t *l) { l->next = l->prev = l; }
-
rt_list_insert_after
/* 在双向链表头部插入一个节点 */ rt_inline void rt_list_insert_after(rt_list_t *l, rt_list_t *n) { l->next->prev = n; /* 第 步 */ n->next = l->next; /* 第 步 */ l->next = n; /* 第 步 */ n->prev = l; /* 第 步 */ }
-
rt_list_insert_before
rt_inline void rt_list_insert_before(rt_list_t *l, rt_list_t *n) { l->prev->next = n; /* 第 步 */ n->prev = l->prev; /* 第 步 */ l->prev = n; /* 第 步 */ n->next = l; /* 第 步 */ }
7. 调度器
主要功能是实现线程的切换,从就绪列表中找到优先级最高的线程,然后执行该线程。
二、对象容器
1. 对象:所有的数据结构都是对象
其中线程,信号量,互斥量、事件、邮箱、消息队列、内存堆、内存池、设备和定时器有明显的枚举定义,即为每个对象打上了一个数字标签
对象容器-对象类型枚举定义
enum rt_object_class_type
{
RT_Object_Class_Thread = 0, /* 对象是线程 */
RT_Object_Class_Semaphore, /* 对象是信号量 */
RT_Object_Class_Mutex, /* 对象是互斥量 */
RT_Object_Class_Event, /* 对象是事件 */
RT_Object_Class_MailBox, /* 对象是邮箱 */
RT_Object_Class_MessageQueue, /* 对象是消息队列 */
RT_Object_Class_MemHeap, /* 对象是内存堆 */
RT_Object_Class_MemPool, /* 对象是内存池 */
RT_Object_Class_Device, /* 对象是设备 */
RT_Object_Class_Timer, /* 对象是定时器 */
RT_Object_Class_Module, /* 对象是模块 */
RT_Object_Class_Unknown, /* 对象未知 */
RT_Object_Class_Static = 0x80/* 对象是静态对象 */
};
为了管理这些对象,专门定义了一个对象数据类型结构体rt_object
struct rt_object
{
char name[RT_NAME_MAX]; (1) /* 内核对象的名字 */
rt_uint8_t type; (2) /* 内核对象的类型 */
rt_uint8_t flag; (3) /* 内核对象的状态 */
rt_list_t list; (4) /* 内核对象的列表节点 */
};
typedef struct rt_object *rt_object_t; (5) /* 内核对象数据类型重定义 */
每个对象都会有一个结构体,比如之前的线程,称为线程控制块,这些控制块都会包含内核对象
struct rt_thread
{
/* rt 对象 */
char name[RT_NAME_MAX]; /* 对象的名字 */
rt_uint8_t type; /* 对象类型 */
rt_uint8_t flags; /* 对象的状态 */
rt_list_t list; /* 对象的列表节点 */
/* 内核对象 */
/* 或者直接通过struct rt_object 创建一个内核变量 */
rt_object_t rtobject_thread;
rt_list_t tlist; /* 线程链表节点 */
void *sp; /* 线程栈指针 */
void *entry; /* 线程入口地址 */
void *parameter; /* 线程形参 */
void *stack_addr; /* 线程起始地址 */
rt_uint32_t stack_size; /* 线程栈大小,单位为字节 */
};
2. 容器:每当创建一个对象,就会将这个对象放到容器中。
struct rt_object_information
{
enum rt_object_class_type type;// (1) /* 对象类型 */
rt_list_t object_list;// (2) /* 对象列表节点头 */
rt_size_t object_size;// (3) /* 对象大小 */
};
容器本质是一个数组,类型为rt_object_information,包含了对象的类型,列表头结点,大小。可以通过节点将同类型的对象连接起来放在双向链表中。
容器的定义:
static struct rt_object_information rt_object_container [RT_Object_Info_Unknown] =
{
/* 初始化对象容器 - 线程 */
{
RT_Object_Class_Thread,
_OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Thread),
sizeof(struct rt_thread)
},
#ifdef RT_USING_SEMAPHORE
/* 初始化对象容器 - 信号量 */
{
RT_Object_Class_Semaphore,
_OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Semaphore),
sizeof(struct rt_semaphore)
},
#endif
#ifdef RT_USING_MUTEX
/* 初始化对象容器 - 互斥量 */
{
RT_Object_Class_Mutex,
_OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Mutex),
sizeof(struct rt_mutex)
},
#endif
#ifdef RT_USING_EVENT
/* 初始化对象容器 - 事件 */
{
RT_Object_Class_Event,
_OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Event),
sizeof(struct rt_event)
},
#endif
#ifdef RT_USING_MAILBOX
/* 初始化对象容器 - 邮箱 */
{
RT_Object_Class_MailBox,
_OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MailBox),
sizeof(struct rt_mailbox)
},
#endif
#ifdef RT_USING_MESSAGEQUEUE
/* 初始化对象容器 - 消息队列 */
{
RT_Object_Class_MessageQueue,
_OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MessageQueue),
sizeof(struct rt_messagequeue)
},
#endif
#ifdef RT_USING_MEMHEAP
/* 初始化对象容器 - 内存堆 */
{
RT_Object_Class_MemHeap,
_OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemHeap),
sizeof(struct rt_memheap)
},
#endif
#ifdef RT_USING_MEMPOOL
/* 初始化对象容器 - 内存池 */
{
RT_Object_Class_MemPool,
_OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemPool),
sizeof(struct rt_mempool)
},
#endif
#ifdef RT_USING_DEVICE
/* 初始化对象容器 - 设备 */
{
RT_Object_Class_Device,
_OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Device),
sizeof(struct rt_device)
},
#endif
/* 初始化对象容器 - 定时器 */
/*
{
RT_Object_Class_Timer,
_OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Timer),
sizeof(struct rt_timer)
},
*/
#ifdef RT_USING_MODULE
/* 初始化对象容器 - 模块 */
{
RT_Object_Class_Module,
_OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Module),
sizeof(struct rt_module)
},
#endif
1)对象的类型与容器数组的下标是一致的,数组容量大小为RT_Object_Info_Unknown,由下面的枚举类型rt_object_info_type定义,根据系统中对象的多少来决定,如果所有的宏都被定义,则RT_Object_Info_Unknown值为11,共有12个对象。
/*
* 对象容器数组的下标定义,决定容器的大小
*/
enum rt_object_info_type
{
RT_Object_Info_Thread = 0, /* 对象是线程 */
#ifdef RT_USING_SEMAPHORE
RT_Object_Info_Semaphore, /* 对象是信号量 */
#endif
#ifdef RT_USING_MUTEX
RT_Object_Info_Mutex, /* 对象是互斥量 */
#endif
#ifdef RT_USING_EVENT
RT_Object_Info_Event, /* 对象是事件 */
#endif
#ifdef RT_USING_MAILBOX
RT_Object_Info_MailBox, /* 对象是邮箱 */
#endif
#ifdef RT_USING_MESSAGEQUEUE
RT_Object_Info_MessageQueue, /* 对象是消息队列 */
#endif
#ifdef RT_USING_MEMHEAP
RT_Object_Info_MemHeap, /* 对象是内存堆 */
#endif
#ifdef RT_USING_MEMPOOL
RT_Object_Info_MemPool, /* 对象是内存池 */
#endif
#ifdef RT_USING_DEVICE
RT_Object_Info_Device, /* 对象是设备 */
#endif
RT_Object_Info_Timer, /* 对象是定时器 */
#ifdef RT_USING_MODULE
RT_Object_Info_Module, /* 对象是模块 */
#endif
RT_Object_Info_Unknown, /* 对象未知 */
};
2)_OBJ_CONTAINER_LIST_INIT©
#define _OBJ_CONTAINER_LIST_INIT(c) \
{&(rt_object_container[c].object_list),&(rt_object_container[c].object_list)}
容器的接口
-
rt_object_get_information()获取对象信息
struct rt_object_information *rt_object_get_information(enum rt_object_class_type type) { int index; for (index = 0; index < RT_Object_Info_Unknown; index ++) if (rt_object_container[index].type == type) return &rt_object_container[index]; return RT_NULL; }
-
rt_object_init()对象初始化
/** * 该函数将初始化对象并将对象添加到对象容器中 * * @param object 要初始化的对象 * @param type 对象的类型 * @param name 对象的名字,在整个系统中,对象的名字必须是唯一的 */ void rt_object_init(struct rt_object *object, (1) enum rt_object_class_type type, (2) const char *name) (3) { register rt_base_t temp; struct rt_object_information *information; /* 获取对象信息,即从容器里拿到对应对象列表头指针 */ information = rt_object_get_information(type); (4) /* 设置对象类型为静态 */ object->type = type | RT_Object_Class_Static; (5) /* 拷贝名字 */ rt_strncpy(object->name, name, RT_NAME_MAX); (6) /* 关中断 */ temp = rt_hw_interrupt_disable(); (7) /* 将对象插入到容器的对应列表中,不同类型的对象所在的列表不一样 */ rt_list_insert_after(&(information->object_list), &(object->list)); (8) /* 使能中断 */ rt_hw_interrupt_enable(temp); }
三、空闲线程与阻塞延时
四、创建线程
创建线程-静态内存
在创建一个线程之前,我们需要预先为每一个线程分配一个固定大小的栈空间在SRAM中,也就是一个数组。这就是静态内存。
创建线程-动态内存
创建一个线程之前不需要事先为其分配一个栈空间,在创建线程的时候会一起开辟一个堆空间,堆空间也是在SRAM中的一段内存空间。类比C语言中的动态内存空间分配,这样做的好处是可以更灵活地为线程分配所需空间,节省内存。
在使用方法上静态内存空间与动态内存空间有很大的不同。静态内存空间需要事先分配一个数组,也就是栈空间,而动态内存空间,不需要事先定义线程栈,
静态内存创建一个线程的四个步骤:
- 定义线程函数
static void led1_thread_entry(void* parameter)
{
while (1)
{
LED1_ON;
rt_thread_delay(500); /* 延时 500 个 tick */ (1)
LED1_OFF;
rt_thread_delay(500); /* 延时 500 个 tick */
}
}
- 定义线程栈
/* 定义线程控栈时要求 RT_ALIGN_SIZE 个字节对齐 */
ALIGN(RT_ALIGN_SIZE)
/* 定义线程栈 */
static rt_uint8_t rt_led1_thread_stack[1024];
- 定义线程控制块
/* 定义线程控制块 */
static struct rt_thread led1_thread;
- 初始化线程
rt_thread_init(&led1_thread, /* 线程控制块 */ (1)
"led1", /* 线程名字 */ (2)
led1_thread_entry, /* 线程入口函数 */ (3)
RT_NULL, /* 线程入口函数参数 */ (4)
&rt_led1_thread_stack[0], /* 线程栈起始地址 */ (5)
sizeof(rt_led1_thread_stack), /* 线程栈大小 */ (6)
3, /* 线程的优先级 */ (7)
20); /* 线程时间片 */ (8)
- 启动线程
rt_thread_startup(&led1_thread);
动态内存创建线程的五个步骤:
- 在board.c里可以通过
#define(RT_USING_HEAP)
来选择是否使用动态内存分配,如果使用动态内存,则下面是board.c文件里有关堆内存初始化的部分代码
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
#define RT_HEAP_SIZE 1024
/* 从内部 SRAM 里面分配一部分静态内存来作为 rtt 的堆空间,这里配置为 4KB */
static uint32_t rt_heap[RT_HEAP_SIZE];
RT_WEAK void *rt_heap_begin_get(void)
{
return rt_heap;
}
RT_WEAK void *rt_heap_end_get(void)
{
return rt_heap + RT_HEAP_SIZE;
}
#endif
void rt_hw_board_init()
{
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}
- 定义线程函数
static void led1_thread_entry(void* parameter)
{
while (1)
{
LED1_ON;
rt_thread_delay(500); /* 延时 500 个 tick */ (1)
LED1_OFF;
rt_thread_delay(500); /* 延时 500 个 tick */
}
}
- 定义线程控制块指针
/* 定义线程控制块指针 */
static rt_thread_t led1_thread = RT_NULL;
- 创建线程
led1_thread = /* 线程控制块指针 */ (1)
rt_thread_create( "led1", /* 线程名字 */ (2)
led1_thread_entry, /* 线程入口函数 */ (3)
RT_NULL, /* 线程入口函数参数 */ (4)
512, /* 线程栈大小 */ (5)
3, /* 线程的优先级 */ (6)
20); /* 线程时间片 */ (7)
- 启动线程
if(led1_thread != RT_NULL)//因为线程的内存是由编译器分配的,所以不能够确保分配成功,因此在启动线程之前需要判断一下是否分配成功
{
rt_thread_startup(led1_thread);
}
else
{
return -1;
}
五、RT-Thread移植到STM32F407
http://t.csdn.cn/KbvVJ
六、消息队列
消息队列控制块
struct rt_messagequeue
{
struct rt_ipc_object_parent;
void *msg_pool;
rt_uint16_t msg_size;
rt_uint16_t max_msgs;
rt_uint16_t entry;
void *msg_queue_head;
void *msg_queue_tail;
void *msg_queue_free;
}
typedef struct rt_messagequeue *rt_mq_t;
定义静态消息队列
struct rt_messagequeue static_mq;
rt_mq_t dynamic_mq;
初始化与脱离
rt_err_t rt_mq_init(rt_mq_t mq, const char *name, void *msgpool, rt_size_t msg_size, rt_size_tpool_size, rt_uint8_t flag);//RT_IPC_FLAG_FIFO,RT_IPC_FLAG_PRIO
rt_err_t rt_mq_detach(rt_mq_t mq);
创建与删除
rt_mq_T rt_mq_create(const char *name,rt_size_t msg_size, rt_size_t max_msgs,rt_uint8_t flag);
rt_err_t rt_mq_delete(rt_mq_t mq);
发送消息
rt_err_t rt_mq_send(rt_mq_t mq, void *buffer, rt_size_t size);
rt_err_t rt_mq_delete(rt_mq_t mq);
接收消息
rt_err_t rt_mq_recv(rt_mq_t mq, void *buffer, rt_size_T size, rt_uint32_t timeout);
七、信号量
线程间通信(Internal Process Communication IPC),RT-Thread中的IPC机制包括信号量、互斥量、时间、邮箱、消息队列。通过IPC机制可以协调多个线程/中断的工作
信号量控制块
struct rt_semaphore
{
struct rt_ipc_object parent;
rt_uint16_t value;
}
定义静态信号量:struct rt_semaphore static_sem
定义动态信号量:rt_sem_t dynamic_sem
API
信号量的初始化与脱离(静态信号量)
rt_err_t rt_sem_init(rt_sem_t sem, const char* name,rt_uint32_value, rt_uint8_t flag);
rt_err_t rt_sem_detach(rt_sem_t sem);
创建与删除
rt_sem_t rt_sem_create(const char* name,rt_uint32_t value, rt_uint8_t flag);//RT_IPC_FLAG_FIFO RT_IPC_FALG_PRIO
获取信号量
rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time);//RT_WAITING_FOREVER = -1
rt_err_t rt_sem_trytake(rt_sem_t sem);
释放信号量
rt_err_t rt_sem_release(rt_sem_t sem);
八、互斥量
互斥量控制块
struct rt_mutex
{
struct_rt_ipc_object_parent;
rt_uint16_t value;
rt_uint8_t original_priority;
rt_uint8_t hold;
struct rt_thread *owner;
};
typedef struct rt_mutex rt_mutex_t;
定义静态互斥量
struct rt_mutex static mutex;
定义动态互斥量
rt_mutex_t dynamic_mutex;
互斥量的操作
初始化与脱离
rt_err_t rt_mutex_init(rT_mutex_t mutex, const char *name, rt_uint8_t flag);//RT_IPC_FLAG_FIFO RT_IPC_FLAG_PRIO
rt_err_t rt_mutex_detach(rT_mutex_t mutex);
创建与删除
rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag);
rt_err_t rt_mutex_delete(rt_mutex_t mutex);
获取互斥量
rt_err_T rt_mutex_take(rt_mutex_t mnutex, rt_int_32_t time);//RT_WAITING_FOREVER=-1
释放互斥量
rt_err_t rt_mutex_release(rt_mutex_t mutex);
九、临界区
每个线程中访问(操作)临界资源的那段代码称为临界区(Critical Section),每次只允许一个线程进入临界区。
比如有两个线程,线程1对全局变量从0到10000对value赋值,线程2对value赋值50000,如果要保证线程1对value的正常赋值,就需要临界区保护
rint32_t value;
void thread1_entry(void *parameter)
{
while(1)
{
rt_uint32_t count;
for(count=0;count<10000;count++)
{
value++;
}
}
}
void thread2_entry(void *parameter)
{
while(1)
{
value = 50000;
}
}
临界段保护的两种方式:
- 禁止调度
禁止调度就是把调度器锁住,不让其进行线程切换。这样就能保证当前运行的任务不被换出,知道调度器解锁,所以进制调度是常用的临界区保护方法。
void thread_entry(void *parameter)
{
while(1)
{
/* 调度器上锁,上锁后将不再切换到其他线程,仅响应中断 */
rt_enter_critical();
/* 以下进入临界区 */
/* 调度器解锁 */
rt_exit_critical();
}
}
- 关闭中断
因为线程的调度都是建立在中断的基础上的,所以关闭中断以后,系统将不能再进行调度,线程本身也自然不会被其他线程抢占了
void thread_entry(void* parameter)
{
rt_base_level;
while(1)
{
/* 关闭中断 */
level = rt_hw_interrupt_disable();
/* 以下是临界区 */
/* 打开中断 */
rt_hw_interrupt_enable(level);
}
}
十、事件
信号量主要用于一对一的线程同步,当需要一对多、多对一、多对多的时候就需要时间集来处理
RT-Thread中用一个32位无符号整型变量来表示,变量中的一个位代表一个时间。线程通过逻辑与、逻辑或与一个或多个事件建立关联形成一个事件组合。
事件集控制块
struct rt_event
{
struct rt_ipc_object parent;
rt_uint32_t set;
};
typedef struct rt_event *rt_event_t;
定义静态事件集
struct rt_event static_evt;
定义动态事件集
rt_event_t dynamic_evt;
事件集的操作
初始化与脱离
rt_err_t rt_event_init(rt_event_t event, const char *name, rt_uint8_t flag);//RT_IPC_FLAG_FIFO RT_IPC_FLAG_PRIO
rt_err_t rt_event_detach(rt_event_t event);
创建与删除
rt_event_t rt_event_create(const char *name, rt_uint8_t flag);
rt_err_t rt_event_delete(rt_event_t event);
发送事件
rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set);
接收事件
rt_err_t rt_event_recv(rt_event_t event, rt_uint32_t set, rt_uint8_t option, rt_uint32_t timeout, rt_uint32_t *recved);
十一、邮箱
邮箱用于线程间通信,特点是开销比较低,效率较高。邮箱中的每一封邮件只能容纳固定的四字节内容,线程或者终端服务例程把一封4字节长度的邮件发送到邮箱中,而其他需要的线程可以从邮箱中接收这些邮件并进行处理
邮箱控制块
struct rt_mailbox
{
struct rt_ipc_object parent;
rt_uint32_t *msg_pool;
rt_uint16_t size;
rt_uint16_t entry;
rt_uint16_t in_offset;
rt_uint16_t out_offset;
rt_list_t suspend_sender_thread;
};
typedef struct rt_mailbox *rt_mailbox_t;
定义静态邮箱
struct rt_mailbox static_mb;
定义动态邮箱
rt_mailbox_t dynamic_mb;
邮箱的操作
初始化与脱离
rt_err_t rt_mb_init(rt_mailbox_t mb, const char *name, void *msgpoll, rt_size_t size, rt_uint8_t flag);RT_IPC_FLAG_FIFO RT_IPC_FLAG_PRIO
rt_err_t rt_mb_detach(rt_mailbox_t mb);
创建与删除
rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag);
rt_err_t rt_mb_delete(rt_mailbox_t mb);
发送邮件
rt_err_t rt_mb_send(rt_mailbox_t mb, rt_uint32_t value);
rt_err_t rt_mb_send_wait(rt_mailbox_t mb, rt_uint32_t value, rt_uint32_t timeout);
接收邮件
rt_err_T rt_mb_recv(rt_mailbox_t mb, rt_uint32_t *value, rt_int32_t timeout);
十二、定时器
定时器的操作
初始化与脱离(静态方式)
coid rt_timer_init(rt_timer_t timer, const char* name, void(*timeout)(void *parameter), void *parameter, rt_tick_t time, rt_uint8_t flag);
rt_err_t rt_timer_detach(rt_timer_t timer);
创建与删除(动态方式)
rt_timer_t rt_timer_create(const char *name, void(*timeout)(void *parameter), void*parameter, rt_tick_t time, rt_uint8_t flag);
flag取值
1 RT_TIMER_FLAG_ONE_SHOT,单次定时器
2 RT_TIMER_FLAG_PERIODIC,周期定时器
3 RT_TIMER_FLAG_HARD_TIMER,硬件定时器
4 RT_TIMER_FLAG_SOFT_TIMER,软件定时器
1、2、3、4需要从1 2中选一个 3 4 中选一个。通过按位或的方式输入。定时器默认工作在HARD模式下
启动定时器
rt_err_t rt_timer_start(rt_timer_t timer);
停止定时器
rt_err_t rt_timer_stop(rt_timer_t timer);