当前位置:文档之家› 单片机c语言知识点

单片机c语言知识点

#ifndef x#define x...#endif这是宏定义的一种,它可以根据是否已经定义了一个变量来进行分支选择,一般用于调试等等.实际上确切的说这应该是预处理功能中三种(宏定义,文件包含和条件编译)中的一种----条件编译。

C语言在对程序进行编译时,会先根据预处理命令进行“预处理”。

C语言编译系统包括预处理,编译和链接等部分。

#ifndef x//先测试x是否被宏定义过#define x程序段1 //如果x没有被宏定义过,定义x,并编译程序段1#endif程序段2 //如果x已经定义过了则编译程序段2的语句,“忽视”程序段1。

千万不要忽略了头件的中的#ifndef,这是一个很关键的东西。

比如你有两个C文件,这两个C文件都include了同一个头文件。

而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。

还是把头文件的内容都放在#ifndef和#endif中吧。

不管你的头文件会不会被多个文件引用,你都要加上这个。

一般格式是这样的:#ifndef <标识>#define <标识>............#endif<标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。

标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h#ifndef _STDIO_H_#define _STDIO_H_......#endif这里是static是静态局部变量,不会随着函数的结束而撤销,放在main函数里是没有实际意义的,下面一个是static的例子:void f(){static int x=0;int y=0;x++;y++;printf("%d %d\n", x, y);}void main(){f();f();f();}这里运行了3次f(),但是static只会被定义一次,并不会随着f()函数的结束而消亡,但是y是局部变量,运行了3次它就被创建了3次消亡了3次,所以它的输出为:1 12 13 1. typedef & #define的问题有下面两种定义pStr数据类型的方法,两者有什么不同?哪一种更好一点?答案与分析:通常讲,typedef要比#define要好,特别是在有指针的场合。

请看例子:在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef 则是为一个类型起新名字。

#define用法例子:以下程序的输出结果是: 36。

因为如此原因,在许多C语言编程规范中提到使用#define定义时,如果定义中包含表达式,必须使用括号,则上述定义应该如下定义才对:当然,如果你使用typedef就没有这样的问题。

4. typedef & #define的另一例下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?答案与分析:是p2++出错了。

这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。

上述代码中const pStr p2并不等于const char * p2。

const pStr p2和const long x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。

因此,const pStr p2的含义是:限定数据类型为char *的变量p2为只读,因此p2++错误。

(注:关于const的限定内容问题,在本系列第二篇有详细讲解)。

#define与typedef引申谈1) #define宏定义有一个特别的长处:可以使用#ifdef ,#ifndef等来进行逻辑判断,还可以使用#undef来取消定义。

2) typedef也有一个特别的长处:它符合范围规则,使用typedef定义的变量类型其作用范围限制在所定义的函数或者文件内(取决于此变量定义的位置),而宏定义则没有这种特性。

5. typedef & 复杂的变量声明在编程实践中,尤其是看别人代码的时候,常常会遇到比较复杂的变量声明,使用typedef作简化自有其价值,比如:下面是三个变量的声明,我想使用typdef分别给它们定义一个别名,请问该如何做?答案与分析:对复杂变量建立一个类型别名的方法很简单,你只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头就行了。

(注:如果你对有些变量的声明语法感到难以理解,请参阅本系列第十篇的相关内容)。

sfr,sfr16,esfr,sbit 收藏伪指令sfr、sfr16 和sbit 与Cx51 编译器完全兼容,我们可以在两种情况下都使用SFR 寄存器定义文件:Ax51 宏汇编器和Cx51 编译器。

伪指令esfr 在Philips 80C51MX 架构的扩展SFR 空间定义符号。

该伪指令只能在AX51 宏汇编器中使用。

这些伪指令的格式如下:sfr sfr_symbol = address;esfr sfr_symbol = address;sfr16 sfr_symbol = address; ; 被Ax51 忽略sbit sfr_symbol = bit_address;其中sfr_symbol 是要定义的特殊功能寄存器(SFR)符号的名称。

address 是在0x80 - 0xFF 范围内的一个SFR 地址。

bit_address 是一个SFR 位的地址,形式为地址^位位置(address^bitpos)或sfr_symbol ^ bitpos。

地址(address)或特殊功能寄存器符号(sfr_symbol)指向一个位可寻址的SFR 和位位置,指明SFR 中的位位置,范围为0-7。

