共享内存方式
消息队列用于任务与任务之间的通信(和全局变量的区别)
信号量:①用于共享资源访问的控制。
②任务同步;中断来了,通过信号量告诉任务,你的中断来了,执行你的任务。
/------------------------------------二值信号量-----------------------------------/
二值信号量:
二值信号量的使命就是同步,完成任务与任务或中断与任务之间的同步。大多数情况下
都是中断与任务之间的同步。
SemaphoreHandle_t BinarySemaphore = NULL;//二值信号量句柄
BinarySemaphore = xSemaphoreCreateBinary();//创建二值信号量
xSemaphoreTake( BinarySemaphore, ( TickType_t ) 10 )//等待10个节拍获取二值信号量
xSemaphoreGive( BinarySemaphore )//释放信号量
xSemaphoreGive() //任务级信号量释放函数
xSemaphoreGiveFromISR() //中断级信号量释放函数
xSemaphoreTake() //任务级获取信号量函数
xSemaphoreTakeFromISR() //中断级获取信号量函数
example:
/* Example usage:
SemaphoreHandle_t xSemaphore = NULL;
// A task that creates a semaphore.
void vATask( void * pvParameters )
{
// Create the semaphore to guard a shared resource.
xSemaphore = xSemaphoreCreateBinary();
}
// A task that uses the semaphore.
void vAnotherTask( void * pvParameters )
{
// … Do other things.
if( xSemaphore != NULL )
{
// See if we can obtain the semaphore. If the semaphore is not available
// wait 10 ticks to see if it becomes free.
if( xSemaphoreTake( xSemaphore, ( TickType_t ) 10 ) == pdTRUE )
{
// We were able to obtain the semaphore and can now access the
// shared resource.
// ...
// We have finished accessing the shared resource. Release the
// semaphore.
xSemaphoreGive( xSemaphore );
}
else
{
// We could not obtain the semaphore and can therefore not access
// the shared resource safely.
}
}
}
/
/----------------------------------------二值信号量 End------------------------------------*/
/----------------------------------------互斥信号量------------------------------------/
在任务与任务,任务与中断之间的任务同步最好用二值信号量
互斥信号量 适合用于那些需要互斥访问的应用中
互斥信号量不能用于中断服务函数中,
原因如下:
● 互斥信号量有优先级继承的机制,所以只能用在任务中,不能用于中断服务函数。
● 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。
/----------------------------------------互斥信号量 End------------------------------------/
/----------------------------------------任务------------------------------------/
!!!Stack Overflow!, task handle 0x221808, task name: task
什么原因导致任务栈溢出
1、任务调度
● 系统调度,系统调度的一些函数。taskYIELD()
● 系统滴答定时器。
他们都是通过向中断控制和状态寄存器 ICSR 的 bit28 写入 1 挂起 PendSV 来启动 PendSV 中
断。这样就可以在 PendSV 中断服务函数中进行任务切换了。
这个函数主要做“上文的保存,切换下文”!将上个任务的非中断自动保存的寄存器进行压栈;第二找到下一个需要执行的任务并且找到其堆栈的栈顶,并将栈顶地址赋值于psp。最后当退出中断时,会自动从目标任务堆栈处出栈pc等其他硬件自动保存的寄存器信息。
看一下这个函数:
__asm void xPortPendSVHandler( void )
{
extern pxCurrentTCB; (1)
extern vTaskSwitchContext; (2)
PRESERVE8 (3)
mrs r0, psp (4)
isb
ldr r3, =pxCurrentTCB (5)
ldr r2, [r3] (6)
stmdb r0!, {r4-r11} (7)
str r0, [r2] (8)
stmdb sp!, {r3, r14} (9)
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY (10)
msr basepri, r0 (11)
dsb
isb
bl vTaskSwitchContext (12)
mov r0, #0 (13)
msr basepri, r0
ldmia sp!, {r3, r14} (14)
ldr r1, [r3] (15)
ldr r0, [r1] (16)
ldmia r0!, {r4-r11} (17)
msr psp, r0 (18)
isb
bx r14 (19)
nop
}
详细情况请看<<STM32F1 FreeRTOS开发手册_V1.1>>手册第八、第九章。
2、时间片调度
时间片调度也是利用滴答定时器出发中断进行同级任务调度。
/----------------------------------------任务 end------------------------------------/
打印系统任务的一些信息
//打印系统运行的任务信息
void pritf_sysState(void)
{
UINT32 TotalRunTime;
UBaseType_t ArraySize,x;
TaskStatus_t *StatusArray;
KEY_DEBUG(" ");
KEY_DEBUG("/**************************pritf_sysState***************************/");
ArraySize = uxTaskGetNumberOfTasks(); //获取系统任务数量
KEY_DEBUG("系统任务数量 %d", ArraySize);
StatusArray = pvPortMalloc_auto_type(ArraySize*sizeof(TaskStatus_t)); //申请内存
if(StatusArray!=NULL) //内存申请成功
{
ArraySize=uxTaskGetSystemState((TaskStatus_t* )StatusArray, (UBaseType_t )ArraySize,(uint32_t* )&TotalRunTime);
for(x=0;x<ArraySize;x++)
{
//任务名称、任务优先级和任务编号。
KEY_DEBUG("%s\t\t%d\t\t\t%d\t\t\t\r\n",
StatusArray[x].pcTaskName,
(int)StatusArray[x].uxCurrentPriority,
(int)StatusArray[x].xTaskNumber);
}
}
vPortFree(StatusArray); //释放内存
KEY_DEBUG("/**************************结束***************************/\r\n");
}
//打印某个任务的信息
void pritf_taskInfo(void)
{
TaskHandle_t TaskHandle;
TaskStatus_t TaskStatus;
TaskHandle = xTaskGetCurrentTaskHandle(); //根据当前任务获取任务句柄
//TaskHandle = xTaskGetHandle("3"); //根据任务名获取任务句柄
vTaskGetInfo((TaskHandle_t )TaskHandle, //任务句柄
(TaskStatus_t* )&TaskStatus, //任务信息结构体
(BaseType_t )pdTRUE, //允许统计任务堆栈历史最小剩余大小
(eTaskState )eInvalid); //函数自己获取任务运行壮态
//通过串口打印出指定任务的有关信息。
KEY_DEBUG(" ");
KEY_DEBUG("/**************************pritf_taskInfo***************************/");
KEY_DEBUG("任务名: %s\r\n",TaskStatus.pcTaskName);
KEY_DEBUG("任务编号: %d\r\n",(int)TaskStatus.xTaskNumber);
KEY_DEBUG("任务状态: %d\r\n",TaskStatus.eCurrentState);
KEY_DEBUG("任务当前优先级: %d\r\n",(int)TaskStatus.uxCurrentPriority);
KEY_DEBUG("任务基优先级: %d\r\n",(int)TaskStatus.uxBasePriority);
KEY_DEBUG("任务堆栈基地址: %#x\r\n",(int)TaskStatus.pxStackBase);
KEY_DEBUG("任务堆栈历史剩余最小值:%d\r\n",TaskStatus.usStackHighWaterMark);
KEY_DEBUG("/**************************结束***************************/\r\n");
}
//打印某个任务处于挂起、阻塞、就绪、运行、删除状态
void pritf_taskState(void)
{
eTaskState TaskState;
TaskHandle_t TaskHandle;
char TaskInfo[10];
TaskHandle = xTaskGetCurrentTaskHandle(); //根据当前任务获取任务句柄
//TaskHandle = xTaskGetHandle("MIX"); //根据任务名获取任务句柄。
TaskState = eTaskGetState(TaskHandle); //获取任务的任务状态
memset(TaskInfo,0,10); //数组清零
KEY_DEBUG(" ");
KEY_DEBUG("/**************************pritf_taskState***************************/");
switch( (int)TaskState )
{
case 0:sprintf(TaskInfo,"Running");break;
case 1:sprintf(TaskInfo,"Ready");break;
case 2:sprintf(TaskInfo,"Suspend");break;
case 3:sprintf(TaskInfo,"Delete");break;
case 4:sprintf(TaskInfo,"Invalid");break;
}
KEY_DEBUG("任务状态值:%d,对应的状态为:%s\r\n",TaskState,TaskInfo);
KEY_DEBUG("/**************************结束**************************/\r\n");
}
myself thread do
#include "all_config.h"
#include "xcl_timer_thread.h"
#include "sys_timer_thread.h"
#include "window_manager.h"
#include "window_common.h"
#include "sys_timer.h"
#include "wdt.h"
#include "lcd.h"
#include "GUI.h"
static void xcl_printf_background(void)
{
KEY_DEBUG("===================xcl_printf_background");
sys_timer_clear(XCL_PRITF_MY_BACKGROUG);
sys_timer_set(XCL_PRITF_MY_BACKGROUG, 100);
}
static sys_timer_struct sys_timer_table_xcl[]=
{
{XCL_PRITF_MY_BACKGROUG, xcl_printf_background},
};
timer_thread_struct thread_xcl =
{
.thread_id = THREAD_ID_XCL,
.timer_sem_id = NULL,
.semaphore_def = {0},
.thread_def = {
.pthread = sys_timer_function,
.name = "thread_xcl",
},
.init = NULL,
.timer_info = {
.sys_timer_max = sizeof(sys_timer_table_xcl)/sizeof(sys_timer_table_xcl),
.sys_timer = sys_timer_table_xcl,
},
.thread_run_flag = 0,
};
void xcl_thread_init(void)
{
KEY_DEBUG("============= %s =============\r\n",__FUNCTION__);
sys_timer_set(XCL_PRITF_MY_BACKGROUG, 100);
}
//os_task_create(&task_test_1, "task_test_1", task1_test_function, NULL, 128, 3);
void xcl_Init(void)
{
sys_timer_thread_create(&thread_xcl,1,1024,xcl_thread_init);
}