单片机c语言知识点_第1页
单片机c语言知识点_第2页
单片机c语言知识点_第3页
单片机c语言知识点_第4页
单片机c语言知识点_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、定义#ifndef x #define x . #endif 这是宏定义的一种,它可以根据是否已经定义了一个变量来进行分支选择,一般用于调试等等.实际上确切的说这应该是预处理功能中三种(宏定义,文件包含和条件编译)中的一种-条件编译。 C语言在对程序进行编译时,会先根据预处理命令进行“预处理”。C语言编译系统包括预处理,编译和链接等部分。#ifndef x/先测试x是否被宏定义过 #define x 程序段1 /如果x没有被宏定义过,定义x,并编译程序段1 #endif 程序段2 /如果x已经定义过了则编译程序段2的语句,“忽视”程序段1。千万不要忽略了头件的中的#ifndef,这是一个很关键

2、的东西。比如你有两个C文件,这两个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。 还是把头文件的内容都放在#ifndef和#endif中吧。不管你的头文件会不会被多个文件引用,你都要加上这个。一般格式是这样的: #ifndef <标识> #define <标识> . . #endif <标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h #ifndef _ST

3、DIO_H_ #define _STDIO_H_ . #endif这里是static是静态局部变量,不会随着函数的结束而撤销,放在main函数里是没有实际意义的,下面一个是static的例子:void f()static int x=0;int y=0;x+;y+;printf("%d %dn", x, y);void main()f();f();f(); 这里运行了3次f(),但是static只会被定义一次,并不会随着f()函数的结束而消亡,但是y是局部变量,运行了3次它就被创建了3次消亡了3次,所以它的输出为:1 12 13 1. typedef &

4、#define的问题有下面两种定义pStr数据类型的方法,两者有什么不同?哪一种更好一点?typedef char *pStr;#define pStr char *; 答案与分析:通常讲,typedef要比#define要好,特别是在有指针的场合。请看例子:typedef char *pStr1;#define pStr2 char *;pStr1 s1, s2;pStr2 s3, s4;在上述的变量定义中,s1、s2、s3都被定义为char *,而s4则定义成了char,不是我们所预期的指针变量,根本原因就在于#define只是简单的字符串替换而typedef则是为一个类型起新名字。#de

5、fine用法例子: #define f(x) x*xmain( )int a=6,b=2,c;c=f(a) / f(b);printf("%d n",c);以下程序的输出结果是: 36。因为如此原因,在许多C语言编程规范中提到使用#define定义时,如果定义中包含表达式,必须使用括号,则上述定义应该如下定义才对:#define f(x) (x*x)当然,如果你使用typedef就没有这样的问题。4. typedef & #define的另一例下面的代码中编译器会报一个错误,你知道是哪个语句错了吗?typedef char * pStr;char string4 =

6、 "abc"const char *p1 = string;const pStr p2 = string;p1+;p2+;答案与分析:是p2+出错了。这个问题再一次提醒我们:typedef和#define不同,它不是简单的文本替换。上述代码中const pStr p2并不等于const char * p2。const pStr p2和const long x本质上没有区别,都是对变量进行只读限制,只不过此处变量p2的数据类型是我们自己定义的而不是系统固有类型而已。因此,const pStr p2的含义是:限定数据类型为char *的变量p2为只读,因此p2+错误。(注:关于

7、const的限定内容问题,在本系列第二篇有详细讲解)。#define与typedef引申谈1) #define宏定义有一个特别的长处:可以使用 #ifdef ,#ifndef等来进行逻辑判断,还可以使用#undef来取消定义。2) typedef也有一个特别的长处:它符合范围规则,使用typedef定义的变量类型其作用范围限制在所定义的函数或者文件内(取决于此变量定义的位置),而宏定义则没有这种特性。5. typedef & 复杂的变量声明在编程实践中,尤其是看别人代码的时候,常常会遇到比较复杂的变量声明,使用typedef作简化自有其价值,比如:下面是三个变量的声明,我想使用typd

