RT-Thread Studio入门(4)— 使用邮箱发送按键状态

RT-Thread Studio使用邮箱发送按键状态

我们在上一个工程(RT-Thread Studio使用轮询法检测按键)的基础上,使用邮箱发送信息给另一个线程,然后对该信息进行处理

一、邮箱的介绍

邮箱是RT-Thread中的一种线程间通信方法,特点是开销比较低,效率较高。邮箱中的每一封邮件只能容纳固定的 4 字节内容(针对 32位处理系统,指针的大小即为 4 个字节,所以一封邮件恰好能够容纳一个指针)。典型的邮箱也称作交换消息,如下图所示,线程或中断服务例程把一封4 字节长度的邮件发送到邮箱中,而一个或多个线程可以从邮箱中接收这些邮件并进行处理。(引用自RT-Thread文档中心)

RT-Thread Studio入门(4)— 使用邮箱发送按键状态_第1张图片

二、创建按键状态邮箱

我们通过动态方法创建一个邮箱
首先,定义一个邮箱控制块结构体指针

/* 定义一个按键状态邮箱控制块结构体指针*/
rt_mailbox_t key_mailbox = RT_NULL;

然后使用动态邮箱创建函数创建一个邮箱

    /* 使用动态创建方法创建一个邮箱 */
    key_mailbox = rt_mb_create ("key mailbox",      /* 邮箱名称 */
                                4,                  /* 邮箱容量,即该邮箱最多可以保存几封邮件 */
                                RT_IPC_FLAG_FIFO);  /* 采用FIFO方式进行线程等待 */

邮箱创建成功后会返回邮箱对象的句柄,如果邮箱创建失败,则返回RT_NULL

    /* 判断邮箱是否创建成功 */
    if( key_mailbox != RT_NULL)
        rt_kprintf("key mailbox create succeed. \n");
    else
        rt_kprintf("key mailbox create failure. \n");

三、发送邮件

在按键被按下时,我们向邮箱中发送对应的邮件,使用非等待方式发送邮件

	if (rt_pin_read(PIN_WK_UP) == PIN_HIGH)
	{
	    /* 按键WK_UP按下,按键按下处理*/
	    rt_kprintf("WK_UP pressed!\n");
	    /* 发送"WK_UP pressed!"字符串地址到key_mailbox邮箱中 */
	    rt_mb_send(key_mailbox, (rt_uint32_t)&"WK_UP pressed!");
	}
	else if (rt_pin_read(PIN_KEY0) == PIN_LOW)
	{
	    /* 按键KEY0按下,按键按下处理*/
	    rt_kprintf("KEY0 pressed!\n");
	    /* 发送"KEY0 pressed!"字符串地址到key_mailbox邮箱中 */
	    rt_mb_send(key_mailbox, (rt_uint32_t)&"KEY0 pressed!");
	}
	else if (rt_pin_read(PIN_KEY1) == PIN_LOW)
	{
	    /* 按键KEY0按下,按键按下处理*/
	    rt_kprintf("KEY1 pressed!\n");
	    /* 发送"KEY1 pressed!"字符串地址到key_mailbox邮箱中 */
	    rt_mb_send(key_mailbox, (rt_uint32_t)&"KEY1 pressed!");
	}
	else if (rt_pin_read(PIN_KEY2) == PIN_LOW)
	{
	    /* 按键KEY0按下,按键按下处理*/
	    rt_kprintf("KEY2 pressed!\n");
	    /* 发送"KEY2 pressed!"字符串地址到key_mailbox邮箱中 */
	    rt_mb_send(key_mailbox, (rt_uint32_t)&"KEY2 pressed!");
	}

其中,邮件发送函数rt_mb_send(),第一个参数为邮箱对象句柄的结构体指针,第二个参数为邮件内容。若邮箱已满,则将该邮件直接丢弃。

四、接收邮件

为了方便,我们直接在主线程中接收邮件,然后对邮件进行处理,我们将超时时间设置为永久等待。

#include 
#include 
#include 

