📄 faq.txt
字号:
答:
RTOS一般只提供实时内核,文件系统为IO系统,一般不会提供,您要自己移植。
-------------------------------------------------------------------------------
问:
你好,你的RTOS在我的keil上仿真是为何看不到screen dispaly里有任何东西显示出来,我以把你DLL的拷进来了.
答:
将dll拷贝到keil c51的c51/bin目录下,重起uv2,进入仿真状态,在peripherals菜单下有Virtual Screen菜单,点击它即可。注意使用我提供的工程。6.14肯定行,6.23、7。00肯定没有显示。
-------------------------------------------------------------------------------
问:
陈老师:
我读您的源程序的过程 遇到这样一个问题
您使用定时器0 作为系统时钟 可是使用定时器方式1的时候为16位方式,而您设定TH0=0
TL0=0,这样要计数65536次系统时钟才中断一次,而51系列单片机的晶振不同,计数频率为晶振频率的1/12,如果用12m晶振,则1us计数一次,65536×1us=65.536ms中断一次,并不是您说的100ms的时钟节拍啊?按您在ex1例程中的写法,时钟节拍是根据单片机的时钟频率不停的变化的。不知道我的想法是否正确,希望您能给我解答。
答:
我写的例子只是只是用来测试用,并没有真正设置时钟节拍频率。
“#define OS_TICKS_PER_SEC 10 /* 设置1秒系统系统节拍数 ”
只是一个或许未来SMALL-RTOS需要使用到的宏,没有什么实际意义。如何定义新系统的节拍,需要用户个根据系统设计自己解决。
-------------------------------------------------------------------------------
问:
个人意见 case(K_TMO|K_SIG) 这部分case内容根本没有必要,
因为程序不可能运行到这里,因为你的输入参数不可能有这个值,
你的函数定义中 只有2个值可以作为typ输入,同时K_TMO|K_SIG是什么意义啊?
您的意思是2个信号同时发生?那也应该是&&而不是按位或啊,如果您的意思是信号同时发生,应该改为&&,并且应放在第一个case的地方。实在搞不懂这里的按位或的意思。
答:
请看一看用户手册。
K_TMO|K_SIG表示两者其一发生时退出睡眠。
-------------------------------------------------------------------------------
问:
陈老师:
在您的程序里面看到这样一句
((uint8 *)(&OSTaskRuning)[LOW_BYTE]|=OSMapTbl[TaskId]
虽然我一看就知道您的算法和目的,可是实在是难懂,我觉得可读性极差。也许您的这种表示方式效率高些,可是读的效率就太低了。
您是取出OSTaskRuning的地址指针,把这个地址指针强制转换为uint8类型指针,然后在移动指针,最后在按位取或。我写了个测试程序
根本就无法通过
#include "at89x52.h"
#define uint8 unsigned char
#define uint16 unsigned int
#define LOW_BYTE 1
uint16 OSTaskRuning=0x3f;
void main(){
((uint8 *)(&OSTaskRuning)[LOW_BYTE]|=0x04;
}
Build target 'Target 1'
compiling test.c...
TEST.C(9): error C193: '|=': bad operand type
TEST.C(9): error C141: syntax error near ';'
Target not created
答:
1、是为了提高效率。
2、你的程序有两处错误:
uint16 OSTaskRuning=0x3f;
^^
应该为半角的“=”
void main(){
((uint8 *)(&OSTaskRuning)[LOW_BYTE]|=0x04;
^^
这里少一个“)”
}
-------------------------------------------------------------------------------
问:
陈老师:
在阅读ucosii的时候了解到:
1)可重入函数,可以被多个任务调用,而不会破坏数据,任何时候都可以被中断。
2)局部变量存储在cpu寄存器或者堆栈中,如果使用全局变量,则需要进行保护。
3)把不可重入函数变为重入函数方法:
(1)只使用局部变量,不使用全局变量。
(2)调用函数前关中断,调用后开中断。
(3)使用信号量,避免函数被再次调用。
而读到您的small rtos中时,提到:
1>不能在中断中和任务中调用非可重入函数。
2>非可重入函数不能递归调用。
3>仅使用寄存器做参变量和自变量的函数,可以重入。
4>c51中定义为可重入的函数,被再次调用时,参变量和局部变量存入可再入堆栈,数据被保护。
5>在small rtos中,可再入函数不许调用small rtos系统函数。
6> 还要保证可再入函数不能被small rtos的任务调度所中断。
7>可再入堆栈不能放在内容ram。
8>KEIL C51中采用变量覆盖的办法分配局部变量,而不是把局部变量分配到堆栈中,所以kc 中使用small rtos,编译系统会把各个任务的局部变量分派在同一个内存,造成程序运行错误。 只允许一个任务函数与?CO?OS_CPU_C进行覆盖分析。
9>如果任务(以及任务调用的函数)不使用局部变量,可以不用禁止覆盖分析。(注:参数也是局部变量)
10>如果用户函数被多个任务调用而且不可重入(程序保证各个任务和中断不同时调用此函数,比如使用信号量等方法),它的变量不能与任何任务的局部变量相覆盖,应该禁止所有调用它的任务与之进行覆盖分析。
我查资料关于重入函数的(for c51)
[1] 定义为再入函数后,一般占用rom都比较大,运行速度比较慢。由于使用模拟栈,不能使用bit参变量和局部变量。
[2] 51与pc中函数的不同:
pc使用堆栈传递参数,且静态变量外的内部变量都在堆栈中。
51一般使用寄存器传递参数,内部变量一般在ram中。
所以非重入函数,重入时会破坏上次调用的数据。
[3] 函数重入的解决:
a. 函数前使用#pragma disable(禁止中断中调用)声明,即只允许主程序或者中断之一调用该函数。如果为#pragma enable,则只允许中断中调用该函数。
b. 声明为重入函数的格式:void func(param...) reentrant,kc编译后将生成一个可重入变量堆栈,然后就可以模拟通过堆栈传递变量的方法。
[4] 由于一般可重入函数由主程序和中断调用,所有通常中断使用和主程序不同的寄存器组。(如using 1,using 2,using 3)
[5] 对可重入函数,在相应函数前加上开关#pragma noaregs,以禁止编译器使用绝对寄存器寻址,可生成不依赖于寄存器组的代码。
这里我有几点疑问:
1)small rtos(包括ucosii)所有函数都必须保证是可重入函数吗?怎样才能保证函数可以重入?如果我使用上面的reentrant编译开关的函数,同时只使用局部变量,是否能保证函数都是可重入的?
2)ucosii的3条重入函数原则,在small rtos中是否可以应用?(在我看来至少第三条可以成立,使用信号量,禁止调用这个函数。不过,small rtos提供的信号量有限,不太可能用这种方法。同时,使用这种方法降低了效率,有时会发生优先级逆转。比如低优先级的taskA使用x函数,发生中断,唤醒高优先级任务taskB,而taskB也要使用x函数。由于taskA占用了信号量,导致taskB无法使用x函数,只能休眠。只有当taskA执行完x函数之后,释放信号量,唤醒taskB,taskB才能继续执行。在TaskA使用一个函数x时,优先级发生了逆转。如果taskA有多个函数,则taskB的响应时间增加了,降低了实时性。至于采用开关中断的方法,如果x函数比较大,则容易造成丢失中断。至于使用局部变量的方法,我有点模糊。我不熟悉keil c51的编译方法,c51中的局部变量是不是都存储在寄存器中啊?)
3)small rtos中,所有函数必须为可重入函数?您说的可重入函数中,不可调用small rtos的系统函数。您的意思是不是是说这些涉及系统操作的函数,必须在任务中调用?其实关于6)还要保证可再入函数不能被small rtos的任务调度所中断。只要在重入函数中不调用small rtos系统函数,就不会发生任务调度,也就能保证6)了.
4)可再入堆栈不可以放在内部ram。那不是要扩展外部ram? 在一般比较简单的应用中,是不会扩展外部ram的,那怎么使用small rtos呢?我想在我们现有的板(无外部ram)上,使用small rtos,该怎么办?
5)KEIL C51中采用变量覆盖的办法分配局部变量。覆盖分析是什么意思?为什么只允许一个任务函数与?CO?OS_CPU_C进行覆盖分析?kc 中使用small rtos,编译系统会把各个任务的局部变量分派在同一个内存(这里的内存是不是指的寄存器组?),造成程序运行错误。
答:
一、Small RTOS(包括ucosii)所有内核函数和系统服务函数都必须是可重入函数,用户函数只要不被多个任务和/或中断同时调用,就不必是可重入函数。内核函数和系统服务函数的可从入性由编写者保证。如果RTOS没有管理重入栈,使用reentrant关键字不能保证函数可重入性,此时唯一的方法是使得函数仅仅使用寄存器R0~R7、ACC、B、和DPTR。网上我见到的ucosii for Keil C51的移植进行了重入栈管理,也就是每一个任务有一个重入栈和系统栈,因而其需要海量RAM(相对51而言),必须使用外部RAM,而Small RTOS没有管理重入栈,只要用户没有多个任务和/或中断调用一个非重入函数的需求(一般均可达到),Small RTOS可在没有外部RAM的情况下使用。事实上,Small RTOS不管理外部RAM。
二、由于Keil C51的特殊性,以上三条应该改为:
(1)只使用寄存器,不使用全局变量。
(2)如果第一条不能实现,则可调用函数前关中断,调用后开中断,并禁止其和所有调用它的任务和中断进行覆盖分析。注意是调用函数前而不是函数开始时关中断。
(3)如果第一条不能实现,还可使用信号量,避免函数被再次调用,也要求禁止其和所有调用它的任务和中断进行覆盖分析。注意是调用函数前而不是函数开始时请求信号量。
三、用户函数只要不被多个任务和/或中断同时调用,就不必是可重入函数。这里所说的可重入函数实指用reentrant关键字定义的函数,而不是仅使用寄存器作变量的函数。
四、一般情况下您不必使用可再入堆栈。可再入堆栈其实可以放在内部RAM中,只要将IDATA_RAM_SIZE的值定义的比实际小得足够多,但要注意给用户的堆栈够不够。
五、至于覆盖分析,具体说起来比较复杂,我就一个例子吧。
void Fuction1(void)
{
uint8 temp1;
/* .......... */
}
void Fuction2(void)
{
uint8 temp2;
/* .......... */
}
void main(void)
{
Fuction1();
Fuction2();
}
为了代码的效率,Keil C51会把局部变量分配到内存固定地址(当然首先尽可能使用寄存器),这样局部变量实际就是全局变量了,所以Keil C51的函数一般不可重入的。如果所有所有局部变量分配到不同地址,则内存肯定不够用。看一看上述代码,KEIL C51在编译它时,分析到Fuction1()和Fuction2()不会同时执行,它就可能会把变量temp1和temp2分配到同一个内存地址如0x20。KEIL C51还可能把更多变量分配到同一个地址。这就是变量覆盖。覆盖分析就是分析那些变量可以分配到同一地址。在前后台系统中,这种做不会出错。但是在RTOS中,由于任务并行执行,覆盖分析的结果就会不对,需要人工干预。我想,Keil C51自带的RTOX用TASK关键字定义任务,其中一个目的就是帮助编译器进行覆盖分析。还是以上述代码来说,假设Fuction1()和Fuction2()是两个任务,它们的变量temp1和temp2分配到同一个内存地址,Fuction1()和Fuction2()执行起来肯定出错。Small RTOS使用函数指针数组保存任务返回地址,这个数组在OS_CPU_C.c文件中定义和使用,Keil C51认为它们依次在段?CO?OS_CPU_C中调用,所以必须禁止它们与之覆盖分析。由于段?CO?OS_CPU_C仅执行一次,为了节省内存,可以让一个任务与之进行覆盖分析。不知我说清楚没有?
-------------------------------------------------------------------------------
问:
陈老师:
你好。在您的small rtos中关于消息队列的函数,我读OSQPend函数,遇到了困难。
SP++;
*((uint8 idata * idata *)SP) = Ret;
象上面类似的操作多处出现,在51中SP是堆栈顶的指针。您这里是为了把数据存储在堆栈中?
这个操作我有点不明白,SP是特殊寄存器,把特殊寄存器强制转化为指针?不懂,请您具体解释一下。
答:
使用上述代码是为了使函数具有重入性。当一个函数调用一个外部函数时,Keil C51编译器认为所有寄存器已经发生变化,当一个变量要存储信息到调用这个函数后使用,这个变量就不可能分配到寄存器中,这个函数也就不可重入了。而RTOS的内核函数必须可重入的。使用这些代码,就是使这些变量的信息存到自己的任务堆栈中,在调用外部函数后再恢复,这样,这个变量就可能分配到寄存器中了。针对Small RTOS 51,使用Keil C51 7.0编译器和7级以上优化,它们肯定分配到寄存器中,这些函数也就可以重入了。SP实际存储的是堆栈顶的地址,这是把SP的值转换为指针,而不是把特殊寄存器强制转化为指针。
-------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -