打印

关于51中的全局变量

[复制链接]
7976|21
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
箫笑|  楼主 | 2008-9-9 10:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
小弟最近在看一个项目的代码,是前人写的。MCU是CS8955,51内核的单片机,OS是keil内嵌的RTX51,状态机是task 0,键盘扫描task 1。
有个疑问是发现他的代码里用了大量的全局变量,基本上所有的信息都是通过全局变量来传递的,比如一些控制标志,收发的缓存数组,就是连循环计数因子也用了全局变量,而每个函数里基本上没有用到过局部变量。老板还告诉我尽量不要开辟局部变量。
想知道他这样做有什么特别的目的吗?是这款MCU有什么特殊性?变量定义在51单片机里是怎样分配的?

相关帖子

沙发
computer00| | 2008-9-9 10:38 | 只看该作者

无所谓吧,能很好的把功能实现就行了。

使用特权

评论回复
板凳
箫笑|  楼主 | 2008-9-9 10:54 | 只看该作者

传统思想是少用局部变量

可能我对编程风格中少用全局变量的传统思想固若金汤,他都使用全局变量我需要非常麻烦地找到底哪里更改了这个变量的值,似乎应该是这个系统有什么特殊的需求。

使用特权

评论回复
地板
Ice_River| | 2008-9-9 14:08 | 只看该作者

对于这个环境

局部变量确实有时候有意想不到的问题!

使用特权

评论回复
5
箫笑|  楼主 | 2008-9-9 14:21 | 只看该作者

能详细说下吗

楼上的,能详细说下吗?谢谢。

使用特权

评论回复
6
刘前辈| | 2008-9-9 20:24 | 只看该作者

我来瞎猜。

我想你在发帖之前已经搜索过“extern”了。没找到?

我认为他的PUBLIC是给自己本函数(任务)用的。其实应该设为静态局部变量static 。

如果用动态局部变量,发生抢占时会有可重入问题,把所有RTX51调度器管理之外的变量设为PUBLIC等于随时把局部变量进行保存。即使发生抢占切换到其他任务,恢复环境后照样运行。

再说一遍,正确的做法是设为static,静态局部变量。不会造成他人误解。

使用特权

评论回复
7
mohanwei| | 2008-9-9 20:27 | 只看该作者

有OS的地方用局部变量是很难以想象的……

使用特权

评论回复
8
icmap| | 2008-9-9 20:36 | 只看该作者

在不增加代码的情况下,能用局部变量就不用全局变量。理由如下:
1:局部变量不会被其它函数修改,从而减少出错的几率。
2:不同函数的局部变量可以共用存储空间,从而节省资源紧张的 MCU RAM。

可以把你老板不用局部变量的理由让大家探讨一下。

使用特权

评论回复
9
箫笑|  楼主 | 2008-9-10 09:47 | 只看该作者

re

To 刘前辈:
不是很明白你这句话:“我想你在发帖之前已经搜索过“extern”了。没找到?”
定义一个变量是这样处理的,在该模块的c文件里全局定义,在h文件里用extern声明以便其他文件使用。
按照我老板的意思,全局变量在任务切换时会入栈保存,而局部变量将丢失,需要在两个任务之间传递信息所以用全局变量。问题是RTX51 tiny根本就不支持抢占,尤其是对于那些无关紧要的循环计数为什么也要用全局呢?

To icmap:
你说的两个理由也是我的想法,除了To 刘前辈说的理由外,他甚至还提到就是因为这个系统的资源紧张,所以才尽量用全局变量,所以比较迷糊。他认为是这个MCU的特殊性才这样处理的。

使用特权

评论回复
10
刘前辈| | 2008-9-10 13:20 | 只看该作者

先了解一下你的TIMESHARING设置为几?

欲理解你的前人为什么这么设计,先要看看你的TIMESHARING设置是什么?请告知。