8、ef分别给它们定义一个别名,请问该如何做?>1:int *(*a5)(int, char*);>2:void (*b10) (void (*)();>3. doube(*)() (*pa)9;答案与分析:对复杂变量建立一个类型别名的方法很简单,你只要在传统的变量声明表达式里用类型名替代变量名,然后把关键字typedef加在该语句的开头就行了。 (注:如果你对有些变量的声明语法感到难以理解,请参阅本系列第十篇的相关内容)。>1:int *(*a5)(int, char*);/pFun是我们建的一个类型别名typedef int *(*pFun)(int, char*);

9、/使用定义的新类型来声明对象,等价于int* (*a5)(int, char*);pFun a5; >2:void (*b10) (void (*)();/首先为上面表达式蓝色部分声明一个新类型typedef void (*pFunParam)();/整体声明一个新类型typedef void (*pFun)(pFunParam);/使用定义的新类型来声明对象,等价于void (*b10) (void (*)();pFun b10;>3. doube(*)() (*pa)9; /首先为上面表达式蓝色部分声明一个新类型typedef double(*pFun)();/整体声明一个新类

10、型typedef pFun (*pFunParam)9;/使用定义的新类型来声明对象,等价于doube(*)() (*pa)9;pFunParam pa; sfr,sfr16,esfr,sbit 收藏 伪指令 sfr、sfr16 和 sbit 与 Cx51 编译器完全兼容,我们可以在两种情况下都使用 SFR 寄存器定义文件:Ax51 宏汇编器和 Cx51 编译器。伪指令 esfr 在 Philips 80C51MX 架构的扩展 SFR 空间定义符号。该伪指令只能在 AX51 宏汇编器中使用。这些伪指令的格式如下: sfr sfr_symbol = address; esfr sfr_symbo

11、l = address; sfr16 sfr_symbol = address; ; 被 Ax51 忽略 sbit sfr_symbol = bit_address; 其中sfr_symbol 是要定义的特殊功能寄存器(SFR)符号的名称。 address 是在 0x80 - 0xFF 范围内的一个 SFR 地址。 bit_address 是一个 SFR 位的地址,形式为地址位位置(addressbitpos)或 sfr_symbol bitpos。地址(address)或特殊功能寄存器符号(sfr_symbol)指向一个位可寻址的 SFR 和位位置,指明 SFR 中的位位置,范围为 07。

12、使用伪指令 esfr、sfr 或 sbit 定义的符号可以用在适合 SFR 地址或 SFR 位地址使用的任意位置。例程sfr P0 = 0x80; sfr P1 = 0x90; sbit P0_0 = P00; sbit P1_1 = 0x901; 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

13、 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; s

14、fr 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,没有就是0 sbit

15、AC = 0xD6; /辅助进借位,(麻烦b) sbit F0 = 0xD5; /没有具体用途,可以由用户决定他的意义,所以它就没有意义 sbit RS1 = 0xD4; sbit RS0 = 0xD3; /工作寄存器选择,这个在下面解释 sbit OV = 0xD2; /over!溢出,有是1,没有是0 sbit P = 0xD0; /奇偶校验,奇数个1是1 /* TCON */ sbit TF1 = 0x8F; /T1的中断请求标志 sbit TR1 = 0x8E; /Timer 1 running,好记吧 sbit TF0 = 0x8D; / sbit TR0 = 0x8C; /把上面两

16、个1换成0 sbit 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 1 sbit

17、 EX1 = 0xAA; /Enable External 1 sbit ET0 = 0xA9; /Enable Timer/counter 0 sbit 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

18、T1 = 0xB5; /T/C1 sbit T0 = 0xB4; /T/C0 sbit INT1 = 0xB3; /外中断1 sbit INT0 = 0xB2; /外中断0 sbit TXD = 0xB1; /串行发送 sbit RXD = 0xB0; /串行接收 /* SCON */ sbit SM0 = 0x9F; / sbit SM1 = 0x9E; /串口工作方式 sbit SM2 = 0x9D; /什么鬼特征位,要用查书,或者等我以后解释,啊哈 sbit REN = 0x9C; /串行接收允许 sbit TB8 = 0x9B; /收到的第九位 sbit RB8 = 0x9A; /要发

19、的第九位 sbit TI = 0x99; /哇,熟悉吧,发送完成中断标志 sbit RI = 0x98; /接收完成中断标志 bit和sbit都是C51扩展的变量类型。 bit和int char之类的差不多,只不过char=8位, bit=1位而已。都是变量,编译器在编译过程中分配地址。除非你指定,否则这个地址是随机的。这个地址是整个可寻址空间,RAM+FLASH+扩展空间。bit只有0和1两种值,意义有点像Windows下VC中的BOOL。 sbit是对应可位寻址空间的一个位,可位寻址区:20H2FH。一旦用了sbi xxx = REGE6这样的定义,这个sbit量就确定地址了。sbit大部

20、分是用在寄存器中的,方便对寄存器的某位进行操作的。 sbit 要在最外面定义,就是说必须定义成外部变量.sbit定义的是SFR(特殊功能寄存器)的bit sbit更像是类型定义,不像是变量定义。 bit 可以在外部或内部定义。bit 动态分配的,有编译器来指定内存地址。sbit: 指示说明性说明 bit : 编译时分配空间 SFR 是特殊功能寄存器的总称,是单片计算机中的一组特殊的临时存储区域,用于动态存放计算机运行过程的一些状态信息、并依此做相应的控制。如楼上介绍的一样,MCS-51单片机就设有18个专用寄存器,P0-P3端口,定时/计数器T0、T1,TMOD、TCON、PCON、SCON

21、、PSW、IE、A、B、IP等等。SFR越多,编和控制功能越强、越灵活,但需要硬资源,所以系统设计时会根据需要来确定。 MCS-51特殊功能寄存器(SPR)的C51定义 收藏 MCS - 51单片机中,除了程序计数器PC和4组工作寄存器组外,其它所有的寄存器均为特殊功能寄存器(SPR),分散在片内RAM区的高128字节中,地址范围为80H0FFH。SFR中有11个寄存器具有位寻址能力,它们的字节地址都能被8整除,即字节地址是以8或0为尾数的。 为了能直接访问这些SPR,Franklin C51提供了一种自主形式的定义方法,这种定义方法与标准C语言不兼容,只适合与对MCS51系列单片机进行C语言

22、编程,特殊的能寄存器C51定义的一般语法格式如下: sfr sfr-name = int constant; “sfr”是定义语句的关键字,其后必须跟一个MSC - 51单片机真实存在的特殊功能寄存器名,“”后面必须是一个整型常数,不允许带有运算符的表达式,是特殊功能寄存器“sfr-name”的字节地址,这个常数值的范围必须在SFR 地址范围内,位于0x800x FF。例如: sfr SCON=0x98;/*串口控制寄存在器地址98H */ sfr TMOD=0x89; /* 定时器计数器方式控制寄存器地址89H */ MCS-51系列单片机的特殊功能寄存器的数量与类型不尽相同,因此建议将所有

23、特殊的“sfr”定义放入一个头文件中,该文件应包括MCS-51单片机系列机型中的SFR定义。C51编译器的 “reg51.h”头文件是这样一个文件。 在新的 MCS-51系列产品中,SFR在功能上经常组合为16位值,当SFR的高字节地址直接位于低字节之后时,对16位SFR的值可以直接进行访问。例如52子系列的定时器计数器2就是这种情况。为了有效地访问这类SFR,可使用关键字“sfr16”来定义,其定义语句的语法格式与8位SFR相同,只是“”后面的地址必须用16位于的SFR的低字节地址,即低字节地址作为“sfr16”的定义地址。例如: sfr16 T2=0xCC /* 定时器/计数器;T2低位地

24、址为0CC H,T2高位地址为0CDH */ 这种定义适用于所有的新的16位SFR,但不能用于定时器计数器0和1。 对于位寻址的SFR中的位,C51的扩充功能支持特殊位的定义,像SFR一样不与标准C兼容,使用“ sbit”来定义位寻址单元。 定义语句的一般语法格式有如下三种: 第一种格式:sbit bit-name=sfr-nameint constant; “sbit”是定义语句的关键字,后跟一个寻址位符号名(该位符号名必须是MCS-51单片机中规定的位名称),“”后的“sfr=name”中的位号,必须是07范围中的数。例如: sfr PSW=0Xd0;/*定义PSW予寄存器地址为D0H*/

25、 sfr OV=PSW2;/*定义OV位为PSW.2,地址为D2H/ * sfr CY=PSW7;/*定义CY位为PSW.7地址为D7H*/ 第二种格式:sbit bit-name=int constantint constant;“”后的 int constant为寻址地址们所在的特殊功能寄存器的字节地址,“”符号后的int constant为寻址位在 特殊功能寄存器中的位号。例如: sbit OV=0Xd0 2; /* 定义OV位地址是D0 H字节中的第2位 */ sbit CY=0XD07; /* 定义C Y位地址是D0H字节中的第7位 */ 第三种格式:sbit bit-name=in

26、t constant;“”后的int constant为寻址位的绝对地址。例如: sbit OV=0XD2;/* 定义OV位地址为D2H */ sbit OY=0XD7;/* 定义CY位地址为D7H */特殊功能位代表了一个独立的定义类,不能与其它位定义和位域互换。C51笔记(1)基本概念 收藏 1. 存储类型a) Data, 直接寻址的内部RAM地址,RAM低128 byte,一个周期内寻址b) bData,data区的16字节按位寻址区c) iData,间接寻址的内部RAM地址,RAM高128 byted) pData,外部存储的256个字节。e) xData,外部存储区,需要使用DPTR

