2020/2/251第10章80C51的C语言程序设计单片机C语言概述10.1C51的数据类型与运算10.2C51流程控制语句10.3C51的指针类型10.4C51的函数10.5C51编程实例10.62020/2/25210.1单片机C语言概述10.1.1C51程序开发过程编译器能自动完成变量的存储单元的分配对常用功能模块和算法编制相应的函数,方便移植采用C51的优点C语言具有良好的可读性、可移植性和基本的硬件操作能力。C51程序开发过程编写源程序建立工程,加入源程序编译生产目标程序仿真调试、写存储器2020/2/253C51源程序C51编译器列表文件浮动目标码模块连接器用户库系统库映像文件绝对定位目标码文件硬件仿真器编程器2020/2/25410.1.2C51程序结构#includereg52.h#includestdio.hvoiddelayms(unsigned);voidmain(void){unsignedchari;P1=0x01;do{for(i=0;i=7;i++){delayms(5000);P1=P11;if(P1==0x0){P1=0x01;}}}while(1);}voiddelayms(unsignedx){unsignedcharj;while(x--){for(j=0;j123;j++){;}}}2020/2/25510.2.1C51的数据类型10.2C51的数据类型与运算数据类型决定其取值范围、占用存储器的大小及可参与哪种运算。数据类型长度(位)取值范围字符型signedchar8-128~127unsignedchar80~255整型signedint16-32768~32767unsignedint160~65535长整型signedlong32-21474883648~21474883647unsignedlong320~4294967295浮点型float32±1.75494E-38~±3.402823E+38位型bit10,1sbit10,1访问SFRsfr80~255sfr16160~655352020/2/256尽可能采用无符号格式bit用于定义位变量的名字,编译器会对其分配地址(RAM的20H~2FH区域)sbit用于定义位变量的名字和地址,地址是确定的且不用编译器分配(SFR及RAM的20H~2FH区域)C51编译器在编译时会自动进行类型转换几点说明:2020/2/25710.2.2C51数据的存储类型C51的存储器类型存储器类型长度(位)对应单片机存储器bdata1片内RAM位寻址区,共128位。(亦能字节访问)data8直接寻址,共128字节。idata8间接寻址,共256字节。pdata8片外RAM分页间址,共256字节。(MOVX@Ri)xdata16间接寻址,共64k字节。(MOVX@DPTR)code16ROM间接寻址,共64k字节。(MOVCA,@A+DPTR)2020/2/258经常使用的变量应该置于片内RAM中,要用bdata、data、idata来定义。不经常使用的变量或规模较大的变量应该置于片外RAM中,要用pdata、xdata来定义。默认存储器类型由编译控制命令的存储模式指令限制。存储模式默认存储类型特点SMALLdata小模式。变量默认在片内RAM。空间小,速度块。COMPACTpdata紧凑模式。变量默认在片外RAM的页(256字节,页号由P2口决定)。LARGExdata大模式。变量默认在片外RAM的64KB范围。空间大,速度慢。2020/2/25910.2.380C51硬件结构的C51定义特殊功能寄存器的声明sfr特殊功能寄存器名=地址常数;格式:例如:sfrSCON=0x98;sfrP0=0x80;2020/2/2510特殊功能寄存器中特定位的声明sbit位变量名=特殊功能寄存器名^位的位置(0~7)例如:sfrPSW=0xD0;sbitOV=PSW^2;sbit位变量名=字节地址^位的位置(0~7)例如:sbitOV=0xD0^2;sbitCY=0xD0^7;sbit位变量名=位地址例如:sbitOV=0xD2;sbitCY=0xD7;2020/2/2511内部RAM中可位寻址对象的定义先定义变量的数据类型和存储类型例如:intbdataibase;charbdataarray[4];再利用sbit进行声明例如:sbitmybit0=ibase^0;sbitmybit15=ibase^15;sbitary07=array[0]^7;sbitary37=array[3]^7;访问示例:ibase=-1;array[2]=‘a’;array[2]=02020/2/2512算术运算符和算术表达式10.2.4C51的运算符和表达式基本算术运算符例如:+加法运算符;-减法(取负)运算符;*乘法运算符;/除法运算符;%取余数运算符。示例:25.0/20.0=1.2525/20=125%20=5取负运算优先级最高。2020/2/2513自增、自减运算符(仅能用于变量)例如:++自增运算符;--自减运算符;类型转换运算符自动转换,顺序:bit→char→int→long→float强制类型转换,如:(double)a2020/2/2514关系运算符和关系表达式关系运算符小于;=小于等于;大于;=大于等于;==等于;!=不等于。关系表达式关系表达式的值为逻辑值:真(1)和假(0)2020/2/2515逻辑运算符和逻辑表达式逻辑运算符&&逻辑与||逻辑或!逻辑非逻辑表达式逻辑表达式的值为逻辑值:真(1)和假(0)例:5||0结果为1,2&&0结果为0。2020/2/2516位运算符&按位与|按位或^按位异或~按位取反左移右移例:P1=P11表示对P1口的所有位左移1位2020/2/2517赋值和复合赋值运算符复合赋值运算符+=加法赋值;-=减法赋值;*=乘法赋值;/=除法赋值;%=取模赋值;符号“=”称为赋值运算符=左移位赋值;=右移位赋值;&=逻辑与赋值;|=逻辑或赋值;^=逻辑异或赋值;~=逻辑非赋值;例:a*=5相当于a=a*5;b&=0x80相当于b=b&0x80。2020/2/251810.3C51流程控制语句10.3.1C51选择语句条件语句if(条件表达式)语句例如:if(p1!=0){c=20;}if(条件表达式)语句1else语句2例如:if(p1!=0){c=20;}else{c=0;}2020/2/2519if(条件表达式1)语句1elseif(条件表达式2)语句2elseif(条件表达式3)语句3……elseif(条件表达式n)语句nelse语句n+12020/2/2520开关语句switch(表达式){case常量表达式1:语句1;break;case常量表达式2:语句2;break;……case常量表达式n:语句n;break;default:语句n+1;}2020/2/252110.3.2C51循环语句while语句一般形式为:while(条件表达式)语句;如果条件表达式的结果一开始就为假,则后面的语句一次也不能执行。Do-while语句一般形式为:do语句while(条件表达式);任何条件下,循环体语句至少会被执行一次。2020/2/2522for语句一般形式为:for([初值表达式];[条件表达式];[更新表达式])语句if语句与goto语句结合当型循环形式为:loop:if(表达式){语句gotoloop;}2020/2/2523直到型循环形式为:loop:{语句if(表达式)gotoloop;}continue是一种循环中断语句,它并不跳出循环体;break语句只能跳出它所处的那一层循环;goto语句可以用于跳出多重循环(从内层到外层)。注意:2020/2/252410.4C51的指针类型有一个变量a,利用&a表示变量a的地址。则语句p=&a;把a的地址赋给了指针变量p,则“p指向了变量a”。*P表示变量a的内容指针变量的定义chardata*p/*定义指针变量*/p=30H/*为指针变量赋值,30H为片内RAM地址*/x=*p/*30H单元的内容送给变量x*/2020/2/2525定义时未指定它所指向的对象的存储器类型10.4.1一般指针一般指针占3个字节第一字节存放该指针的默认存储器类型编码(见表)第二字节存放该指针的高位地址偏移量第三字节存放该指针的低位地址偏移量存储器类型编码存储器类型bdata/data/idataxdatapdatacode编码0x000x010xfe0xff2020/2/2526一般指针定义示例:char*xdatastrptr;/*指针本身存于xdata空间,它指向char型数据*/int*datanumber;/*指针本身存于data空间,它指向int型数据*/由于指向对象的存储空间在编译时无法确定(运行时确定),因此必须生成一般代码以保证对任意空间的对象进行存取。所以一般指针所产生的代码速度较慢。2020/2/252710.4.2基于存储器的指针定义时就指定它所指向的对象的存储器类型指针占1个字节(idata*,data*,pdata*)或2个字节(code*,xdata*)基于存储器指针定义示例:chardata*str;/*指针指向的char型数据存于data空间*/intxdata*num;/*指针指向的int型数据存于xdata空间*/基于存储器的指针长度比一般指针短,可以节省存储器空间,运行速度快,但它所指对象具有确定的存储器空间,兼容性不好。2020/2/252810.5C51的函数10.5.1C51函数的定义一般形式:返回值类型函数名(形式参数列表)[编译模式][reentrant][interruptn][usingn]{函数体}编译模式为SMALL、COPACT或LARGEreentrant用于定义可重入函数interruptn用于定义中断函数,n为中断号,可以为0~31usingn确定工作寄存器组,取值为0~32020/2/252910.5.2C51函数的调用与参数传递主调函数要向被调函数传递所需的参数传递给被调函数的数据称为实际参数,即实参实参向形参的传递是单向的参数传递可以采用寄存器、固定存储器位置方式参数传递寄存器参数传递传递的参数char、1字节指针int、2字节指针long、float一般指针参数1R7R6、R7R4~R7R1、R2、R3参数2R5R4、R5R4~R7R1、R2、R3参数3R3R2、R3R1、R2、R32020/2/2530SMALL模式下,在内部RAM中完成COMPACT模式下,在外部RAM中完成LARGER模式下,在外部RAM中完成固定存储器位置参数传递80C51单片机不采用堆栈传递参数。但C51提供一种模拟堆栈,从而支持可重入函数的递归调用。10.5.3C51的库函数常用的C51库函数参见附录B.22020/2/253110.6C51编程实例10.6.180C51内部资源的编程中断服务函数示例中断函数的定义形式void函数名(void)interruptn[usingm]{函数体}中断源外中断0定时器0外中断1定时器1串行口中断号012342020/2/2532【例10-1】单片机应用系统中,外中断0引脚接一个开关,并行口线P1.0接一个发光二级管。要求:开关闭合一次,发光二极管的状态改变一次。试编写程序#include“reg51.h”#include“intrins.h”sbitP10=P1^0;voiddelay(void){inta=5000;while(a--)_nop_();}voidint_srv(void)interrupt0{delay();if(INT0==0){P10=!P10;while(INT0==0);}}voidmain(){P10=0;EA=1;EX0=1;while(1);}2020/2/2533定时计数器编程示例【例10-2】利用定时/计数