4单片机嵌入式系统原理及应用(贾好来)单片机的程序设计基础.ppt

上传人:夺命阿水 文档编号:236058 上传时间:2023-03-10 格式:PPT 页数:126 大小:1.70MB
返回 下载 相关 举报
4单片机嵌入式系统原理及应用(贾好来)单片机的程序设计基础.ppt_第1页
第1页 / 共126页
4单片机嵌入式系统原理及应用(贾好来)单片机的程序设计基础.ppt_第2页
第2页 / 共126页
4单片机嵌入式系统原理及应用(贾好来)单片机的程序设计基础.ppt_第3页
第3页 / 共126页
4单片机嵌入式系统原理及应用(贾好来)单片机的程序设计基础.ppt_第4页
第4页 / 共126页
4单片机嵌入式系统原理及应用(贾好来)单片机的程序设计基础.ppt_第5页
第5页 / 共126页
点击查看更多>>
资源描述

《4单片机嵌入式系统原理及应用(贾好来)单片机的程序设计基础.ppt》由会员分享,可在线阅读,更多相关《4单片机嵌入式系统原理及应用(贾好来)单片机的程序设计基础.ppt(126页珍藏版)》请在课桌文档上搜索。

1、1,第4章 8051单片机程序设计基础,语言:汇编还是C?,确定了单片机,另一个老生常谈的争论就不得不面对了,学汇编还是C好?现在很多宣传一味鼓吹C语言的好,似乎“万恶的汇编”早就该下地狱了。这种观点是有失偏颇的。客观的讲,汇编语言和C语言各有特点。汇编语言的本质是机器码,是直接和单片机对话的唯一途径。优点是效率高,缺点是难以驾驭。C语言的逻辑性更强,优点是只要掌握了语言本身编程就变得简单,而且移植性好。缺点是即使你写出了程序,完成了功能,但是对单片机本身的了解还是很少。,2,实际开发中大多会使用C语言,汇编语言在较为复杂的工程面前还是显得很无力。但是汇编语言在学习单片机的过程中却很有用,想要

2、真正懂得单片机的内部奥妙,还得借助汇编语言这个窗口。因此,学习的正确流程应该是:先通过汇编语言将单片机硬件资源掌握透彻,C语言仅是一门语言,对硬件了解清楚的基础之上再学习C语言,很容易上手。,3,主要内容,4.1 汇编语言程序结构4.2 算术运算程序设计4.3 C51基础4.4 C51和汇编语言的混合编程,4,4.1 汇编语言程序结构,4.1.1简单程序结构4.1.2分支结构4.1.3循环结构4.1.4子程序及其参数传递方法4.1.5中断服务程序*4.1.6 前后台结构*4.1.7 并行结构,5,4.1.1简单程序结构,简单结构程序执行时,从第一条指令开始顺序执行,直到最后一条指令为止。它是构

3、成较大、较复杂程序的最基本的结构。但它本身只能完成一些简单的任务,所以叫做简单程序。,6,例4.1将单字节BCD码转换成二进制数,ORG 100H MOV R2,#28H;要转换的BCD数送入R2,入口 MOV A,R2 ANL A,#0F0H;屏蔽低4位,取高4位 SWAP A;高低4位交换 MOV B,#10 MUL AB;210 MOV R3,A;乘积送R3保存,7,MOV A,R2ANL A,#0FH;取低4位ADD A,R3;2108送AMOV R3,A;结果1CH送R3 END;程序结束,8,例4.2 双字节移位,将30H、31H单元存放的无符号数除2,商仍在原单元中,余数送入CY

4、中。由于8051指令系统中只有单字节移位指令,故双字节移位需要分步进行,只给出程序段。,9,CLR C MOV A,30H RRC A MOV 30H,A MOV A,31H RRC A MOV 31H,A,10,4.1.2分支结构,在大量的实用程序中,需要对某些指令的执行结果进行判断,根据判断的结果决定程序的走向。判断后有“是”和“非”两种结果,程序也就有两种可能的执行方向,也就是程序产生了分支,形成了分支结构。改变程序的执行顺序有两种方法:一是事先安排好的,程序执行到某条指令后转去执行指定的指令。这是通过无条件转移指令来实现的;第二种就是根据程序执行的结果来决定转移到何处去。这是通过条件转