一个extern变量说明必能找到对应的同名PUBLIC变量定义。因此你说“我需要非常麻烦地找到底哪里更改了这个变量的值,”其实不用到处找,搜索一下extern变量就行。

那么如果有些PUBLIC定义变量在源文件各模块中找不到相对应的同名extern,只有2种可能:
1、为了以后的程序扩展;
2、把自己的局部变量设置为全局变量,(本模块使用当然不用extern。)目的是:  a、静态保护;  b、私有。

.......了解TIMESHARING值后再说。

使用特权

评论回复
11
箫笑|  楼主 | 2008-9-10 13:57 | 只看该作者

re

我说找的意思是,比如它在键盘那里更改设置一下keystatus,在别的一个模块下通过判断keystatus执行操作,又在另外一个地方把keystatus设置成初值,所以看得比较辛苦。要追踪一个变量。
就像我上面说的,他基本上的变量都有extern声明的,也就是确实需要全局使用的。

TIMESHARING的值是0,没有时间片轮询,任务要主动释放资源才能切换的,代码里执行一定的时间就加个os_wait切换。

使用特权

评论回复
12
刘前辈| | 2008-9-10 18:43 | 只看该作者

大概明白了。

既然是信号量,当然要用全局变量。其实不用在代码里找,在xxx.M51里有详细的PUBLIC/EXTERN交叉对照表及变量地址。打印出来仔细看看就行了。

既然是任务切换,那循环因子确实没必要用全局变量。也许是你前人担心系统节拍中断时造成什么变量丢失吧。当然这是不可能,系统节拍中断用的是另一个寄存器区。

 全局变量区域本身就受保护,根本不用“切换时入栈”。何况任务切换只保留2字节返回地址,连15个寄存器都不用保存,更不可能将全局变量入栈了。即使reentrant入栈保护的也只是局部变量。

   可以想象,你前人是在利用全局变量区域自动受保护的特征,代替实现reentrant的局部变量入栈保护操作。(把全局变量区看做保护栈。)


使用特权

评论回复
13
箫笑|  楼主 | 2008-9-10 22:20 | 只看该作者

明白了~多谢刘前辈!

利用全局变量区域自动受保护的特征,代替实现reentrant的局部变量入栈保护操作.读到这里就完全明白了.

不过他这么做是出于什么目的呢?局部变量入栈在这里有什么缺点吗?难道是因为这么做需要很大一片栈区?
比如task 0与task 1之间需要共享的值有char a,b,c三个,如果使用局部变量,task 0和task 1分别要用三个char空间栈区保护这三个值,当task 0释放资源之前,它必须把a,b,c的值压在一片栈里,同样,当task 1释放资源之前,它必须把a,b,c的值压在另一片栈里,也就是说使用局部变量需要用到的栈区要比直接使用全局变量的空间多一倍.虽然局部变量是用完就释放,但真正耗费的是栈.

不知道这么理解对不对?

使用特权

评论回复
14
1248| | 2008-9-10 22:29 | 只看该作者

第一次听闻把全局变量来保护现场

这种代码的可读性之差可想而知。
我没用过RTX51,不过可以想像RTX51在任务切换时应该不会先做现场保护就直接切换到其他任务。可能有以下原因:
1.用那么多全局变量占用不少RAM资源,但使用重入函数也许会消耗更多的堆栈空间资源。
2.既然使用重入函数可能会消耗更多的堆栈空间资源,不使用重入函数又无法做现场保护(因为如果使用局部变量,非重入函数的局部变量存在固定的RAM区域中),RTX51在任务切换时不做现场保护也是很好理解的。
C51的资源有限,在C51上使用操作系统不是很好吧。

使用特权

评论回复
15
箫笑|  楼主 | 2008-9-11 09:29 | 只看该作者

RTX51任务切换时保护现场吗?

>我没用过RTX51,不过可以想像RTX51在任务切换时应该不会先做现场保护就直接切换到其他任务。

难道这才是主要原因?需要在任务间传递信号量,而RTX51不保护现场,只能用全局变量来达到这个目的??

使用特权

评论回复
16
刘前辈| | 2008-9-11 11:54 | 只看该作者

15楼正解。

难道这才是主要原因?需要在任务间传递信号量,而RTX51不保护现场,只能用全局变量来达到这个目的??
***********************************************************
   对!
   任务切换是任务自动放弃CPU资源,例如调用os_wait()函数前,RTX51是认为用户没什么现场可保护的。os_wait()直接跳到系统调度切换程序。系统这时只保护了当前任务的返回地址。根本认为没有什么现场保护!这正是和系统切换操作时的重大区别。
     这时的情景,如hotpower、d1d2等所说:“非抢占内核是零耗时切换的前提。”就是为了实现快速切换!

     问题是特殊用户情况下,如果当前任务实际上有某些需要保护的东西怎么办?把task设为reentrant不行。reentrant的作用不在这里。只能像13楼说的那样,由用户自己压栈进行保护?
     可惜,OS不允许用户进行任何涉及内核的操作。(这就是OS的可靠性原因。当用户都是外行,怎么可能懂得硬件堆栈?)用户要进行压栈操作,只能唯一地通过(核外)系统服务函数进行。——隔着一层呢。
     因此任何OS都提供了任务间传递信号的功能函数,RTX51也是。它不是通过堆栈进行的。是通过信号量、邮箱。

     3个信号量传递RTX51还是可以实现的。没有邮箱功能函数怎么办?呵呵,借助全局变量吧。多用几个RAM算什么?本系统足够用了就行了。还套什么规则?具体情况具体变招、变通,你前人有经验。

再说前人做程序的时候,难道还考虑留给后人易于看懂?借用?他恨不得就他一个人看得懂,如此竞争,是吧。



 

使用特权

评论回复
17
刘前辈| | 2008-9-11 12:47 | 只看该作者

修正一点。

RTX51TNY应用中,不涉及可重入函数问题。所有系统服务函数和用户任务都没必要用reentrant。

因为它是非抢占内核。

所以,用全局变量是为了任务间传递信号(量)。(或者保护什么参量。)与reentrant无关。

使用特权

评论回复
18
箫笑|  楼主 | 2008-9-11 16:49 | 只看该作者

受教了~

谜团解开了,多谢~

使用特权

评论回复
19
刘前辈| | 2008-9-12 12:01 | 只看该作者

再费两句话。

不过他这么做是出于什么目的呢?局部变量入栈在这里有什么缺点吗?
*******************************************************************

一个RTX51系统分2个重要RAM区:
1、用户管理全局变量区,(共享局部变量也属这个区。不妨称为动态全局变量。)
2、OS管理RAM区。包括堆栈、PCB等。

2个RAM区互不搭界。OS并不知道那里有一个用户管理的全局变量区存在,它当然也不会去管理。
用户也不可能去操控OS管理区内的堆栈或者内存申请、删除等。

邮箱服务就像是OS为用户任务之间传递信息当邮差,之间的所有操作,像申请邮箱(内存),通知收信方读取消息等,都由OS完成,用户是不必关心其如何完成的。
    现在RTX51没有邮箱服务,那么只好由用户自己来当邮差来传送邮件。而用户又不可能申请内存,创建邮箱,他只能在自己管理权限的RAM区——全局变量区域内开辟信号量或者邮箱。——这个全局变量区域是在编译阶段就由编译器预先保留出来的。

使用特权

评论回复
20
清风一士| | 2008-9-12 13:52 | 只看该作者

RTX Tiny任务切换时要进行堆栈管理

RTX Tiny任务切换时要进行堆栈管理,当任务切换后,会检查当前RAM剩余空间,如果小于20(默认)字节,系统会出错,停机,局部变量太多可能会导致问题?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

78

主题

368

帖子

0

粉丝