变量就是一种在程序执行过程中其值能不断变化的量。要在程序中使用变量必须先用标识符作为变量名,并指出所用的数据类型和存储模式,这样编译系统才能为变量分配相应的存储空间。定义一个变量的格式如下:
  [存储种类] 数据类型 [存储器类型] 变量名表
  在定义格式中除了数据类型和变量名表是必要的,其它都是可选项。存储种类有四种:自动(auto)、外部(extern)、静态(static)和寄存器(register),缺省类型为自动(auto)。这些存储种类的具体含义和使用方法,将在第七课《变量的存储》中进一步进行学习。
  而这里的数据类型则是和我们在第四课中学习到的名种数据类型的定义是一样的。说明了一个变量的数据类型后,还可选择说明该变量的存储器类型。存储器类型的说明就是指定该变量在单片机c语言硬件系统中所使用的存储区域,并在编译时准确的定位。表6-1中是KEIL uVision2所能认别的存储器类型。注意的是在AT89c51芯片中RAM只有低128位,位于80H到FFH的高128位则在52芯片中才有用,并和特殊寄存器地址重叠。

存储器类型

说 明

data

直接访问内部数据存储器(128字节),访问速度最快

bdata

可位寻址内部数据存储器(16字节),允许位与字节混合访问

idata

间接访问内部数据存储器(256字节),允许访问全部内部地址

pdata

分页访问外部数据存储器(256字节),用MOVX @Ri指令访问

xdata

外部数据存储器(64KB),用MOVX @DPTR指令访问

code

程序存储器(64KB),用MOVC @A+DPTR指令访问

  如果省略存储器类型,系统则会按编译模式SMALL、COMPACT或LARGE所规定的默认存储器类型去指定变量的存储区域。无论什么存储模式都能声明变量在任何的8051存储区范围,然而把最常用的命令如循环计数器和队列索引放在内部数据区能显著的提高系统性能。还有要指出的就是变量的存储种类与存储器类型是完全无关的。

  数据存储模式
存储模式决定了没有明确指定存储类型的变量,函数参数等的缺省存储区域,共三种:
Small模式:所有缺省变量参数均装入内部RAM,优点是访问速度快,缺点是空间有限,只适用于小程序。
Compact模式:所有缺省变量均位于外部RAM区的一页(256Bytes),具体哪一页可由P2口指定,在STARTUP.A51文件中说明,也可用pdata指定,优点是空间较Small为宽裕速度较Small慢,较large要快,是一种中间状态。
large模式:所有缺省变量可放在多达64KB的外部RAM区,优点是空间大,可存变量多,缺点是速度较慢。
  提示:存储模式在单片机c语言编译器选项中选择。

  之前提到简单提到sfr,sfr16,sbit定义变量的方法,下面我们再来仔细看看。sfr和sfr16能直接对51单片机的特殊寄存器进行定义,定义方法如下:
sfr 特殊功能寄存器名= 特殊功能寄存器地址常数;
sfr16 特殊功能寄存器名= 特殊功能寄存器地址常数;
我们能这样定义AT89c51的P1口

  1. sfr P1 = 0x90; //定义P1 I/O口,其地址90H

  sfr关键定后面是一个要定义的名字,可任意选取,但要符合标识符的命名规则,名字最好有一定的含义,如P1口能用P1为名,这样程序会变的好读好多。等号后面必须是常数,不允许有带运算符的表达式,而且该常数必须在特殊功能寄存器的地址范围之内(80H-FFH),具体可查看附录中的相关表。sfr是定义8位的特殊功能寄存器,而sfr16则是用来定义16位特殊功能寄存器,如8052的T2定时器,能定义为:

  1. sfr16 T2 = 0xCC; //这里定义8052定时器2,地址为T2L=CCH,T2H=CDH

  用sfr16定义16位特殊功能寄存器时等号后面是它的低位地址,高位地址一定要位于物理低位地址之上。注意的是不能用于定时器0和1的定义。

  sbit可定义可位寻址对象。如访问特殊功能寄存器中的某位。其实这样应用是经常要用的如要访问P1口中的第2个引脚P1.1。我们能照以下的方法去定义:
