关于单片机的using使用

发布者:彩虹微笑最新更新时间:2016-07-01 来源: eefocus关键字:单片机  using 手机看文章 扫描二维码
随时随地手机看文章
C51的中断函数的格式为:void FuncIr(void) interrupt x [using y]
以下是梦游的一些分析:
      一、中断函数是一个特殊的函数,没有参数,也没有返回值;但是程序中允不允许使用return呢?答案是允许的,不过只能用"return;",不能用"return(z);";用在一些需要快速返回的地方,对应的汇编会有多个ret语句,相对效率会高一些。
      二、using的用法,using可以修饰任何函数,不过个人建议只用来修饰中断函数;简单的说,“using”会指定工作寄存器组,由于中断函数一般都是比较紧急的事情,有时一条语句都会斤斤计较,所以使用using切换寄存器组可以省去一些压栈的动作,由于51只有两级中断,同级中断不能被打断,因此,我们可以同级中断设成同样的寄存器组,从某种意义上来说,有一组寄存器是多余的。同时个人建议中断函数应该使用using这个关键字。
      三、中断中调用函数,首先要讨论中断函数中调用函数的必要性,前天在论坛上我和别人争论过这个问题,现在我还是这个观点:有些情况中断中调用函数还是必要的,这个时候是不是该调用函数,其实和普通函数差不多,首先是这个函数如果调用多次,或者要带一些参数什么的就更加必要的;前天有人跟我叫劲,说假如只调用一次且无参数无返回的函数要直接写,因为如果用函数,至少会增加CALL和RET两条语句,我不敢苟同,我是实际调试发现的,当你程序比较复杂时,你将那部单独拉出来做成函数,可能代码和时间都会更好。
      四、中断中调用的函数最好不要被中断外的其它函数调用,因为会出现“重复调用”的警告,有时这种调用是很致命的,有人说这个函数可以用reentrant来修饰,是的,的确可以这样解决,不过个人不建议这么做,也许这样会跟你减少很多堆栈空间,并且整个程序的优化要差很多,个人建议出现这种情况就把这个函数写两遍,分成两个函数分别调用。
        五、中断调用了函数,会出现一些莫名其妙的问题,一些数据不对(我现在遇到这个问题)其实一般是因为汇编中使用了绝对寄存器引起的,有人说中断函数使用那个寄存器组,被中断调用的函数就使用哪个寄存器组(我认为好参考C51.PDF:Functions called from an interrupt procedure must function with the same register bank as the interrupt procedure. When the NOAREGS directive is not explicitly specified, the compiler may generate absolute register accesses using the register bank selected (by the using attribute or by the REGISTERBANK control) for that function. Unpredictable results may occur when a function assumes a register bank other than the one currently selected. Refer to “Register Bank Access” on page 124 for more information.),我认为这样不好:
      这样会增加额外的消耗,使用using会增加一下语句:
       PUSH PSW
       MOV PSW, #XX
        ....
        POP PSW
      更重要的是,使用using的函数不能有返回值(这个地方有问题,应该可以有返回值,下文说是不能不能返回bit类型的值),这是致命伤(所以这不是致命伤,可以使用using解决这个问题)
      个人推荐的方法有两种:
       1、使用“#pragma NOAREGS”禁止使用绝对寄存器
       2、使用“#pragme RB(x)”来指定本文件的工作寄存器组
      六、一般说来,要求中断函数尽可能的短,但也有特殊情况,有些前/后台的系统中,就会把很多相对重要的事情放到定时中断(这个定时中断类似实时操作系统中的时钟节拍)去做,而且程序很长。我单独提出来这点是想告诉大家,中断函数也是一个函数而已,只要系统有必要,可以做一些看似不合理的事情,该出手时就出手,就像goto语句一样。

 

