(玩电子) 电子技术学习与研究
当前位置单片机教程网 >> 基础教程 >> 浏览文章

第五课 C51变量

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

表61存储器类型

存储器类型

说明

data

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

bdata

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

idata

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

pdata

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

xdata

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

code

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

 


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

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

之前提到简单提到sfr,sfr16,sbit定义变量的方法下面我们再来仔细看础
sfr和sfr16能直接对51单片机的特殊寄存器进行定义定义方法如下
sfr 特殊功能寄存器名= 特殊功能寄存器地址常数;
sfr16 特殊功能寄存器名= 特殊功能寄存器地址常数;
我们能这样定义AT89c51的P1口
sfr P1 = 0x90; //定义P1 I/O口其地址90H
sfr关键定后面是一个要定义的名字可我选取但要符合标识符的命名规则名字最好有一定的含义如P1口能用P1为名这样程序会变的好读好多等号后面必须是常数不允许有带运算符的表达式而且该常数必须在特殊功能寄存器的地址范围之内80HFFH具体可查看附录中的相关表sfr是定义8位的特殊功能寄存器而sfr16则是用来定义16位特殊功能寄存器如8052的T2定时器能定义为
sfr16 T2 = 0xCC; //这里定义8052定时器2地址为T2L=CCH,T2H=CDH
用sfr16定义16位特殊功能寄存器时等号后面是它的低位地址高位地址一定要位于物理低位地分上注意的是不能用于定时器0和1的定义
sbit可定义可位寻址对象如访问特殊功能寄存器中的某位其实这样应用是经常要用的如要访问P1口中的第2个引脚P1.1我们能照以下的方法去定义:
(1)sbit 位变量名位地址
sbit P1_1 = Ox91;
这样前位的绝对地址赋给位变量同sfr一样sbit的位地址必须位于80H-FFH之间
(2)Sbit 位变量名教殊功能寄存器名^位位置
sft P1 = 0x90;
sbit P1_1 = P1 ^ 1; //先定义一个特殊功能寄存器名再指定位变量名所在的位置
当可寻址位位于特殊功能寄存器中时可采用这种方法
(3)sbit 位变量名字节地址^位位置
sbit P1_1 = 0x90 ^ 1;
这种方法其实和2是一样的只前特殊功能寄存器的位分接用常数表示
在单片机c语源储器类型中供给有一个bdata的存储器类型这个是指可位寻址的数据存储器位于单片机的可位寻址区中能将要求可位录址的数据定义为bdata,如:
unsigned char bdata ib; //在可位录址区定义ucsigned char类型的变量ib
int bdata ab[2]; //在可位寻址区定义数组ab[2]这些也称为可寻址位对象
sbit ib7=ib^7 //用关键字sbit定义位变量来独立访问可寻址位对象的其中一位
sbit ab12=ab[1]^12;
操作符""后面的位位置的最大值取决于指定的基址类型char0-7,int0-15,long0-31
下面我们用上一课的电路来实践一下这一课的知识同样是做一下简单的跑马灯实验项目名为RunLED2程序如下:

sfr P1 = 0x90; //这里没有使用预定义文件
sbit P1_0 = P1 ^ 0; //而是自己定义特殊寄存器
sbit P1_7 = 0x90 ^ 7; //之前我们使用的预定义文件其实就是这个作用
sbit P1_1 = 0x91; //这里分别定义P1端口和P10,P11,P17引脚

void main(void)
{
unsigned int a;
unsigned char b;
do{
for (a=0;a<50000;a++)
P1_0 = 0; //点亮P1_0
for (a=0;a<50000;a++)
P1_7 = 0; //点亮P1_7
for (b=0;b<255;b++)
{
for (a=0;a<10000;a++)
P1 = b; //用b的值来做跑马灯的花样
}
P1 = 255; //熄灭P1系LED
for (b=0;b<255;b++)
{
for (a=0;a<10000;a++) //P1_1了
P1_1 = 0;
for (a=0;a<10000;a++)
P1_1 = 1;
}
}while(1);
}

 

. Keil c51指针变量
单片机c语言支持一般指针(Generic Pointer)和存储器指针(Memory_Specific Pointer).
1. 1. 一般指针
一般指针的声明和使用均与标准C相同不过同时还能说明指针的存储类型例如
long * state;为一个指向long型整数的指针而state本身则来储模式存放
char * xdata ptrptr为一个指向char数据的指针而ptr本身放于外部RAM区以系long,char等指针指向的数据可存放于任何存储器中
一般指针本身用3个字节存放分别为存储器类型高位偏移低位偏移量
2. 2. 存储器指针
基于存储器的指针说明时即指定了存贮类型例如
char data * str;str指向data区中char型数据
int xdata * pow; pow指向外部RAM的int型整数
这种指针存放时只需一个字节或2个字节就够了因为只需存放偏移量
3. 3. 指针转换
即指针在上两种类型之间转化
l 当基于存储器的指针作为一个实参传递给需要一般指针的函数时指针自动转化
l 如果不说明外部函数原形基于存储器的指针自动转化为一般指针导致错误因而请用“include”说明所有函数原形
l 能强行改变指针类型

 变量的存储类别

一static静态局部变量
1静态局部变量在程序整个运行期间都不会释放内存
2对于静态局部变量是在编译的时候赋初值的即只赋值一次如果在程序运行时已经有初值则以后看调用的时候不再重新赋值
3如果定义局部变量的时候不赋值则编译的时候自动赋值为0而对于自动变量而言定义的时候不赋值则是一个不确定的值
4虽然静态变量在函数调用结束后仍然存在但是其他函数不能引用
 
  二用extern声明外部变量
用extern声明外部变量是为了扩展外部变量的作用范围比如一个程序能由多个源程序文件组成如果一个程序中需要引用另外一个文件中已经定义的外部变量就需要使用extern来声明
  正确的做法是在一个文件中定义外部变量而在另外一个文件中使用extern对该变量作外部变量声明
  一个文件中   int abc;
  另外一个文件中   extern abc;
 
例子
用extern将外部变量的作用域扩展到其他文件
文件1
//用extern将外部变量的作用域扩展到其他文件中
#include
#include
#include
unsigned int array[10];
void fillarray();
void init_ser()
{
 SCON=0X50;
 TMOD|=0X20;
 TH1=0XF3;
 TR1=1;
 TI=1;
}
void main()
{
 unsigned int i;
 init_ser();
 fillarray();
 for(i=0;i<10;i++)
 {
  printf("array[%d]=%d\n",i,array[i]);
 }
  for(;;){;}
}
 
文件2
extern int array[10];
void fillarray()
{
 unsigned char i;
 for(i=0;i<10;i++)
 {
  array[i]=i;
 }
}

在单片机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区

发表评论告诉好友收藏此文关闭窗口

文章评论

相关文章

qqȺ