5、移指令来实现的,分支程序就属这种情况。,11,转移指令都有条件测试功能,根据测试后的结果来确定是否转移,条件成立则转移,否则执行下一条指令。例4.3 给定8位有符号数X,求符号函数Y。所谓符号函数,即当X0时,Y为1,当X0时,Y等于-1,而当X=0时,Y=0。这是一个典型的分支程序。,12,13,图4-1 例4.3程序流程图,ORG 100H START:MOV R0,#30H;存放有符号数的地址指针;30H送R0,而(30H)=X MOV A,R0;(A)X ANL A,R0;做与运算,出标志 JZ ZERO;判(A)=0否?(A)=0,转ZERO,(A)非0,;下一条 JNB ACC.7

6、,NEXT;(A)的最高位不是1,即为正数,转;标号NEXT,如是1,执行下一条 MINUS:MOV R1,#0FFH;(A)的最高位是1,即为负数,;(R1)=-1 SJMP EXIT;转出口 ZERO:MOV R1,#0;(R1)0 SJMP EXIT;转出口 NEXT:MOV R1,#1;(R1)=1,即R1做为出口Y=1 EXIT:SJMP EXIT;原地踏步,14,4.1.3循环结构,一个程序若包含多次重复执行的程序段,则称为循环结构。循环程序和分支程序都是非顺序结构程序,但它们在程序走向和所实现的功能上是不同的。先看实例:,15,例4.4 求存放在片内RAM 20H单元开始的10个

7、无符号数的最小值,ORG 100H MOV R0,20H;置地址指针 MOV R7,10;计数器初值 MOV A,R0;取第一个数 DEC R7;实际的比较次数LOOP:INC R0;修改地址指针 MOV 40H,R0;取后一个数 CJNE A,40H,NEXT;前数与后数比较,16,17,NEXT:JC LOPP1;前一个数小,不交换 MOV A,40H;前一个数大,把后一个数送A LOPP1:DJNZ R7,LOOP;计数器减1,不为0转LOOP MOV 41H,A;循环结束,最小值送;41H单元 HERE:SJMP$;$指HERE标号,踏步 END,18,图42 例4.4程序流程图,19

8、,循环程序的构成,设置初值部分,进入循环之前要给出初始状态,称为初始化,一般包括建立计数器,设置地址指针及其他变量的初值。初值又分为循环工作部分的初值和循环结束条件的初值。循环工作部分,这是循环结构的基本部分,也叫循环体,是为重复执行任务编写的程序段。循环控制部分,控制循环的次数,一般包括修改计数器,修改指针,检测循环结束条件等。结束部分用于分析和存储结果。,20,图4-3 循环程序流程图,如果循环工作部分又包含新的循环程序,称为循环嵌套,如出现多次嵌套,就称为多重嵌套。而循环工作部分不包含另外的循环体就称为单重循环。,21,单重循环和多重循环,单重循环及其控制方法,控制循环的方法有多种,这里

9、只介绍其中的三种。当循环次数已知时,利用计数器控制循环最方便。当循环次数未知时,可采用按实际条件控制循环,或采用逻辑尺的方法。,22,例4.5 求存放于首地址为20H单元的多个学生考试成绩之和。这个问题可利用成绩是正数的特点,在成绩数据区后放一个负数作为结束条件。ORG 1000HSTART:MOV R0,#20H;首地址指针 MOV R1,#0 MOV R2,#0,23,LOOP:MOV A,R0;取第1个数 JB ACC.7,DONE;是负数,结束循环 ADD A,R1 JNC NEXT INC R2NEXT:INC R0 MOV R1,A SJMP LOOPDONE:SJMP$,24,用

10、逻辑尺控制循环,例4.6 若单片机进行8路巡回检测,采集的数据要用不同的函数加以处理。设第0、3、5路用FUNC1处理,而1、2、4、6、7路用FUNC2处理,这样在一个循环中包括两个支路,可使用一个二进制位串来控制程序沿那一个位串来循环,本题的位串设计为11010110,0表示用FUNC1处理,1表示用FUNC2处理,这个二进制位串称为逻辑尺。其长度根据需要可为一字节,或多字节。程序运行时,可将逻辑尺移位,判断是0还是1,以决定对数据如何处理。程序流程如图4-4所示。,25,26,图4-4 用逻辑尺控制循环,多重循环,如果在一个循环体中又包含了其他的循环程序,即循环中还套着循环,这种程序称为

11、多重循环程序。例4.7 10秒延时程序。延时程序与MCS-51执行指令的时间有关,如果使用12MHz晶振,一个机器周期为1s计算出执行一条指令以至一个循环所需要的时间,给出相应的循环次数,便能达到延时的目的。,27,DEL:MOV R5,#100DEL0:MOV R6,#200DEL1:MOV R7,#248;248*2+1=497个机器周期DEL2:DJNZ R7,DEL2;(248*2+1+2)*200+1=99801个机器周期 DJNZ R6,DEL1;(248*2+1+2)*200+2)*100+1+2s DJNZ R5,DEL0 RET,28,4.1.4子程序及其参数传递方法,在实际

