STC32位8051单片机原理及应用 课件 第八章 C语言程序设计4_第1页
STC32位8051单片机原理及应用 课件 第八章 C语言程序设计4_第2页
STC32位8051单片机原理及应用 课件 第八章 C语言程序设计4_第3页
STC32位8051单片机原理及应用 课件 第八章 C语言程序设计4_第4页
STC32位8051单片机原理及应用 课件 第八章 C语言程序设计4_第5页
已阅读5页,还剩44页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第八章C语言程序设计何宾2023.08函数C251编译器为标准C函数声明提供了很多扩展这些扩展包括:将函数声明为中断过程设置寄存器组选择存储器模型声明可重入函数声明外来函数程序开发人员可以在函数声明中包含这些扩展或属性(许多可以进行组合)函数使用下面的格式声明函数:[return_type]funcname([args])[{small|large}][__attribute__((attrib_spec))][reentrant][interruptn][usingy]其中:return_type是从函数返回值的类型。如果没有指定类型,假定为intfuncname是函数的名字args是函数的参数列表函数small显式定义函数使用小(small)存储器模型large显式定义函数使用大(large)存储器模型__attribute__是后跟属性规范的关键字attrib_spec是用双括号括起来的属性规范。例如,noreturnreentrant指示函数是递归的或可重入的interrupt指示函数是一个中断函数n是中断号using指定函数使用的寄存器组y是寄存器组的编号函数

--存储器模型函数参数和局部变量保存在存储器模型指定的默认存储器空间中程序开发人员可以通过在函数声明中包含small或large函数属性来指定用于单个函数的存储器模型使用SMALL存储器模型的函数的优点在于本地数据和函数参数保存在STC32G系列单片机的片上RAM中。因此,数据访问非常高效。内部存储器是有限的有时,small模型不能满足非常大的程序的要求,必须使用其他存储器模型。对于这种情况,程序开发人员可以声明函数使用不同的存储器模型函数

--存储器模型通过在函数声明中指定函数模型属性,可以选择使用两个可能的可重入堆栈和帧指针中其中一个。在SMALL模型中堆栈访问比LARGE模型中的更有效注:C251版本2或更高版本提供#pragma函数命令。使用该指命令,程序开发人员可以为一个或多个函数单独指定模型或可重入属性,而无需修改函数声明函数

--寄存器组在STC32G系列单片机中,DATA存储器的前32个字节(0x00~0x1F)被分为4组,每组8个寄存器程序以R0~R7的形式访问这些寄存器。寄存器组由程序状态字PSW的两位选择当处理中断或使用实时操作系统时,寄存器组非常有用,因为单片机可以为任务或中断切换到不同的寄存器组,而不是保存堆栈上的所有8个寄存器。然后,单片机可以在返回之前将切换到原始寄存器组函数

--寄存器组using函数属性指定函数使用的寄存器组。比如:voidrb_function(void)using3{…………}using属性的参数是0~3之间的整数常数不允许使用带运算符的表达式在函数原型中不允许使用using属性using属性影响函数的目标代码如下:当前选择的寄存器组保存在函数入口的堆栈上设置指定的寄存器组在退出函数之前,将恢复以前的寄存器组函数

--寄存器组注:using属性不能用于在寄存器中返回值的函数中。程序开发人员必须格外小心,确保寄存器组切换仅在精心控制的区域进行。否则,可能产生错误的函数结果。即使使用相同的寄存器组,使用using属性声明的函数也不能返回位值using属性在中断函数中最有用通常为每个中断优先级指定不同的寄存器组程序开发人员可以为所有非中断代码分配一个寄存器组。为高级中断分配第二个寄存器组和为低级中断分配第三个寄存器组函数

--中断函数STC32G系列单片机提供了大量的硬件中断,可用于计数器、定时器、检测外部事件以及使用串口发送和接收数据C251编译器支持最多32个中断(0~31)的中断函数!!!!对于多于32个中断的其他中断,使用STC公司提供的工具进行特殊处理,本章后续将详细说明函数

--中断函数interrupt函数属性指定相关的函数是一个中断服务例程(InterruptServiceRoutine,ISR)unsignedintinterruptcnt;unsignedchardatasecond;

