基于先后台设计的系统随着功能的递增变得愈来愈难以维护, 因此决定为STC15F2K单片机编写一个基于时分的非抢占式内核,方便进行任务模块的开发。bash
内核TCB结构定义以下:框架
typedef struct os_tcb { void(*task)(void *); //任务处理函数 INT32U cpu_load; //任务分配CPU时间片 INT32U cpu_run; //任务当前运行CPU时间片 INT8U status; //任务状态 INT8U id; //任务ID void *pd; //任务参数,方便数据共享交互 } OS_TCB;
经过STC的内部定时器0产生系统的tick,在定时器0的ISR中轮询TCB列表并对cpu_run进行计数,在main主循环中,轮询tcb中status为Ready的task,并进行调用。下面是简单的框架代码:函数
void timer0_isr (void) interrupt 1 { OSSched(); } void OSSched() { INT8U i; for (i = 0; i < OS_TASK_NUM; i++) { if ((OSTCBList[i].task != 0u) && (OSTCBList[i].status == OS_STAT_PEND)) { OSTCBList[i].cpu_run++; if (OSTCBList[i].cpu_run >= OSTCBList[i].cpu_load) { OSTCBList[i].cpu_run = 0u; OSTCBList[i].status = OS_STAT_RDY; } } } } void main() { OSStart(); } void OSStart() { INT8U i; EA = 1; while (OS_TRUE) { for (i = 0; i < OS_TASK_NUM; i++) { if ((OSTCBList[i].task != 0u) && (OSTCBList[i].status == OS_STAT_RDY)) { OSTCBList[i].task(OSTCBList[i].pd); OSTCBList[i].status = OS_STAT_PEND; } } } }
在实际使用中我建立了APPLedTask和APPKeyTask两个Task,每一个Task单独运行功能都正常,但只要同时开启这两个Task,那么每一个Task功能都会异样,有时候删除一行代码就正常,但我以为问题以为不出如今被删除代码处,因此怀疑是出现个函数指针Overlay的问题。spa
查看问题代码编译生成的m51文件设计
?PR?APPINIT?MAIN ----- ----- +--> ?PR?BSPGPIOINIT?GPIO +--> ?PR?BSPLEDINIT?LED ?PR?APPTASKINIT?MAIN ----- ----- +--> ?PR?_APPKEYTASK?APP_KEY <--- 错误处 +--> ?PR?_OSTASKCREATE?OS +--> ?PR?_APPLEDTASK?APP_LED <--- 错误处 ?PR?_APPKEYTASK?APP_KEY 0029H 0003H <--- 错误处 +--> ?PR?BSPKEYSTATUS?KEY ?PR?_OSTASKCREATE?OS 0029H 0008H ?PR?_APPLEDTASK?APP_LED 0029H 0003H <--- 错误处 +--> ?PR?_BSPLEDLIGHT?LED +--> ?PR?_BSPLEDDISPLAY?LED ?PR?_BSPLEDDISPLAY?LED ----- ----- +--> ?PR?_SEND_595?LED +--> ?PR?UPDATE_595?LED ?PR?UPDATE_595?LED ----- ----- +--> ?CO?LED +--> ?PR?_SEND_595?LED BL51 BANKED LINKER/LOCATER V6.22 08/01/2017 14:01:54 PAGE 3 ?PR?OSSTART?OS 0029H 0001H <--- 错误处
你们能够看到我标记出来的错误处。BL51错误的认为在函数: APPTASKINIT中调用了APPKeyTask, APPLedTask(实际上我只是对于函数指针进行赋值), 因而BL51把OSStart、APPKeyTask、APPLedTask都链接到了相同的Data memory地址0x0029,这就会致使在OSStart中调用Task函数时出现异常。指针
解决方案的话,在BL51 Misc的Overlay框中构建正确的调用树code
?PR?APPTASKINIT?MAIN ~ ?PR?_APPKEYTASK?APP_KEY, ?PR?APPTASKINIT?MAIN ~ ?PR?_APPLEDTASK?APP_LED, ?PR?OSSTART?OS ! ?PR?_APPKEYTASK?APP_KEY, ?PR?OSSTART?OS ! ?PR?_APPLEDTASK?APP_LED // ~: 删除调用关系 !: 插入调用关系
观察更新后m51文件,两个task已经被OSStart调用,并与OSStart处于不一样的Data memory地址上对象
?PR?APPTASKINIT?MAIN ----- ----- +--> ?PR?_OSTASKCREATE?OS ?PR?_OSTASKCREATE?OS 0029H 0008H <----- ?PR?OSSTART?OS 0029H 0001H +--> ?PR?_APPKEYTASK?APP_KEY +--> ?PR?_APPLEDTASK?APP_LED ?PR?_APPKEYTASK?APP_KEY 002AH 0003H <----- +--> ?PR?BSPKEYSTATUS?KEY ?PR?_APPLEDTASK?APP_LED 002AH 0003H <----- +--> ?PR?_BSPLEDLIGHT?LED +--> ?PR?_BSPLEDDISPLAY?LED
另一种解决方案就是建立一个const code的函数指针对象,由于在code区,而BL51对于code区是另外对待的,因此不存在Overlay的状况,这样也省去了修改调用树的麻烦。开发
typedef struct os_task { void(*task[OS_TASK_NUM])(void *); } OS_TASK; OS_TASK const code OSTaskList = {APPKeyTask, APPLedTask};