12、程序中,常常会多次进行一些相同的计算和操作。如数制转换、函数式计算等等。如果每次都从头开始编制一段程序,不仅麻烦,而且浪费存储空间。因而对一些常用的程序段以子程序的形式,事先存放在存储器的某一个区域。当主程序在运行时,需要用子程序时,只要执行调用子程序的指令,使程序转至子程序。当子程序处理完毕,返回主程序,继续进行以后的操作。,29,30,调用子程序的优点:(1)避免了对相同程序段的重复编制。(2)简化程序的逻辑结构,同时也便于子程序调试。(3)节省存储器空间。,8051指令系统中,提供了两条调用子程序指令ACALL及LCALL,并提供了一条返回主程序的指令RET。ACALL:子程序距离本指令

13、的距离不超过2KLCALL:子程序距离本指令的距离在64K内子程序的调用,包含两个部分:保护现场和恢复现场。,31,参数传递,调用子程序时,主程序应先把有关的参数存放在约定的位置,子程序在执行时,可以从约定的位置取得参数,当子程序执行完,将得到的结果存入约定的位置,返回主程序后,主程序可以从这些约定的位置读取到需要的结果,这就是参数的传递。,32,用累加器或寄存器进行参数的传递,用累加器和寄存器存放输入参数及结果参数,可以提高程序的运算速度,而且程序也很简单。其不足之处是参数不能传递得很多,因为寄存器的数量有限;主程序在调用子程序前必须将参数先送入寄存器;由于子程序参数的个数是固定的,故主程序

14、不能任意设定参数的多少。,33,用指针寄存器进行参数的传递,当程序中所需处理的数据量比较大时,常常用存储器存放数据,而不用寄存器。用指针指示数据在存储器中所处的位置,可以大大节省参数传递中的工作量,使用指针的方法能实现数据长度可变的运算。8051指令系统中提供的由R0、R1作间址寄存器的指令很多,当参数存放在内部RAM时,用R0、R1作指针,使参数的传递十分方便。当参数在外部RAM或在程序存储器时,可用DPTR作指针。对可变长度运算时,数据长度可由寄存器指出,也可采用在数据后设置标志的办法。,34,用堆栈进行参数传递,堆栈可以用于主程序调用子程序时相互之间的参数传递。调用前,主程序用PUSH指

15、令把参数压入堆栈,子程序在执行中按堆栈指针间接访问栈中参数,并且把运算结果送回堆栈。返回主程序后,主程序用POP指令得到堆栈中的结果参数。利用堆栈传递参数的方法比较简单,而且传递参数量比用寄存器来传递参数多得多,也不必为特定的参数分配存储单元。,35,例4.8 一位16进制数转换成ASCII码,HEASC:MOV R0,SP;借用R0,为堆栈指针 DEC R0 DEC R0;R0指向被转换参数地址 XCH A,R0;保护累加器,取被转换参数 ANL A,#0FH ADD A,#2;表首地址 MOVC A,A+PC;查表 XCH A,R0;结果送回堆栈 RETATAB:DB 30H,31H,32

16、H,39H DB 41H,46H,36,例4.9 把内部RAM中40H单元一字节的16进制数转换成两位ASCII码,存放在R1指出的两个单元中,调用HEASC子程序。,程序如下:HEX_TO_ASCII:MOV A,40H;直接寻址,(40H)A SWAP A;两位16进制数半字节交换 PUSH ACC ACALL HEASC POP ACC,37,MOV R1,A;高半字节转换成ASCII码存结果 INC R1 PUSH 40H ACALL HEASC POP ACC MOV R1,A;低半字节转换成ASCII码存结果 RET END,38,4.1.5中断服务程序,中断服务程序对实时事件请求

17、作必要的处理,使系统能实时地并行完成各个操作,中断服务程序必须包括现场保护、中断服务、现场恢复、中断返回4个部分。中断服务程序编写方法与子程序类似,同时应注意以下问题:(1)在中断程序的结尾一定要使用RETI,以便返回到主程序中断处。(2)中断服务程序中要清除中断标志,以免重复进入。具体标志和清除方法参见各中断部分。,39,(3)中断服务程序的长度应尽量短小,以免执行时占用CPU过多时间。所以主程序与中断服务程序之间的数据交换多采用标志位。(4)中断嵌套深度受堆栈区的影响。系统复位后,栈指针SP的初始值为07H,与工作寄存器区重叠,所以程序中一般要重新定义。AT89S52内部虽有256B的RA