voidtimer0(void)interrupt1using2{if(++interruptcnt==4000)//计数到400{second++;//第二个计数器interruptcnt=0;//清除计数器}}函数

--中断函数Interrupt属性将值在0~31范围内的整数常数作为参数函数原型中不允许使用带有运算符和中断属性的表达式interrupt属性影响函数的目标代码如下:当需要时,ACC、B、DPH、DPL、PSW和PSW1的内容将在函数调用时保存在堆栈中如果未使用using属性指定寄存器组,则中断函数中使用的所有工作寄存器都将保存在堆栈中退出函数之前,将恢复保存在堆栈中的工作寄存器和特殊寄存器在使用汇编语言编写ISR时,中断函数的末尾需要使用RETI指令,表示该中断函数从中断返回此外,C251编译器自动生成中断向量函数

--中断函数下面的规则适用于中断函数,包括:无法传递参数。当中断程序中包含任何参数声明时,编译器会发出错误消息中断函数声明不能包含返回值。它们必须声明为void。如果尝试定义中断函数的返回值,则编译器会发出错误消息。返回类型void应用于所有中断程序声明。但是编译器会忽略隐含int返回值编译器识别对中断函数的直接调用并拒绝它们。使用RETI指令退出中断程序。RETI恢复PSW1的值并影响STC32G系列单片机的中断系统。不要通过函数指针间接调用中断函数编译器为每个中断函数生成一个中断向量。为向量生成的代码是跳转到中断函数的开头。通过在C251命令行中使用C251命令NOINTVECTOR,可以抑制中断向量的生成。在这种情况下,必须从单独的汇编程序模块中提供中断向量函数

--中断函数C251编译器允许范围为0~31的中断号由于大多数C251库函数都是完全可重入的,因此对调用这些函数没有任何限制。C251在堆栈中为自动变量使用可重入代码。因此,程序开发人员可以调用任何使用reentrant属性编译的C251函数,或者在函数执行期间只使用寄存器C251从不为寄存器访问生成绝对地址。每个C251函数独立于实际使用的寄存器组。不再需要C51编译器中已知的NOAREGS命令注:有时,删除using属性并让C251编译器PUSH(入栈)使用的寄存器会更有效。这也节省了额外寄存器组所需要的数据存储器。程序开发人员可以将使用或不使用属性生成的代码与C251CODE命令进行比较函数

--可重入函数可重入函数可以同时由多个进程共享当一个可重入函数正在执行时,另一个进程可以中断执行,然后开始执行相同的可重入功能默认情况下,C251编译器生成静态代码,这意味着函数通常不能递归调用或以导致可重入的方式调用静态代码的优点是函数参数和局部变量保存在固定的存储位置,这允许STC32G系列单片机快速访问变量函数属性reentrant允许程序开发人员声明可重入的函数,因此可以递归调用函数

--可重入函数intcalc(chari,intb)reentrant{intx;x=table[i];return(x*b);}

#pragmaFUNCTIONS(reentrant)//C251生成可重入CODEintfunc(unsignedcharindex){return(table[index]);}

#pragmaFUNCTIONS(static)//再次选择静态CODE函数

--可重入函数重入函数可以递归调用,也可以由两个或多个进程同时调用在实时应用中,或者在中断代码和非中断代码必须共享一个函数的情况下,通常需要重入函数与上面的代码一样,程序开发人员可以选择性地(使用reentrant属性或者FUNCTIONS命令)将函数定义为可重入函数重入代码使用STC32G系列单片机的硬件堆栈区作为非寄存器参数和自动变量函数

--可重入函数对于可重入函数,由于STC32G系列单片机硬件架构,存在一些限制包括:不能使用位类型参数。本地位标量也不可用。可重入功能不支持位可寻址变量不能从外来函数(alienfunction)调用可重入函数。重入代码不能使用alien属性,因为PL/M-51参数传递仅是静态的注:访问使用STC32G系列单片机硬件堆栈的变量要比访问静态存储器慢。因此,仅在需要时使用可重入函数函数

--外来函数C251编译器可轻松与IntelPL/M-51编译器接口,并允许程序开发人员:从C调用PL/M-51例程从PL/M-51调用C例程要从C函数调用PL/M-51例程,必须使用alien(外来)函数类型说明符将它们声明位外部函数

--外来函数externaliencharplm_func(int,char);

charc_func(void){inti;charc;

for(i=0;i<100;i++){c=plm_func(i,c);//调用PL/M函数}return(c);}函数

--外来函数要创建可以从PL/M例程调用的C函数,必须在C函数声明中使用alien函数类型说明符。比如:aliencharc_func(chara,intb){return(a*b);}PL/M-51函数的参数和返回值可以是bit、char、unsignedchar、int和unsignedint。其他类型(包括long、float和所有类型的指针)可以在C函数中使用alien类型说明符声明。但是,请谨慎使用这些类型,因为PL/M-51不直接支持32位二进制整数或浮点数PL/M-51模块中声明的公共变量可用于C程序,方法是将它们声明为外部变量,就像对任何C变量一样函数

--外来函数C251编译器支持带有_task_和_priority_关键字的RTX251FULL和RTX251Tiny实时多任务操作系统其中:_task_关键字指定函数是实时任务_priority_关键字指定任务的优先级比如:voidfunc(void)_task_num_priority_pri其中,num为任务ID号,对于RTX51Full为0~255;对于RTX251Tiny为0~15pri是任务的优先级注:任务函数必须使用void返回类型和void参数列表函数

--函数参数C函数可以传递寄存器和/或固定存储器位置中的参数REGPARMS和NOREGPARMS命令使能/禁止使用寄存器传递参数如果禁止使用寄存器传递参数,或者传递的参数套多而无法装入寄存器,则在固定存储器位置传递参数通常,使用寄存器参数函数参数

--存储器传递传递到固定存储器位置的汇编程序例程的参数使用名字为?function_name?BYTE和?function_name?BIT保存传递给函数function_name的参数值在调用函数之前,位参数被复制到?function_name?BIT段。所有其他参数都复制到?function_name?BYTE段即使使用寄存器传递参数,所有参数也会在这些段中分配空间。参数按照在每个段中声明的顺序保存用于参数传递的固定存储器位置可以是存储器类DATA、EDATA或XDATA,具体取决于所使用的存储器模型函数参数

--用寄存器传递C251编译器使用寄存器R11和R0~R7进行参数传递寄存器中最多可以传递9个参数所有其他参数都使用固定存储器位置或STC32G系列单片机内的硬件堆栈传递(取决于函数reentrant/static属性)函数参数

--用寄存器传递用于传递参数的寄存器分配顺序char,1字节ptrint,2字节ptrlong,float4字节ptrdouble1R11WR6(MSB在R6,LSB在R7)DR4DR0DR0,DR42R7WR4DR0DR4—3R6WR2———4R5WR0———5R4————6R3————7R2————8R1————9R0————函数参数

--用寄存器传递对于传递给C51函数的参数,使用3字节指针;3字节指针在寄存器R1/R2/R3中传递C251按照R11、R7、R6、R5、R4、R3、R2、R1和R0的顺序分配寄存器如果某个寄存器已经用于某个参数变量,C251将继续向下列表,直到找到空闲寄存器函数参数

--用寄存器传递选择寄存器进行参数传递声明描述func1(inta)第一个也是唯一的参数a在寄存器WR6中传递func2(intb,intc,intfar*d)第一个参数b在寄存器WR6中传递。第二个参数c在寄存器WR4中传递,第三个参数d在寄存器DR0中传递func3(longe,longf,longg)第一个参数e在寄存器DR4中传递。第二个参数f在寄存器DR0中传递。由于可用于long类型的参数已经被其他参数使用,因此第三个参数g不能放在寄存器中。使用固定存储器位置或STC32G系列单片机内的硬件堆栈来传递该参数func4(charh,floati)第一个参数h在寄存器R11中传递。第二个参数i在寄存器DR4中传递函数参数

--函数返回值单片机寄存器传递函数返回值返回类型寄存器功能bit进位标志CY进位标志中返回单个位char/unsignedchar,1字节指针R11R11中返回单个字节类型int,unsignedint,2字节指针WR6MSB在R6中,LSB在R7中long,unsignedlongDR4MSB在R4中,LSB在R7中floatDR432位IEEE格式:‘指数’和‘符号’在WR4中doubleDR0,DR464位IEEE格式:’指数‘和’符号‘在WR0中4字节指针DR0MSB在R0中,LSB在R3中函数参数

--函数返回值对于传递给C51函数的参数;寄存器R1/R2/R3中返回3字节指针。大小为[1..8]的结构返回类型返回到寄存器R0~R7中,最后一个结构元素的LSB始终以R7结尾例如,在R5、R6和R7中返回3字节的结构值。大小为5的结构返回到R3、R4、R5、R6和R7包含超过8个字节的结构在内部memcpy函数的帮助下返回目的地址必须在DR12的调用时传递给函数函数

--使用SRC命令SRC命令指导编译器生成汇编程序而不是目标模块这样,程序开发人员可以使用该命令生成汇编语言源文件的外壳,或者帮助他们确定编译器期望的参数传递规约要创建汇编源文件,必须在C251编译器中使用SRC命令,如下:函数

--使用SRC命令#pragmaSRC//SRC命令生成汇编器输出#pragmaXTINY//指定要使用的存储器模型

unsignedintasmfunc1(unsignedintarg){return(1+arg);}函数调用实例函数参数传递的C语言描述/*定义函数sum,三个不同类型入口参数*/longintsum(chara,shortintb,longintc){ return(a+b+c);//三个不同类型参数相加,返回longint}函数调用实例voidmain()//定义main主函数{ volatilecharx=100;//定义并初始化字符型变量x volatileshortinty=10000;//定义并初始化16位整型变量y volatilelongintz=1000000;//定义并初始化32位整型变量z volatilelongintw;//定义32位整型变量w w=sum(x,y,z);//调用函数sum,返回值保存在长整型变量}注:读者可定位到本书配套资源的下面路径\stc32_example\example_8_13,用keilμVision打开top.uvproj函数调用实例修改前面给出的C语言代码在子程序调用中增加一个longint类型参数longintsum(chara,shortintb,longintc,longintd){ return(a+b+c+d);}函数调用实例voidmain(){ volatilecharx=100; volatileshortinty=10000; volatilelongintz=1000000; volatilelongintw=2000000; volatilelongintu; u=sum(x,y,z,w);}函数调用实例数组变量参数传递的C语言描述该代码中的函数sort实现对数组中的元素从小到大的重新排序voidsort(intarray[],intn)//声明排序子函数,不返回值{ inti,j,k,t; for(i=0;i<n-1;i++)//二重循环排序{ k=i;//设置标记k,在标记处放置最小的array[k] for(j=k+1;j<n;j++)//在array[k]~array[n]范围内找最小,

函数调用实例/*在搜索过程中,如果后面的元素array[j]<array[k]*/if(array[j]<array[k]) k=j;//则索引值j赋值给k, t=array[k];//array[k]保存到临时变量t中 array[k]=array[i];//array[i]覆盖掉array[k]的值 array[i]=t;//临时变量t的值覆盖array[i]的值 }}函数调用实例voidmain(){/*声明并初始化整型数组变量a,该数组中有10个元素 volatileinta[10]={200,100,2000,400,50,90,3000,10,300,600}; sort(a,10);//调用排序函数,数组名传递 while(1);//循环处,用于设置断点}函数调用实例指针变量参数传递的C语言描述该代码将两个字符串变量首尾连接#include"stdio.h"//包含头文件stdio.h#include"reg251s.h"//包含头文件reg251s.hvoidcon_string(char*s1,char*s2)//声明函数,有两个字符指针参数{while(*s1!='\0')//如果指针*s1指向的字符不是结束,则继续s1++;//指针递增while(*s2!='\0')//如果指针*s2指向的字符不是结束,则继续 *s1++=*s2++;//将指针*s2指向的内容赋值到*s1的末尾 *s1='\0';//在*s1当前指向的内容后添加结束标志}函数调用实例voidmain(){charxdataa[40];//声明字符数组变量a,位于xdatacharxdatab[40];//声明字符数组变量b,位于xdataSCON=0x52;//设置串口控制寄存器SCONTMOD=0x20;//设置串口控制寄存器TMODTCON=0x69;//设置串口控制寄存器TCONTH1=0xF3;//设置串口控制寄存器TH1printf("pleaseenterthestringofa[40]\n");//提示输入字符串agets(a,40);//输入字符串a,可以有空格,回车键结束printf("pleaseenterthestringofb[40]\n");//提示输入字符串b函数调用实例gets(b,40); //输入字符串b,可以有空格,回车键结束printf("\nconnectedthestringis\n");//提示连接后的字符串信息con_string(a,b);//调用连接字符串函数puts(a); //打印字符串awhile(1); //无限循环设置断点}函数调用实例可重入函数/递归函数的C语言描述在该设计中,使用递归算法实现斐波那契数列即满足下面的条件:

函数调用实例intfib(intn)reentrant//reentrant声明为递归函数{if(n==1||n==2)//如果n=1或n=2,则返回值为1 return1;else//如果n>2,则递归调用函数fib(n-1)和fib(n-2) return(fib(n-1)+fib(n-2));}函数调用实例voidmain()//定义main主函数{intn=5;//定义整型和初始化整型变量n volatileinty;//定义整型变量yy=fib(n);//调用函数fib,并将调用结果赋值给ywhile(1); }函数调用实例在函数定义中使用存储器模型的C语言描述/*函数small_func,声明为small*/intsmall_func(inta,intb,intc,intd,inte,intf)small{ return(a+b+c+d+e+f);//返回6

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论