2020/1/191第10章80C51的C语言程序设计单片机C语言概述10.1C51的数据类型与运算10.2C51流程控制语句10.3C51的指针类型10.4C51的函数10.5C51编程实例10.62020/1/19210.1单片机C语言概述10.1.1C51程序开发过程编译器能自动完成变量的存储单元的分配对常用功能模块和算法编制相应的函数,方便移植采用C51的优点C语言具有良好的可读性、可移植性和基本的硬件操作能力。C51程序开发过程编写源程序建立工程,加入源程序编译产生目标程序仿真调试、写存储器10.1.2C51程序结构C51程序由一个或多个函数组成,至少包含一个主函数main;若被调用函数在main()前,可直接调用,否则需说明,再调用;2020/1/19310.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~65535等同double等同short•bit:位变量的名字,编译器分配地址(RAM的20H~2FH区)•sbit定义位变量的名字和地址•(SFR及RAM的20H~2FH区)2020/1/19410.2.2C51数据的存储类型C51的存储器类型存储器类型长度(位)对应单片机存储器bdata1片内RAM位寻址区,共128位。(亦能字节访问)data8直接寻址,共128字节。idata8间接寻址,共256字节(包括SFR)。pdata8片外RAM分页间址,共256字节。(MOVX@Ri,A)xdata16间接寻址,共64k字节。(MOVX@DPTR,A)code16ROM间接寻址,共64k字节。(MOVCA,@A+DPTR)经常使用的变量应置于片内RAM中,用bdata、data、idata定义不经常使用或规模较大的变量应置于片外RAM中,用pdata、xdata定义2020/1/195默认存储器类型由编译控制命令的存储模式指令限制存储模式默认存储类型特点SMALLdata小模式。变量在片内RAM。空间小,速度块COMPACTpdata紧凑模式。变量在片外RAM的页LARGExdata大模式。变量在片外RAM的64KB范围。空间大,速度慢在µVision中,在projectOptionforTarget1TargetMemoryModel中指定sfr特殊功能寄存器名=地址常数sfrSCON=0x98;2020/1/196特殊功能寄存器中特定位的声明sbit位变量名=特殊功能寄存器名^位的位置(0~7)sfrPSW=0xD0;sbitOV=PSW^2;sbit位变量名=字节地址^位的位置(0~7)sbitOV=0xD0^2;sbit位变量名=位地址sbitOV=0xD2;注:SFR及其位在头文件reg51.h或reg52.h中有定义,故程序中加reg51.h等,可省10.2.380C51硬件结构的C51定义特殊功能寄存器的声明书上为0x90,错2020/1/197内部RAM中可位寻址对象的定义先定义变量的数据类型和存储类型例如:intbdataibase;charbdataarray[4];再利用sbit进行声明例如:sbitmybit0=ibase^0;sbitmybit15=ibase^15;sbitary07=array[0]^7;访问示例:ibase=-1;array[2]=‘a’;2020/1/198算术运算符和算术表达式10.2.4C51的运算符和表达式基本算术运算符例如:+加法运算符;-减法(取负)运算符;*乘法运算符;/除法运算符;%取余数运算符。示例:25.0/20.0=1.2525/20=125%20=5取负运算优先级最高。2020/1/199自增、自减运算符(仅能用于变量)例如:++自增运算符;--自减运算符;类型转换运算符自动转换,顺序:bit→char→int→long→float强制类型转换,如:(double)a2020/1/1910关系运算符和关系表达式关系运算符小于;=小于等于;大于;=大于等于;==等于;!=不等于。关系表达式关系表达式的值为逻辑值:真(1)和假(0)2020/1/1911逻辑运算符和逻辑表达式逻辑运算符&&逻辑与;||逻辑或;!逻辑非。逻辑表达式逻辑表达式的值为逻辑值:真(1)和假(0)例:5||0结果为1,2&&0结果为02020/1/1912位运算符&按位与;|按位或;^按位异或;~按位取反;左移;右移。例:P1=P11表示对P1口的所有位左移1位2020/1/1913赋值和复合赋值运算符复合赋值运算符+=加法赋值;-=减法赋值;*=乘法赋值;/=除法赋值;%=取模赋值;符号“=”称为赋值运算符=左移位赋值;=右移位赋值;&=逻辑与赋值;|=逻辑或赋值;^=逻辑异或赋值;~=逻辑非赋值例:a*=5相当于a=a*5;b&=0x80相当于b=b&0x80。2020/1/191410.3C51流程控制语句10.3.1C51选择语句条件语句if(条件表达式)语句例如:if(p1!=0){c=20;}if(条件表达式)语句1else语句2例如:if(p1!=0){c=20;}else{c=0;}2020/1/1915if(条件表达式1)语句1elseif(条件表达式2)语句2elseif(条件表达式3)语句3……elseif(条件表达式n)语句nelse语句n+12020/1/1916开关语句switch(表达式){case常量表达式1:语句1;break;case常量表达式2:语句2;break;……case常量表达式n:语句n;break;default:语句n+1;}2020/1/191710.3.2C51循环语句while语句一般形式为:while(条件表达式)语句;如果条件表达式的结果一开始就为假,则后面的语句一次也不能执行。do-while语句一般形式为:do语句while(条件表达式);任何条件下,循环体语句至少会被执行一次。2020/1/1918for语句一般形式为:for([初值表达式];[条件表达式];[更新表达式])语句if语句与goto语句结合当型循环形式为:loop:if(表达式){语句gotoloop;}2020/1/1919直到型循环形式为:loop:{语句if(表达式)gotoloop;}continue是一种循环中断语句,它并不跳出循环体;break语句只能跳出它所处的那一层循环;goto语句可以用于跳出多重循环(从内层到外层)。注意:2020/1/192010.4C51的指针类型p=&a;/*将变量a的地址送变量p*/指针变量的定义chardata*p/*定义指针变量*/p=30H/*为指针变量赋值,30H为片内RAM地址*/x=*p/*30H单元的内容送给变量x*/定义时未指定它所指向的对象的存储器类型10.4.1一般指针一般指针占3个字节第一字节存放该指针的默认存储器类型编码第二字节存放该指针的高位地址偏移量第三字节存放该指针的低位地址偏移量2020/1/1921一般指针定义示例:int*datanumber;/*指针本身存于data空间,它指向int型数据*/由于指向对象的存储空间在编译时无法确定(运行时确定),因此必须生成一般代码以保证对任意空间的对象进行存取。所以一般指针所产生的代码速度较慢。存储器类型编码存储器类型bdata/data/idataxdatapdatacode编码0x000x010xfe0xff2020/1/192210.4.2基于存储器的指针定义时就指定它所指向的对象的存储器类型指针占1个字节(idata*,data*,pdata*)或2个字节(code*,xdata*)基于存储器指针定义示例:intxdata*num;/*指针指向的int型数据存于xdata空间*/基于存储器的指针长度比一般指针短,可以节省存储器空间,运行速度快,但它所指对象具有确定的存储器空间,兼容性不好。2020/1/192310.5C51的函数10.5.1C51函数的定义一般形式:返回值类型函数名(形式参数列表)[编译模式][reentrant][interruptn][usingn]{函数体}编译模式为SMALL、COMPACT或LARGEreentrant用于定义可重入函数interruptn用于定义中断函数,n为中断号,可以为0~31usingn确定工作寄存器组,取值为0~3书上错可以被中断。若使用全局变量,则应通过关中断等手段对其加以保护2020/1/192410.5.2C51函数的调用与参数传递参数传递可以采用寄存器、固定存储器位置方式参数传递寄存器参数传递传递的参数char、1字节指针int、2字节指针long、float一般指针参数1R7R6、R7R4~R7R1、R2、R3参数2R5R4、R5R4~R7R1、R2、R3参数3R3R2、R3R1、R2、R3用#pragmaregparms/noregparms编译命令控制SMALL模式下,在内部RAM中完成COMPACT模式下,在外部RAM中完成LARGER模式下,在外部RAM中完成固定存储器位置参数传递2020/1/192510.5.3C51的库函数stdio.h---输入和输出math.h---数学计算ctype.h---字符转换和分类string.h---字符串处理stdlib.h---类型转换及存储器分配intins.h---本征函数(含移位等函数)reg51.h---51的特殊寄存器reg52.h---52的特殊寄存器常用的C51库函数参见附录B.22020/1/192610.6C51编程实例10.6.180C51内部资源的编程中断服务函数示例中断函数的定义形式void函数名(void)interruptn[usingm]{函数体}中断源外中断0定时器0外中断1定时器1串行口中断号012342020/1/1927【例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/1/1928定时计数器编程示例【例10-2】利用定时/计数器T0的方式1,产生10ms的定时,并使P1.0引脚上输出周期为20ms的方波,采用中断方式,设系统时钟频率为12MHz。1、计算计数初值X:N=t/Tcy=10×10-3/1×10-6=10000计数器初值应为-10000。即应将-(10000/256)送入TH0中,-(10000%256)送入TL0中。2、求T0的方式控制字TMOD:M1M0=01,GATE=0,C/T=0,可取方式控制字为01H3、程序清单(见下页)2020/1/1929#includereg51.hsbitP10=P1^0;voidtimer0(void)interrupt1{P10=!P10;TH0=-(10000/256);TL0=-(10000%256);}voidmai