18、M,但堆栈需利用低128B开辟,所以其堆栈深度有限。,40,4.1.6 前后台结构,41,4.1.7 并行结构(多任务结构),一个系统可以实现多任务的轮转调度,并允许“准并行”地执行多个循环或任务。任务不是同时执行,而是以时间片(time slice)调度执行。操作系统OS(Operation System)将可用的CPU时间划分成若干时间片,为每个任务指定一个时间片,每个任务允许在预先规定的一段时间内执行。然后,OS切换到另一个就绪的任务,使这个任务也执行一段时间。时间片是很短的,通常是几个毫秒。因此,任务看起来是同时执行的。,42,4.2 算术运算程序设计,4.2.1 不带符号的多字节加法

19、4.2.2 双字节二进制无符号数乘法4.2.3 码制转换程序4.2.4 查表程序,43,4.2.1不带符号的多字节加法,不带符号的多字节二进制数定点加法程序在处理多字节运算时,应注意低字节向高字节的进位(或借位),用进位位CY判别,当CY=0时表示无进位或借位,反之则表示有进位或借位。在进行不带符号的单字节二进制数加减运算时,用进位CY判别和溢出与否。例4.11 两个多字节数P、Q均以低字节在前,高字节在后的次序,分别存放在由R0、R1指出的内部RAM中,相加后存入P数据区。,44,ORG 1000H STAT1:CLR C;清进位 MOV R2,#N;取字节数MADD:MOV A,R0;取加

20、数(一个字节)ADDC A,R1;两数相加(由低字节开始)MOV R0,A INC R0 INC R1 DJNZ R2,MADD;两数加完?JCERR;和字节数大于N,则溢出 RET ERR:N EQU 0AH END,45,4.2.2双字节二进制无符号数乘法,将(R2R3)和(R6R7)中双字节无符号数相乘,结果送R4R5R6R7。本子程序使用累加器A、寄存器R0、R2R7及标志CY。子程序及其框图如图4-5所示。NMUL:MOV R4,#0;0R4R5 MOV R5,#0 MOV R0,#16;16位计数器R0 CLR C NMLP:MOV A,R4;右移一位 RRC A MOV R4,A

21、,46,47,图4-5 NMUL子程序框图,MOV A,R5 RRC A MOV R5,A MOV A,R6 RRC A MOV R6,A MOV A,R7 RRC A MOV R7,A JNC NMLN;C为移出的乘数最低位 MOV A,R5;执行加法 ADD A,R3 MOV R5,A MOV A,R4 ADDC A,R2 MOV R4,ANMLN:DJNZ R0,NMLP;循环16次,MOV A,R4;最后结果再右移位 RRC A MOV R4,A MOV A,R5 RRC A MOV R5,A MOV A,R6RRC AMOV R6,AMOV A,R7RRC AMOV R7,ARET,

22、48,4.2.3 码制转换程序,例4.13 ASCII码到BCD码的转换。设ASCII字符置于工作寄存器R2中,转换结果放在R3中(高4位为0)。为提高程序的容错性,若转换结果9,R3为FFH。例如,ASCII码39H转换为BCD码应为9。,49,ASCII_TO_BCD:MOV A,R2 CLR C SUBB A,30H MOV R3,A JC ERR SUBB A,0AH JC ENNDERR:MOV R3,#0FFH;转换结果0,或;10置出错标志ENND:SJMP$END,50,例4.14 BCD数到二进制数之间的转换。n+1位的BCD数可表示为(AnAn-1A1A0)BCD=An10

23、n+An-110n-1+A1101+A0=(An10+An1)10+An-2)10+A1)10+A0可以根据此式编制转换程序,为方便编程,从BCD数的高位做起。下面是双字节BCD数到二进制数的转换程序。;功能:将4位BCD数转换为二进制数;入口:BCD码为R5(千位,百位),R4(十位,个位)。;出口为R5R4,为16位无符号数二进制整数。;使用资源:累加器ACC、寄存器R5、R4、B、R2、R6、R3、进位标志C,51,BCD4B:MOV A,R5 MOV R2,A ACALL BCD2B MOV B,#64H MUL AB MOV R6,A XCH A,B MOV R5,A MOV A,R