(1)sbit 位变量名=位地址

  1. sbit P1_1 = 0x91;

这样是把位的绝对地址赋给位变量。同sfr一样sbit的位地址必须位于80H-FFH之间。
(2)Sbit 位变量名=特殊功能寄存器名^位位置

  1. sfr P1 = 0x90;
  2. sbit P1_1 = P1^; //先定义一个特殊功能寄存器名再指定位变量名所在的位置

  当可寻址位位于特殊功能寄存器中时可采用这种方法
(3)sbit 位变量名=字节地址^位位置

  1. sbit P1_1 = ;

  这种方法其实和2是一样的,只是把特殊功能寄存器的位址直接用常数表示。
  在单片机c语言存储器类型中供给有一个bdata的存储器类型,这个是指可位寻址的数据存储器,位于单片机的可位寻址区中,能将要求可位录址的数据定义为bdata,如:

  1. unsigned char bdata ib;  //在可位录址区定义ucsigned char类型的变量ib
  2. ];      //在可位寻址区定义数组ab[2],这些也称为可寻址位对象
  3. sbit ib7=ib^7        //用关键字sbit定义位变量来独立访问可寻址位对象的其中一位
  4. sbit ab12=ab[]^;

  操作符"^"后面的位位置的最大值取决于指定的基址类型,char0-7,int0-15,long0-31。
  

  下面我们用上一课的电路来实践一下这一课的知识。同样是做一下简单的跑马灯实验,项目名为RunLED2。程序如下:

  1. sfr P1 = 0x90; //这里没有使用预定义文件,
  2. sbit P1_0 = P1^; //而是自己定义特殊寄存器
  3. sbit P1_7 = ; //之前我们使用的预定义文件其实就是这个作用
  4. sbit P1_1 = 0x91; //这里分别定义P1端口和P10,P11,P17引脚
  5. void main(void)
  6. {
  7. unsigned int a;
  8. unsigned char b;
  9.  
  10. do{
  11. ;a<;a++)
  12. P1_0 = ; //点亮P1_0
  13. ;a<;a++)
  14. P1_7 = ; //点亮P1_7
  15.  
  16. ;b<;b++)
  17. {
  18. ;a<;a++)
  19. P1 = b; //用b的值来做跑马灯的花样
  20. }
  21.  
  22. P1 = ; //熄灭P1上的LED
  23. ;b<;b++)
  24. {
  25. ;a<;a++) //P1_1闪烁
  26. P1_1 = ;
  27. ;a<;a++)
  28. P1_1 = ;
  29. }
  30. });
  31. }

Keil c51指针变量
单片机c语言支持一般指针(Generic Pointer)和存储器指针(Memory_Specific Pointer).
1. 1. 一般指针
一般指针的声明和使用均与标准C相同,不过同时还能说明指针的存储类型,例如:

  1. long * state;   //为一个指向long型整数的指针,而state本身则依存储模式存放。
  2. char * xdata ptr //ptr为一个指向char数据的指针,而ptr本身放于外部RAM区,以上的long,char等指针指向的数据可存放于任何存储器中。

一般指针本身用3个字节存放,分别为存储器类型,高位偏移,低位偏移量。
2. 2. 存储器指针
基于存储器的指针说明时即指定了存贮类型,例如:

  1. char data * str; //str指向data区中char型数据
  2. int xdata * pow; //pow指向外部RAM的int型整数。

这种指针存放时,只需一个字节或2个字节就够了,因为只需存放偏移量。
3. 3. 指针转换
即指针在上两种类型之间转化:
当基于存储器的指针作为一个实参传递给需要一般指针的函数时,指针自动转化。
如果不说明外部函数原形,基于存储器的指针自动转化为一般指针,导致错误,因而请用“#include”说明所有函数原形。
能强行改变指针类型。

变量的存储类别

