已阅读5页,还剩40页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1,4.7函数,C语言程序由函数组成,下面介绍函数的要点。4.7.1函数的分类及定义从用户使用角度划分,函数分为库函数和用户定义函数库函数是编译系统为用户设计的一系列标准函数(见本书附录二),用户只需调用,而无需自己去编写这些复杂的函数。如前面所用到的头文件reg51.h等,有的头文件中包括一系列函数,要使用其中的函数必须先使用#包含语句,然后才能调用。用户自定义函数是用户根据任务编写的函数。从参数形式上函数分为无参函数和有参函数。无参函数:函数中无参数定义。有参函数:函数中定义形式参数,在调用时,调用函数用实际参数代替形式参数,调用完返回结果给调用函数。,2,4.7.2函数的定义无参函数的定义:返回值类型函数名()函数体语句如果函数没有返回值,可以将返回值类型设为void函数以“”开始,以“”结束,有参函数的定义:返回值类型函数名(形式参数表列)形式参数类型说明/形式参数类型说明可放在形式参数表列函数体语句return(返回形参名),3,也可以这样定义,返回值类型函数名(类型说明形式参数表列)函数体语句return(返回形参名)其中形式参数表列的各项要用,隔开,通过return语句将需返回的值返回给调用函数。4.7.3.函数的调用函数调用的形式为:函数名(实际参数表列);对于无参函数当然不存在实际参数表列实参和形参的数目相等类型一致。,4,函数的调用方式有三种函数调用语句:即把被调函数名作为调用函数(无返回值)的一个语句,如fun1();被调函数作为表达式的运算对象(有返回值)如rett=2*get(a,b);此时拿函数中的a,b应为实参,其以返回值参予式中的运算。被调函数作为另一个数的实际参数(函数调用嵌套)如m=max(a,get(a,b);函数get(a,b)作为max()的一个实际参数被调用。,5,4.7.4对被调函数的说明,如果被调函数出现在主调函数之后,在主调函数前应对被调函数作以说明,形式为:返回值类型被调函数名(形参表列);例如:intfun1(a,b);/*函数说明*/main()/*主函数*/intd,u=3,v=2;d=2*fun1(u,v);/调用函数fun1(u,v)intfun1(a,b)/定义函数inta,b;intc;c=a+b;return(c);上例中被调函数在后、在主调函数前对被调函数进行明,6,被调函数出现在主调函数之前,可以不对被调函数说明。下面以一个简单例子来说明。intfun1(a,b)/定义在前inta,b;intc;c=a+b;return(c);main()intd,u=3,v=2;d=2*fun1(u,v);/调用在后此例中被调函数在主调函数前,不用说明,7,4.8单片机的C语言编程实例由于C51编译器是针对单片机的,因此ANSIC中的scanf(串口接受)和printf(串口发送)等对PC机的输入输出语句无效,运算的数据可以通过变量置入或取出,这时C51会自动安排使用的存贮单元。也可以用户自行通过具体的内存地址置入数据或从特定地址取出数据。C语言的上机调试和汇编程序使用同一仿真调试软件(例如伟福集成环境)。下面是一个C语言程序编译后生成的机器代码及对应的反汇编程序。,8,4.8.1、C语言程序的反汇编程序(源代码)【例4-5】例3-1曾用汇编语言完成了外部RAM的000EH单元和000FH单元的内容交换,现改用C语言编程。C语言对地址的指示方法可以采用指针变量,也可以引用absacc.h头文件作绝对地址访问,下面采用绝对地址访问方法。#includemain()charc;for(;)c=XBYTE14;XBYTE14=XBYTE15;XBYTE15=c;程序中为方便反复观察,使用了死循环语句for(;)只要用Ctrl+C即可退出死循环。,9,上面程序(例4-5)通过编译后机器代码和反汇编程序如下:0000020014LJMP0014H000390000EMOVDPTR,#000EH;设置单元地址0eh0006E0MOVXA,DPTR;取000eh单元内容0007FFMOVR7,A;保存000eh单元内容0008A3INCDPTR;指向000fh单元0009E0MOVXA,DPTR;取000fh单元内容000A90000EMOVDPTR,#000EH;指向000eh单元000DF0MOVXDPTR,A;000fh单元内容送000eh单元000EA3INCDPTR;指向000fh单元000FEFMOVA,R7;取回000eh单元内容0010F0MOVXDPTR,A;000eh单元内容送000fh单元001180F0SJMP0003H;转到0003H(循环)001322RET0014787FMOVR0,#7FH;本行以下4行,00h7fh单元清00016E4CLRA0017F6MOVR0,A0018D8FDDJNZR0,0017H;0fdh=17h-1ah补001A758107MOVSP,#07H;设置栈底001D020003LJMP0003H;转到0003H(执行FOR循环),10,例中可见:一进入C语言程序,首先执行将内部RAM的07FH128个单元清零,然后置SP为07H(视变量多少不同,SP置不同值,依程序而定),因此如果要对内部RAM置初值,一定要在执行了一条C语言语句后进行。C语言程序设定的变量,C51自行安排寄存器或存贮器作参数传递区,通常在R0R7(一组或两组,视参数多少定),因此,如果对具体地址置数据,应避开这些R0R7的地址。如果不特别指定变量的存贮类型,通常被安排在内部RAM中。,11,4.8.2、顺序程序的设计,【例4-6】完成1980524503的编程分析:两个乘数比较大,其积更大,采用unsignedlong类型,设乘积存放在外部数据存贮器0号开始的单元。程序如下:main()unsignedlongxdata*p;/*设定指针p*/unsignedlonga=19805;/*设置a的类型*/unsignedlongb=24503,c;/*设置b和积c为unsignedlong类型,并赋初值*/p=0;/*设地址指向0号单元*/c=a*b;*p=c;/*积存入外部RAM0号单元*/上机通过软件仿真调试,在变量观察窗口看到运算结果c=485281915,即为乘积的十进制数。观察XDATA区(外部RAM)的0000H0003H单元分别为1CECD07B,即存放的为485281915的十六进制数。,12,观察DATA区:(例4-6)单元地址:0B0C0D0E0F10111213141516单元内容:00005FB700004D5D1CECD07Ba变量b变量C变量(积)可见定义为unsignedlong类型,给每个变量分配四个单元,如果定义类型不对,将得不到正确的结果。如果未定义变量类型,默认为内部RAM,如a、b、c变量。对于复杂的运算通常采用查表的方法。如同汇编程序设计一样,在程序存贮器建立一张表,在C语言中表格定义为数组,表内数据(元素)的偏移量表现为下标。数组的使用如同变量一样,要先进行定义:即说明数组名、维数、数据类型和存贮类型,在定义数组的同时还可以给数组各元素赋初值。通过下例说明C51数组的定义方法和用C语言编查表程序的方法。,13,例4-7片内RAM20H单元存放着一个005H的数,用查表法,求出该数的平方值放入内部RAM21H单元。,main()charx,*p;/p为字符型通用存储型(一般为内部RAM)指针。charcodetab6=0,1,4,9,16,25;p=0 x20;/内部RAM中的20H单元内容为下标(即自变量)x=tab*p;/求因变量(平方值),并存X变量中。p+;/指向21H单元。*p=x;/将结果保存到21H单元。,14,4.8.3、循环程序的设计,C语言的循环语句有以下几种形式1.while(表达式)语句;其中表达式为循环条件,语句为循环体,当表达式值为真(值为1),重复执行“语句”。,15,2.do语句;while(表达式)表达式为真执行循环体“语句”,直至表达式为假,退出循环执行下一个语句。,16,3.for(表达式1;表达式2;表达式3)语句;,语句可只一条以“;”结尾;可以多条组成复合语句,复合语句必须用括起;也以没有语句,通常用于等待中断,或查询。,17,例4-9.分析下列程序的执行结果:main()intsum=0,i=0;dosum+=ii+;/修改循环条件while(i=10);本程序完成0+1+2+10的累加,执行后sum=55,18,例4-10.将“例4-9”改用for语句编程,mainintsum=0,i;for(i=0;i=10;i+)sum+=i;/循环次数可预测(11次)4.8.4、分支程序的设计C语言的分支选择语句有以下几种形式:1.if(表达式)语句;句中表达式为真执行语句,否则执行下一条语句。当花括号中的语句不只一条(复合语句),花括号不能省。2.if(表达式)语句1;else语句2;,19,句中表达式为真执行语句1,否则执行语句2再执行下一条语句,见下面流程图。If语句可以嵌套。,if语句流程,ifelse语句流程,20,【例4-11】片内RAM的20H单元存放一个有符号数x,函数y与x有如下关系式:(设y存放于21H单元)xx0y=20Hx=0x+5x0,程序如下:main()Signedcharx,*p,*y;p=0 x20;y=0 x21;for(;)/未填充循环条件,死循环。x=*p;if(x0)*y=x;if(x0)*y=x+5;if(x=0)*y=0 x20;程序中为观察不同数的执行结果,采用了死循环语句for(;),上机调试时退出死循环可用Ctrl+C。,21,3.Switchcase语句(多分之语句)该语句常用于多分支转移,格式如下:switch(表达式)case常量表达式1:语句1;break;case常量表达式2:语句2;break;case常量表达式n:语句n;break;default:(语句n+1;,22,说明语句先进行表达式的运算,当表达式的值与某一case后面的常量表达式比较,相等时就执行它后面的语句。当case语句后有break语句时,执行完这一case语句后,跳出switch语句,当case后面无break语句,程序将执行下一条case语句。如果case中常量表达式值和表达式的值都不匹配,就执行default后面的语句。如果无default语句就退出switch语句。default的次序不影响执行的结果,也可无此语句。,23,【例4-12】根据R3的内容转向不同子程序(对两个数a和b处理)。r3=0,执行子程序pr0(完成两数相加)r3=1,执行子程序pr1(完成两数相减)r3=2,执行子程序pr2(完成两数相乘)r3=3,执行子程序pr3(完成两数相除)分析:C语言中的子程序即为函数,因此需编四个处理函数。在C51编译器中通过头文件reg51.h可以识别特殊功能寄存器,但不能识别R0R7通用寄存器,因此R0R7只有通过绝对地址访问识别,程序如下:,24,#include(例4-12)#definer3DBYTE0 x03intc,c1,a,b;,Pr0()c=a+b;pr1()c=a-b;pr2()c=a*b;pr3()c=a/b;main()a=90;b=30;for(;)switch(r3)case0:,pr0();break;case1:pr1();break;case2:pr2();break;case3:pr3();break;c1=56;/为调试增加语句,在上述程序中,为便于调试观察,加了C1=56语句,并使用了死循环语句for(;),用Ctrl+C可退出死循环。,25,*4.9汇编语言和C语言的混合编程(略),本节介绍不同的模块,不同的语言相结合的编程方法。通常情况下以高级语言编写主程序,用汇编语言编写与硬件有关的子程序。不同的编译程序高级语言对汇编的调用方法不同,在FranklinC51中,是将不同的模块(包括不同语言的模块)分别汇编或编译,再通过连接生成一个可执行文件。C语言程序调用汇编语言程序要注意以下几点:1.被调函数要在主函数中说明,在汇编程序中,要使用伪指令使CODE选项有效并声明为可再定位段类型,并且根据不同情况对函数名作转换,见表4.6。,26,27,2.对为其他模块使用的符号进行PUBLIC声明,对外来符号进行EXTRN声明。3.参数的传递。*4.9.1C语言程序和汇编语言程序参数的传递在混合语言编程中,关键是入口参数和出口参数的传递,FranklinC编译器可使用寄存器传递参数,也可以使用固定存贮器或使用堆栈,由于8XX51的堆栈深度有限,因此多用寄存器或存贮器传递。用寄存器传递最多只能传递三个参数,选择固定的寄存器,见表4.7。表4.7传入参数,28,例如func1(inta)“a”是第一个参数,在R6,R7传递,func2(intb,intc,int*d)“b”在R6,R7中传递,“c”在R4,R5中传递,“d”在R1,R2,R3中传递。如果传递参数寄存器不够用,可以使用存贮器传送,通过指针取得参数。汇编语言通过寄存器或存贮器传递参数给C语言程序,汇编语言通过寄存器传递给C语言的返回值见表4.8。表4.8返回参数,29,下面通过实例说明混合编程的方法及参数传递过程。*4.9.2C语言程序调用汇编语言程序举例例4-13用P1.0产生周期为4ms的方波,同时用P1.1产生周期为8ms的方波。说明:设计三个模块模块一:C语言编主程序,使P1.1产生周期为8ms的方波;模块二:用C语言编程,使P1.0产生周期为4ms的方波;模块三:用汇编语言编写延时1ms程序。模块一调用模块二获得8ms方波,模块二调模块三,向汇编程序传递字符型参数(x=2),延时2ms。各模块程序如下:,30,/模块一:P1.1产生周期为8ms的方波#include#defineucharunsignedcharsbitP1-1=P11;voiddelay4ms(void);/*定义延时4ms函数(模块二)*/main()uchari;for(;)/由P1.1产生周期为8ms的方波。P1-1=0;delay4ms();/*调模块二延时4ms*/P1-1=1;delay4ms();/*调模块二延时4ms*/,31,/模块二(delay4ms):使P1.0产生周期为4ms的方波#include#defineucharunsignedcharsbitP1-0=P10;delaylms(ucharx);/*定义延时1ms函数(模块三)*/voiddelay4ms(void)/由P1.0产生周期为4ms的方波。P1-0=0;delaylms(2);/*调汇编函数(模块三)*/P1-0=1;delaylms(2);/*调汇编函数(模块三)*,32,模块三:PUBLIC-DELAY1MS;DELAY1MS(参数传递)为其他;模块调用DESEGMENTCODE;定义DE段为再定位程序段RSEGDE;选择DE为当前段-DELAY1MS:NOPDELA:MOVR1,#0F8H;延时LOP1:NOPNOPDJNZR1,LOP1DJNZR7,DELA;R7为C程序传递过来的参数(x=2)EXIT:RETEND上例可见汇编语言程序从R7中获取C程序传递参数(x=2)。,33,例4-14.在汇编程序中比较两数大小,将大数放到指定的存储区,由C程序的主调函数取出。C语言程序,模块一:#defineucharunsignedcharvoidmax(uchara,ucharb);/*定义汇编函数*/main()uchara=5,b=35,*c,d;c=0 x30;/*c指针变量指向内部RAM30H单元*/max(a,b);/*调汇编函数(取大数),a,b为传递的参数*/d=*c;/*d存放模块二传递过来(指针)的参数*/,34,模块二:汇编语言程序(通过指针返回参数)PUBLIC-MAX;MAX(参数传递)为其他模块调用DESEGMENTCODE;定义DE段为再定位程序段RSEGDE;选择DE为当前段MAX:MOVA,R7;取模块一的参数aMOV30H,R5;取模块一的参数bCJNEA,30H,TAG1;比较a,b的大小TAG1:JCEXIT;ab=(30H),转EXIT。MOV30H,R7;大数存于30H单元EXIT:RETEND此例中,C语言程序通过R7和R5传递字符型参数a和b到汇编语言程序,汇编语言程序将返回值放在固定存贮单元,主调函数通过指针取出返回值。,35,*4.9.3C语言和汇编语言混合编程传递的参数多于3个的编程方法C语言程序调用汇编程序最多只能传递3个参数,如果多于3个参数,就需要通过存贮qu区传递,这就需要在汇编程序中建立数据段,在下例中C语言程序向汇编传递6个参数,汇编程序将6个参数相加并返回结果。*C_CALL.C*#pragmacodesmallexternintafunc(charv_a,charv_b,charv_c,charv_d,charv_e,charv_f);/外来函数说明voidC_call(void)charv_a=0 x11;/*传递参数赋值*/charv_b=0 x18;charv_c=0 x33;charv_d=0 x44;charv_e=0 x55;charv_f=0 x98;intdata*aa;/*指针变量指向int型data区*/intA_ret;/*存汇编返回结果的变量*/aa=0 x30;/*置指针*/A_ret=afunc(v_a,v_b,v_c,v_d,v_e,v_f);/*调汇编函数*/*aa=A_ret;/*取汇编返回结果*/*aa=(int)0;/*为方便观察改值,强制0为int型*/*aa=A_ret;/*再次观察汇编返回结果*/,36,voidmain(void)/*主函数*/chara1,a2,a3;/为方便观察设置变量a1,a2,a3a1=0;a2=2;a3=3;C_call();a1=1;a2=3;while(1);,37,*AFANC.ASM*PR_AFUNCSEGMENTCODE;名为AFUNC,段为代码段(PR);在CODE区可再定位,DT_AFUNCSEGMENTDATAOVERLAYABLE;名为AFUNC,段为数据段(DT);在DATA区,可再定位,可以覆盖PUBLIC?_afunc?BYTE;公共符号定义(字符型char)PUBLIC_afuncRSEGDT_AFUNC;数据段定义?_afunc?BYTE:;数据段保留参数传递区v_a:DS1;第1个参数对应R7v_b:DS1;第2个参数对应R5v_c:DS1;第3个参数对应R3v_d:DS1v_e:DS1v_f:DS1,38,RSEGPR_AFUNC;程序段_afunc:USING0;00H07H单元对应R0R7。MOVA,R7;取R7中的v_aADDA,R5;取R5中的v_bADDA,R3;取R3中的v_cADDA,v_dADDA,v_eADDA,v_fMOVR7,A;和存R7,进位存R6MOVA,#0;以便返回RLCAMOVR6,ARETEND,39,编译连接方法以上各模块可以先分别汇编(A51)和编译(C51)(选择DEBUG编译控制项),生成的.OBJ文件,然后运行L51将各OBJ文件连接,生成一个新的文件。在集成环境下的连接调试可以连续进行,比上面方法更为方便,现使用wave(伟福)的仿真软件ICExplorerW(ICEForWindows)的编译连接步骤如下:1.编辑好各个模块,保存。2.点击文件/新建项目,弹出项目窗口。,40,3.点击项目菜单,选加入模块,此时弹出有文件目录的对话框,选中要加入刚才编辑好的文件(模块),并打开。此时在项目窗口中可以看到加入的模块文件。4.点击项目菜单中的全部编辑,并取名保存项目。于是系统对加入各模块进行编译,并进行连5.编译连接完成会弹出信息窗口,如编译连接有错,信息窗口将出现错误信息。6.模块连接成功,生成二进制文件(.BIN)和十六进制文件(.HEX)。7.点击跟踪或单步按钮,就可对程序进行跟踪调试,程序运行到不同模块时,wave就会弹出相应的模块源程序窗口,显示程序运行情况。,41,4.10小结本章介绍了C51的基本数据类型、存贮类型及对C51对单片机内部部件的定义,并介绍了C语言基础知识,最后
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 家庭防灾减灾知识与技能培训手册
- 幼儿园教师心理健康与职业规划指导
- 应用运维工程师运维知识库建设方案
- 2025年新型生态园区建设可行性研究报告
- 2023年嘉峪关市税务系统遴选笔试真题汇编附答案解析
- 2023年襄樊市直机关遴选公务员笔试真题汇编含答案解析(夺冠)
- 2023年渭南市直属机关遴选公务员考试真题汇编附答案解析(夺冠)
- 2025年全自动化生产线升级项目可行性研究报告
- 2024年云浮市直属机关遴选公务员考试真题汇编附答案解析(夺冠)
- 2023年成都市直属机关遴选公务员笔试真题汇编含答案解析(夺冠)
- 山东大学MBA考试真题及答案解析2025年
- 卷烟厂安全培训考核制度
- 歌唱中的共鸣课件
- 2025年招标采购从业人员专业能力评价考试(招标采购专业理论与法律基础初、中级)综合试题及答案一
- 《我终于回来了》(2019年北京市中考满分作文10篇)
- 公路机电工程合同协议书
- 中医理论现代化-洞察及研究
- 钣金工下料基础知识
- 消防安全演讲
- 韩语语法大全(超全)
- 贵阳紫境府别墅样板间设计方案
评论
0/150
提交评论