四十二、freertos内存管理2
/**
**************************************************************************************************/
#include <stdio.h>
#include <limits.h>//标准C库文件,定义了各种类型的范围
#include "board.h"
#include "led.h"
#include "key.h"
#include "uart.h"
#include "tim_mrt.h"
/**********************系统相关和硬件接口**************************************/
/*** System oscillator rate and clock rate on the CLKIN pin ****/
/**/const uint32_t OscRateIn = MAIN_OSC_XTAL_FREQ_HZ; /**/
/**/const uint32_t ExtRateIn = EXT_CLOCK_IN_FREQ_HZ; /**/
//系统复位
#define System_restart (LPC_SWM->PINENABLE0 = 0xffffffffUL) /**/
/**********************End**************************************/
//static void TIM_CallBack1(void);
//static void TIM_CallBack2(void);
/**********************FreeRTOS操作系统头文件**************************************/
#include "FreeRTOSConfig.h"
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"//事件头文件
#include "queue.h"//队列头文件
#include "semphr.h"//信号量头文件
#include "timers.h"//软件定时器头文件
/**********************End**************************************/
/**************************** 任务句柄 ********************************/
static xTaskHandle LED_TaskHandle=NULL;
static xTaskHandle KEY_TaskHandle=NULL;
static QueueHandle_t xQueue1 = NULL;
typedef struct Msg
{
uint8_t ucMessageID;
uint16_t usData[2];
uint32_t ulData[2];
}MSG_T;
/*************************** 宏定义 ************************************/
#define TASK_STACK_SIZE 32//每个任务的栈大小
/* Sets up system hardware
**********************************************************************
* @ 函数名 : BSP_Init
* @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
* @ 参数 :
* @ 返回值 : 无
*********************************************************************/
static void prvSetupHardware(void)
{
SystemCoreClockUpdate();
DEBUGINIT();
led_Init() ;
Key_INIT();
MRT_Init();
DEBUGOUT("%u MHz\n",SystemCoreClock/1000000);
Board_UARTPutSTR("build date: " __DATE__ " build time: " __TIME__ "\n");
}
/**********************************************************************
* @ 函数名 :
* @ 功能说明: 接收发送通知
* @ 参数 :
* @ 返回值 : 无
********************************************************************/
static void LED_Task(void* parameter)
{
TickType_t xLastWakeTime;
const TickType_t xFrequency = 500;
/* 获取当前的系统时间 */
xLastWakeTime = xTaskGetTickCount();
while(1)
{
Board_LED_Toggle(0);
/* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
}
/**********************************************************************
* @ 函数名 :
* @ 功能说明: 发送任务
* @ 参数 :
* @ 返回值 : 无
********************************************************************/
static void KEY_Task(void* parameter)
{
MSG_T *ptMsg;
uint8_t ucCount = 0;
u8 ucKeyCode=0;
while(1)
{
u8 key=0;
if(Scan_Key())
vTaskDelay(20);
else continue;
if(!Scan_Key())continue;
else
{
key=Scan_Key();
ucKeyCode=key;
}
while(Scan_Key()){};//等按键抬起
if(ucKeyCode)
{
switch(ucKeyCode)
{
case 1:
{
/* K1键按下 */
// printf ( "KEY1 被按下\n" );
Board_LED_Toggle(6);
printf("=================================================\r\n");
printf("当前动态内存大小 = %d\r\n", xPortGetFreeHeapSize());
ptMsg = (MSG_T *)pvPortMalloc(sizeof(MSG_T));
printf("申请动态内存后剩余大小 = %d\r\n", xPortGetFreeHeapSize());
ptMsg->ucMessageID = ucCount++;
ptMsg->ulData[0] = ucCount++;
ptMsg->usData[0] = ucCount++;
/* 使用消息队列实现指针变量的传递 */
if(xQueueSend(xQueue1, /* 消息队列句柄 */
(void *) &ptMsg, /* 发送结构体指针变量ptMsg的地址 */
(TickType_t)10) != pdPASS )
{
/* 发送失败,即使等待了10个时钟节拍 */
printf("K2键按下,向xQueue2发送数据失败,即使等待了10个时钟节拍\r\n");
vPortFree(ptMsg);
printf("释放申请的动态内存后大小 = %d\r\n", xPortGetFreeHeapSize());
}
else
{
/* 发送成功 */
printf("K2键按下,向xQueue2发送数据成功\r\n");
/* 由于是低优先级任务向高优先级任务发送消息队列,如果成功的话说明高优先级任务已经执行。
并获得了消息队列中的数据,所以我们可以在此处释放动态内存,不会出现高优先级任务还没有
获得消息队列数据,我们就将动态内存释放掉了。
*/
vPortFree(ptMsg);
printf("释放申请的动态内存后大小 = %d\r\n", xPortGetFreeHeapSize());
}
}break;
case 2:
{
/* K2键按下 */
// printf ( "k2 被按下\n" );
Board_LED_Toggle(5);
}break;
case 3:
{
/* K3键按下*/
}break;
default:break;
}
ucKeyCode=0;
}
}
}
/*
*********************************************************************************************************
* 函 数 名: vTaskMsgPro
* 功能说明: 使用函数xQueueReceive接收任务vTaskTaskUserIF发送的消息队列数据(xQueue1)
* 形 参: pvParameters 是在创建该任务时传递的形参
* 返 回 值: 无
* 优 先 级: 3
*********************************************************************************************************
*/
static void vTaskMsgPro(void *pvParameters)
{
MSG_T *ptMsg;
BaseType_t xResult;
const TickType_t xMaxBlockTime = pdMS_TO_TICKS(200); /* 设置最大等待时间为200ms */
while(1)
{
xResult = xQueueReceive(xQueue1, /* 消息队列句柄 */
(void *)&ptMsg, /* 这里获取的是结构体的地址 */
(TickType_t)xMaxBlockTime);/* 设置阻塞时间 */
if(xResult == pdPASS)
{
/* 成功接收,并通过串口将数据打印出来 */
printf("接收到消息队列数据ptMsg->ucMessageID = %d\r\n", ptMsg->ucMessageID);
printf("接收到消息队列数据ptMsg->ulData[0] = %d\r\n", ptMsg->ulData[0]);
printf("接收到消息队列数据ptMsg->usData[0] = %d\r\n", ptMsg->usData[0]);
}
else
{
/* 超时 */
Board_LED_Toggle(1);
Board_LED_Toggle(4);
}
}
}
/***********************************************************************
* @ 函数名 : AppTaskCreate
* @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面
* @ 参数 : 无
* @ 返回值 : 无
**********************************************************************/
static void AppTaskCreate(void)
{
BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
taskENTER_CRITICAL();//进入临界区,禁止中断打断
xReturn = xTaskCreate( LED_Task,
"LED_Task",
TASK_STACK_SIZE*1,
NULL,
2,
&LED_TaskHandle);
if (pdPASS == xReturn)
printf("创建 Receive1_Task 任务成功!\r\n");
xReturn = xTaskCreate( KEY_Task,
"KEY_Task",
TASK_STACK_SIZE*2,
NULL,
1,
&KEY_TaskHandle);
if (pdPASS == xReturn)
printf("创建 KEY_Task 任务成功!\r\n");
xTaskCreate( vTaskMsgPro, /* 任务函数 */
"vTaskMsgPro", /* 任务名 */
TASK_STACK_SIZE*2, /* 任务栈大小,单位word,也就是4字节 */
NULL, /* 任务参数 */
3, /* 任务优先级*/
NULL ); /* 任务句柄 */
taskEXIT_CRITICAL(); //退出临界区
}
/*
*********************************************************************************************************
* 函 数 名: AppObjCreate
* 功能说明: 创建任务通信机制
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void AppObjCreate (void)
{
/* 创建10个存储指针变量的消息队列,由于CM3/CM4内核是32位机,一个指针变量占用4个字节 */
xQueue1 = xQueueCreate(10, sizeof(struct Msg *));
if( xQueue1 == 0 )
{
/* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
}
}
/**
* @brief main routine for blinky example
* @return Function should not exit.
*/
int main(void)
{
prvSetupHardware();
Board_UARTPutSTR("LPC824 FreeRTOS 任务通知任务间通信 \n");
DEBUGSTR("内存管理\n");
AppTaskCreate();
/* 创建任务通信机制 */
AppObjCreate();
vTaskStartScheduler();//任务调度
/* Loop forever */
while (1) {
printf("FreeRTOS 运行失败\n\r");
}
}
/******************
*函数名 : HardFault_Handler
*功能 :硬件错误时会跳进这里
*说明 :
******(1)可能是内存溢出,堆栈溢出。
******(2)可能是开启了中断,但没有中断函数。
******(3)可能指针赋值错误,最有可能是函数指针赋值错误。
******************/
void HardFault_Handler(void)
{
printf("硬件错误中断\n");
while(1)
{
}
}
获取当前内存大小
xPortGetFreeHeapSize();
pvPortMalloc();获取当前内剩余存大小
xPortGetFreeHeapSize();
vPortFree(); //释放内存