/* defined the LED0 pin: PE7 */
#define LED0_PIN    GET_PIN(E, 7)

void app_key_init(void);
extern rt_mailbox_t key_mailbox;

int main(void)
{
    int count = 1;
    rt_ubase_t * str;  /* 用以存放邮件 */
    /* set LED0 pin mode to output */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);

    app_key_init();

    while (count++)
    {
        /* 从邮箱中收取邮件 */
        if (rt_mb_recv(key_mailbox, (rt_ubase_t *)&str, RT_WAITING_FOREVER) == RT_EOK)
        {
            rt_kprintf("main: %s \n",(char *)str);
        }
        //rt_kprintf("Hello warld! \n");

        rt_pin_write(LED0_PIN, PIN_HIGH);
        rt_thread_mdelay(500);
        rt_pin_write(LED0_PIN, PIN_LOW);
        rt_thread_mdelay(500);
    }

    return RT_EOK;
}

其中要特别注意的是接收邮件函数的第二个参数,需要填入的是我们用来接收邮件的变量的地址,因为我们的邮件是一个字符串指针,所以该参数应该为一个字符串指针的指针,即要在字符串指针变量前加入取地址符&

五、实现效果

RT-Thread Studio入门(4)— 使用邮箱发送按键状态_第2张图片
可以看到,邮箱创建成功,同时在main线程中也接收到了邮件,且接收正确。

六、代码

最后,把app_key.c的代码贴上:

/*
 * Copyright (c) 2006-2020, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2020-04-06     william       the first version
 */

#include 
#include 
#include 

/* 使用静态方法线程创建*/
//#define STATIC_METHON

#ifndef STATIC_METHON
/* 定义一个按键检测线程句柄结构体指针 */
static rt_thread_t key_thread = RT_NULL;
/* 定义一个按键状态邮箱控制块结构体指针*/
rt_mailbox_t key_mailbox = RT_NULL;
#else
/*定义一个按键检测静态线程栈*/
static char key_thread_stack[256];
/*定义一个按键检测静态线程句柄*/
static struct rt_thread key_thread;
#endif

/* 获取相应的引脚编号 */
#define PIN_WK_UP   GET_PIN(C, 13)
#define PIN_KEY0    GET_PIN(D, 10)
#define PIN_KEY1    GET_PIN(D, 9)
#define PIN_KEY2    GET_PIN(D, 8)

/* 按键检测线程入口函数*/
static void key_thread_entry(void *parameter)
{
    static rt_uint8_t key_up = 1;   /* 按键松开标志 */
    /* 初始化按键 */
    rt_pin_mode(PIN_WK_UP, PIN_MODE_INPUT);
    rt_pin_mode(PIN_KEY0, PIN_MODE_INPUT);
    rt_pin_mode(PIN_KEY1, PIN_MODE_INPUT);
    rt_pin_mode(PIN_KEY2, PIN_MODE_INPUT);

    while (1)
    {
        /* 检测按键是否按下 */
        if (key_up && ((rt_pin_read(PIN_WK_UP) == PIN_HIGH) ||
                      (rt_pin_read(PIN_KEY0) == PIN_LOW)    ||
                      (rt_pin_read(PIN_KEY1) == PIN_LOW)    ||
                      (rt_pin_read(PIN_KEY2) == PIN_LOW) )       )
        {
            rt_thread_mdelay(50);   /* 延时消抖*/
            key_up = 0;
            if (rt_pin_read(PIN_WK_UP) == PIN_HIGH)
            {
                /* 按键WK_UP按下,按键按下处理*/
                rt_kprintf("WK_UP pressed!\n");
                /* 发送"WK_UP pressed!"字符串地址到key_mailbox邮箱中 */
                rt_mb_send(key_mailbox, (rt_uint32_t)&"WK_UP pressed!");
            }
            else if (rt_pin_read(PIN_KEY0) == PIN_LOW)
            {
                /* 按键KEY0按下,按键按下处理*/
                rt_kprintf("KEY0 pressed!\n");
                /* 发送"KEY0 pressed!"字符串地址到key_mailbox邮箱中 */
                rt_mb_send(key_mailbox, (rt_uint32_t)&"KEY0 pressed!");
            }
            else if (rt_pin_read(PIN_KEY1) == PIN_LOW)
            {
                /* 按键KEY0按下,按键按下处理*/
                rt_kprintf("KEY1 pressed!\n");
                /* 发送"KEY1 pressed!"字符串地址到key_mailbox邮箱中 */
                rt_mb_send(key_mailbox, (rt_uint32_t)&"KEY1 pressed!");
            }
            else if (rt_pin_read(PIN_KEY2) == PIN_LOW)
            {
                /* 按键KEY0按下,按键按下处理*/
                rt_kprintf("KEY2 pressed!\n");
                /* 发送"KEY2 pressed!"字符串地址到key_mailbox邮箱中 */
                rt_mb_send(key_mailbox, (rt_uint32_t)&"KEY2 pressed!");
            }
        }
        else if((rt_pin_read(PIN_WK_UP) == PIN_LOW) &&
                (rt_pin_read(PIN_KEY0) == PIN_HIGH) &&
                (rt_pin_read(PIN_KEY1) == PIN_HIGH) &&
                (rt_pin_read(PIN_KEY2) == PIN_HIGH)     )
        {
            key_up = 1;     /* 按键已松开 */
        }
        rt_thread_mdelay(100);
    }

}