转自http://www.ednchina.com/blog/hotchip/,请大家去他的博客中支持他,里面有不错的文章。括号中是我的理解
关于using:
举个例子来说:
定义一个函数
void func(unsigned char i) {
...
}
有如下一个中断函数
void int_0(void) interrupt 0 using 1 {
....
}
在默认状态下,func使用寄存器组0(BANK0),那么当int_0调用func时是否存在当传递参数时会造成参数传递错误?
如果在中断服务函数ISR中使用寄存器,那么必须处理好using的使用问题:
1、中断服务函数使用using指定与主函数不同的寄存器组(主函数一般使用Register bank 0)。
2、中断优先级相同的ISR可用using指定相同的寄存器组,但优先级不同的ISR必须使用不同的寄存器组,在ISR中被调用的函数也要使用using指定与中断函数相同的寄存器组。(应该是这样的)
3、如果不用using指定,在ISR的入口,C51默认选择寄存器组0,这相当于中断服务程序的入口首先执行指令:
MOV PSW #0
这点保证了,没使用using指定的高优先级中断。可以中断使用不同的寄存器组的低优先级中断。
4、使用using关键字给中断指定寄存器组,这样直接切换寄存器组而不必进行大量的PUSH和POP操作,可以节省RAM空间,加速MCU执行时间。寄存器组的切换,总的来说比较容易出错,要对内存的使用情况有比较清晰的认识,其正确性要由你自己来保证。特别在程序中有直接地址访问的时候,一定要小心谨慎!至于“什么时候要用到寄存器组切换”,一种情况是:当你试图让两个(或以上)作业同时运行,而且它们的现场需要一些隔离的时候,就会用上了。在ISR或使用实时操作系统RTOS中,寄存器非常有用。
寄存器组使用的原则:
1、8051的最低32个字节分成4组8寄存器。分别为寄存器R0到R7。寄存器组由PSW的低两位选择。在ISR中,MCU可以切换到一个不同的寄存器组。对寄存器组的访问不可位寻址,C51编译器规定使用using或禁止中断的函数(#pragma disable)均不能返回bit类型的值。
2、主程序(main函数)使用一组,如bank 0;低中断优先级的所有中断均使用第二组,如bank 1;高中断优先级的所有中断均使用再另外一组,如bank 2。显然,同级别的中断使用同一组寄存器不会有问题,因为不会发生中断嵌套;而高优先级的中断则要使用与低优先级中断不同的一组,因为有可能出现在低优先级中断中发生高优先级中断的情况。编译器会自动判断何时可使用绝对寄存器存取。
3、在ISR中调用其它函数,必须和中断使用相同的寄存器组。当没用NOAREGS命令做明确的声明,编译器将使用绝对寄存器寻址方式访问函数选定(即用using或REGISTERBANK指定)的寄存器组,当函数假定的和实际所选的寄存器组不同时,将产生不可预知的结果,从而可能出现参数传递错误,返回值可能会在错误的寄存器组中。
举一例子:当需要在中断内和中断外调用同一个函数,假定按照程序的流程控制,不会出现函数的递归调用现象,这样的调用会不会出现问题?若确定不会发生重入情况,则有以下两种情况:
1、如果ISR和主程序使用同一寄存器组(主程序缺省使用BANK 0,若ISR没有使用using为其指定寄存器区,则缺省也使用BANK 0),则不需其他设置。
2、如果ISR和主程序使用不同的寄存器组(主程序缺省使用BANK 0,ISR使用using指定了其他BANK),则被调用函数必须放在:
#pragma NOAREGS
#pragma AREGS
控制参数对中,指定编译器不要对该函数使用绝对寄存器寻址方式;或者也可在Options->C51,选中“Don''t use absolute register accesses”,使所有代码均不使用绝对寄存器寻址方式(这样,执行效率将稍有降低)。不论以上的哪一种情况,编译器均会给出重入警告,需手工更改OVERLAY参数,做重入说明。
3、还有一种办法:如果被调用函数的代码不是很长,还是将该函数复制一份,用不同的函数名代替,这种情况适合ROM有足够多余的空间。
因此,对using关键字的使用,如果没把握,宁可不用,交给编译系统自己去处理好了。

 

 

例子

用上using可以精简代码,节省堆栈,不过有时会出现一个问题:
用上using ,在中断服务程序里调用函数要小心一点,因为keil C有时会产生依赖绝对地址的代码,例如如下函数,功能是从片外的存储设备中读取一个字节:
uchar ReadByte(uchar address)
{
  retrun PBYTE[address];
}
会被编译成如下代码:
  MOV      R0,0x07
  MOVX     A,@R0
  MOV      R7,A
这时,如果在中断服务程序里调用 ReadByte(0xAA); 就会发现读出的数据根本不对,因为using 1使得中断服务程序在调用函数时使用第一组寄存器传递参数,编译器生成的代码如下:
  MOV      R7,#0xAA
  LCALL    ReadByte
而ReadByte这个函数的代码是使用绝对地址为0x07的第0组寄存器的R7来传递参数的,所以会出问题。
解决方法是在定义ReadByte这个函数的前面加上"#pragma noaregs",这样编译器就会生成不依赖于绝对地址的代码了,函数ReadByte被编译生成的代码如下:
XCH      A,R0
MOV      A,R7
XCH      A,R0
MOVX     A,@R0
MOV      R7,A
这样就可以大胆的使用using了,使用using才是充分利用51架构的使用方法。

关键字:单片机  using 引用地址:关于单片机的using使用

上一篇:深入C51中断向量表
下一篇:KELl警告: MULTIPLE CALL TO SEGMENT

推荐阅读最新更新时间:2024-03-16 14:59

NEC电子新款32位闪存微控制器产品,功耗降低50%
           ~低功耗的全闪存微控制器全新问世~ NEC电子日前完成了8款低功耗版32位闪存微控制器的开发,并将其作为全闪存微控制器的第一阶段产品,于即日起开始供应样品。此次推出的系列产品共包括4款V850ES/JG3-L产品和4款V850ES/JF3-L产品,它们均使用了低功耗技术,因此功耗仅为现有产品的一半左右。 新系列产品以32位全闪存微控制器“V850ES/JG3”为基础,大幅度降低了功耗。该系列产品的最大优势在于功耗由以往的1.7mW/MIPS降低至0.9 mW/MIPS,该功耗值不仅约为NEC电子以往同类产品的一半,而且低于普通16位微控制器的1MIPS的平均功耗值的一半。 通过使用新产品,用户不仅可以用更小
[新品]
8051单片机教程第二十一课:串行接口
概述 串行接口的一般概念单片机与外界进行信息交换称之为通讯。 8051单片机的通讯方式有两种: 并行通讯:数据的各位同时发送或接收。串行通讯:数据一位一位顺序发送或接收。参看下图: 串行通讯的方式: 异步通讯:它用一个起始位表示字符的开始,用停止位表示字符的结束。其每帧的格式如下: 在一帧格式中,先是一个起始位0,然后是8个数据位,规定低位在前,高位在后,接下来是奇偶校验位(可以省略),最后是停止位1。用这种格式表示字符,则字符可以一个接一个地传送。 在异步通讯中,CPU与外设之间必须有两项规定,即字符格式和波特率。字符格式的规定是双方能够在对同一种0和1的串理解成同一种意义。原则上字符格式可以由通讯的
[单片机]
8051<font color='red'>单片机</font>教程第二十一课:串行接口
浅谈单片机最小系统
单片机最小系统 我们已经大概知道了单片机是一个什么东西,那么接下来我们就正式开始单片机的学习吧。 单片机是一门实践性很强的课程,假如单纯的去学习理论知识,而不实践,是很难完全把握单片机的。 单片机虽然是一个只能化的集成芯片,其本质上还是一个电子元件的。既然是电子元件,那么,就必须在一定的电路中才能运行起来,才能实现它的功能。这就像电阻一样,如果把一个电阻独立的放着,是没有任何意义的,只有将电阻接在电路中,才能实现它的功能,毕竟是分压,分流,还是限流,还得看详细电路。 单片机里虽然集成了很多电路,但仍旧不能独立运行,必须要外连一些电路,才能使单片机运行起来。这种能使单片机工作的最简电路,我们叫做单片机最小系
[模拟电子]
PIC32单片机IO口操作之LED灯
#include plib.h #define uchar unsigned char #define uint unsigned int /*void delay(uint x) { uint a,b; for(a=x;a 0;a--) for(b=110;b 0;b--); } int main(void) { TRISB=0x00;//设置端口输出;可以参看数据手册 while(1) { PORTB=0x3C00;//四个控制LED的端口输出高电平; delay(100); PORTB=0x00;//关闭LED delay(100); } }//以上代码实现了LED灯的同时闪烁。*/ /*void delay(uint
[单片机]
单片机的ISP在线编程设计
  随着电子技术的日益发展,芯片的规模越来越大,封装日趋小型化,相应地对系统板级调试的困难也在加大。在传统的调试方式中,频繁的调试和更换程序需要频繁地插拔芯片,开发效率极低。AT89S系列单片机提供的ISP在线编程技术彻底地改变了传统的开发模式,开发单片机系统时不会损坏芯片的引脚,加速了产品的上市并降低了研发成本,缩短了从设计、制造到现场调试的时间,简化了生产流程,大大提高了工作效率,因此它是对市场定型产品进行现场升级和维护的经济、有效的方式,极大地促进了PLD产品的发展。 1 PC机并行口 1.1 并行口硬件接口简介   标准并行口有25个引脚,其中数据端口引脚为2~9,状态端口引脚为15、10~13,控制端口引脚1、14
[单片机]
<font color='red'>单片机</font>的ISP在线编程设计
基于硅压式传感器和MSP430F149单片机的电子血压计设计
  1 引言   测量血压的传统仪器是机械式水银血压计,电子血压计近几年才在市场上出现。电子血压计与传统血压计相比,虽然操作简单、使用方便,但准确性、稳定性往往不太理想。本设计力求准确、稳定,以适用于老年人或病人随时监测自己血压情况及临床医学检测。   2 系统的硬件设计   本设计采用Motorola公司的MPX53GC硅压式传感器和TI公司MSP430F149单片机为主要器件, 构成电子血压计,系统构成如图1。系统由MCU、 传感器、LCD液晶显示器、操作面板、充放气控制 电路、气泵和气阀、蜂鸣器、存贮器、电源等部分 构成。      2.1 微处理器的选择   单片机是整个系统的大脑,它不仅要对系统进 行
[单片机]
基于硅压式传感器和MSP430F149<font color='red'>单片机</font>的电子血压计设计
NXP:微控制器在边缘人工智能中扮演着越来越重要的角色
就在几年前,人们还认为机器学习(ML)甚至深度学习(DL)只能在高端硬件上执行,在边缘侧需要通过网关、边缘服务器或数据中心执行训练和推理,这在当时是一个主流观念,因为在云和边缘之间研究如何分配计算资源还处于早期阶段。但由于工业界和学术界的深入研究和开发努力,这种情况已经发生了巨大的变化。 如今,最新的微控制器(其中一些带有嵌入式ML加速器)可以将ML带到边缘设备中,性能也很强大,已经可以达到数TOPS了。 这些设备不仅可以执行ML,而且还可以以低成本、低功耗、仅在绝对必要时才连接到云端的特性。简言之,集成了ML加速器的微控制器代表了下一步,将计算应用到麦克风、摄像头和监控环境条件的传感器上,这些传感器产生的数据将在模块中就
[单片机]
NXP:<font color='red'>微控制器</font>在边缘人工智能中扮演着越来越重要的角色
基于单片机控制的高精密直流电流源的设计
高精密电流源能为精密仪器提供精度较高的电流供给,适用于半导体和材料科学研究中各种电阻的自动测量任务。具体应用中,对电流源的精度、可控性要求较高,使用单片机控制的高精密电流源设计,相对于现行的其他设计方法而言,可以较好地满足上述要求,并且具有设计容易、性价比高、开发周期短等特点。本设计使用了ATMEL公司生产的AT89S系列高性价比的52单片机进行设计,体积轻小,实用性强,具有很好的应用前景。 1 系统组成及工作原理 本设计通过 AT89S52 单片机实现对D/A转换芯片DAC714和A/D转换芯片TLC2543的控制,来产生直流电压信号,经输出采样电路的电压/电流转换、放大,输出稳定的直流电流。系统中使用D/A输出
[电源管理]
基于<font color='red'>单片机</font>控制的高精密直流电流源的设计
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved