RT-Thread线程&设备&通信接口(备忘录)

发布时间 2023-05-02 01:28:29作者: 当最后一片树叶落下

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()

1.邮箱


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字节的数据,通常用邮箱传数据结构的地址,比如,数组的地址,结构体的地址等.

2.消息队列

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)
  • 消息队列的用法

1.发送消息(不带有ACK)

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)
    {
        /* 成功接收到消息,进行相应的数据处理 */
    }
}

2.发送同步消息(带有ACK)

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++*/
}

线程间同步接口

1.临界区

rt_enter_critical()
rt_exit_critical()

2.信号量

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线程->xxx线程
/***************静态创建********************/
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的实时性得不到保障.

3.互斥锁

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 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 */