1.创建任务
2.任务状态
3.获取当前线程句柄,让出处理器资源yield,获取时钟节拍tick,高精度延时
4.定时器
5.临界值
6.信号量
7.互斥信号量
8.事件集
9.初始化INIT_BOARD_EXPORT和MSH_CMD_EXPORT
10.消息队列
11.软件方式微妙延时
12.ESP8266 wifi
1.创建任务
原型
rt_thread_t rt_thread_create(const char *name,
void (*entry)(void *parameter),
void *parameter,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick);
参数解释:
name: 线程的名称,通常用于调试和日志记录。
entry: 线程的入口函数,即线程启动后要执行的函数。
parameter: 传递给入口函数的参数。
stack_size: 线程栈的大小,以字节为单位。
priority: 线程的优先级。在 RTOS 中,优先级决定了线程的执行顺序。
tick: 线程的时间片长度(在某些 RT-Thread 配置中可能不使用此参数)
示例
```#include <rtthread.h>
/* 线程入口函数 */
static void thread_entry(void *parameter)
{
/* 线程主体代码 */
while (1)
{
rt_kprintf("Hello RT-Thread!\n");
rt_thread_mdelay(1000); /* 延时1000毫秒 */
}
}
int main(void)
{
rt_thread_t tid;
/* 创建线程:线程名称为 "mythread",入口函数为 thread_entry,入口参数为 RT_NULL,
* 栈大小为 1024 字节,优先级为 25(最高优先级为 32,最低为 0,值越小优先级越高)*/
tid = rt_thread_create("mythread",
thread_entry, RT_NULL,
1024, 25, 10);
if (tid != RT_NULL)
{
rt_kprintf("Create thread success!\n");
rt_thread_startup(tid);
}
else
{
rt_kprintf("Create thread failed!\n");
}
/* 如果获得了线程控制块,线程通常会自动启动,
* 但在某些情况下,你可能需要手动启动线程:
* rt_thread_startup(tid);
* 注意:在 RT-Thread 的某些版本中,rt_thread_create 会自动启动线程,
* 因此不需要再调用 rt_thread_startup。
*/
return 0;
}
2.任务状态
挂起:
rt_thread_suspend(rt_thread_t thread)
恢复
rt_thread_resume(rt_thread_t thread)
删除
rt_thread_delete(rt_thread_delete)
延时
rt_thread_mdelay(1000);
3.获取当前线程句柄
获取当前线程句柄:
rt_thread_t rt_rthread_self(void)
让出处理器资源
rt_err_t rt_thread_yield(void);
获取时钟节拍
rt_tick_t tick = 0;
tick = rt_tick_get();
高精度延时:
void rt_hw_us_delay(rt_uint32_t us);
4.定时器
原型:
示例:
//定时器回调
void timer_cb(void *p)
{
}
//定义
static rt_timer_t timer_hander;
//创建和启动定时器
{
timer_hander = rt_timer_create("timer1",timer_cb,
RT_NULL, 10,
RT_TIMER_FLAG_PERIODIC);//周期//RT_TIMER_FLAG_ONE_SHOT单次
rt_timer_start(timer_hander);
}
//修改超时时间
{
uint32_t value=100; //100 tick
// #define RT_TIMER_CTRL_SET_TIME 0x0 /* 设置定时器超时时间 */
// #define RT_TIMER_CTRL_GET_TIME 0x1 /* 获得定时器超时时间 */
// #define RT_TIMER_CTRL_SET_ONESHOT 0x2 /* 设置定时器为单一超时型 */
// #define RT_TIMER_CTRL_SET_PERIODIC 0x3 /* 设置定时器为周期型定时器 */
rt_timer_control(timer_hander, RT_TIMER_CTRL_SET_TIME, (void*)&value);
}
//停止定时器
{
rt_timer_stop(timer_hander);
}
``
//返回RT_EOK (如果参数timer句柄是一个RT_NULL,将会导致一个ASSERT断言)
rt_err_t rt_timer_delete(rt_timer_t timer);
高的精度延时:微妙
rt_hw_us_delay(us)
5.临界值
屏蔽中断:
rt_base_t level;
/* 禁用中断 */
level = rt_hw_interrupt_disable();
/* 临界区代码开始 */
// 访问或修改共享资源的代码
//在RT-Thread实时操作系统中,屏蔽(禁用)中断通常不是一个推荐的做法,因为它可能会破坏系统的实时性和稳定性。 ...
/* 临界区代码结束 */
/* 重新启用中断 */
rt_hw_interrupt_enable(level);
屏蔽任务:
void rt_enter_critical(void);//调度器上锁,进入调度临界区,不再切换线程
void rt_exit_critical(void);//调度器解锁,退出调度临界区
6.信号量
原型:
flag:
0x00:先进先出
0x01:按线程优先级获取信号量资源
rt_sem_t rt_sem_create(const char* name,rt_uint32_t value,rt_uint8_t flag)
示例:
rt_sem_t sem;
/* 创建一个信号量,初始值为1 */
sem = rt_sem_create("my_sem", 1, RT_IPC_FLAG_FIFO);
if (sem == RT_NULL)
{
rt_kprintf("Create semaphore failed!\n");
return -1;
}
static void thread1_entry(void *parameter)
{
while (1)
{
/* 请求信号量 */
rt_sem_take(sem, RT_WAITING_FOREVER);
rt_kprintf("Thread 1 is running\n");
/* 执行一些任务... */
/* 释放信号量 */
rt_sem_release(sem);
rt_thread_mdelay(500);
}
}
7.互斥信号量
互斥信号量不能在中断中使用
/**
参数的含义:
1、name 互斥量名称
2、flag 该标志已经作废,无论用户选择 RT_IPC_FLAG_PRIO 还是 RT_IPC_FLAG_FIFO,
内核均按照 RT_IPC_FLAG_PRIO 处理
返回值:
互斥量创建成功,返回互斥量的控制块指针
互斥量创建失败,返回RT_BULL
*/
rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag)
/**
获取互斥信号量
参数:
1、mutex 互斥量对象的句柄
2、time 指定的等待时间,单位是操作系统时钟节拍(OS Tick)
返回值:
RT_EOK 成功获得互斥量
-RT_ETIMEOUT 超时依然未获得互斥量
-RT_ERROR 获取失败
*/
rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time)
释放互斥信号量
/**
参数:
mutex 互斥量对象的句
返回值:
RT_EOK 成功
*/
rt_err_t rt_mutex_release(rt_mutex_t mutex)
8.事件集
/**
参数的含义:
1、name 事件集的名称
2、flag 事件集的标志,它可以取如下数值: RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO理
返回值:
事件集创建成功,返回事件集的控制块指针
事件集创建失败,返回RT_BULL
*/
rt_event_t rt_event_create(const char *name, rt_uint8_t flag)
/**
参数:
event 事件集对象的句柄
返回值:
RT_EOK 成功
*/
rt_err_t rt_event_delete(rt_event_t event)
/**
参数的含义:
1、event 事件集对象的句柄
2、set 发送的一个或多个事件的标志值
返回值:
RT_EOK 成功
*/
rt_err_t rt_event_send(rt_event_t event, rt_uint32_t set)
/**
参数的含义:
1、event 事件集对象的句柄
2、set 接收线程感的事件
3、option 接收选项,可取的值为
#define RT_EVENT_FLAG_AND 0x01 逻辑与
#define RT_EVENT_FLAG_OR 0x02 逻辑或
#define RT_EVENT_FLAG_CLEAR 0x04 选择清除重置事件标志位
4、timeout 指定超时时间
5、recved 指向接收到的事件,如果不在意,可以使用 NULL
返回值:
RT_EOK 成功
-RT_ETIMEOUT 超时
-RT_ERROR 错误
*/
rt_err_t rt_event_recv(rt_event_t event,
rt_uint32_t set,
rt_uint8_t option,
rt_int32_t timeout,
rt_uint32_t *recved)
#define EVENT_FLAG (1u<<1)
rt_event_send(event, EVENT_FLAG);
static void thread2_entry(void *parameter)
{ rt_uint32_t eve;
while (1)
{
/* 等待事件,超时时间为 RT_WAITING_FOREVER,表示无限期等待 */
rt_event_recv(event, EVENT_FLAG, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
RT_WAITING_FOREVER, &eve); //RT_NULL指向接收到的事件
rt_kprintf("Thread 2 received event!\n");
/* 线程休眠一段时间 */
rt_thread_mdelay(500);
}
}
9.初始化
函数初始化
int fn(void)
{
return 0;
}
INIT_BOARD_EXPORT(fn)
finsh命令
list_fn:命令
list semaphore in system:说明
MSH_CMD_EXPORT(list_fn, list semaphore in system);
10.消息队列
函数:
创建:
/**
参数:
1、name 消息队列的名称
2、msg_size 消息队列中一条消息的最大长度,单位字节
3、max_msgs 消息队列的最大个数
4、flag 消息队列采用的等待方式,它可以取如下数值: RT_IPC_FLAG_FIFO 或 RT_IPC_FLAG_PRIO
返回:
RT_EOK 发送成功
消息队列对象的句柄 成功
RT_NULL 失败
*/
rt_mq_t rt_mq_create(const char *name,
rt_size_t msg_size,
rt_size_t max_msgs,
rt_uint8_t flag)
发送:
/**
看函数原型,其实就是把等待方式发送的时间改成了0
参数:
1、mq 消息队列对象的句柄
2、buffer 消息内容
3、size 消息大小
返回:
RT_EOK 成功
-RT_EFULL 消息队列已满
-RT_ERROR 失败,表示发送的消息长度大于消息队列中消息的最大长度
*/
rt_err_t rt_mq_send(rt_mq_t mq, const void *buffer, rt_size_t size)
{
return rt_mq_send_wait(mq, buffer, size, 0);
}
接收
/**
参数:
mq 消息队列对象的句柄
buffer 消息内容
size 消息大小
timeout 指定的超时时间 RT_WAITING_FOREVER
返回:
RT_EOK 成功收到
-RT_ETIMEOUT 超时
-RT_ERROR 失败,返回错误
*/
rt_err_t rt_mq_recv(rt_mq_t mq,
void *buffer,
rt_size_t size,
rt_int32_t timeout)
删除
/**
参数
mq 消息队列对象的句柄
返回
RT_EOK 成功
*/
rt_err_t rt_mq_delete(rt_mq_t mq)
示例:
11.软件延时
void delay_us_software(uint32_t us) {
// 假设CPU的主频是F_CPU MHz,这里需要根据实际情况设置
// 这个延时函数的大致延时时间将是 us * (F_CPU / 1000000) 个CPU周期
const uint32_t cyclesPerUs = F_CPU / 1000000; // CPU周期数/微秒
uint32_t i, j;
for (i = 0; i < us; i++) {
for (j = 0; j < cyclesPerUs; j++) {
__NOP(); // 无操作指令,消耗一个CPU周期
}
}
}
12.ESP8266 wifi
+++退出透传,不能添加回车换行