共2条
1/1 1 跳转至页
uc,os,ii 一个uc/os-ii程序,运行结果与所要的预期不同,求教大家。
问
#include "config.h"
#include "stdlib.h"
#define DIR1 1<<18
#define DIR2 1<<19
#define DIR3 1<<20
#define Task0_Stk_Size 64
#define Task_Stk_Size 64
OS_STK Task0Stk [Task_Stk_Size];
OS_STK Task1Stk[Task_Stk_Size];
void Task0(void *pdata); //Task0函数
void Task1(void *pdata); //Task1函数
int main (void)
{
OSInit ();
(1) OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0_Stk_Size - 1], 10);
OSStart ();
return 0;
}
/*********************************************************************************************************
** Task0 初始化PWM
********************************************************************************************************/
void Task0(void *pdata)
{
pdata = pdata;
TargetInit ();
PINSEL0 = 0x02 << 14|(0x02<<16);
PINSEL2 = PINSEL2&(~0x80);
IO1DIR = DIR1|DIR2|DIR3;
PWMPR = 0;
PWMMCR = 0x02;
PWMPCR = 0x0400|0x01000;
PWMMR0 = Fpclk/10;
PWMMR2 = PWMMR0 / 2;
PWMMR4 = PWMMR0 / 2;
PWMTCR = 0x02;
PWMTCR = 0x01;
(2) OSTaskCreate (Task1,(void *)0, &Task1Stk[Task_Stk_Size-1], 9);
IO1SET = DIR1|DIR2|DIR3;// 使开始时都置高电平
while (1)
{
IO1CLR = DIR1|DIR2;
OSTimeDly(OS_TICKS_PER_SEC);
IO1SET = DIR1|DIR2;
OSTimeDly(OS_TICKS_PER_SEC);
}
}
/*********************************************************************************************************
** Task1 ******************************** ************************************************************************/
void Task1(void *pdata)
{
pdata = pdata;
while(1)
{
IO1CLR = DIR3;
OSTimeDly(OS_TICKS_PER_SEC);
IO1SET = DIR3;
OSTimeDly(OS_TICKS_PER_SEC);
}
}
pwm的初始化,都正确的。我调试时p0.7口的蜂鸣器按所给的频率蜂鸣;
问题1)我是在main函数中通过OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0_Stk_Size - 1], 10)创建Task0的,
而在Task0中,先初始化pwm之后再通过OSTaskCreate (Task1,(void *)0, &Task1Stk[Task_Stk_Size-1], 9)创建Task1的,
我单步step in运行时, 只能走到
void OSStartHighRdy(void)
{
_OSStartHighRdy();
}然后就不能单步了。困惑啊,是不是汇编写的就调试不到了。
而且,在uc/os-ii中,运行过程不像c语言那样,看不到运行过程是怎么样的啊。。
有什么书可以查得到吗?怎么看到任务task1的创建过程,我都没有看到
运行(2) OSTaskCreate (Task1,(void *)0, &Task1Stk[Task_Stk_Size-1], 9);这句代码。。迷惑的很。。
问题二:
主要是DIR1(即LED1,因为我是用这些口控制步进电机的正反转的。用lpc2131板上的LED来调试,以下类同。),DIR2(即LED2),DIR3(即LED3),
我用EasyARM LPC2131调试,此时由于第二行分给Task1优先级是九,比Task0 优先级10高,LED1,LED2先亮,然后,LED3亮,如果我把task1的优先级改为13,
LED3 就始终不亮了。。不是执行OSTimeDly(OS_TICKS_PER_SEC)是挂起当前任务吗,然后进行任务切换,,
怎么LED3始终亮不起来呢。。。。。。。
答 1: 2:看一下os_cfg.h里的OS_LOWEST_PRIO值 答 2: 调试再调试
(1)在task0里面设置断点调试
(2)再在task1里面设置断点
调试即可看出问题出在哪里,怎么调试,不用大家教了吧 答 3: 调试中发现一个更怪的问题啊。。。。昨天刚开始调试,发现一个很怪的问题,大家可以试试,,
我用的是zlg提供的移植到lpc2131代码, 我step in 运行OSInit ();进入了OS_InitRdyList();然后进入了OS_InitTCBList();我把这个函数copy出来,
static void OS_InitTCBList (void)
{
INT8U i;
OS_TCB *ptcb1;
OS_TCB *ptcb2;
OSTCBList = (OS_TCB *)0; /* TCB Initialization */
for (i = 0; i < (OS_LOWEST_PRIO + 1); i++) { /* Clear the priority table */
OSTCBPrioTbl[i] = (OS_TCB *)0;
}
ptcb1 = &OSTCBTbl[0];
ptcb2 = &OSTCBTbl[1];
for (i = 0; i < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1); i++) { /* Init. list of free TCBs */
ptcb1->OSTCBNext = ptcb2;
ptcb1++;
ptcb2++;
}
ptcb1->OSTCBNext = (OS_TCB *)0; /* Last OS_TCB */
OSTCBFreeList = &OSTCBTbl[0];
} /**********************************************/
当step in 方式运行到最后一行的时候,再step in 一次,,整个程序就运行了。不会返回到OSInit()中的下一步。
但是在OSInit()中,你如果用step方式运行,运行OS_InitTCBList()之后,则不会使整个程序运行起来。。会继续下条指令。
怎么回事啊。。。我把周公深入浅出—LPC2131下册p250的例子重试 ,也有这样的结果。。。怎么回事,。。。想不通啊。。。。
答 4: re:没这回事。。。
我试过了。
肯定是你某些地方有问题所致。 答 5: re:seahai我试过了。。。。一直都是这样的。。
大家有板子再试试。。 答 6: re:自己顶下 答 7: Solution one:调试_OSStartHighRdy的方法_OSStartHighRdy有两种实现方式,直接调用assembler function或者借助SWI。在ADS中要Step into SWI Handler,需要在AXD中把OSStartHighRdy所在的文件点开,然后在里面设置Break point。 答 8: Solution Two:饥饿现象在Priority-driven,Full-preemptive 的OS,如果高优先级任务不主动交出OS的使用权的话,那么低优先级的任务永远的不到运行,这称为饥饿。
所以,UCOS要求用户任务在执行完任务代码后一定要调用系统服务,就是为了主动交出OS的使用权。UCOS中有一个任务是不会主动交出OS的使用权,那就是Idle Task。你的现象跟优先级大小有关,估计是发生了饥饿问题。
我的教训供你借鉴:仅调用系统函数而不检查其返回值是非常危险的,一般来说应该这样做比较好:
err = OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0_Stk_Size - 1], 10);
if(err != OS_NO_ERR)
{
//Error handler
}
答 9: Solution Three:再试再step in 到OS_InitTCBList,
然后点击右键,选择Interleaving Disassembler,
这时进入汇编指令级Step 状态,由此可以发现到底是哪条指令出现问题;
另外,如果你在进入OS_InitTCBList时,中断已经打开,很可能中断发生致使程序执行顺序发生了改变,要在Debug时关注处理器的当前状态。
xianfei520 ,希望你解决问题后,能把最后的问题所在和原因在发上来,我也能一起学习:) 答 10: re:问题二答案利用设置断点的方式。我终于整懂了一些东西,把五一节学的东西写出来。。
与大家一起分享。好东西要与大家一起分享。这才是人生一大快事。有不对的
大虾门要指点一二啊。。
问题二答案:我find all 找到了周公定义的#define OS_LOWEST_PRIO 12,也就是说。我把task1的优先级改为13,当然都没有机会使它运行了。改为11也不行的。因为uc/os中 OS_LOWEST_PRIO-1也占用了。调试时像terrence说那样err = OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0_Stk_Size - 1], 10);
if(err != OS_NO_ERR)
{
//Error handler
}
会发现err的值不是OS_NO_ERR.这是个好方法。。多谢terrence。。
下面把ocos的运行顺序写出来。给大家参考。。
利用设置断点的方式。
可以知道本程序
开始运行OSInit(); 利用下面的函数创建
OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0_Stk_Size - 1], 10);
然后开始运行 OSStart ();
然后进入了task0函数中,直到走到
OSTaskCreate (Task1,(void *)0, &Task1Stk[Task_Stk_Size-1], 9);
如果大家单步运行进去后,会因为这时候OSRunning=ture;
9又比10大,所以会进行任务切换的。然后进入了task1中运行,,
直到在任务task1中,
IO1CLR = DIR3;
OSTimeDly(OS_TICKS_PER_SEC); 单步进去发现,此函数把任务task1 挂起
进行任务切换,,
然后就进入了task0中。。
以后就好分析了。。
答 11: 关于中断的机理。。五一一直在搞中断,苦读几天有些眉目,跟大家共享,共同探讨。共同进步。。。
讲讲时间中断吧。。这个在ucos是核心的。。。少了它那整个系统就是没有头了。
在lpc2131中,周公使用了time0作中断用,首先必须建立起时间中断,原因大家去看贝贝的书,周公在TargetInit ();中有
void TargetInit(void)
{
OS_ENTER_CRITICAL();
srand((uint32) TargetInit);
VICInit();
Timer0Init();
OS_EXIT_CRITICAL();
}
我把VICInit() copy出来。
void VICInit(void)
{
extern void IRQ_Handler(void);
extern void Timer0_Handler(void);
VICIntEnClr = 0xffffffff;
VICDefVectAddr = (uint32)IRQ_Handler;
VICVectAddr0 = (uint32)Timer0_Handler;//这句是关键啊。。记住Timer0_Handler等下用它的。
VICVectCntl0 = (0x20 | 0x04);
VICIntEnable = 1 << 4;
}
函数Timer0Init()是初始化,这个我不多说了。
好了。有了这些东东后,
看看工作过程:
首先根据中断机理,当发生中断的时候,
执行LDR PC, [PC, #-0xff0](对菜鸟来说,不知道这是硬件强制执行,我
当时也蒙了。后来才知道)
然后执行到Timer0_Handler HANDLER Timer0_Exception(在IRQ.S中) 一定要知道,HANDLER
是个宏名,在IRQ.inc中,有宏的定义,如下。
$IRQ_Label HANDLER $IRQ_Exception_Function
EXPORT $IRQ_Label ; 输出的标号
IMPORT $IRQ_Exception_Function ; 引用的外部标号
$IRQ_Label
SUB LR, LR, #4 ; 计算返回地址
STMFD SP!, {R0-R3, R12, LR} ; 保存任务环境
MRS R3, SPSR ; 保存状态
STMFD SP, {R3, SP, LR}^ ; 保存用户状态的R3,SP,LR,注意不能回写
; 如果回写的是用户的SP,所以后面要调整SP
LDR R2, =OSIntNesting ; OSIntNesting++
LDRB R1, [R2]
ADD R1, R1, #1
STRB R1, [R2]
SUB SP, SP, #4*3
MSR CPSR_c, #(NoInt | SYS32Mode) ; 切换到系统模式
CMP R1, #1
LDREQ SP, =StackUsr
(1) BL $IRQ_Exception_Function ; 调用c语言的中断处理程序
MSR CPSR_c, #(NoInt | SYS32Mode) ; 切换到系统模式
LDR R2, =OsEnterSum ; OsEnterSum,使OSIntExit退出时中断关闭
MOV R1, #1
STR R1, [R2]
BL OSIntExit
LDR R2, =OsEnterSum ; 因为中断服务程序要退出,所以OsEnterSum=0
MOV R1, #0
STR R1, [R2]
MSR CPSR_c, #(NoInt | IRQ32Mode) ; 切换回irq模式
LDMFD SP, {R3, SP, LR}^ ; 恢复用户状态的R3,SP,LR,注意不能回写
; 如果回写的是用户的SP,所以后面要调整SP
LDR R0, =OSTCBHighRdy
LDR R0, [R0]
LDR R1, =OSTCBCur
LDR R1, [R1]
CMP R0, R1
ADD SP, SP, #4*3 ;
MSR SPSR_cxsf, R3
LDMEQFD SP!, {R0-R3, R12, PC}^ ; 不进行任务切换
LDR PC, =OSIntCtxSw ; 进行任务切换
MEND
执行到(1)中,然后跳到Timer0_Exception函数中,
void Timer0_Exception(void)
{
T0IR = 0x01;
VICVectAddr = 0;
OSTimeTick();
}
大家不会不知道OSTimeTick()作用吧。那就自己看书好了。。
答 12: re:对于swi函数的应用,我写得不好,大家要多多指点,,
个人理解为:首先是 LDR PC, SWI_Addr,然后走到
SoftwareInterrupt
LDR SP, StackSvc ;
STMFD SP!, {R0-R3, R12, LR}
MOV R1, SP ;
MRS R3, SPSR
TST R3, #T_bit ;
LDRNEH R0, [LR,#-2] ;
BICNE R0, R0, #0xff00
LDREQ R0, [LR,#-4] ;
BICEQ R0, R0, #0xFF000000
;
CMP R0, #1
LDRLO PC, =OSIntCtxSw
LDREQ PC, =__OSStartHighRdy ;
BL SWI_Exception
LDMFD SP!, {R0-R3, R12, PC}^
StackSvc DCD (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4)
然后根据r0的值,判别怎么走,有点像c中switch case 语句。
中间的堆栈数据保护,大家自己仔细分析了。然后是中断返回。其中还包含一些
任务调度方面的。。我下次写全些。。
答 13: re:terrence
调试_OSStartHighRdy的方法
_OSStartHighRdy有两种实现方式,直接调用assembler function或者借助SWI。在ADS中要Step into SWI Handler,需要在AXD中把OSStartHighRdy所在的文件点开,然后在里面设置Break point。
一种方式我会,把OSStartHighRdy所在的文件点开,然后在里面设置Break point。
“直接调用assembler function或者借助SWI ” 是什么意思。没有懂。。。
答 14: re:terrence
关于这个怪问题。我回复terrence兄弟
“step in 到OS_InitTCBList,
然后点击右键,选择Interleaving Disassembler,
这时进入汇编指令级Step 状态;
另外,如果你在进入OS_InitTCBList时,中断已经打开,很可能中断发生致使程序执行顺序发生了改变,要在Debug时关注处理器的当前状态。”
///////////////////////////////////////////////
我step in 在Interleaving Disassembler step in OS_InitTCBList,发现
中断都是禁止的。所以没有你说的那方面的可能。
我用周功自写得启动代码,提供的ucos的代码。有位seahai兄他的就没有
出现这种问题。那我就郁闷了。。
答 15: 好人做到底,转贴 waitwait 的东东,一起给大家前一段时间对何时任务调度一直搞不清楚,苦读几天有些眉目,跟大家共享,共同探讨。
所谓任务调度说的明白些就是将控制权交给内核,那么在程序上其实就是实现了程序上的一个跳转(汇编),C语言的话就是调用了一个函数sched().在这个函数里执行的功能就是从就绪表中找到就绪的最高级的任务,并将该任务的TCB复给OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];然后调用OS_TASK_SW();这个函数是用汇编写的(其中涉及到一个宏定义),这个函数就的入口就是OSIntCtxSw,功能就是保存当前任务的信息,将其压入堆栈,将OSTCBHighRdy 所对应的任务的指针付给PC,将数据从堆栈中弹出。开始执行新的任务。
那么什么时候调用sched()呢?有几种情况,第一种应当就是通常所说的中断级任务调度。大家都知道有一个时钟节拍的概念。它的一个重要作用就是当任务通过ostimedly()挂起时,在中断中提供准确的tick数。那么中断中到底执行了什么呢?当时钟节拍发生中断时函数的入口是IRQ向量中断,地址是timer0。
如下:
;定时器0中断
Timer0_Handler HANDLER Timer0
这里用到了一个宏定义
MACRO
$IRQ_Label HANDLER $IRQ_Exception
初次看时并没有看懂其中的意思,后经过反复思考,结合自己认为正确的想法,终于有所突破。
在这个宏中调用了留给用户自己编写的用C语言写的中断处理函数。
void Timer0(void)
{
T0IR = 0x01;
T0MR0 += (Fpclk / OS_TICKS_PER_SEC);
VICVectAddr = 0; // 通知中断控制器中断结束
OSTimeTick();
}
这个函数中调用了 OSTimeTick();这个函数,那么这个函数又完成了什么呢?
他负责检查是否在挂起的任务中有完成tick数的如果有将其加到任务就绪表中,返回宏中,在宏的末尾调用了任务处理函数OSIntCtxSw。进行了任务切换。
这种就应到是中断级任务调度。
另外的就是任务及调度,任务的就绪目前认为只有两种情况,一是tick数到期,另外一种就是信号量,消息,邮箱等非中断产生的信号是任务就绪。第一种上面已经讨论过。剩下的就是第二种,所以以信号量为例,如果一个任务要等待某个信号量那么他会调用ossempend()函数,任务要等待,以我们的想法,她没事做了,要等,那么就别占着茅坑不拉屎,交权吧!没措事实就是这样,这个函数中再次调用了sched()这个函数,寻找高优先级任务,进行任务切换。
那么有了ossempend()这个函数我们就会想到ossempost()这个函数,它是发送信号量的,当一个任务发送了信号量,那么内核就应该看看是不是有任务在等待信号量,oseventtaskrdy(),如果有任务在等待,怎么办,应该让这个任务执行,内核让一个任务执行的方法就是任务调度,本质就是程序跳转,再次调用sched()这个函数,这样是不是就通了。当然这块还涉及到事件控制块的机制,要细究的朋友,可以弄一下,弄点心得出来,大家一起进步。
总结一下,操作系统是人写出来的,别忘了它是一个程序。在想一个操作系统是如何工作时,我们首先要想如果我设计应该怎么设计,当然不考虑细节,先考虑整体,然后再按着自己的思路看源码,这是我的体会!还请大家指教!
称为抢占式的操作系统,也是有一个极小的时间片在里边的,就是时钟节拍。当然与时间片轮转式的操作系统大不一样。之所以能够进行抢占,就是在每种使任务就绪的情况发生的地方都进行了任务调度,寻找出高优先级的任务,进行执行。
共同努力! 答 16: 顶一下!学RTOS学的超快!
不得不顶,呵呵 答 17: terrenceterrence过奖了。多谢你老兄帮忙,兄弟我万分感谢啊。。
今后还希望多多指教。 答 18: 好人不少呢。谢谢。。。 答 19: 麻烦周公给解答啊。。。。。关于上面讲到的一个 “调试中发现一个更怪的问题啊。。。。”
麻烦周公给解答啊。。。。。
我把程序重新整理了下。注释显示不对的。对高手来说,这些注释也没有用。
#include "config.h"
#include "stdlib.h"
/*********************************************************************************************************
** ½Ó¿Ú¶¨Ò岿·Ö¡¢Ïà¹ØµÄÊý¾Ý¶¨Ò岿·Ö£»
********************************************************************************************************/
#define Task0_Stk_Size 64 //Define the Task0 stack length ¶¨ÒåÓû§ÈÎÎñ0µÄ¶ÑÕ»³¤¶È
#define Task_Stk_Size 64
OS_STK Task0Stk [Task_Stk_Size]; //Define the Task0 stack ¶¨ÒåÓû§ÈÎÎñ0µÄ¶ÑÕ»
OS_STK Task1Stk[Task_Stk_Size]; //Define the Task£± stack ¶¨ÒåÓû§ÈÎÎñ0µÄ¶ÑÕ»
void Task0(void *pdata); //Task0 ÈÎÎñ0
void Task1(void *pdata); //Task1 ÈÎÎñ1
/********************************************************************************************************
** º¯ÊýÃû³Æ: Delay
** ¹¦ÄÜÃèÊö: Èí¼þÑÓʱº¯Êý
*******************************************************************************************************
*/
void Delay(uint32 dly)
{
uint32 i;
for(; dly > 0; dly--)
for(i = 0; i < 50000; i++);
}
/*
*********************************************************************************************************
** º¯ÊýÃû³Æ £ºmain()
** º¯Êý¹¦ÄÜ £º
** µ÷ÊÔ˵Ã÷ £º
*********************************************************************************************************
*/
int main (void)
{
OSInit ();
OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0_Stk_Size - 1], 10);
OSStart ();
return 0;
}
/*********************************************************************************************************
** Task0 ÈÎÎñ0,³õʼ»¯Ä¿±ê°å£¬³õʼ»¯PWM
********************************************************************************************************/
void Task0 (void *pdata)
{
uint32 i;
pdata = pdata;
i = 10;
TargetInit ();
PINSEL0 = 0x02 << 14|(0x02<<16); // P0.7Ñ¡ÔñPWM2¹¦ÄÜ,P0.8Ñ¡ÔñPWM4¹¦ÄÜ£»
PINSEL2 = PINSEL2&(~0x80); //±ØÐëʹÓÃÕâÖÖ·½Ê½£¬²»ÄÜʹÓà PINSEL2 = 0x00·½Ê½£»
//ÉèÖÃp1:25--p1:16ΪGPIO¹¦ÄÜ£»
IO1DIR = DIR1|DIR2|DIR3;
OSTaskCreate (Task1,(void *)0, &Task1Stk[Task_Stk_Size-1], 5);
/* PWM³õʼ»¯ */
((1)) PWMPR = 0; // ²»·ÖƵ£¬¼ÆÊýƵÂÊΪFpclk£»
PWMMCR = 0x02; // ÉèÖÃPWMMR0Æ¥Åäʱ¸´Î»PWMTC ÇÒ²»²úÉúÖжϣ»
PWMPCR = 0x0400|0x01000; // ÔÊÐíPWM2ºÍPWM4Êä³ö£¬µ¥±ßPWM
PWMMR0 = Fpclk/10; //¸ø³öµÄÂö³åƵÂÊ
PWMMR2 = PWMMR0 / 2; // 50%Õ¼¿Õ±È£»
PWMMR4 = PWMMR0 / 2; // 50%Õ¼¿Õ±È£»
PWMTCR = 0x02; // ¸´Î»PWMTC£»
PWMTCR = 0x01; // Æô¶¯PWMÊä³ö£»
while (1)
{
IO1CLR = DIR1; //¸ºÏòÐýת£»
// Delay(100);
OSTimeDly(OS_TICKS_PER_SEC);
IO1SET = DIR1; //ÕýÏòÐýת£»
OSTimeDly(OS_TICKS_PER_SEC);
// Delay(100);
}
}
/*********************************************************************************************************
** Task1 ÈÎÎñ1,ÔËÐУø,£ùÖá
******************************** ************************************************************************/
void Task1(void *pdata)
{
uint32 i;
pdata = pdata;
((2)) IO1SET = DIR1|DIR2|DIR3;
i = 5;
while(1)
{
IO1CLR = DIR3;
//Delay(100);
OSTimeDly(OS_TICKS_PER_SEC);
IO1SET = DIR3;
//Delay(100);
OSTimeDly(OS_TICKS_PER_SEC);
//OSTimeDly(10);
}
}
/*************************************************/
先使程序运行到OSTaskCreate (Task1,(void *)0, &Task1Stk[Task_Stk_Size-1], 5);句,
分别在((1)),((2))中设置断点,然后全速运行,程序首先在((2)),但是如果不是这种方式,step in 去运行,程序就会先运行在((1)),我都迷惑了。跟踪时候,我知道可以进入任务OS_Sched,但是优先级还是十,没有改变,,
我真的很纳闷啊。。。。。。怎么会有这样的事情。。我都没有开发的
信心了。。感觉随时都有定时炸弹似的。。。
估计这两样事情出现的原因是一样的。。周公解答。。
#include "stdlib.h"
#define DIR1 1<<18
#define DIR2 1<<19
#define DIR3 1<<20
#define Task0_Stk_Size 64
#define Task_Stk_Size 64
OS_STK Task0Stk [Task_Stk_Size];
OS_STK Task1Stk[Task_Stk_Size];
void Task0(void *pdata); //Task0函数
void Task1(void *pdata); //Task1函数
int main (void)
{
OSInit ();
(1) OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0_Stk_Size - 1], 10);
OSStart ();
return 0;
}
/*********************************************************************************************************
** Task0 初始化PWM
********************************************************************************************************/
void Task0(void *pdata)
{
pdata = pdata;
TargetInit ();
PINSEL0 = 0x02 << 14|(0x02<<16);
PINSEL2 = PINSEL2&(~0x80);
IO1DIR = DIR1|DIR2|DIR3;
PWMPR = 0;
PWMMCR = 0x02;
PWMPCR = 0x0400|0x01000;
PWMMR0 = Fpclk/10;
PWMMR2 = PWMMR0 / 2;
PWMMR4 = PWMMR0 / 2;
PWMTCR = 0x02;
PWMTCR = 0x01;
(2) OSTaskCreate (Task1,(void *)0, &Task1Stk[Task_Stk_Size-1], 9);
IO1SET = DIR1|DIR2|DIR3;// 使开始时都置高电平
while (1)
{
IO1CLR = DIR1|DIR2;
OSTimeDly(OS_TICKS_PER_SEC);
IO1SET = DIR1|DIR2;
OSTimeDly(OS_TICKS_PER_SEC);
}
}
/*********************************************************************************************************
** Task1 ******************************** ************************************************************************/
void Task1(void *pdata)
{
pdata = pdata;
while(1)
{
IO1CLR = DIR3;
OSTimeDly(OS_TICKS_PER_SEC);
IO1SET = DIR3;
OSTimeDly(OS_TICKS_PER_SEC);
}
}
pwm的初始化,都正确的。我调试时p0.7口的蜂鸣器按所给的频率蜂鸣;
问题1)我是在main函数中通过OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0_Stk_Size - 1], 10)创建Task0的,
而在Task0中,先初始化pwm之后再通过OSTaskCreate (Task1,(void *)0, &Task1Stk[Task_Stk_Size-1], 9)创建Task1的,
我单步step in运行时, 只能走到
void OSStartHighRdy(void)
{
_OSStartHighRdy();
}然后就不能单步了。困惑啊,是不是汇编写的就调试不到了。
而且,在uc/os-ii中,运行过程不像c语言那样,看不到运行过程是怎么样的啊。。
有什么书可以查得到吗?怎么看到任务task1的创建过程,我都没有看到
运行(2) OSTaskCreate (Task1,(void *)0, &Task1Stk[Task_Stk_Size-1], 9);这句代码。。迷惑的很。。
问题二:
主要是DIR1(即LED1,因为我是用这些口控制步进电机的正反转的。用lpc2131板上的LED来调试,以下类同。),DIR2(即LED2),DIR3(即LED3),
我用EasyARM LPC2131调试,此时由于第二行分给Task1优先级是九,比Task0 优先级10高,LED1,LED2先亮,然后,LED3亮,如果我把task1的优先级改为13,
LED3 就始终不亮了。。不是执行OSTimeDly(OS_TICKS_PER_SEC)是挂起当前任务吗,然后进行任务切换,,
怎么LED3始终亮不起来呢。。。。。。。
答 1: 2:看一下os_cfg.h里的OS_LOWEST_PRIO值 答 2: 调试再调试
(1)在task0里面设置断点调试
(2)再在task1里面设置断点
调试即可看出问题出在哪里,怎么调试,不用大家教了吧 答 3: 调试中发现一个更怪的问题啊。。。。昨天刚开始调试,发现一个很怪的问题,大家可以试试,,
我用的是zlg提供的移植到lpc2131代码, 我step in 运行OSInit ();进入了OS_InitRdyList();然后进入了OS_InitTCBList();我把这个函数copy出来,
static void OS_InitTCBList (void)
{
INT8U i;
OS_TCB *ptcb1;
OS_TCB *ptcb2;
OSTCBList = (OS_TCB *)0; /* TCB Initialization */
for (i = 0; i < (OS_LOWEST_PRIO + 1); i++) { /* Clear the priority table */
OSTCBPrioTbl[i] = (OS_TCB *)0;
}
ptcb1 = &OSTCBTbl[0];
ptcb2 = &OSTCBTbl[1];
for (i = 0; i < (OS_MAX_TASKS + OS_N_SYS_TASKS - 1); i++) { /* Init. list of free TCBs */
ptcb1->OSTCBNext = ptcb2;
ptcb1++;
ptcb2++;
}
ptcb1->OSTCBNext = (OS_TCB *)0; /* Last OS_TCB */
OSTCBFreeList = &OSTCBTbl[0];
} /**********************************************/
当step in 方式运行到最后一行的时候,再step in 一次,,整个程序就运行了。不会返回到OSInit()中的下一步。
但是在OSInit()中,你如果用step方式运行,运行OS_InitTCBList()之后,则不会使整个程序运行起来。。会继续下条指令。
怎么回事啊。。。我把周公深入浅出—LPC2131下册p250的例子重试 ,也有这样的结果。。。怎么回事,。。。想不通啊。。。。
答 4: re:没这回事。。。
我试过了。
肯定是你某些地方有问题所致。 答 5: re:seahai我试过了。。。。一直都是这样的。。
大家有板子再试试。。 答 6: re:自己顶下 答 7: Solution one:调试_OSStartHighRdy的方法_OSStartHighRdy有两种实现方式,直接调用assembler function或者借助SWI。在ADS中要Step into SWI Handler,需要在AXD中把OSStartHighRdy所在的文件点开,然后在里面设置Break point。 答 8: Solution Two:饥饿现象在Priority-driven,Full-preemptive 的OS,如果高优先级任务不主动交出OS的使用权的话,那么低优先级的任务永远的不到运行,这称为饥饿。
所以,UCOS要求用户任务在执行完任务代码后一定要调用系统服务,就是为了主动交出OS的使用权。UCOS中有一个任务是不会主动交出OS的使用权,那就是Idle Task。你的现象跟优先级大小有关,估计是发生了饥饿问题。
我的教训供你借鉴:仅调用系统函数而不检查其返回值是非常危险的,一般来说应该这样做比较好:
err = OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0_Stk_Size - 1], 10);
if(err != OS_NO_ERR)
{
//Error handler
}
答 9: Solution Three:再试再step in 到OS_InitTCBList,
然后点击右键,选择Interleaving Disassembler,
这时进入汇编指令级Step 状态,由此可以发现到底是哪条指令出现问题;
另外,如果你在进入OS_InitTCBList时,中断已经打开,很可能中断发生致使程序执行顺序发生了改变,要在Debug时关注处理器的当前状态。
xianfei520 ,希望你解决问题后,能把最后的问题所在和原因在发上来,我也能一起学习:) 答 10: re:问题二答案利用设置断点的方式。我终于整懂了一些东西,把五一节学的东西写出来。。
与大家一起分享。好东西要与大家一起分享。这才是人生一大快事。有不对的
大虾门要指点一二啊。。
问题二答案:我find all 找到了周公定义的#define OS_LOWEST_PRIO 12,也就是说。我把task1的优先级改为13,当然都没有机会使它运行了。改为11也不行的。因为uc/os中 OS_LOWEST_PRIO-1也占用了。调试时像terrence说那样err = OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0_Stk_Size - 1], 10);
if(err != OS_NO_ERR)
{
//Error handler
}
会发现err的值不是OS_NO_ERR.这是个好方法。。多谢terrence。。
下面把ocos的运行顺序写出来。给大家参考。。
利用设置断点的方式。
可以知道本程序
开始运行OSInit(); 利用下面的函数创建
OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0_Stk_Size - 1], 10);
然后开始运行 OSStart ();
然后进入了task0函数中,直到走到
OSTaskCreate (Task1,(void *)0, &Task1Stk[Task_Stk_Size-1], 9);
如果大家单步运行进去后,会因为这时候OSRunning=ture;
9又比10大,所以会进行任务切换的。然后进入了task1中运行,,
直到在任务task1中,
IO1CLR = DIR3;
OSTimeDly(OS_TICKS_PER_SEC); 单步进去发现,此函数把任务task1 挂起
进行任务切换,,
然后就进入了task0中。。
以后就好分析了。。
答 11: 关于中断的机理。。五一一直在搞中断,苦读几天有些眉目,跟大家共享,共同探讨。共同进步。。。
讲讲时间中断吧。。这个在ucos是核心的。。。少了它那整个系统就是没有头了。
在lpc2131中,周公使用了time0作中断用,首先必须建立起时间中断,原因大家去看贝贝的书,周公在TargetInit ();中有
void TargetInit(void)
{
OS_ENTER_CRITICAL();
srand((uint32) TargetInit);
VICInit();
Timer0Init();
OS_EXIT_CRITICAL();
}
我把VICInit() copy出来。
void VICInit(void)
{
extern void IRQ_Handler(void);
extern void Timer0_Handler(void);
VICIntEnClr = 0xffffffff;
VICDefVectAddr = (uint32)IRQ_Handler;
VICVectAddr0 = (uint32)Timer0_Handler;//这句是关键啊。。记住Timer0_Handler等下用它的。
VICVectCntl0 = (0x20 | 0x04);
VICIntEnable = 1 << 4;
}
函数Timer0Init()是初始化,这个我不多说了。
好了。有了这些东东后,
看看工作过程:
首先根据中断机理,当发生中断的时候,
执行LDR PC, [PC, #-0xff0](对菜鸟来说,不知道这是硬件强制执行,我
当时也蒙了。后来才知道)
然后执行到Timer0_Handler HANDLER Timer0_Exception(在IRQ.S中) 一定要知道,HANDLER
是个宏名,在IRQ.inc中,有宏的定义,如下。
$IRQ_Label HANDLER $IRQ_Exception_Function
EXPORT $IRQ_Label ; 输出的标号
IMPORT $IRQ_Exception_Function ; 引用的外部标号
$IRQ_Label
SUB LR, LR, #4 ; 计算返回地址
STMFD SP!, {R0-R3, R12, LR} ; 保存任务环境
MRS R3, SPSR ; 保存状态
STMFD SP, {R3, SP, LR}^ ; 保存用户状态的R3,SP,LR,注意不能回写
; 如果回写的是用户的SP,所以后面要调整SP
LDR R2, =OSIntNesting ; OSIntNesting++
LDRB R1, [R2]
ADD R1, R1, #1
STRB R1, [R2]
SUB SP, SP, #4*3
MSR CPSR_c, #(NoInt | SYS32Mode) ; 切换到系统模式
CMP R1, #1
LDREQ SP, =StackUsr
(1) BL $IRQ_Exception_Function ; 调用c语言的中断处理程序
MSR CPSR_c, #(NoInt | SYS32Mode) ; 切换到系统模式
LDR R2, =OsEnterSum ; OsEnterSum,使OSIntExit退出时中断关闭
MOV R1, #1
STR R1, [R2]
BL OSIntExit
LDR R2, =OsEnterSum ; 因为中断服务程序要退出,所以OsEnterSum=0
MOV R1, #0
STR R1, [R2]
MSR CPSR_c, #(NoInt | IRQ32Mode) ; 切换回irq模式
LDMFD SP, {R3, SP, LR}^ ; 恢复用户状态的R3,SP,LR,注意不能回写
; 如果回写的是用户的SP,所以后面要调整SP
LDR R0, =OSTCBHighRdy
LDR R0, [R0]
LDR R1, =OSTCBCur
LDR R1, [R1]
CMP R0, R1
ADD SP, SP, #4*3 ;
MSR SPSR_cxsf, R3
LDMEQFD SP!, {R0-R3, R12, PC}^ ; 不进行任务切换
LDR PC, =OSIntCtxSw ; 进行任务切换
MEND
执行到(1)中,然后跳到Timer0_Exception函数中,
void Timer0_Exception(void)
{
T0IR = 0x01;
VICVectAddr = 0;
OSTimeTick();
}
大家不会不知道OSTimeTick()作用吧。那就自己看书好了。。
答 12: re:对于swi函数的应用,我写得不好,大家要多多指点,,
个人理解为:首先是 LDR PC, SWI_Addr,然后走到
SoftwareInterrupt
LDR SP, StackSvc ;
STMFD SP!, {R0-R3, R12, LR}
MOV R1, SP ;
MRS R3, SPSR
TST R3, #T_bit ;
LDRNEH R0, [LR,#-2] ;
BICNE R0, R0, #0xff00
LDREQ R0, [LR,#-4] ;
BICEQ R0, R0, #0xFF000000
;
CMP R0, #1
LDRLO PC, =OSIntCtxSw
LDREQ PC, =__OSStartHighRdy ;
BL SWI_Exception
LDMFD SP!, {R0-R3, R12, PC}^
StackSvc DCD (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4)
然后根据r0的值,判别怎么走,有点像c中switch case 语句。
中间的堆栈数据保护,大家自己仔细分析了。然后是中断返回。其中还包含一些
任务调度方面的。。我下次写全些。。
答 13: re:terrence
调试_OSStartHighRdy的方法
_OSStartHighRdy有两种实现方式,直接调用assembler function或者借助SWI。在ADS中要Step into SWI Handler,需要在AXD中把OSStartHighRdy所在的文件点开,然后在里面设置Break point。
一种方式我会,把OSStartHighRdy所在的文件点开,然后在里面设置Break point。
“直接调用assembler function或者借助SWI ” 是什么意思。没有懂。。。
答 14: re:terrence
关于这个怪问题。我回复terrence兄弟
“step in 到OS_InitTCBList,
然后点击右键,选择Interleaving Disassembler,
这时进入汇编指令级Step 状态;
另外,如果你在进入OS_InitTCBList时,中断已经打开,很可能中断发生致使程序执行顺序发生了改变,要在Debug时关注处理器的当前状态。”
///////////////////////////////////////////////
我step in 在Interleaving Disassembler step in OS_InitTCBList,发现
中断都是禁止的。所以没有你说的那方面的可能。
我用周功自写得启动代码,提供的ucos的代码。有位seahai兄他的就没有
出现这种问题。那我就郁闷了。。
答 15: 好人做到底,转贴 waitwait 的东东,一起给大家前一段时间对何时任务调度一直搞不清楚,苦读几天有些眉目,跟大家共享,共同探讨。
所谓任务调度说的明白些就是将控制权交给内核,那么在程序上其实就是实现了程序上的一个跳转(汇编),C语言的话就是调用了一个函数sched().在这个函数里执行的功能就是从就绪表中找到就绪的最高级的任务,并将该任务的TCB复给OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];然后调用OS_TASK_SW();这个函数是用汇编写的(其中涉及到一个宏定义),这个函数就的入口就是OSIntCtxSw,功能就是保存当前任务的信息,将其压入堆栈,将OSTCBHighRdy 所对应的任务的指针付给PC,将数据从堆栈中弹出。开始执行新的任务。
那么什么时候调用sched()呢?有几种情况,第一种应当就是通常所说的中断级任务调度。大家都知道有一个时钟节拍的概念。它的一个重要作用就是当任务通过ostimedly()挂起时,在中断中提供准确的tick数。那么中断中到底执行了什么呢?当时钟节拍发生中断时函数的入口是IRQ向量中断,地址是timer0。
如下:
;定时器0中断
Timer0_Handler HANDLER Timer0
这里用到了一个宏定义
MACRO
$IRQ_Label HANDLER $IRQ_Exception
初次看时并没有看懂其中的意思,后经过反复思考,结合自己认为正确的想法,终于有所突破。
在这个宏中调用了留给用户自己编写的用C语言写的中断处理函数。
void Timer0(void)
{
T0IR = 0x01;
T0MR0 += (Fpclk / OS_TICKS_PER_SEC);
VICVectAddr = 0; // 通知中断控制器中断结束
OSTimeTick();
}
这个函数中调用了 OSTimeTick();这个函数,那么这个函数又完成了什么呢?
他负责检查是否在挂起的任务中有完成tick数的如果有将其加到任务就绪表中,返回宏中,在宏的末尾调用了任务处理函数OSIntCtxSw。进行了任务切换。
这种就应到是中断级任务调度。
另外的就是任务及调度,任务的就绪目前认为只有两种情况,一是tick数到期,另外一种就是信号量,消息,邮箱等非中断产生的信号是任务就绪。第一种上面已经讨论过。剩下的就是第二种,所以以信号量为例,如果一个任务要等待某个信号量那么他会调用ossempend()函数,任务要等待,以我们的想法,她没事做了,要等,那么就别占着茅坑不拉屎,交权吧!没措事实就是这样,这个函数中再次调用了sched()这个函数,寻找高优先级任务,进行任务切换。
那么有了ossempend()这个函数我们就会想到ossempost()这个函数,它是发送信号量的,当一个任务发送了信号量,那么内核就应该看看是不是有任务在等待信号量,oseventtaskrdy(),如果有任务在等待,怎么办,应该让这个任务执行,内核让一个任务执行的方法就是任务调度,本质就是程序跳转,再次调用sched()这个函数,这样是不是就通了。当然这块还涉及到事件控制块的机制,要细究的朋友,可以弄一下,弄点心得出来,大家一起进步。
总结一下,操作系统是人写出来的,别忘了它是一个程序。在想一个操作系统是如何工作时,我们首先要想如果我设计应该怎么设计,当然不考虑细节,先考虑整体,然后再按着自己的思路看源码,这是我的体会!还请大家指教!
称为抢占式的操作系统,也是有一个极小的时间片在里边的,就是时钟节拍。当然与时间片轮转式的操作系统大不一样。之所以能够进行抢占,就是在每种使任务就绪的情况发生的地方都进行了任务调度,寻找出高优先级的任务,进行执行。
共同努力! 答 16: 顶一下!学RTOS学的超快!
不得不顶,呵呵 答 17: terrenceterrence过奖了。多谢你老兄帮忙,兄弟我万分感谢啊。。
今后还希望多多指教。 答 18: 好人不少呢。谢谢。。。 答 19: 麻烦周公给解答啊。。。。。关于上面讲到的一个 “调试中发现一个更怪的问题啊。。。。”
麻烦周公给解答啊。。。。。
我把程序重新整理了下。注释显示不对的。对高手来说,这些注释也没有用。
#include "config.h"
#include "stdlib.h"
/*********************************************************************************************************
** ½Ó¿Ú¶¨Ò岿·Ö¡¢Ïà¹ØµÄÊý¾Ý¶¨Ò岿·Ö£»
********************************************************************************************************/
#define Task0_Stk_Size 64 //Define the Task0 stack length ¶¨ÒåÓû§ÈÎÎñ0µÄ¶ÑÕ»³¤¶È
#define Task_Stk_Size 64
OS_STK Task0Stk [Task_Stk_Size]; //Define the Task0 stack ¶¨ÒåÓû§ÈÎÎñ0µÄ¶ÑÕ»
OS_STK Task1Stk[Task_Stk_Size]; //Define the Task£± stack ¶¨ÒåÓû§ÈÎÎñ0µÄ¶ÑÕ»
void Task0(void *pdata); //Task0 ÈÎÎñ0
void Task1(void *pdata); //Task1 ÈÎÎñ1
/********************************************************************************************************
** º¯ÊýÃû³Æ: Delay
** ¹¦ÄÜÃèÊö: Èí¼þÑÓʱº¯Êý
*******************************************************************************************************
*/
void Delay(uint32 dly)
{
uint32 i;
for(; dly > 0; dly--)
for(i = 0; i < 50000; i++);
}
/*
*********************************************************************************************************
** º¯ÊýÃû³Æ £ºmain()
** º¯Êý¹¦ÄÜ £º
** µ÷ÊÔ˵Ã÷ £º
*********************************************************************************************************
*/
int main (void)
{
OSInit ();
OSTaskCreate (Task0,(void *)0, &Task0Stk[Task0_Stk_Size - 1], 10);
OSStart ();
return 0;
}
/*********************************************************************************************************
** Task0 ÈÎÎñ0,³õʼ»¯Ä¿±ê°å£¬³õʼ»¯PWM
********************************************************************************************************/
void Task0 (void *pdata)
{
uint32 i;
pdata = pdata;
i = 10;
TargetInit ();
PINSEL0 = 0x02 << 14|(0x02<<16); // P0.7Ñ¡ÔñPWM2¹¦ÄÜ,P0.8Ñ¡ÔñPWM4¹¦ÄÜ£»
PINSEL2 = PINSEL2&(~0x80); //±ØÐëʹÓÃÕâÖÖ·½Ê½£¬²»ÄÜʹÓà PINSEL2 = 0x00·½Ê½£»
//ÉèÖÃp1:25--p1:16ΪGPIO¹¦ÄÜ£»
IO1DIR = DIR1|DIR2|DIR3;
OSTaskCreate (Task1,(void *)0, &Task1Stk[Task_Stk_Size-1], 5);
/* PWM³õʼ»¯ */
((1)) PWMPR = 0; // ²»·ÖƵ£¬¼ÆÊýƵÂÊΪFpclk£»
PWMMCR = 0x02; // ÉèÖÃPWMMR0Æ¥Åäʱ¸´Î»PWMTC ÇÒ²»²úÉúÖжϣ»
PWMPCR = 0x0400|0x01000; // ÔÊÐíPWM2ºÍPWM4Êä³ö£¬µ¥±ßPWM
PWMMR0 = Fpclk/10; //¸ø³öµÄÂö³åƵÂÊ
PWMMR2 = PWMMR0 / 2; // 50%Õ¼¿Õ±È£»
PWMMR4 = PWMMR0 / 2; // 50%Õ¼¿Õ±È£»
PWMTCR = 0x02; // ¸´Î»PWMTC£»
PWMTCR = 0x01; // Æô¶¯PWMÊä³ö£»
while (1)
{
IO1CLR = DIR1; //¸ºÏòÐýת£»
// Delay(100);
OSTimeDly(OS_TICKS_PER_SEC);
IO1SET = DIR1; //ÕýÏòÐýת£»
OSTimeDly(OS_TICKS_PER_SEC);
// Delay(100);
}
}
/*********************************************************************************************************
** Task1 ÈÎÎñ1,ÔËÐУø,£ùÖá
******************************** ************************************************************************/
void Task1(void *pdata)
{
uint32 i;
pdata = pdata;
((2)) IO1SET = DIR1|DIR2|DIR3;
i = 5;
while(1)
{
IO1CLR = DIR3;
//Delay(100);
OSTimeDly(OS_TICKS_PER_SEC);
IO1SET = DIR3;
//Delay(100);
OSTimeDly(OS_TICKS_PER_SEC);
//OSTimeDly(10);
}
}
/*************************************************/
先使程序运行到OSTaskCreate (Task1,(void *)0, &Task1Stk[Task_Stk_Size-1], 5);句,
分别在((1)),((2))中设置断点,然后全速运行,程序首先在((2)),但是如果不是这种方式,step in 去运行,程序就会先运行在((1)),我都迷惑了。跟踪时候,我知道可以进入任务OS_Sched,但是优先级还是十,没有改变,,
我真的很纳闷啊。。。。。。怎么会有这样的事情。。我都没有开发的
信心了。。感觉随时都有定时炸弹似的。。。
估计这两样事情出现的原因是一样的。。周公解答。。
共2条
1/1 1 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
vscode+cmake搭建雅特力AT32L021开发环境被打赏30分 | |
【换取逻辑分析仪】自制底板并驱动ArduinoNanoRP2040ConnectLCD扩展板被打赏47分 | |
【分享评测,赢取加热台】RISC-V GCC 内嵌汇编使用被打赏38分 | |
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 |