社区导航

 

搜索
查看: 3995|回复: 0

在IAR编译器中使用NEC 78K0系列单片机_转

[复制链接]

22

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2010-11-12 11:39 | 显示全部楼层 |阅读模式
在IAR编译器中使用NEC 78K0系列单片机_转
 
最近在IAR编译器下针对NEC的78K0系列单片机作了一些开发。主要原因是IAR的编译器确实编译效果不错啊。最大体现就是编译出的代码空间比较小。毕竟人家是专门做编译器的。
    下面是最近学会的一些扩展功能,写出来共享。如果以后会用其它功能的的话,我会及时更新。
1、__disable_interrupt();__enable_interrupt();
这两个大家一看应该就知道是干什么用的了——禁止中断和使能中断的。
2、#pragma constseg = OPTBYTE
__root const CPU_CHAR OptionByte[5]=
{
    0x00,
    0x00,
    0x00,
    0x00,
    0x02
};
#pragma constseg = default

使用NEC单片机的工程师知道,NEC的单片机里面有option byte这个东东。那么在IAR编译器里面怎么设置option byte呢?如上所示。感觉IAR编译器把OPTBYTE也做成一个关键字了。

/* set the OPTION BYTE 0080-0084*/
/* WDTON Counter operation enabled   217/fRL (496.48 ms)   Watchdog timer window open period 100%*/
/* On-chip debug operation control enabled*/
/*
#pragma constseg=OPTBYTE
__root unsigned char
ucOptionBytes[5]={0x7e,0x00,0x00,0x00,0x03};
#pragma constseg=default
*/