一、static(静态局部)变量。
1、静态局部变量在程序整个运行期间都不会释放内存。
2、对于静态局部变量,是在编译的时候赋初值的,即只赋值一次。如果在程序运行时已经有初值,则以后每次调用的时候不再重新赋值。
3、如果定义局部变量的时候不赋值,则编译的时候自动赋值为0。而对于自动变量而言,定义的时候不赋值,则是一个不确定的值。
4、虽然静态变量在函数调用结束后仍然存在,但是其他函数不能引用。
二、用extern声明外部变量。
用extern声明外部变量,是为了扩展外部变量的作用范围。比如一个程序能由多个源程序文件组成。如果一个程序中需要引用另外一个文件中已经定义的外部变量,就需要使用extern来声明。
正确的做法是在一个文件中定义外部变量,而在另外一个文件中使用extern对该变量作外部变量声明。
一个文件中: int abc;
另外一个文件中: extern abc;
例子:用extern将外部变量的作用域扩展到其他文件:
文件1:

  1. //用extern将外部变量的作用域扩展到其他文件中
  2. #include
  3. #include
  4. #include
  5.  
  6. unsigned ];
  7. void fillarray();
  8.  
  9. void init_ser()
  10. {
  11. SCON=0X50;
  12. TMOD|=0X20;
  13. TH1=0XF3;
  14. TR1=;
  15. TI=;
  16. }
  17. void main()
  18. {
  19. unsigned int i;
  20. init_ser();
  21. fillarray();
  22.  
  23. ;i<;i++)
  24. {
  25. printf("array[%d]=%d\n",i,array[i]);
  26. }
  27.  
  28. for(;;){;}
  29. } 

文件2:

  1. ];
  2. void fillarray()
  3. {
  4. unsigned char i;
  5.  
  6. ;i<;i++)
  7. {
  8. array[i]=i;
  9. }
  10. }

  在单片机c语言中变量的空间分配几个方法
1、data区空间小,所以只有频繁用到或对运算速度要求很高的变量才放到data区内,比如for循环中的计数值。
2、data区内最好放局部变量。因为局部变量的空间是能覆盖的某个函数的局部变量空间在退出该函数是就释放,由别的函数的局部变量覆盖,能提高内存利用率。当然静态局部变量除外,其内存使用方式与全局变量相同;
3、确保你的程序中没有未调用的函数。 在Keil C里遇到未调用函数,编译器就将其认为可能是中断函数。函数里用的局部变量的空间是不释放,也就是同全局变量一样处理。这一点Keil C做得很愚蠢,但也没办法。
4、程序中遇到的逻辑标志变量能定义到bdata中,能大大降低内存占用空间。在51系列芯片中有16个字节位寻址区bdata,其中能定义8*16=128个逻辑变量。定义方法是: bdata bit LedState;但位类型不能用在数组和结构体中
5、其他不频繁用到和对运算速度要求不高的变量都放到xdata区。
6、如果想节省data空间就必须用large模式,将未定义内存位置的变量全放到xdata区。当然最好对所有变量都要指定内存类型。
7、当使用到指针时,要指定指针指向的内存类型。
  在单片机c51语言中未定义指向内存类型的通用指针占用3个字节;而指定指向data区的指针只占1个字节;指定指向xdata区的指针占2个字节。如指针p是指向data区,则应定义为: char data *p;。还可指定指针本身的存放内存类型,如:char data * xdata p;。其含义是指针p指向data区变量,而其本身存放在xdata区。