使用伪指令esfr、sfr 或sbit 定义的符号可以用在适合SFR 地址或SFR 位地址使用的任意位置。

例程sfr P0 = 0x80;sfr P1 = 0x90;sbit P0_0 = P0^0;sbit P1_1 = 0x90^1;esfr MXCON = 0xFF; /* 扩展的Philips 80C51MX SFR */sfr16 T2 = 0xCC; /* 被Ax51 忽略*/reg51.h 详解/* BYTE Register */sfr P0 = 0x80; //P0口sfr P1 = 0x90; //P1口sfr P2 = 0xA0; //P2口sfr P3 = 0xB0; //P3口sfr PSW = 0xD0; //程序状态字,具体位意义见位定义sfr ACC = 0xE0; //累加器,程序员最常用的sfr B = 0xF0; //寄存器,主要用于乘除sfr SP = 0x81; //堆栈指针,初始化为07;先加1后压栈,先出栈再减1,sfr DPL = 0x82;sfr DPH = 0x83; //数据指针,用途大sfr PCON = 0x87; //电源控制sfr TCON = 0x88; //Timer/Counter控制sfr TMOD = 0x89; //Timer/Counter方式控制sfr TL0 = 0x8A;sfr TL1 = 0x8B; //sfr TH0 = 0x8C; //存着当前的计数值sfr TH1 = 0x8D; //我就想不明白,当时设计的时候,为什么不把TH0,TL0放在连续的地址!sfr IE = 0xA8; //好东西,中断控制sfr IP = 0xB8; //中断优先级控制,没有设计过要求时间严格的系统,所以至今没有用过sfr SCON = 0x98; //哇,熟悉,串口控制寄存器sfr SBUF = 0x99; //哇,更熟悉,串口缓冲寄存器/* BIT Register *//* PSW */sbit CY = 0xD7; //进位或借位,有就是1,没有就是0sbit AC = 0xD6; //辅助进借位,(麻烦b)sbit F0 = 0xD5; //没有具体用途,可以由用户决定他的意义,所以它就没有意义sbit RS1 = 0xD4;sbit RS0 = 0xD3; //工作寄存器选择,这个在下面解释sbit OV = 0xD2; //over!溢出,有是1,没有是0sbit P = 0xD0; //奇偶校验,奇数个1是1/* TCON */sbit TF1 = 0x8F; //T1的中断请求标志sbit TR1 = 0x8E; //Timer 1 running,好记吧~sbit TF0 = 0x8D; //sbit TR0 = 0x8C; //把上面两个1换成0sbit IE1 = 0x8B; //interrupt external 1 外中断请求标志sbit IT1 = 0x8A; //interrupt triggle 1 外中断触发方式sbit IE0 = 0x89;sbit IT0 = 0x88; //同样,把上面的两个1换成0/* IE */sbit EA = 0xAF; //Enable all哇,重要,全局中断控制,光着他,哈哈,什么都不用作了,就像放假一样sbit ES = 0xAC; //Enable Serial,开串口中断sbit ET1 = 0xAB; //Enable Timer/Counter 1sbit EX1 = 0xAA; //Enable External 1sbit ET0 = 0xA9; //Enable Timer/counter 0sbit EX0 = 0xA8; //Enable External 0/* IP */sbit PS = 0xBC; //串行中断优先级sbit PT1 = 0xBB; //T1优先级sbit PX1 = 0xBA; //外部中断1优先级sbit PT0 = 0xB9; //sbit PX0 = 0xB8; //上面两个1换成0/* P3 */ //控制寄存器!!!!sbit RD = 0xB7; //读sbit WR = 0xB6; //写sbit T1 = 0xB5; //T/C1sbit T0 = 0xB4; //T/C0sbit INT1 = 0xB3; //外中断1sbit INT0 = 0xB2; //外中断0sbit TXD = 0xB1; //串行发送sbit RXD = 0xB0; //串行接收/* SCON */sbit SM0 = 0x9F; //sbit SM1 = 0x9E; //串口工作方式sbit SM2 = 0x9D; //什么鬼特征位,要用查书,或者等我以后解释,啊哈sbit REN = 0x9C; //串行接收允许sbit TB8 = 0x9B; //收到的第九位sbit RB8 = 0x9A; //要发的第九位sbit TI = 0x99; //哇,熟悉吧,发送完成中断标志sbit RI = 0x98; //接收完成中断标志bit和sbit都是C51扩展的变量类型。

相关主题