27、访问数据地址f) Code,代码存储区,存放代码和查询表,需要使用DPTR访问数据地址2. 寻址方式:a) 直接:SFR,data, 位地址b) 间接:code, idata, xdata, data3. 常用SFRa) R0,R1,可以用作数据区指针,寻址iData。b) IP,中断优先级寄存器c) IE,中断使能寄存器。d) SMOD:控制串行通信波特率e) SCON:设置串口工作模式f) PSW即程序状态字(有些教材也叫程序状态寄存器)RS0,RS1,用于选择4个寄存器组之一设置 nv(清除) ov(溢出)方向 dn(减) up(增) 中断 ei(启用) di(禁用) 正负 ng(负)

28、pl(正) 零 zr(0) nz(非0) 辅助进位 ac(进位) na(不进位) 奇偶校验 pe(偶校验) po(奇校验) 进位 cy(进位) nc(不进位)4. 中断a) 中断向量位于代码段最低地址b) 8051在每个周期查询中断标志,如有中断请求,置位标志,下个周期查询标志位。5. 电源控制:a) 节电(低功耗)模式 i. PCON进入; ii. RAM保存; iii. 晶振停止工作,定时器,串口不工作 iv. 通过上电、复位退出b) 空闲模式。 i. IDLE进入 ii. RAM保存; iii. 晶振工作,但与CPU断开,定时器,串口工作 iv. 通过中断、上电、复位退出6. Timera) TCON:控制timer0,timer1;溢出位。b) TMOD:控制timer0,timer1工作方式、时钟源。计数器模式:对IO引脚脉冲计数;定时器模式:对内部时钟脉冲计数。c) Timer工作模式: i. 方式 0为 13位的定时器计数器方式。低位 TLx为 5位,高位 THx为 8位(x= 0,1)。当低位加1计数溢出时向高位进位,高位计数溢出则置"1"

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论