24、4 MOV R2,A ACALL BCD2B ADD A,R6 MOV R4,A MOV A,R5 ADDC A,#00H MOV R5,A RET,52,BCD2B:MOV A,R2ANL A,#0F0H SWAP A MOV B,#0AH MUL AB MOV R3,A MOV A,R2 ANL A,#0FH ADD A,R3 MOV R2,A RET,4.2.4 查表程序,查表是一种常用的非数值操作,利用查表可以使复杂的计算简单化,并能完成如数据补偿、转换、检索、实现程序的多分支转移等多种功能。有简单查表和查表散转两种。,53,简单查表程序,利用指令MOVC A,A+DPTR 查表例如,

25、查表求输入数据X的函数值Y=f(X),假设表在ROM中,首地址为TAB;X的取值为1,2,N-1,N;对应的Y值存放地址为TABX;X,Y均占一个字节,输入数据X(X值在累加器A中),查表结果仍存于A MOV DPTR,TAB MOVC A,ADPTR TAB:DB,54,用MOVC A,APC指令查表,将16进制数0F转换成ASCII码,程序入口在A,出口仍在A中 HASC2:INC A MOVC A,APC HASC22:RET ASCTAB:DB 30H,31H,32H,33H DB 34H,35H,36H,37H,38H DB 39H,41H,42H,43H,44H DB 45H,46

26、H,55,散转程序设计,这是一种多分支程序,它可根据运算结果或输入数据将程序转至不同的分支,例如,根据工作寄存器R0内容的不同,使程序转入相应的分支。设R0=0,对应的分支程序标号为PR0;R0=1对应的分支程序标号为PR1;R0=n对应的分支程序标号为PRn。,56,LP0:MOV DPTR,#TAB;取表头地址 MOV A,R0 ADD A,R0;R0内容乘以2 JNC LP1;无进位转移 INC DPH;加进位位 LP1:JMP A+DPTR;跳至散转表中相应位置 TAB:AJMP PR0;跳至不同的分支,2字节指令 AJMP PR1 AJMP PRn,57,顺序检索程序例4.18 从片

27、内RAM的表中,顺序检索出关键字,给出关键字在表中的序号,当找遍整个表而无关键字时,序号为00H。表首地址为#TABLE,表长为#LENTH。程序如下:TABLE EQU 20HLENGTH EQU 10HKEY EQU 33HSEARCH:MOV R0,#TABLE MOV R1,#LENGTHMOV R2,#00H,58,LOOP:MOV A,#KEY XRL A,R0 INC R0 INC R2 JZ EXIT DJNZ R1,LOOP MOV R2,#00HEXIT:MOV A,R2 RET,59,4.3 C51基础,4.3.1 Keil C51标识符与关键字4.3.2 C51数据与数

28、据类型4.3.3 C51变量及其存储方式4.3.4 C51数据的存储类型和存储模式4.3.5 C51对8051特殊功能寄存(SFR)的定义4.3.6 C51对8051并行接口的定义4.3.7 中断服务函数与寄存器组定义4.3.8函数的参数和局部变量的存储器模式,60,4.3.1 Keil C51标识符与关键字,1.标识符 C51编译器规定标识符最长可达255个字符,但只有前面32个字符在编译时有效,因此在编写源程序时标识符的长度不要超过32个字符,这对于一般应用程序来说已经足够了。程序中对于标识符的命名应简洁明了,含义清晰,便于阅读理解,如用标识符“max”表示最大值,用“Timer0”表示定

29、时器0等。,61,2.关键字 C51 编译器除了支持ANSI C标准关键字之外,还扩充了表4-1所示的关键字。表4-1 C51扩展的关键字,62,4.3.2 C51数据与数据类型,C51支持的数据与数据类型和ANSI C基本相同,仅多了“bit”数据类型,如表4-2所列。由于8051是8位机,因而不存在字节对准问题。这意味着数据结构成员是顺序放置的。,63,表4-2 Keil C51编译器支持的数据类型、长度和数域,4.3.3 C51变量及其存储方式,除了支持位变量外,C51变量定义和标准C变量定义是相似的,下面予以简要说明。位变量(bit)的值可以是1(true)或0(false)。与805