void app_key_init(void)
{
    rt_err_t rt_err;
#ifndef STATIC_METHON
    /* 创建按键检测线程*/
    key_thread = rt_thread_create(  "key thread",       /* 线程的名称 */
                                    key_thread_entry,   /* 线程入口函数 */
                                    RT_NULL,            /* 线程入口函数的参数   */
                                    256,                /* 线程栈大小,单位是字节  */
                                    5,                  /* 线程的优先级,数值越小优先级越高*/
                                    10);                /* 线程的时间片大小 */
    /* 如果获得线程控制块,启动这个线程 */
    if (key_thread != RT_NULL)
        rt_err = rt_thread_startup(key_thread);
    else
        rt_kprintf("key thread create failure !!! \n");

    /* 判断线程是否创建成功 */
    if( rt_err == RT_EOK)
        rt_kprintf("key thread startup ok. \n");
    else
        rt_kprintf("key thread startup err. \n");

    /* 使用动态创建方法创建一个邮箱 */
    key_mailbox = rt_mb_create ("key mailbox",      /* 邮箱名称 */
                                4,                  /* 邮箱容量,即该邮箱最多可以保存几封邮件 */
                                RT_IPC_FLAG_FIFO);  /* 采用FIFO方式进行线程等待 */
    /* 判断邮箱是否创建成功 */
    if( key_mailbox != RT_NULL)
        rt_kprintf("key mailbox create succeed. \n");
    else
        rt_kprintf("key mailbox create failure. \n");

#else
    /* 初始化按键检测线程,名称是thread2,入口是thread2_entry */
    rt_err = rt_thread_init(&key_thread,                /* 线程句柄 */
                           "key thread",                /* 线程的名称 */
                           key_thread_entry,            /* 线程入口函数 */
                           RT_NULL,                     /* 线程入口函数的参数   */
                           &key_thread_stack[0],        /* 线程栈起始地址*/
                           sizeof(key_thread_stack),    /* 线程栈大小,单位是字节*/
                           5,                           /* 线程的优先级,数值越小优先级越高*/
                           10);                         /* 线程的时间片大小 */
    /* 如果线程创建成功,启动这个线程 */
    if (rt_err == RT_EOK)
        rt_err = rt_thread_startup(&key_thread);
    else
        rt_kprintf("key thread init failure !!! \n");

    /* 判断线程是否启动成功 */
    if( rt_err == RT_EOK)
        rt_kprintf("key thread startup ok. \n");
    else
        rt_kprintf("key thread startup err. \n");
#endif
}

你可能感兴趣的:(RT-Thread)