keil C51 指针总结的更多相关文章

  1. Keil C51 vs 标准C

    深入理解并应用C51对标准ANSIC的扩展是学习C51的关键之一.因为大多数扩展功能都是直接针对8051系列CPU硬件的.大致有以下8类: 8051存储类型及存储区域 存储模式 存储器类型声明 变量类 ...

  2. keil c51笔记

    第一章 Keil C51开发系统基本知识 第一节 系统概述 Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上.结构性.可读性. ...

  3. Keil C51 中的函数指针和再入函数

    函数指针是C语言中几个难点之一.由于8051的C编译器的独特要求,函数指针和再入函数有更多的挑战需要克服.主要由于函数变量的传递.典型的(绝大部分8051芯片)函数变量通过堆栈的入栈和出栈命令来传递. ...

  4. Keil C51中函数指针的使用

    函数指针在C语言中应用较为灵活.在单片机系统中,嵌入式操作系统.文件系统和网络协议栈等一些较为复杂的应用都大量地使用了函数指针.Keil公司推出的C51编译器是事实上80C51 C编程的工业标准,它针 ...

  5. Keil C51里关于堆栈指针的处理

    Keil C是非常优秀的C51编译器,可能是最好的C51编译器,提供各种优化模式,对变量的优化和地址安排做得非常好.这是用C语言写代码的好处之一,如果用汇编写,得费一大番功夫给各个变量安排内存物理地址 ...

  6. Keil C51 中指针的使用

    指针是C语言中比较难的一个内容,Keil C51在指针方面有和标准C不一样的地方,今天看了一些资料学习了一下Keil C51 中指针的使用. keil51的指针,包含两种指针:普通指针,兼容标准C:内 ...

  7. Hash查找法在Keil C51中的实现

    摘要:散列(hash)是一种重要的存储方法,也是一种常见的查找方法.它是指在记录的存储位置和它的关键字之间建立一个确定的对应关系.本文以射频卡门禁控制器为例,说明用射频卡卡号作为关键字,用Hash查找 ...

  8. KEIL C51高级编程

    第一节 绝对地址访问C51提供了三种访问绝对地址的方法: 1. 绝对宏:在程序中,用“#include”即可使用其中定义的宏来访问绝对地址,包括:CBYTE.XBYTE.PWORD.DBYTE.CWO ...

  9. Keil C51中变量的使用

    引言 8051内核单片机是一种通用单片机,在国内占有较大的市场份额.在将C语言用于51内核单片机的研究方面,Keil公司做得最为成功.由于51内核单片机的存储结构的特殊性,Keil C51中变量的使用 ...

随机推荐

  1. BZOJ 1877 晨跑

    http://www.lydsy.com/JudgeOnline/problem.php?id=1877 思路:拆点费用流,答案就是最大流量和最小费用. #include<algorithm&g ...

  2. BZOJ 2298 problem a(区间DP)

    题意:一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低.”问最少有几个人没有说真话(可能有相同的分数) 思路:考虑最多有多少人说真,那么答案就是n-max. ai个人分数 ...

  3. (转载)解决WPF动画属性锁死问题

    此文来自: 马开东博客 转载请注明出处 网址:http://www.makaidong.com 一般锁死问题都是出在后台代码写的动画中,以下为转载的解决方案! 方法一:将动画的 FillBehavio ...

  4. windows下将隐藏文件通过命令行改变为普通的显示文件

    attrib -h -s *.* /s /d 不懂的看下 attrib /? 帮助.保存为bat也可以.

  5. 微信开放JS-SDK,助力网页开发

    From:http://mp.weixin.qq.com/s?__biz=MjM5NDAwMTA2MA==&mid=209208141&idx=1&sn=1f075212b34 ...

  6. Axure 原型设计工具画业务流程图

    加入人人都是产品经理[起点学院]产品经理实战训练营,BAT产品总监手把手带你学产品点此查看详情! 软件行业从业6年,流程图看过太多,大部分流程图是在考验阅读者的理解能力,近期在设计公司新版APP,对流 ...

  7. JQuery DOM 有关代码练习

    //累加你选择的个数 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <hea ...

  8. Pure Css 菜单的使用

    本人新手,之前偶尔接触Bootstrap,也做过一些响应式开发,但是都是略显皮毛,公司的业务需求也限制了深入学习. 现着手Pure Css学习,尝试了简单的左边菜单自动隐藏的demo.闲话少说,代码贴 ...

  9. 我为什么放弃Go语言

    有好几次,当我想起来的时候,总是会问自己:我为什么要放弃Go语言?这个决定是正确的吗?是明智和理性的吗?事实上我一直在认真思考这个问题. 开门见山地说,我当初放弃Go语言(golang),就是由于两个 ...

  10. (36)JS运动之使物体向右运动

    基本思路:样式要是绝对定位,不然的话根本走不起来.当开启一个定时器的时候.必须先清除定时器.这是为了防止鼠标连续点击button而开启多个定时器,导致物体的速度加快等原因,其次要控制好物体的运动和停止 ...