RT-Thread线程&设备&通信接口(备忘录)
RT-Thread线程通信接口
线程接口
#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 512
#define THREAD_TIMESLICE 5
rt_thread_yield();/*让出CPU资源*/
rt_thread_sleep(ticks);
rt_thread_delay(ticks);
rt_thread_delay(ms);
rt_thread_suspend(xxx_thread);
rt_thread_resume(xxx_thread);
void xxx_thread_entry(void *parameter)
{
while(1)
{
}
}
static int xxx_task_init(void)
{
rt_err_t ret = RT_EOK;
/*device初始化*/
/*ipc初始化*/
/* 创建 xxx 线程 --- 动态分配*/
rt_thread_t xxx_thread = rt_thread_create("xxx",
xxx_thread_entry,
RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY,
THREAD_TIMESLICE);
/* 创建成功则启动线程 */
if (thread != RT_NULL)
{
rt_thread_startup(xxx_thread);
}
else
{
ret = RT_ERROR;
}
/*创建线程 --- 静态分配*/
ALIGN(RT_ALIGN_SIZE)
static char xxx_thread_stack[THREAD_STACK_SIZE];
static struct rt_thread xxx_thread;
rt_thread_init(xxx_thread,
"xxx",
xxx_thread_entry,
RT_NULL,
&xxx_thread_stack[0],
THREAD_STACK_SIZE,
THREAD_PRIORITY - 1, THREAD_TIMESLICE);
rt_thread_startup(&xxx_thread);
}
INIT_APP_EXPORT(xxx_task_init);
- 注意:
线程必须加入while(1),不然执行一遍后会调用rt_thread_exit(),进入exit状态,相当于执行了rt_thread_delete/detach().
设备接口(device)
/*device flag*/
#define RT_DEVICE_FLAG_RDONLY 0x001 /**< read only */
#define RT_DEVICE_FLAG_WRONLY 0x002 /**< write only */
#define RT_DEVICE_FLAG_RDWR 0x003 /**< read and write */
#define RT_DEVICE_FLAG_INT_RX 0x100 /**< INT mode on Rx */
#define RT_DEVICE_FLAG_DMA_RX 0x200 /**< DMA mode on Rx */
#define RT_DEVICE_FLAG_INT_TX 0x400 /**< INT mode on Tx */
#define RT_DEVICE_FLAG_DMA_TX 0x800 /**< DMA mode on Tx */
#define RT_DEVICE_FLAG_STREAM 0x040 /**< stream mode */
/*cmd--device config*/
#define RT_DEVICE_CTRL_CONFIG 0x03 /**< configure device */
static rt_err_t xxx_input(rt_device_t dev, rt_size_t size);
struct serial_configure config= {};/*串口的配置结构体*/
char str[XXX_RB_BUFSZ+1];
/****************设备操作****************/
rt_device_t xxx_device = NULL;
xxx_device = rt_device_find("xxx");
rt_device_control(xxx_device,cmd,param)
ret = rt_device_open(xxx_device,flag);
rt_device_set_rx_indicate(xxx_device,xxx_input)
/*tips回调函数包含dev*/
rt_device_write(xxx_device,pos,str,sizeof(str)-1)
length = rt_device_read(xxx_device,pos,str,size)
线程间通信接口
线程间通信
线程间通信的接口都提供了两种初始化方式 —— 动态和静态.
它们的接口有如下关系:
动态的创建和删除:xxx_create()/xxx_delete()
静态的创建和解绑:xxx_init()/xxx_detach()
typedef struct rt_mailbox* rt_mailbox_t;
#define XXX_MB_BUFSZ 64
#define XXX_STR_BUFSZ 32
/*************** 静态创建 ********************/
/* 邮箱控制块 */
static struct rt_mailbox xxx_mb;
/* 用于放邮件的内存池 */
static char mb_pool[XXX_MB_BUFSZ];
static char mb_str[XXX_STR_BUFSZ] = "I'm a mail!"
static char *str
result = rt_mb_init(&xxx_mb,
"xxx_mb", /* 名称是 mbt */
&mb_pool[0], /* 邮箱用到的内存池是 mb_pool */
sizeof(mb_pool) / 4, /* 邮箱中的邮件数目,因为一封邮件占 4 字节 */
RT_IPC_FLAG_FIFO); /* 采用 FIFO 方式进行线程等待 */
/*************** 动态创建 ********************/
rt_mailbox_t xxx_mb = RT_NULL;
xxx_mb = rt_mb_create("xxx_mb",sizeof(mb_pool) / 4,RT_IPC_FLAG_FIFO)
/* xxx_thread发送 */
rt_mb_send(&mb, (rt_uint32_t)&mb_str)
/* yyy_thread接收 */
rt_mb_recv(&mb, (rt_uint32_t *)&str, RT_WAITING_FOREVER)
- 邮箱用法
邮箱只能传4字节的数据,通常用邮箱传数据结构的地址,比如,数组的地址,结构体的地址等.
typedef struct rt_messagequeue* rt_mq_t;
#define XXX_MQ_BUFSZ 2048
/*************** 动态创建 ********************/
rt_mq_t xxx_mq = RT_NULL;
xxx_mq = rt_mq_create("xxx_mq",sizeof(msg_pool),RT_IPC_FLAG_FIFO);
/*************** 静态创建 ********************/
/* 消息队列控制块 */
static struct rt_messagequeue xxx_mq;
/* 消息队列中用到的放置消息的内存池 */
static rt_uint8_t msg_pool[XXX_MQ_BUFSZ];
/* 初始化消息队列 */
result = rt_mq_init(&xxx_mq,
"xxx_mq",
&msg_pool[0], /* 内存池指向 msg_pool */
1, /* 每个消息的大小是 1 字节 */
sizeof(msg_pool), /* 内存池的大小是 msg_pool 的大小 */
RT_IPC_FLAG_PRIO); /* 如果有多个线程等待,优先级大小的方法分配消息 */
/*xxx_thread中 发送消息到消息队列中 */
result = rt_mq_send(&xxx_mq, &buf, 1);/*发送一个字节....*/
/*yyy_thread */
ret = rt_mq_recv(&xxx_mq, &buf, sizeof(buf), RT_WAITING_FOREVER)
- 消息队列的用法
struct msg
{
rt_uint8_t *data_ptr; /* 数据块首地址 */
rt_uint32_t data_size; /* 数据块大小 */
};
void send_op(void *data, rt_size_t length)
{
struct msg msg_ptr;
msg_ptr.data_ptr = data; /* 指向相应的数据块地址 */
msg_ptr.data_size = length; /* 数据块的长度 */
/* 发送这个消息指针给 mq 消息队列 */
rt_mq_send(mq, (void*)&msg_ptr, sizeof(struct msg));
}
void message_handler()
{
struct msg msg_ptr; /* 用于放置消息的局部变量 */
/* 从消息队列中接收消息到 msg_ptr 中 */
if (rt_mq_recv(mq, (void*)&msg_ptr, sizeof(struct msg), RT_WAITING_FOREVER) == RT_EOK)
{
/* 成功接收到消息,进行相应的数据处理 */
}
}
struct msg
{
/* 消息结构其他成员 */
struct rt_mailbox ack;
/* 消息的数据成员 */
rt_uint8_t *data_ptr; /* 数据块首地址 */
rt_uint32_t data_size; /* 数据块大小 */
};
/* 或者 */
struct msg
{
/* 消息结构其他成员 */
struct rt_semaphore ack;
/* 消息的数据成员 */
rt_uint8_t *data_ptr; /* 数据块首地址 */
rt_uint32_t data_size; /* 数据块大小 */
};
#define XXX_MSG_BUFSZ 512
struct rt_mailbox xxx_mb;
rt_uint8_t xxx_data_pool[XXX_MSG_BUFSZ]
struct msg = {
.ack = xxx_mb
.data = xxx_data_pool;
.data_size = XXX_MSG_BUFSZ;
}
/* xxx_thread发送消息 */
send_op(&msg,sizeof(msg))
/* 使用mailbox作为ack */
ret = rt_mq_recv(xxx_mb,&ack_state, 1, timeout);
/* 使用信号量作为ack */
ret = rt_sem_take(xxx_sem, timeout);/*val--*/
/* 超时 */
if(ret = -RT_ETIMEOUT)
{
/* 超时处理 */
}
else
{
/*ack正常处理*/
}
/* yyy_thread接收消息 */
void message_handler()
{
struct msg msg_ptr; /* 用于放置消息的局部变量 */
int state = 0;
/* 从消息队列中接收消息到 msg_ptr 中 */
if (rt_mq_recv(mq, (void*)&msg_ptr, sizeof(struct msg), RT_WAITING_FOREVER) == RT_EOK)
{
/* 成功接收到消息,进行相应的数据处理 */
/* 使用msg_ptr->data_ptr & msg_ptr->data_size的数据 */
}
rt_mq_send(msg_ptr->ack, state, 1);
/* 信号量同样 */
rt_sem_release(msg_ptr->ack);/*val++*/
}
线程间同步接口
rt_enter_critical()
rt_exit_critical()
typedef struct rt_semaphore* rt_sem_t;
/*************** 动态创建 ********************/
rt_err_t result = RT_EOK;
rt_sem_t xxx_sem= RT_NULL;
/* 创建信号量--基于优先级 */
xxx_sem = rt_sem_create("dsem", 0, RT_IPC_FLAG_PRIO)
/* 在yyy线程(优先级N)释放信号量 */
rt_sem_release(xxx_sem);/* val++ */
/* 在xxx线程(优先级N-1)获取信号量,此时xxx线程与yyy线程同步 */
result = rt_sem_take(xxx_sem, RT_WAITING_FOREVER);/* val-- */
if (result != RT_EOK)
{
rt_sem_delete(xxx_sem)/* 删除信号 */
}
效果:
/* 在yyy线程(优先级N)释放信号量 */
/* code 1 */
rt_sem_release(xxx_sem);/* val++ */
/* code 2 */
/* 在xxx线程(优先级N-1)获取信号量,此时xxx线程与yyy线程同步 */
result = rt_sem_take(xxx_sem, RT_WAITING_FOREVER);/* val-- */
if (result != RT_EOK)
{
rt_sem_delete(xxx_sem)/* 删除信号 */
}
/* code 3 */
/***********************************
* 执行顺序:code 1 -> code 3 -> code 2
************************************/
/*************** 静态创建 ********************/
struct rt_semaphore xxx_sem;
rt_sem_init(&xxx_sem, "xxx", 1, RT_IPC_FLAG_PRIO);/* 允许访问一次 */
/* 原子操作 */
rt_sem_take(xxx_sem, RT_WAITING_FOREVER);
/* 资源M */
rt_sem_release(xxx_sem);
/* xxx线程,yyy线程的优先级不同,不能相差>=2,否则会有优先级反转的问题 */
- 注意:
信号量的问题:优先级反转
优先级A>B>C,A和C有共享资源(M)时,当C占有资源,则A会被挂起,此时B因为不需要访问共享资源(M),所以抢占了C的执行,从而A的实时性得不到保障.
typedef struct rt_mutex* rt_mutex_t;
/*************** 动态创建 ********************/
static rt_mutex_t xxx_mutex = RT_NULL;
/* 基于优先级创建一个mutex */
xxx_mutex = rt_mutex_create("xxx_mutex", RT_IPC_FLAG_PRIO);
/* xxx_thread中,对共享资源M上锁 */
rt_mutex_take(xxx_mutex, RT_WAITING_FOREVER);
/* 资源M */
rt_mutex_release(xxx_mutex);
/* xxx线程,yyy线程优先级不同,可以相差>=2 */
/*************** 静态创建 ********************/
struct rt_mutex xxx_mutex;
rt_mutex_init(xxx_mutex, "xxx_mutex",RT_IPC_FLAG_PRIO)
typedef struct rt_event* rt_event_t;
/*************** 动态创建 ********************/
static rt_event_t xxx_event = RT_NULL;
/* 基于优先级创建一个mutex */
xxx_event = rt_event_create("xxx_event", RT_IPC_FLAG_PRIO);
/* xxx_thread中 发生事件 EVENT_FLAG1 */
rt_event_send(xxx_event, EVENT_FLAG1);
/* yyy_thread中,接收到EVENT_FLAG1, 会触发该事件往下执行*/
rt_event_recv(xxx_event, EVENT_FLAG1|EVENT_FLAG2|EVENT_FLAG3, RT_EVENT_FLAG_OR|RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &e); /* 事件之间逻辑或 */
rt_kprintf("thread1: OR recv event 0x%x\n", e); /* 显示当前的事件 */
rt_event_recv(xxx_event, EVENT_FLAG4|EVENT_FLAG5, RT_EVENT_FLAG_AND|RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &e); /* 事件之间逻辑与 */
rt_kprintf("thread1: AND recv event 0x%x\n", e); /* 显示当前的事件 */
/*************** 静态创建 ********************/
struct rt_event xxx_event;
rt_event_init(&xxx_event, "xxx_event",RT_IPC_FLAG_PRIO);
/* 操作相同 */
- 事件集的用法
用来同步多个线程.
可以用事件集来触发那些状态机线程
比如按键线程发送EVENT_UP_FLAG
相关的线程 —— LCD线程,电机线程,以及其它执行线程,收到该事件后:
LCD线程:显示值增加
电机线程:电机的PWM增加
其它执行线程:LED关闭,执行器动作,蜂鸣器鸣叫一下等.
常用数据类型
typedef signed long rt_base_t; /**< Nbit CPU related date type */
typedef rt_base_t rt_err_t; /**< Type for error number */
typedef rt_uint32_t rt_time_t; /**< Type for time stamp */
typedef rt_uint32_t rt_tick_t; /**< Type for tick count */
typedef rt_base_t rt_flag_t; /**< Type for flags */
typedef rt_ubase_t rt_dev_t; /**< Type for device */
typedef rt_base_t rt_off_t; /**< Type for offset */
常用返回值
#define RT_EOK 0 /**< There is no error */
#define RT_ERROR 1 /**< A generic error happens */
#define RT_ETIMEOUT 2 /**< Timed out */
#define RT_EFULL 3 /**< The resource is full */
#define RT_EEMPTY 4 /**< The resource is empty */
#define RT_ENOMEM 5 /**< No memory */
#define RT_ENOSYS 6 /**< No system */
#define RT_EBUSY 7 /**< Busy */
#define RT_EIO 8 /**< IO error */
#define RT_EINTR 9 /**< Interrupted system call */
#define RT_EINVAL 10 /**< Invalid argument */
#define RT_ETRAP 11 /**< Trap event */
#define RT_ENOENT 12 /**< No entry */
#define RT_ENOSPC 13 /**< No space left */
本文来自博客园,作者:当最后一片树叶落下,转载请注明原文链接:https://www.cnblogs.com/Rabbit-susu/p/17367261.html