C51 基本函数、中断函数和库函数的详解

简介: 本文详解了C51程序中的基本函数、中断函数和库函数

函数的定义和调用

此外,C51编译器本身还提供了丰富的库函数,用户可以根据需要随时调用,从而大大提高编程效率。

1. 函数的定义

函数定义的一般形式为:

​ 函数类型 函数名(形参列表)

​ { 局部变量定义

​ 函数体

​ }

在用户的角度看来,有两类函数可以调用:用户自定义的函数标准库函数

  • 标准库函数是C51编译其提供的,不需要由用户进行定义,只需要包含相应的头文件即可(见库函数的说明)。
  • 用户自定义的函数是根据自己需要实现的功能编写的函数,必须先定义后调用(先调用后定义也可,不过要在调用前进行声明,就像上例。

2. 重入函数

通常情况下,C51的函数不能被递归调用,也不能应用导致递归调用的结构。

重入函数特性允许你声明一个重入函数,使得该函数能够被递归调用。 实际上,当多个进程需要同时使用同一个函数时,这个函数就应定义成重入函数。当一个重入函数被调用运行时,另外的一个进程可以中断此运行过程,然后再次调用此重入函数。

定义重入函数的方法就是在函数声明时,用关键字“reentrant”进行声明。

例如:

#include  <reg52.h>  //包含特殊功能寄存器库

#include  <stdio.h>  //包含I/O函数库

extern  serial_initial();

int  fac(int  n)  reentrant

{

     int  result;

     if  (n == 0)

        result=1;

     else

        result=n*fac(n-1);

      return(result);

}

main()

{

  int  fac_result;

  serial_initial();

  fac_result=fac(11);

  printf(“%d\n”,fac_result);

}

重入函数在实时应用中,在中断服务程序代码和非中断程序代码必须共用一个函数的场合中经常用到。

需要注意的是, 可以选择哪些必须的函数为重入函数而不需将全部程序声明为重入函数。把全部程序声明为重入函数,将增加目标代码的长度并减慢运行速度。

中断函数的定义

中断系统对于单片机系统来说十分重要,C51编译器支持用C语言编写中断函数,从而减轻了用汇编语言编写中断服务程序的繁琐程度。中断服务程序的一般格式如下:

函数类型 函数名(形参列表) interrupt n [using m];

  • 中断函数类型一般为void。
  • interrupt后面的n是中断号,取值为0~4,编译器从8n+3处产生一条长跳转指令,转向中断号为n的中断服务程序。
  • using m用于选择不同的工作寄存器组。m的取值范围为0~3,分别对应与低128字节内部RAM区中的四组寄存器

    该项为可选项。

image-20220806224810653

编写MCS-51中断函数注意如下:

  • 中断函数不能进行参数传递,如果中断函数中包含任何参数声明都将导致编译出错。
  • 中断函数没有返回值,如果企图定义一个返回值将得不到正确的结果,建议在定义中断函数时将其定义为void类型,以明确说明没有返回值。
  • 在任何情况下都不能直接调用中断函数,否则会产生编译错误。因为中断函数的返回是由8051单片机的RETI指令完成的,RETI指令影响8051单片机的硬件中断系统。如果在没有实际中断情况下直接调用中断函数,RETI指令的操作结果会产生一个致命的错误。
  • 如果在中断函数中调用了其它函数,则被调用函数所使用的寄存器组必须与中断函数相同。否则会产生不正确的结果。

C51编译器对中断函数编译时会自动在程序开始和结束处加上相应的内容,具体如下:

  • 在程序开始处对ACC、B、DPH、DPL和PSW入栈,结束时出栈。
  • 中断函数未加using m修饰符的,开始时还要将R0~R7入栈,结束时出栈。
  • 如中断函数加using m修饰符,则在开始将PSW入栈后还要修改PSW中的工作寄存器组选择位。

中断函数定义示例:

  #include<reg51.h>

   unsigned char status;

   bit flag;

   void service_int1( ) interrupt 2 using 2   /* INT1中断服务程序,使用第2组工作寄存器 */

   {

       flag=1;      /* 设置标志 */

       status=p1;  /* 存输入口状态 */

    }

C51库函数的说明

C51提供了可直接调用的库函数。调用这些库函数可以使程序代码简单、结构清晰、易于调试和维护。

  • 本征库函数:指在编译时直接将固定的代码插入当前行,而不是用ACALL或LCALL进行函数调用(类似于宏的处理),这样就大大提高了访问效率。
  • 非本征函数: 并不是把固定代码插入当前行,而是通过ACALL或LCALL进行函数调用

本征库函数 9个

(1)_crol_和_cror_: 将char型变量循环向左(右)移动指定位数后返回。

(2)_irol_和_iror_: 将int型变量循环向左(右)移动指定位数后返回。

(3)_lrol_和_lror_: 将long型变量循环向左(右)移动指定位数后返回。

(4)_nop_: 相当于插入汇编指令nop

(5)_testbit_: 相当于JBC Label测试该位变量并跳转同时清除该位

(6)_chkfloat_: 测试并返回浮点数状态

上面所列举的本征函数的说明都包含在头文件 <intrins.h> 中,因此若想使用上述本征函数,必须在源程序开头包涵该头文件即:#include<intrins.h>。

非本征函数

  • <reg51.h>或<reg52.h>:文件reg51.h中包括了所有80C51的SFR及其位定义;reg52.h中包含了所有的80C52的SFR及其位定义。

    一般源程序中都包涵该头文件。即:#include <reg51.h>或#include <reg52.h>。

    包含了这个头文件后,就可以在程序中使用这些特殊功能寄存器及其位, P0 = 0x01;

  • <absacc.h>:该文件中定义了几个宏,以确定各存储空间的绝对地址。例如
     #define XBYTE ((unsigned char volatile xdata *) 0)
  • <stdlib.h>:该文件中包涵了动态内存分配函数的声明。
  • <string.h>:该文件包涵了缓冲区处理函数的声明。其中包括字符串复制、比较、移动等函数,
如:memccpy,strcat,strcmp等。这样可以很方便的对缓冲区进行处理。

如:extern char strcat (char s1, char *s2);

  • <stdio.h>:该文件包涵了输入输出流函数的声明。流函数通过串口或用户定义的I/O口读写数据,默认为串口,如果需要修改,可修改lib目录中的getkey.c和putchar.c源文件,然后在库中替换他们即可。例extern char putchar (char);
  • <math.h>:虽然单片机不适合大量的数学运算,不过C51还是提供了一些基本的数学运算函数,该函数的声明都包含在<math.h>中。例:extern float sqrt (float val);
注意: 除了上面介绍的几种常用的头文件,C51的头文件还包括ctype.h,assert.h,errno.h,float.h,ltmits.h,rtx51tny.h,srom.h,setjmp.h,stdarg.h等以上所介绍的头文件在keil目录下的C51\INC文件夹中。

运算符及实例

1. 算术运算符及其规则

C51最基本的算术运算符有五种:

A、 +

B、 -

C、 *

D、 /

E、 %

2. C51关系运算符

C51提供6种关系运算符

​ < (小于)

​ >(大于)

​ <= (小于或等于)

​ >= (大于或等于)

​ == (测试等于)

​ != (测试不等于)

3. 关系运算符的优先级

(1) 关系运算符的优先级低于算术运算符

(2) 关系运算符的优先级高于赋值运算符

C51逻辑运算符

C51提供三种逻辑运算符:

&& 逻辑与

| | 逻辑或

! 逻辑非

C51位操作

C51提供了如下位操作运算符:

& 按位求与

| 按位求或

^ 按位求异或

~ 按位求反

<< 位左移

>> 位右移

#include <reg51.h>                                 /*包含的头文件*/

#include <absacc.h>

#define ADC XBYTE[0x4000]                    /*定义需访问的绝对地址*/

#define CON8255 XBYTE[0x2003]

#define PA8255 XBYTE[0x2000]

#define PB8255 XBYTE[0x2001]

uchar  code disp[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,

​          0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; /*7段LED译码表*/

uchar  data  ad_w_l,ad_w_h;             

void delay(uchar t)                      /*延时子程序*/

{uchar i,j;

 for(i=0;i<=100;i++);

 for(j=0;j<=t;j++);

}

void dis_p(uchar disp_h,disp_l)           /*两位LED数码显示子程序*/

{PB8255=disp[disp_l];

 PA8255=0xf7;

 delay(100);

 PB8255=disp[disp_h];

 PA8255=0xfb;

 delay(100);

}

void main(void)

{uchar temp1;

 CON8255=0x89;

 IT0=1;

 EX0=1;

 EA=1;

 ADC=temp1;

 while(1)                                /*主程序中的主体循环*/

 {dis_p(ad_w_h,ad_w_l);}

}

 

adint() interrupt 0 using 1       /*外部中断0中断服务子程序*/

{uchar adc_w,temp;                         /*变量的定义*/

 EA=0;

 adc_w=ADC;

 if(adc_w>=255){adc_w=adc_w-5;}

 temp=adc_w/5;

 ad_w_h=temp/10;

 ad_w_l=temp%10;

 EA=1;

 ADC=adc_w;

}
目录
相关文章
|
Web App开发 机器学习/深度学习 语音技术
在ModelScope-FunASR中,语音识别系统中的声音活动检测
在ModelScope-FunASR中,语音识别系统中的声音活动检测【4月更文挑战第3天】
924 1
|
存储 数据处理 数据格式
51单片机双机通信实现
51单片机双机通信实现
1075 1
|
9月前
|
人工智能 监控 BI
抖音电商 API 接口:开启抖音小店直播带货数据新洞察
在数字化电商浪潮中,抖音小店凭借直播带货迅速崛起。本文详解抖音电商 API 接口如何实现直播数据实时监控与深度分析,助力商家优化策略、提升转化,迈向数据驱动运营新时代。
1031 29
|
PHP iOS开发 MacOS
CCS(Code Composer Studio 10.4.0)编译软件中文乱码怎么解决
通过合理配置CCS和操作系统,可以确保中文字符在开发过程中能够正确显示,避免由于乱码问题带来的困扰。希望本文能帮助您更好地使用CCS进行嵌入式开发。
2708 19
|
存储 NoSQL 知识图谱
7 种查询策略教你用好 Graph RAG 探索知识图谱
我们在这篇文章中探讨了知识图谱,特别是图数据库 NebulaGraph,是如何结合 LlamaIndex 和 GPT-3.5 为 Philadelphia Phillies 队构建了一个 RAG。 此外,我们还探讨了 7 种查询引擎,研究了它们的内部工作,并观察了它们对三个问题的回答。我们比较了每个查询引擎的优点和缺点,以便更好地理解了每个查询引擎设计的用例。
1681 0
7 种查询策略教你用好 Graph RAG 探索知识图谱
|
数据采集 Web App开发 测试技术
使用Selenium与WebDriver实现跨浏览器自动化数据抓取
在网络爬虫领域,Selenium与WebDriver是实现跨浏览器自动化数据抓取的利器。本文详细介绍了如何利用Selenium和WebDriver结合代理IP技术提升数据抓取的稳定性和效率。通过设置user-agent和cookie来模拟真实用户行为,避免被网站检测和阻止。文章提供了具体的代码示例,展示了如何配置代理IP、设置user-agent和cookie,并实现了跨浏览器的数据抓取。合理的参数配置能有效减少爬虫被封禁的风险,提高数据抓取效率。
1475 6
使用Selenium与WebDriver实现跨浏览器自动化数据抓取
|
机器学习/深度学习 自动驾驶 计算机视觉
使用Python实现简单的图像识别
【8月更文挑战第31天】在本文中,我们将探索如何使用Python语言和其强大的库来创建一个简单的图像识别系统。通过逐步指导,我们将了解如何准备图像数据,选择和训练模型,以及评估我们的成果。无论你是机器学习的初学者还是希望扩展你的技能集,这篇文章都将为你提供实用的知识和代码示例。
|
Python
结构化程序设计方法
结构化程序设计方法是一种软件开发的原则和技巧,旨在创建易于理解、维护和修改的高质量程序。它强调使用清晰的控制结构、模块化设计和数据抽象来减少程序的复杂性,从而提高程序的可靠性和效率。本文将详细介绍结构化程序设计方法的核心概念,并通过一个示例代码来展示其应用。
819 1
|
Web App开发 测试技术 网络安全
vmware 无法安装 (出现原因及解决办法)
vmware 无法安装 (出现原因及解决办法) 2008/09/12 00:25 vmware 无法安装 (出现原因、解决思路和解决办法) ----------------------------------------------- 遇到这个问题两次了,第一次是表弟(一个电脑高手)解决的,但具体过程和原因他却忘记了,这次一定要弄清楚,免的再次遇到这个问题,却依然糊里糊涂。
7202 0
|
数据可视化 算法 数据挖掘
Python、R对小说进行文本挖掘和层次聚类可视化分析案例
Python、R对小说进行文本挖掘和层次聚类可视化分析案例