18.3 实验例程说明(4字节对齐)
18.3.1 STM32F103开发板实验
配套例子:
V4-417_RTX实验_内存管理(4字节对齐)
实验目的:
1. 学习RTX的内存管理(4字节对齐)。
2. 函数_declare_box和_init_box用于4字节对齐的内存池初始化。这里4字节对齐的含义
a. 内存池的首地址是4字节对齐(4字节对齐就是地址对4求余等于0)。
b. 每个内存块大小也得是4字节的倍数,这样才能保证每申请到的一个内存块的首地址也是4字节对齐。
c. 4字节对齐是由RTX系统完成的。
实验内容:
1. K1按键按下,串口打印。
2. K2键按下,申请一个内存块用于8位整形变量,然后向消息邮箱发送数据。
3. K3键按下,申请一个内存块用于16位整形变量,然后向消息邮箱发送数据。
4. 摇杆OK键按下,申请一个内存块用于32位整形变量,然后向消息邮箱发送数据。
5. 各个任务实现的功能如下:
AppTaskUserIF任务 :按键消息处理。
AppTaskLED任务 :LED闪烁。
AppTaskMsgPro任务
:消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
RTX配置向导详情如下:

u Task
Configuration
l Number
of concurrent running tasks
允许创建4个任务,实际创建了如下四个任务:
AppTaskUserIF任务 :按键消息处理。
AppTaskLED任务 :LED闪烁。
AppTaskMsgPro任务
:消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。
l Number
of tasks with user-provided stack
创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:

程序设计:
u 任务栈大小分配:
static uint64_t
AppTaskUserIFStk[512/8];
static uint64_t
AppTaskLEDStk[256/8];
static uint64_t
AppTaskMsgProStk[512/8];
static uint64_t
AppTaskStartStk[512/8];
将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
u 系统栈大小分配:

u RTX初始化:
int main (void)
{
bsp_Init();
os_sys_init_user
(AppTaskStart,
4,
&AppTaskStartStk,
sizeof(AppTaskStartStk));
while(1);
}
u RTX任务创建:
static void AppTaskCreate
(void)
{
HandleTaskUserIF
=
os_tsk_create_user(AppTaskUserIF,
1,
&AppTaskUserIFStk,
sizeof(AppTaskUserIFStk));
HandleTaskLED
=
os_tsk_create_user(AppTaskLED,
2,
&AppTaskLEDStk,
sizeof(AppTaskLEDStk));
HandleTaskMsgPro
=
os_tsk_create_user(AppTaskMsgPro,
3,
&AppTaskMsgProStk,
sizeof(AppTaskMsgProStk));
}
u 内存管理的初始化和消息邮箱的创建:
#define
PoolBlocks 10
#define
PoolPerBlockSize 8
os_mbx_declare (mailbox,
10);
_declare_box(mpool,
PoolPerBlockSize, PoolBlocks);
static void AppObjCreate
(void)
{
os_mbx_init
(&mailbox, sizeof(mailbox));
_init_box
(mpool, sizeof (mpool), PoolPerBlockSize);
}
u 四个RTX任务的实现:
__task void
AppTaskUserIF(void)
{
uint8_t *pucMsg;
uint16_t
*pusMsg;
uint32_t
*pulMsg;
uint8_t
ucKeyCode, ucCount = 0;
while(1)
{
ucKeyCode
= bsp_GetKey();
if
(ucKeyCode != KEY_NONE)
{
switch
(ucKeyCode)
{
case
KEY_DOWN_K1:
printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
break;
case
KEY_DOWN_K2:
pucMsg =
_alloc_box (mpool);
*pucMsg
= ucCount++;
if(os_mbx_send
(&mailbox, pucMsg, 100) != OS_R_OK)
{
printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
_free_box
(mpool, pucMsg);
}
else
{
printf("K2键按下,向消息邮箱发送数据成功\r\n");
_free_box
(mpool, pucMsg);
}
break;
case
KEY_DOWN_K3:
pusMsg =
_alloc_box (mpool);
*pusMsg
= ucCount++;
if(os_mbx_send
(&mailbox, pusMsg, 100) != OS_R_OK)
{
printf("K3键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
_free_box
(mpool, pusMsg);
}
else
{
printf("K3键按下,向消息邮箱发送数据成功\r\n");
_free_box
(mpool, pusMsg);
}
break;
case
JOY_DOWN_OK:
pulMsg =
_alloc_box (mpool);
*pulMsg
= ucCount++;
if(os_mbx_send
(&mailbox, pulMsg, 100) != OS_R_OK)
{
printf("摇杆OK键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
_free_box
(mpool, pulMsg);
}
else
{
printf("摇杆OK键按下,向消息邮箱发送数据成功\r\n");
_free_box
(mpool, pulMsg);
}
break;
default:
break;
}
}
os_dly_wait(20);
}
}
__task void
AppTaskLED(void)
{
const
uint16_t usFrequency = 200;
os_itv_set(usFrequency);
while(1)
{
bsp_LedToggle(2);
bsp_LedToggle(3);
os_itv_wait();
}
}
__task void
AppTaskMsgPro(void)
{
uint8_t
*pMsg;
OS_RESULT
xResult;
const
uint16_t usMaxBlockTime = 200;
while(1)
{
xResult
= os_mbx_wait(&mailbox, (void *)&pMsg,
usMaxBlockTime);
switch
(xResult)
{
case
OS_R_OK:
printf("无需等待接受到消息邮箱数据,pMsg
= %d\r\n", *pMsg);
break;
case
OS_R_MBX:
printf("因为消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据,pMsg
= %d\r\n", *pMsg);
break;
case
OS_R_TMO:
bsp_LedToggle(1);
bsp_LedToggle(4);
break;
default:
break;
}
}
}
__task void
AppTaskStart(void)
{
AppTaskCreate();
AppObjCreate();
while(1)
{
bsp_KeyScan();
os_dly_wait(10);
}
}
18.3.2 STM32F407开发板实验
配套例子:
V5-417_RTX实验_内存管理(4字节对齐)
实验目的:
1. 学习RTX的内存管理(4字节对齐)。
2. 函数_declare_box和_init_box用于4字节对齐的内存池初始化。这里4字节对齐的含义
a. 内存池的首地址是4字节对齐(4字节对齐就是地址对4求余等于0)。
b. 每个内存块大小也得是4字节的倍数,这样才能保证每申请到的一个内存块的首地址也是4字节对齐。
c. 4字节对齐是由RTX系统完成的。
实验内容:
1. K1按键按下,串口打印。
2. K2键按下,申请一个内存块用于8位整形变量,然后向消息邮箱发送数据。
3. K3键按下,申请一个内存块用于16位整形变量,然后向消息邮箱发送数据。
4. 摇杆OK键按下,申请一个内存块用于32位整形变量,然后向消息邮箱发送数据。
5. 各个任务实现的功能如下:
AppTaskUserIF任务 :按键消息处理。
AppTaskLED任务 :LED闪烁。
AppTaskMsgPro任务
:消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。
RTX配置:
RTX配置向导详情如下:

u Task
Configuration
l Number
of concurrent running tasks
允许创建4个任务,实际创建了如下四个任务:
AppTaskUserIF任务 :按键消息处理。
AppTaskLED任务 :LED闪烁。
AppTaskMsgPro任务
:消息处理,等待任务AppTaskUserIF发来的消息邮箱数据。
AppTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。
l Number
of tasks with user-provided stack
创建的4个任务都是采用自定义堆栈方式。
RTX任务调试信息:

程序设计:
u 任务栈大小分配:
static uint64_t
AppTaskUserIFStk[512/8];
static uint64_t
AppTaskLEDStk[256/8];
static uint64_t
AppTaskMsgProStk[512/8];
static uint64_t
AppTaskStartStk[512/8];
将任务栈定义成uint64_t类型可以保证任务栈是8字节对齐的,8字节对齐的含义就是数组的首地址对8求余等于0。如果不做8字节对齐的话,部分C语言库函数,浮点运算和uint64_t类型数据运算会出问题。
u 系统栈大小分配:

u RTX初始化:
int main (void)
{
bsp_Init();
os_sys_init_user
(AppTaskStart,
4,
&AppTaskStartStk,
sizeof(AppTaskStartStk));
while(1);
}
u RTX任务创建:
static void AppTaskCreate
(void)
{
HandleTaskUserIF
=
os_tsk_create_user(AppTaskUserIF,
1,
&AppTaskUserIFStk,
sizeof(AppTaskUserIFStk));
HandleTaskLED
=
os_tsk_create_user(AppTaskLED,
2,
&AppTaskLEDStk,
sizeof(AppTaskLEDStk));
HandleTaskMsgPro
=
os_tsk_create_user(AppTaskMsgPro,
3,
&AppTaskMsgProStk,
sizeof(AppTaskMsgProStk));
}
u 内存管理的初始化和消息邮箱的创建:
#define
PoolBlocks 10
#define
PoolPerBlockSize 8
os_mbx_declare (mailbox,
10);
_declare_box(mpool,
PoolPerBlockSize, PoolBlocks);
static void AppObjCreate
(void)
{
os_mbx_init
(&mailbox, sizeof(mailbox));
_init_box
(mpool, sizeof (mpool), PoolPerBlockSize);
}
u 四个RTX任务的实现:
__task void
AppTaskUserIF(void)
{
uint8_t *pucMsg;
uint16_t
*pusMsg;
uint32_t
*pulMsg;
uint8_t
ucKeyCode, ucCount = 0;
while(1)
{
ucKeyCode
= bsp_GetKey();
if
(ucKeyCode != KEY_NONE)
{
switch
(ucKeyCode)
{
case
KEY_DOWN_K1:
printf("K1键按下,使用MDK中自带的RTX调试组件,请务必使用MDK4.74版本进行调试\r\n");
break;
case
KEY_DOWN_K2:
pucMsg =
_alloc_box (mpool);
*pucMsg
= ucCount++;
if(os_mbx_send
(&mailbox, pucMsg, 100) != OS_R_OK)
{
printf("K2键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
_free_box
(mpool, pucMsg);
}
else
{
printf("K2键按下,向消息邮箱发送数据成功\r\n");
_free_box
(mpool, pucMsg);
}
break;
case
KEY_DOWN_K3:
pusMsg =
_alloc_box (mpool);
*pusMsg
= ucCount++;
if(os_mbx_send
(&mailbox, pusMsg, 100) != OS_R_OK)
{
printf("K3键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
_free_box
(mpool, pusMsg);
}
else
{
printf("K3键按下,向消息邮箱发送数据成功\r\n");
_free_box
(mpool, pusMsg);
}
break;
case
JOY_DOWN_OK:
pulMsg =
_alloc_box (mpool);
*pulMsg
= ucCount++;
if(os_mbx_send
(&mailbox, pulMsg, 100) != OS_R_OK)
{
printf("摇杆OK键按下,向消息邮箱发送数据失败,即使等待了100个时钟节拍\r\n");
_free_box
(mpool, pulMsg);
}
else
{
printf("摇杆OK键按下,向消息邮箱发送数据成功\r\n");
_free_box
(mpool, pulMsg);
}
break;
default:
break;
}
}
os_dly_wait(20);
}
}
__task void
AppTaskLED(void)
{
const
uint16_t usFrequency = 200;
os_itv_set(usFrequency);
while(1)
{
bsp_LedToggle(2);
bsp_LedToggle(3);
os_itv_wait();
}
}
__task void
AppTaskMsgPro(void)
{
uint8_t
*pMsg;
OS_RESULT
xResult;
const
uint16_t usMaxBlockTime = 200;
while(1)
{
xResult
= os_mbx_wait(&mailbox, (void *)&pMsg,
usMaxBlockTime);
switch
(xResult)
{
case
OS_R_OK:
printf("无需等待接受到消息邮箱数据,pMsg
= %d\r\n", *pMsg);
break;
case
OS_R_MBX:
printf("因为消息邮箱空,usMaxBlockTime等待时间从消息邮箱内获得数据,pMsg
= %d\r\n", *pMsg);
break;
case
OS_R_TMO:
bsp_LedToggle(1);
bsp_LedToggle(4);
break;
default:
break;
}
}
}
__task void
AppTaskStart(void)
{
AppTaskCreate();
AppObjCreate();
while(1)
{
bsp_KeyScan();
os_dly_wait(10);
}