30、1硬件特性操作有关的位变量必须定位在8051 CPU片内存储区(RAM)的可位寻址空间中。,64,1.位变量,(1)位变量的C51定义的语法及语义:bit driverP11;/*将driverP11定义为位变量*/bit led_pointer;/*将led_pointer定义为位变量*/bit led_number;/*将led_number定义为位变量*/(2)函数可包含类型为bit的参数,也可以将其作为返回值。例 bit func(bit b0,bit b1)/*/return(b1);,65,注意:使用禁止中断#pragma disable或包含明确的寄存器组切换(using n)的

31、函数不能返回位值,否则编译器会返回一个错误信息。,(3)对位变量定义的限制:位变量不能定义成一个指针,如不能定义 bit*led_pointer;也不存在位数组,如不能定义 bit b_array;在位定义中,允许定义存储类型,位变量都被放入一个位段,此段总位于8051内部RAM中,因此存储类型限制为data或idata。如果将位变量的存储类型定义成其他类型,都将导致编译出错。,66,(4)可位寻址对象指可以字节或位寻址的对象。该对象应位于8051片内可位寻址RAM区中,C51编译器允许数据类型为idata的对象放入8051片内可位寻址RAM区中。例 先定义变量的数据类型和存储类型:bdata

32、 int ibase;/*ibase定义为bdata整型变量*/bdata char bary4;/*bary4定义为bdata字符型数组*/然后可使用“sbit”定义可独立寻址访问的对象位,即 sbit mybit0=ibase0;/*mybit0定义为ibase的第0位*/sbit mybitl5=ibase15;/*mybit15定义为ibase的第15位*/sbit Ary07=bary07;/*Ary07定义为bary0的第7位*/sbit Ary37=bary37;/*Ary37定义为bary3的第7位*/,67,对象“ibase”、“bary”也可以字节寻址。例 Ary37=0;

33、/*bary3的第7位赋值为0*/bary3=a;/*字节寻址:bary3赋值为 a*/sbit定义要求基址对象的存储类型为bdata,否则只有绝对的特殊位定义(sbit)是合法的。位置(操作符)后的最大值依赖于指定的数据类型,对于char/uchar而言是07;对于int/uint 而言是015;对于long/ulong而言是031。,68,2.其它类型变量,字符变量的长度为1字节(Byte)即8位。除非指明是有符号变量(signed char),字符变量的值域范围是0255(无符号)。对于有符号的变量,最具有重要意义的位是最高位上的符号标志位(MSB),在此位上,1代表“负”,0代表“正”

34、。有符号字符变量(signed char)和无符号字符变量(unsigned char)在表示0127的数值时,其含义是一样的,都是000 x7F。负数一般用补码表示,即用11111111表示-1,用11111110表示-2等。,69,整型变量的长度为16位,8051系列CPU将int型变量的MSB存放在低地址字节。有符号整型变量(signed int)也使用MSB位作为标志位,并使用二进制的补码表示数值。可直接使用几种专用的机器指令来完成多字节的加、减、乘、除运算。整型变量值0 x1234以图4-6a)所示的方式保存在内存中。长整型变量的长度是32位,占用4字节,其它方面与整型变量(int)

35、相似。长整型变量(long int)值0 x12345678以图4-6b)所示的方式保存在内存中。,70,浮点型变量为32位,占4字节。许多复杂的数学表达式都采用浮点变量数据类型。它用符号位表示数的符号,用阶码和尾数表示数的大小。用它们进行任何数学运算都需要使用由编译器决定的各种不同效率等级的库函数。Keil C51的浮点变量数据类型的使用格式与IEEE-754标准(32)有关,具有24位精度,尾数的高位始终为“1”,因而不保存。,71,浮点变量的位分布如下:1位符号位;8位指数位;23位尾数。符号位是最高位,尾数为最低的23位,内存中按 字节存储如下:其中,S:符号位,1表示负,0表示正;E

36、:阶码(在两个字节中)偏移为127;M:23位尾数,最高位为“1”。,72,73,a)b)c),图4-6 变量储存方式 a)整型变量 b)长整型变量 c)浮点变量,4.3.4 C51数据的存储类型和存储模式,1存储类型在讨论KEIL C51的数据类型的时候,必须同时提及它的存储类型以及它与8051单片存储器结构的关系,因为KEIL C51是面向8051系列单片机及其硬件控制系统的开发工具。它定义的任何数据类型必须以一定的存储类型定位在8051的某一存储区中,否则便没有任何的实际意义。,74,由第2章,8051系列单片机在物理上有四个存储空间:片内程序存储器空间;片外程序存储器空间;片内数据存储

37、器空间;片外数据存储器空间。KEIL C51编译器完全支持8051单片机的硬件结构,可完全访问8051硬件系统的所有部分。该编译器通过将变量、常量定义成不同的存储类型(data,bdata,idata,pdata,xdata,code)的方法,将它们定位在不同的存储区中。,75,表4-3 C51存储器类型与8051存储器空间的关系,76,当使用存储类型data、bdata定义常量和变量时,C51编译器会将它们定位在片内数据存储区中(片内RAM),这个存储区根据8051单片机CPU的型号不同,其长度分别为64,128,256或512字节。这个存储区不很大,但它能快速存取各种数据。外部数据存储器从

