跑RT-Thread的邮箱应用例程
《RT-Thread内核实现与应用开发实战》详细介绍了RT-Thread的邮箱应用。https://doc.embedfire.com/rtos/rtthread/zh/latest/application/mailbox.html 有详细介绍邮箱原理及其应用。
配套带有例子程序的工程文件存放于配套程序文件夹:ebf_rtthread_base_code_stm32f103_zhinanzhe-master\23,邮箱。打开文件夹 23,邮箱\Project\RVMDK(uv4)文件夹下的工程文件: Fire_RT-Thread.uvprojx
若直接仿真运行,会出现错误:
*** error 65: access violation at 0x40021000 : no 'read' permission
需要修改:
即工程配置的Debug选项里面的设置有问题:
Dialog DLL默认是DCM3.DLL
Parameter默认是-pCM3
应改为
Dialog DLL是DARMSTM.DLL
Parameter是-pSTM32F103VC
就可以仿真运行,打开串口窗口、以及外围GPIOA、GPIOC,运行的效果:
本代码在 野火“开发板RT-Thread 3.0 + STM32 邮箱”的例程上修改。原代码是2个线程,这里改为3个线程,并在按下key2时连续发送消息,造成邮箱发送错误。
/**
*********************************************************************
* @file main.c
* @author fire
* @version V1.0
* @date 2018-xx-xx
* @brief RT-Thread 3.0 + STM32 邮箱
*********************************************************************
* @attention
*
* 实验平台:野火 F103-指南者 STM32 开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :https://fire-stm32.taobao.com
*
**********************************************************************
*/
/*
*************************************************************************
* 包含的头文件
*************************************************************************
*/
#include "board.h"
#include "rtthread.h"
/*
******************************************************************
* 变量
******************************************************************
*/
/* 定义线程控制块 */
static rt_thread_t receive_thread = RT_NULL;
static rt_thread_t send_thread = RT_NULL;
/* 定义邮箱控制块 */
static rt_mailbox_t test_mail = RT_NULL;
/************************* 全局变量声明 ****************************/
/*
* 当我们在写应用程序的时候,可能需要用到一些全局变量。
*/
char test_str1[] = "this is a mail test 1";/* 邮箱消息test1 */
char test_str2[] = "this is a mail test 2";/* 邮箱消息test2 */
/*
*************************************************************************
* 函数声明
*************************************************************************
*/
static void receive_thread_entry(void* parameter);
static void key1_send_thread_entry(void* parameter);
static void key2_send_thread_entry(void* parameter);
/*
*************************************************************************
* main 函数
*************************************************************************
*/
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
/*
* 开发板硬件初始化,RTT系统初始化已经在main函数之前完成,
* 即在component.c文件中的rtthread_startup()函数中完成了。
* 所以在main函数中,只需要创建线程和启动线程即可。
*/
rt_kprintf("这是一个[野火]-STM32F103-指南者-RTT邮箱消息实验!\n");
rt_kprintf("按下K1 | K2进行邮箱实验测试!\n");
/* 创建一个邮箱 */
test_mail = rt_mb_create("test_mail", /* 邮箱名字 */
10,
RT_IPC_FLAG_FIFO);/* 信号量模式 FIFO(0x00)*/
if (test_mail != RT_NULL)
rt_kprintf("邮箱创建成功!\n\n");
receive_thread = /* 线程控制块指针 */
rt_thread_create( "receive", /* 线程名字 */
receive_thread_entry, /* 线程入口函数 */
RT_NULL, /* 线程入口函数参数 */
512, /* 线程栈大小 */
3, /* 线程的优先级 */
20); /* 线程时间片 */
/* 启动线程,开启调度 */
if (receive_thread != RT_NULL)
rt_thread_startup(receive_thread);
else
return -1;
send_thread = /* 线程控制块指针 */
rt_thread_create( "send", /* 线程名字 */
key1_send_thread_entry, /* 线程入口函数 */
RT_NULL, /* 线程入口函数参数 */
512, /* 线程栈大小 */
2, /* 线程的优先级 */
20); /* 线程时间片 */
/* 启动线程,开启调度 */
if (send_thread != RT_NULL)
rt_thread_startup(send_thread);
else
return -1;
send_thread = /* 线程控制块指针 */
rt_thread_create( "send", /* 线程名字 */
key2_send_thread_entry, /* 线程入口函数 */
RT_NULL, /* 线程入口函数参数 */
512, /* 线程栈大小 */
2, /* 线程的优先级 */
20); /* 线程时间片 */
/* 启动线程,开启调度 */
if (send_thread != RT_NULL)
rt_thread_startup(send_thread);
else
return -1;
}
/*
*************************************************************************
* 线程定义
*************************************************************************
*/
static void receive_thread_entry(void* parameter)
{
rt_err_t uwRet = RT_EOK;
char *r_str;
/* 任务都是一个无限循环,不能返回 */
while(1)
{
/* 等待接邮箱消息 */
uwRet = rt_mb_recv(test_mail, /* 邮箱对象句柄 */
(rt_uint32_t*)&r_str, /* 接收邮箱消息 */
RT_WAITING_FOREVER);/* 指定超时事件,一直等 */
if(RT_EOK == uwRet) /* 如果接收完成并且正确 */
{
rt_kprintf ( "邮箱的内容是:%s\n\n",r_str);
LED1_TOGGLE; //LED1 反转
}
else
rt_kprintf ( "邮箱接收错误!错误码是0x%x\n",uwRet);
rt_thread_delay(100); //100ms后再接收
}
}
static void key1_send_thread_entry(void* parameter)
{
rt_err_t uwRet = RT_EOK;
/* 任务都是一个无限循环,不能返回 */
while (1)
{ //如果KEY1被单击
if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON )
{
rt_kprintf ( "KEY1被单击\n" );
/* 发送一个邮箱消息1 */
do
{
uwRet = rt_mb_send(test_mail,(rt_uint32_t)&test_str1);
rt_thread_delay(10); //释放CPU控制
}while(uwRet!=RT_EOK); //直至发送成功
rt_kprintf ( "邮箱消息发送成功\n" );
}
rt_thread_delay(20); //每20ms扫描一次
}
}
static void key2_send_thread_entry(void* parameter)
{
rt_err_t uwRet = RT_EOK;
/* 任务都是一个无限循环,不能返回 */
while (1)
{
//如果KEY2被单击
if( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON )
{
rt_kprintf ( "KEY2被单击\n" );
/* 连续发送15次邮箱消息2 */
for(int i=0;i<15;i++)
{
do
{
uwRet = rt_mb_send(test_mail,(rt_uint32_t)&test_str2);
rt_thread_delay(10); //释放CPU控制
}while(uwRet!=RT_EOK); //直至发送成功
rt_kprintf ( "邮箱消息发送成功\n" );
}
}
rt_thread_delay(20); //每20ms扫描一次
}
}
/********************************END OF FILE****************************/
在GPIOA窗口的Pins打勾后取消打勾(相当于按下Key1),即会通过邮箱发送信息:
在发送线程,打印输出“KEY1被单击”“邮箱消息发送成功”。
在接收线程,打印输出邮箱内容“邮箱的内容是:this is a mail test 1”。