3、__saddr unsigned char tick_10ms;
之前我介绍过,在NEC的单片机里有短地址直接寻址区域,如果想把变量放在这个区域的话,在IAR编译器中是按照上述的格式书写的。如果你还不太清楚短地址直接寻址区域,可以去看俺前面的文章。
4、__root const unsigned char SecuIDCode[]   @ 0x0085 = {
       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

想把常量放在某个固定的地址,参考上面的格式就可以了。只要把0x0085改成你期望的地址就行了。

=========================================

如何使用C的扩展功能-78K0(1)

    使用单片机,一个很重要的体现就是要写程序(废话)。由于现在的单片机中的程序存储空间都比较大了,所以开发人员可以不再像最初阶段那样斤斤计较程序的大小,这样C语言就登上舞台了。同时,考虑到程序的可移植性和可读性,现在越来越多的公司和个人都开始弃汇编而择C语言了。
    使用C语言编写单片机程序的时候,针对各个厂家的单片机编程都会有一些特殊的使用方法。而这些方法是不一样的,因为他们不是标准C规定的。为了让大家能更好的、更容易的使用C语言编程、使用NEC的单片机,从现在开始我将逐一介绍大家编程中常用到的一些C的扩展功能。
    首先,介绍如何使用寄存器。
    寄存器是单片机的一个特点,只要你使用单片机,就不可避免的与寄存器打交道。我们知道在汇编里可以直接使用寄存器,可是标准C里面并没有规定如何使用寄存器(这个也比较难规定,因为各个厂家的寄存器着实相差太大。),那么在C语言里怎么使用这些寄存器呢?
    NEC的编译器里面使用寄存器比较简单,只要在文件的开始写一句#pragma sfr,那么这个文件之后就都可以使用寄存器了。多了不再罗嗦了,下面给出一个例子,相信你一看就明白了。——什么?不明白?本人本着诲人不倦的态度,你找地方,我单独给你开班。
#pragma sfr
void main(void)
{
    IMS = 0xcc;
    IXS = 0x00;

    while(1);
}

如何使用C的扩展功能-78K0(2)

    中断功能是单片机很有特点的一个功能,如果使用单片机不使用中断的话,那么单片机的魅力将会大大降低。
    那么在C语言里面怎么怎么使用中断功能呢,同样,下面给一个例子:
#pragma interrupt INTP0 isr_intp0
__interrupt void isr_intp0()
{
    ......;
}
    其中INTP0是中断的名称,isr_intp0是中断服务函数,通过上面的声明就把中断INTP0和函数isr_intp0关联到一起来。对于__interrupt这个关键字我之前试验是可有可无的,不过为了增强程序的可读性,让人一看就知道这是个中断服务函数,那么还是加上比较方便一些,反正也费不了多少事。

你还不知道什么是中断?对不起,找本单片机的书看看吧,任何单片机的书籍里面都有介绍。或者单独与我联系。

如何使用C的扩展功能-78K0(3)

    有一些特殊的指令是针对汇编层面而设定的,这些指令的诸如如何使能和禁止中断等。在这里我列出几个常见指令的使用方法,如果大家在使用的过程中还需要其他的指令,也可以提醒我,看看我之前发现没有。
    一起交流,共同进步!
#pragma HALT
#pragma STOP
#pragma BRK
#pragma NOP
#pragma DI
#pragma EI
void main(void)
{
    DI();
    EI();

    HALT();
    STOP();
    BRK();
    NOP();
}

如何使用C的扩展功能-78K0(4)

    C和汇编混合编程是单片机编程常用到的一种情况。因为虽然使用C语言编程有很多我们熟悉的优点,但是汇编的优势同样是无法取代的。比如汇编的效率会比较高。
    接下来介绍如何在C语言中嵌入汇编。有两种方法,如下:
#pragma asm
void main(void)
{
    #asm
    NOP;
    #endasm
    __asm("\tmovw ax, !_a \t;ax <- a");
    __asm("\tmovw !_b, ax \t;b <- ax");
    while(1);
}

同样,需要在前面声明一下:#pragma asm。main函数里面介绍的是两种嵌入汇编的方法。

分享 如何使用C的扩展功能-78K0(callt/callf)

在NEC的单片机里面,有两块比较特殊的区域,一个是从40H-7FH;另一块是800H-FFFH。前一块区域叫做CALLT区域,后一块区域叫做CALLF区域。
我们先不管这两块名字的由来,因为就个人来看,名字完全是当年起名人的一时兴致使然。
说一下这两两个函数的特点:
CALLT函数:
定义一个函数的时候,如果前面加上关键字callt/__callt,那么这个函数就是callt函数了。callt函数会把函数的入口地址放在40H-7FH,每个函数占用两个字节,这个很好理解。当我们调用函数时,系统会自动地找到函数入口地址并且跳向调用的函数。那么,这个函数有什么好处呢?一、调用的指令之产生一个字节,因为40H-7FH区域寻址只要6位就可以了(其实真正用到的是5位,因为最后一位是0,以保证偶地址对起),还有两位做指令码。二、速度更快。
CALLF函数:
定义方式同callt。callf函数会把函数体放在800H-FFFH。该函数调用的时候是两字节指令,所以同样可以节省代码空间,再者速度快。
速度:callt 〉callf 〉call
代码:callt 〈callf〈 call
既然callt和callf函数这么好,我们把所有的函数都定义成这两种函数不就得了吗。
想法是好的,可现实往往是残酷的。
因为上述两个区域的大小都是有限制的,所以这两种函数的个数也是有限制的。
callt不能超过32个。callf函数总的大小不能超过2K。
所以,我们应该将那些经常调用的函数定义成callt和callf函数。
__callt int tsub(void);
__callf int tadd(void);
void main()
{
    ret_num = tadd();
    ret_val = tsub();
    ret_data = tmul();
    while(1);
}
__callt int tsub(void)
{
    int val;

    return val;
}
__callf int tadd(void)
{
int num;
return num;
}
int tmul(void)
{
int data;
return data;
}

如何使用C的扩展功能-78K0(指定变量或代码的存放地址)

有时候我们希望把有些数据或者代码放在某个特定的地址,那么如何来实现这个功能呢?
下面介绍一种在C语言层面实现的方法。
实现这个功能主要就是使用如下一条语句:
#pragma section @@**** xxxx AT address
#pragma section:固定部分,只要实现这个功能先把这个写上。
@@****:这是个很关键的部分,用于说明这条语句是对那些属性的数据起作用的。
比如:@@CODE:表示对这条语句后面的代码起作用。
      @@DATA:表示对这条语句后面不带初始值的变量起作用。
      @@INIT:表示对这条语句后面带初始值的变量起作用。
      @@CNST:表示对这条语句后面的常量起作用。
这样的关键字大概有十几个,但是一般用得着的也就这个。
如果你对其他的关键字感兴趣的话,可以参考手册NEC单片机安装工具自带的手册——C language的附录部分。
xxxx:段的名称,其一个你自己喜欢的名称就可以了。
AT: 固定部分。
address:指定从哪个地址开始放。
#pragma section @@DATA   ??DATA
#pragma section @@CNST   ??CNST AT 9000H
      int    a1;            
sreg int    b1;             
      int    c1 = 1;        
      const int    d1 = 2;        
#pragma section @@DATS   ??DATS
      int    a2;            
sreg int    b2;             
      int    c2 = 3;        
       const int    d2 = 4;        
#pragma section @@DATA   ??DATA2
#pragma section @@CNST   ??CNST AT 7000H
      int    a3;            
sreg int    b3;             
      int    c3 = 5;        
const int    d3 = 6;        

#pragma section @@DATA   @@DATA

#pragma section @@INIT   ??INIT
#pragma section @@R_INIT ??R_INIT AT 2000H
      int    a4;            
sreg int    b4;             
      int    c4 = 7;        
const int    d4 = 8;        
#pragma section @@INIT   @@INIT
#pragma section @@R_INIT @@R_INIT
#pragma section @@BITS   ??BITS
__boolean    e4;             // ??BITS
int a;
#pragma section @@DATA DAT1 AT 0e000H
int b;
sreg int c;
#pragma section @@DATA DAT2 AT 0FB20H
int d;
#pragma section @@CNST   ??CNST
char *const p   = "Hello";

void main ()
{
b++;
   while (1)
   {b++;
   d++;
   c4++;
   }
}

如何使用C的扩展功能-78K0(变量短直接寻址)

这个功能是不说不知道,一说。。。。。。。。也不奇妙。
在NEC的单片机里有块RAM使用的短直接寻址,如果把变量放在这个区域,那么对变量进行存取的时候速度会快一些。
方法很简单,只要在定义变量的时候在前面加上一个关键字sreg,那么变量就被分配到这个特殊的RAM区域了。
顺便说一下,这个区域的RAM是可以位操作的,所以前面说的位变量也是放在这个区域的。
而这个区域一般不用做堆栈,所以就位变量也就不能定义成局部变量了。
#pragma sfr
sreg int hsmm0, hsmm1;

void main( ) {
    hsmm0 -= hsmm1;
    while(1);
}

此帖出自单片机论坛

您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐上一条 /5 下一条

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2020-2-24 13:52 , Processed in 0.094266 second(s), 19 queries , Gzip On, MemCache On.

快速回复 返回顶部 返回列表