38、物理上讲属于单片机的一个组成部分,但用这种存储器存放数据,在使用前必须将它们移到片内数据存储区中。片内数据存储区是存放临时性变量或使用频率较高的变量的理想场所。,77,当使用xdata存储类型定义常量、变量时,C51编译器会将其定位在外部数据存储空间(片外RAM)。该空间位于片外附加的8KB、16KB、32KB或64KB RAM芯片中(如一般常用的6264、62256等)。其最大可寻址范围为64KB。在使用外部数据区的信息之前,必须用指令将它们移动到内部数据区中;当数据处理完之后,将结果返回到片外数据存储区。片外数据存储区主要用于存放不常使用的变量,或收集等待处理的数据,或存放要被发往另一台计

39、算机的数据。,78,还有两种存储类型是pdata和idata。pdata属于xdata类型,它的高8位地址被妥善保存在P2口中,用于I/O操作。idata:可以间接寻址内部数据存储器(可以超过128字节)。访问片内数据存储器(data、bdata、idata)比访问片外数据存储器(xdata、pdata)相对要快一些,因此可将经常使用的变量置于片内数据存储器,而将规模较大、不常使用的数据置于片外数据存储器中。,79,当使用code存储类型定义数据时,C51编译器会将其定义在代码空间(ROM或EPROM或Flash或ISP Flash)。这里存放着指令代码和其他非易失信息。调试完成的程序代码被写

40、入8051单片机的片内ROM/EPROM或片外EPROM中。在程序执行过程中,不会有信息写入这个区域,因为程序代码是不能进行自我改变的。,80,表4-4 C51存储器类型及其大小和值域,81,变量的存储类型定义举例:,char data var1;/*jsu1*/bit bdata flags;/*jsu2*/float idata a,b,c;/*jsu3*/unsigned int pdata dimension;/*jsu4*/unsigned char xdata vector 1044;/*jsu5*/,82,2.存储模式,如果在变量定义时略去存储类型标志符,则编译器会自动选择默认的

41、存储类型。默认的存储类型进一步由SMALL、COMPACT和LARGE存储模式指令限制。例如,若声明char var1,则在使用SMALL存储模式下,var1被定位在data存储区中;在使用COMPACT存储模式下,var1被定位在idata存储区中;在使用LARGE存储模式下,var1被定位在xdata存储区中。存储模式决定了变量的默认存储类型、参数传递区和无明确存储类型说明变量的存储类型。,83,在固定的存储器地址上进行变量的传递,是C51的标准特征之一。在SMALL模式下,参数传递是在片内数据存储区中完成的。LARGE和COMPACT模式允许参数在外部存储器中传递。C51同时也支持混合模

42、式,例如,在LARGE模式下,生成的程序可将一些函数放入SMALL模式中,从而加快执行速度。存储模式的详细说明见表4-5。C51甚至允许在变量类型定义之前,指定存储类型。因此,定义data char x与char data x是等价的,但应尽量使用后一种方法。,84,表4-5 存储模式及说明,85,4.3.5 C51对8051特殊功能寄存(SFR)的定义,为了能直接访问8051单片机的特殊功能寄存器SFR,KEIL C51提供了一种自主形式的定义方法。这种定义方法与标准C语言不兼容,只适用于对8051系列单片机进行C编程。这种定义的方法是引入关键字“sfr”,语法如下:sfr sfr_name

43、 int constant;例 sfr P1=0 x90;/*P1口地址 90H*/sfr TMOD=0 x89;/*定时器/计数器方式控制寄存器地址 89H*/注意:sfr后面必须跟一个特殊寄存器名,“=”后面的地址必须是常数,不允许带有运算符的表达式,这个常数值的范围必须在特殊功能寄存器地址范围内,位于0 x800 xFF之间。,86,对SFR的16位数据的访问:,对SFR的16位数据的访问:在新的8051系列产品中,SFR在功能上经常组合为16位值。当SFR的高端地址直接位于其低端地址之后时,对SFR 16位值可以进行直接访问。例如8052的定时器2就是这种情况。为了有效地访问这类SFR

44、,可使用关键字“sfr16”。16位SFR定义的语法与8位SFR相同,16位SFR的低端地址必须作为“sfr16”的定义地址。,87,例 sfr16 T2=0 xCC;/*定时器2:T2低8位地址=0CCH T2高8位地址=0CDH*/定义中名字后面不是赋值语句,而是一个SFR地址,高字节必须位于低字节之后。这种定义适用于所有新的SFR,但不能用于定时器/计数器0和1。,88,访问8051 SFR的位,在典型的8051应用问题中,经常需要单独访问SFR中的位,C51的扩充功能使之成为可能。特殊位(sbit)的定义,像SFR一样不与标准C兼容,使用关键字“sbit”可以访问位寻址对象。与SFR定

