C51程序设计基础C是一种源于UNIX操作系统的语言,它是一种结构化语言,可以产生紧凑代码。C可以进行许多机器级函数控制而不用汇编语言。与汇编相比,有如下优点:(1)对单片机的指令系统不要求了解,仅要求对8051的存储器结构有初步了解;(2)寄存器分配、不同存储器的寻址以及数据类型等细节可由编译器管理;(3)程序有规范的结构,可分为不同的函数,这种方式可使程序结构化;C51程序设计基础C51程序设计基础(4)关键字及运算函数可用近似人的思维过程方式使用;(5)编程及程序调试时间显著缩短,从而提高效率;(6)提供的库包含许多标准子程序,具有较强的数据处理能力;(7)已编号的程序可容易地植入新程序中,因为它具有方便的模块化编程技术。C语言作为一种非常方便的语言而得到广泛的支持,C语言程序本身并不依赖于机器硬件系统,基本上不作修改就可根据单片机的不同较快地移植过来。C51程序设计基础用C语言编写MCS–51单片机的应用程序,虽然不像用汇编语言那样具体地组织、分配存储器资源和处理端口数据,但在C语言编程中,对数据类型与变量的定义,必须要与单片机的存储结构相关联,否则编译器不能正确地映射定位。用C语言编写单片机应用程序与编写标准的C语言程序的不同之处就在于根据单片机存储结构及内部资源定义相应的C语言中的数据类型和变量,其它的语法规定、程序结构及程序设计方法都与标准的C语言程序设计相同。C51程序设计基础一、C51的程序结构与一般C语言的结构相同,以main()函数为程序人口,程序体中包含若干语句还可以包含若干函数。常用的数据类型有:位型字符型整型长整型浮点型bitcharintlongintfloat1位1字节2字节4字节4字节数组型指针型二、C51的数据类型C51程序设计基础三、C51数据的存储类型存储类型与存储空间的对应关系databdataidatapdataxdatacode直接寻址片内RAM区,访问速度快(128byte)可位寻址片内RAM区,运行位和字节混合访问(16byte)间接寻址片内RAM区,可访问片内全部RAM(256byte)分页寻址片外RAM区(256byte),由MOVX@R0访问片外RAM区(64Kbyte),由MOVX@DPTR访问程序存储器ROM区,由MOVC@DPTR访问C51程序设计基础变量的存储类型定义举例:charvar;bitbdataflag;floatidatax,y;unsignedintpdatadim;unsignedcharxdatavector[10][10];#defineuintunsignedint#defineucharunsignedchar(1)var被定义在片内RAM区,地址00H~0FFH。(2)flag被定义在片内RAM的可位寻址区,地址20H~2FH。(3)x,y被定义在片内RAM区,只能用间接寻址方式。(4)dim被定义的片外RAM区,并用MOVX@Ri访问。(5)vector被定义在片外RAM区,并用MOVX@DPTR访问。C51程序设计基础如果在定义变量时略去存储类型标志符,编译器会自动选择默认的存储类型。默认的存储类型进一步由SMALL、COMPACT、LARGE存储模式指令限制。例如:若声明charvar;在SMALL存储模式下,var变量被定位在DATA存储区;在COMPACT存储模式下,var变量被定位在PDATA存储区;在LARGE存储模式下,var变量被定位在XDATA存储区。存储模式:存储模式决定了变量的默认存储类型,参数传递区和无明确存储类型的说明。四、C51数据的存储模式C51程序设计基础存储模式说明SMALL参数及局部变量放入可直接寻址的片内RAM区(最大128字节,默认存储类型是DATA),因此访问十分方便。参数及局部变量放入分页片外RAM区(最大256字节,默认存储类型是PDATA),通过寄存器R0和R1间接寻址。LARGECOMPACT参数及局部变量放入片外RAM区(最大64K字节,默认存储类型是XDATA),使用数据指针DPTR来间接寻址。用DPTR进行访问效率较低。C51程序设计基础通常有:reg51.h或regx51.hmath.habsacc.hstdio.hstdlib.h五、C51包含的头文件其中:reg51.h(定义特殊功能寄存器和位寄存器)math.h(定义常用数学运算)absacc.h(定义存储类型及地址)stdio.h(定义标准输入输出函数)stdlib.h(定义动态内存分配函数)注:这些头文件存放的路径是:“C:\C51\INC”。C51程序设计基础C51程序设计基础C51程序设计基础C51程序设计基础C51程序设计基础C51程序设计基础与C语言基本相同:+-*/(加减乘除)==(大于大于等于小于小于等于)==!=(测试等于测试不等于)&&||!(逻辑与逻辑或逻辑非)(位右移位左移)&|(按位与按位或)^~(按位异或按位取反)六、C51的运算符C51程序设计基础与标准C语言基本相同:if选择语言switch/case多分支选择语言while循环语言do-while循环语言for循环语言七、C51的基本语句C51程序设计基础为了能直接访问特殊功能寄存器SFR,C51提供了一种自主形式的定义方法,这种定义方法与标准C语言不兼容,只适用于对8051系列单片机进行C编程。八、C51对特殊功能寄存器的定义这种定义的方法是引入关键字“sfr”,语法如下:sfrsfr_name‘=’intconstant;例如:sfrSCON=0x98;sfrTMOD=0x89;C51程序设计基础对于要经常单独访问SFR中的位,C51使用关键字“sbit”可以访问位寻址对象。有以下几种方法:方法一:例如:sfrPSW=0xD0;sbitOV=PSW^2;方法二:例如:sbitOV=0xD0^2;方法三:例如:sbitOV=0xD2;C51程序设计基础8051单片机没有专用I/O指令,其口地址与数据存储器地址是统一编址的,即把一个口当作数据存储器中的一个单元来看待。九、C51对并行接口的定义对于8051片内I/O口用关键字“sfr”来定义。例如:sfrP0=0x80;sfrP1=0x90;C51程序设计基础对于片外扩展I/O口,则根据其硬件译码地址,将其视为片外数据存储器的一个单元,使用#define语句进行定义。一旦在头文件或程序中对这些片内外I/O口进行定义后,在程序中就可以自由使用这些口了。例如:#includeabsacc.h#defineP_DATAXBYTE[0x5eff]#defineP_CONXBYTE[0x5fff]XBYTE被定义为(char*)0x20000L,0x20000L为一般指针,其存储类型为2,基地址为0000H,这样XBYTE成为指向xdata零地址的指针。而XBYTE[0x5eff]则是外部数据存储器的0x5eff绝对地址。C51程序设计基础【例1】清零程序(将2000H—20FFH的内容清零)十、C51程序设计举例★汇编语言程序ORG0000HSE01:MOVR0,#00HMOVDPTR,#2000H;(0000H)送DPTRLOO1:CLRAMOVX@DPTR,A;0送(DPTR)INCDPTR;DPTR+1INCR0;字节数加1CJNER0,#00H,LOO1;不到FF个字节再清LOOP:SJMPLOOPC51程序设计基础★C-51程序#includereg51.h#defineucharunsignedcharvoidmain(){inti;ucharxdata*p=0x2000;/*指针指向2000H单元*/for(i=0;i256;i++)/*清零2000H-20FFH单元*/{*p=0;p++;}}C51程序设计基础★汇编语言程序ORG0000HL00:MOVR0,#10H;查找16个字节MOVR1,#00HMOVDPTR,#2000HL11:MOVXA,@DPTRCJNEA,#00H,L16;取出内容与00H相等吗?INCR1;取出个数加1L16:INCDPTRDJNZR0,L11;未完继续MOVDPTR,#2100HMOVA,R1MOVX@DPTR,A;相同数个数送2100HL1E:SJMPL1E【例2】查找零的个数(在2000H--200FH中查出有几个字节是零,把个数放在2100H单元中)C51程序设计基础★查找零的个数C-51程序#includereg51.h#defineucharunsignedcharvoidmain(){ucharxdata*p=0x2000;/*指针p指向2000H单元*/intnum=0,i;for(i=0;i16;i++){if(*p==0)num++;/*若该单元内容为零,则n+1*/p++;/*指针指向下一单元*/}p=0x2100;/*指针p指向2100H单元*/*p=n;/*把个数放在2100H单元中*/}C51程序设计基础★汇编程序ORG0000HMOVA,R3MOVB,R7MULAB;R3*R7XCHA,R7;R7=(R3*R7)低字节MOVR5,B;R5=(R3*R7)高字节MOVB,R2MULAB;R2*R7ADDA,R5MOVR4,ACLRAADDCA,BMOVR5,A;R5=(R2*R7)高字节MOVA,R6MOVB,R3MULAB;R3*R6ADDA,R4XCHA,BADDCA,R5MOVR5,AMOVPSW.5,C;存CYMOVA,R2MULAB;R2*R6ADDA,R5MOVR5,ACLRAMOVACC.0,CMOVC,PSW.5;加上次加法的位ADDCA,BMOVR4,AJMP$【例3】双字节无符号整数快速乘法C51程序设计基础★C-51程序#includereg51.h#defineuintunsignedint#defineulongunsignedlongvoidmain(){uintxdata*p1=0x2000;/*双字节被乘数在2000H单元*/uintxdata*p2=0x2002;/*双字节乘数在2002H单元*/ulongxdata*p3=0x2010;/*4字节乘积放在2010H单元*/*p3=(*p1)*(*p2);}C51程序设计基础十一、8051内部资源的C51编程1、中断C51编译器支持在C源程序中直接开发中断程序,因此减轻了用汇编语言开发中断程序的繁琐过程。使用该扩展属性的函数定义语法如下:返回值函数名interruptn[usingm]{……}(其中,n对应中断源的编号,m对应工作寄存器组编号)C51程序设计基础编号中断源入口地址0外部中断00003H1定时器/计数器0000BH2外部中断10013H3定时器/计数器1001BH4串行口中断0023H表1MCS-51中断源编号C51程序设计基础usingm选项用于实现工作寄存器组的切换,m是中断服务子程序中选用的工作寄存器组号(0~3)。在许多情况下,响应中断时需保护有关现场信息,以便中断返回后,能使中断前的源程序从断点处继续正确地执行下去。这在MCS-51单片机中,能很方便地利用工作寄存器组的切换来实现。即在进入中断服务程序前的程序中使用一组工作寄存器,进入中断服务程序后,由usingm切换到另一组寄存器,中断返回后又恢复到原寄存器组。这样互相切换的两组寄存器中的内容彼此都没有被破坏。C51程序设计基础图1扩展多个中断源【例4】下图所示是利用优先权解码芯片,在单片机8031的一个外部中断INT1上扩展多个中断源的原理电路图。图中是以开关闭合来模拟中断请求信号。当有任一中断源产生中断请求,能给8031的INT1引脚送一个有效中断信号,由P1的低3位可得对应中断源的中断号。C51程序设计基础#includereg51.h#defineucharunsignedcharucharstatus;bitflag=0;voidservice_int1()interrupt2using2/*INT1