45、义一样,用关键字“sbit”定义某些特殊位,并接受任何符号名,“=”号后将绝对地址赋给变量名。这种地址分配有三种方法。,89,第一种方法:sfr_name“”int_constant 当特殊寄存器的地址为字节(8位)时,可使用这种方法。sfr_name必须是已定义的SFR的名字。“”后的常数定义了基地址上的特殊位的位置。该值必须是07的数。如:sfr PSW=0 x0D0;/*定义PSW寄存器地址为0 xD0*/sbit OV=PSW2;/*定义OV位为PSW.2,位地址为 0 xD2*/sbit CY=PSW7;/*定义CY位为PSW.7,位地址为0 xD7*/,90,第二种方法:int_c

46、onstant“”int_constant 这种方法以一个整常数作为基地址。该值必须在0 x800 xFF之间,并能被8整除,确定位置的方法同上。例如:sbit OV=0 xD02;/*OV位地址为0 xD2*/sbit CY=0 xD07;/*CY位地址为0 xD7*/,91,第三种方法:int constant;这种方法将位的绝对地址赋给变量,地址必须位于0 x800 xFF之间。例如:sbit OV0 xD2;sbit CY0 xD7;特殊功能位代表了一个独立的定义类,不能与其他位定义和位域互换。,92,4.3.6 C51对8051并行接口的定义,对于8051片内I/O口用关键字sfr来

47、定义。例 sfr P0=0 x80;/*定义P0口,地址80H*/sfr P1=0 x90;/*定义P1口,地址90H*/,93,对于片外扩展I/O口,则根据其硬件译码地址,将其视为片外数据存储器的一个单元,使用#define语句进行定义:例#include/*将PORTA定义为外部I/O口,地址为0 x0FFC0,长度为8位*/#define PORTA XBYTE 0 x0FFC0 PORTA=0 x01;/*向外部I/O口输出数据*/一旦在头文件或程序中对这些片内外I/O口进行定义以后,在程序中就可以自由使用这些口了。,94,实例:sfr P1=0 x90;/*P1的SFR定义*/sfr

48、 P3=0 xb0;/*P3的SFR定义*/sbit DIPswitch=P14;/*P1口位4的DIP开关输入*/sbit greenLED=P15;/*P1口位5的绿LED输出*/void main(void)unsigned char inval;inval=0;/*inval的初始化值*/while(1),95,if(DIPswitch=1)/检查P1.4输出是否为高 inval=P1/*置P1.5输出为高*/P3=(P3&0 xF0)|inval;/*值输出到P3.0P3.3*/,96,4.3.7 中断服务函数与寄存器组定义,定义中断服务函数的一般形式为:函数类型函数名(形式参数表)

49、interrupt nusing n关键字interrupt后面的n是中断号,n的取值范围为031,编译器从8n+3处产生中断向量,具体的中断号n和中断向量取决于不同的8051系列单片机芯片。8051单片机的常用中断源和中断向量见表6-1。,97,关键字using,专门用来选择8051单片机中不同的工作寄存器组。using后面的n是一个03的常整数,分别选中4个不同的工作寄存器组。在定义一个函数时using是一个选项,如果不用该选项,则由编译器选择一个寄存器组作绝对寄存器组访问。需要注意的是,关键字using和interrupt的后面都不允许跟带运算符的表达式。,98,关键字using对函数目

50、标代码的影响如下:在函数的入口处将当前工作寄存器组保护到堆栈中;指定的工作寄存器内容不会改变。函数返回之前将被保护的工作寄存器组从堆栈中恢复。使用关键字using在函数中确定一个工作寄存器组时必须十分小心,要保证任何寄存器组的切换都只在仔细控制的区域内发生,如果不做到这一点将产生不正确的函数结果。另外还要注意,带using属性的函数原则上不能返回bit类型的值。并且关键字using不允许用于外部函数。,99,关键字interrupt也不允许用于外部函数,它对中断函数目标代码的影响如下:在进入中断函数时,特殊功能寄存器ACC,B,DPH,DPL,PSW将被保存入栈;如果不使用寄存组切换,则将中断

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 在线阅读 > 生活休闲


备案号:宁ICP备20000045号-1

经营许可证:宁B2-20210002

宁公网安备 64010402000986号