EDN首页   博客首页

最新日志

发表于:2007-3-26 16:47:16
标签:AVR  

6

AVR读写外部RAM时出现的问题

AVR读写外部RAM时出现的问题

问:
1
,对AT90S8515来说,外部RAM的地址肯定是从0x0260开始的?
2
,我用ICE200仿真8515读写外部RAMRAM大小为32K Bytes,地址映射到0x0000-0x7fff,PC7做它的片选。把SRE置为1,当我访问0x0300PC7为低,这是对的,但当我不去访问0x0000-0x7fff地址空间时(例如进入死循环),问题出现了,此时PC7仍为低,按道理应为高的。这是阿AVR51的不同,还是我弄错了。

答:
1
、对AT90S8515来说,外部RAM的地址肯定是从0x0260开始的。这是没问题的,访问0x0000-0x025F的地址为内部RAM
2
、当你访问过0x0300PC7为低,当你不访问0x0000-0x7FFF时,由于没有一条把PC7置高的指令,所以PC7当然还为低了。不过这也不要紧,因为当你访问0x0000-0x025F的时候,RDWR是没有的,所以即使外部RAM被选中了,没不会产生读写。当你访问0x0260-0x7FFF的时候,RDWR就自动产生了。所以就是你把外部RAMCS直接接地也是可以的。

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 转贴

评论(1) | 阅读(794)
发表于:2007-3-26 15:45:57
标签:avr  

5

理解#defineSREG(*(volatileunsignedchar*)0x5F

以前看到#define SREG    (*(volatile unsigned char *)0x5F)
这样的定义,总是感觉很奇怪,不知道为什么,今天终于有了一点点心得,请大虾们多多批砖~~~

   嵌入式系统编程,要求程序员能够利用C语言访问固定的内存地址。既然是个地址,那么按照C语言的语法规则,这个表示地址的量应该是指针类型。所以,知道要访问的内存地址后,比如0x5F,
   第一步是要把它强制转换为指针类型
 (unsigned char *)0x5F,AVR的SREG是八位寄存器,所以0x5F强制转换为指向unsigned char类型。
   volatile(可变的)这个关键字说明这变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值了。这种“意想不到地改变”,不是由程序去改变,而是由硬件去改变——意想不到。
   第二步,对指针变量解引用,就能操作指针所指向的地址的内容了
*(volatile unsigned char *)0x5F
   第三步,小心地把#define宏中的参数用括号括起来,这是一个很好的习惯,所以:                     #define SREG    (*(volatile unsigned char *)0x5F)
    类似的,如果使用一个32位处理器,要对一个32位的内存地址进行访问,可以这样定义:                #define RAM_ADDR     (*(volatile unsigned long  *)0x0000555F)
    然后就可以用C语言对这个内存地址进行读写操作了
    读:tmp = RAM_ADDR;
    写:RAM_ADDR = 0x55;

定义volatile是因为它的值可能会改变,大家都知道为什么改变了;
如果在一个循环操作中需要不停地判断一个内存数据,例如要等待SREG的I标志位置位,因为SREG也是映射在SRAM空间,为了加快速度,编译器可能会编译出这样的代码:把SREG读取到Register中,然后不停地判断Register相应位。而不会再读取SREG,这样当然是不行了,因为程序或其它事件(中断等)会改变SREG,结果很可能是一个死循环出不来了。如果定义成volatile型变量,编译的代码是这样的:每次要操作一个变量的时候都从内存中读取一次。
#define SREG (*(volatile unsigned char *)0x5F) 之后,可以进行如下基本操作,
unsigned char temp,*ptr;
temp=SREG;把SREG值保存到temp中
SREG=temp;把temp的值赋给SREG
ptr = & SREG; 不知对否,大家试一下。

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(704)
发表于:2007-3-26 12:56:10
标签:AVR  

4

AVR复位和中断处理

AVR提供了几种不同的中断源。这些中断和复位向量在程序存储器空间内都有自己单独的程序向量。所有中断都被分配一个私有的使能位,要想使能某一中断,就要向其使能位写入逻辑1,而且要把状态寄存器中的全局中断使能位置1。

    程序存储器空间最低的一些地址,被默认定义为复位和中断向量。完整的向量列表见“中断”部分。该列表也决定了不同中断的优先级。地址越小,优先级越高。RESET具有最高的优先级,其次是INT0——外部中断请求0。详细讨论见“中断”部分。

    当某个中断产生时,全局中断使能位I被清零,所有中断都被禁止。用户程序可以向I位写入1,以实现中断嵌套。所有已使能的中断就可以中断当前的中断程序。当从中断指令——RETI——的执行返回时,I位被自动置位。

    基本上有两种类型的中断。第一种是由事件触发的,把中断标志置位。对于这些中断,程序计数器被引导到实际的中断向量,以执行中断处理程序,同时硬件把相应的中断标志清除。通过向要清除的标志位位置写一个逻辑1,也可以被清除中断标志。如果中断使能位被清除后,相应的中断条件发生时,中断标志将被设置,而后保持到中断被使能为止,或者由软件把标志清除。类似地,如果在全局中断使能位被清除后,一个或多个中断条件产生时,相应的中断标志将被设置,并保持到全局中断使能位被设置为止,然后按优先级顺序执行。

    第二种中断,只要中断条件存在,就会被触发。这些中断没有必要具有中断标志。如果中断条件在中断被使能前消失,那么中断将不被触发。

    当AVR从一个中断中退出时,它一般会返回主程序,并且执行再执行一条指令后,才会响应后续的中断。

    注意,当进入中断程序时状态寄存器不会自动保存,当从中断程序返回时,它也不会自动恢复。这必须由用户软件来完成。

    当使用CLI指令禁能中断时,中断将立即被禁能。当CLI指令执行后,将没有中断再被执行,即使中断在CLI执行的同时发生。下例所示为怎样使用CLI指令来避免在定时的EEPROM写时序期间避免产生中断。

 汇编代码例子
  in      r16, SREG              ; 保存SREG值 
  cli            ; 在定时程序中禁能中断
  sbi    EECR, EEMWE    ; 开始写入EEPROM
  sbi    EECR, EEWE
  out    SREG, R16            ; 恢复SREG值(I位)
C代码例子
  char    cSREG;
  cSREG = SREG;     /* 保存SREG值*/ 
  /* 在定时程序中禁能中断 */
  _CLI ();
  EECR  |= (1<  EECR  |= (1<  SREG  =  cSREG;                /* 恢复SREG值(I位) */

当使用SEI指令来使能中断时,紧跟在SEI后面的指令将在任何后续的中断前被执行,示例如下。

 汇编代码例子
 sei     ; 置位全局中断使能
 sleep ; 进入休眠,等待中断
 ; 注意:将在任意中断前进入休眠
 C代码例子
   _SEI();         /* 置位全局中断使能
   _SLEEP();  /* 进入休眠,等待中断 */
  /* 注意:将在任意中断前进入休眠 */

中断响应时间

    对于所有使能的AVR中断,中断执行响应最少为四个时钟周期。在四个时钟周期之后,实际中断处理程序的向量地址被执行。在这四个时钟周期内,程序指针(PC)被压入堆栈。该失量正常为一到中断程序的跳转,并且该跳转花费三个时钟周期。如果中断发生在一个多周期指令的执行期间,在中断被响应前,该指令要执行完毕。如果当MCU在休眠模式中有中断产生,那么该中断响应时间要再增加四个时钟周期。这是由于从选择的睡眠模式中唤醒需要启动时间。

    从中断处理程序返回需要四个时钟周期。在这四个时钟周期内,程序指针(两个字节)从堆栈中被弹出,堆栈指针加2,SREG的I位被置位。

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(849)
发表于:2007-3-26 0:28:36
标签:IAR  红外遥控  

4

红外线遥控原理


作者:微电  出处:微电通讯  更新时间: 2006年07月14日   
 
 
    红外线遥控是目前使用最广泛的一种通信和遥控手段。由于红外线遥控装置具有体积小、功耗低、功能强、成本低等特点,因而,继彩电、录像机之后,在录音机、音响设备、空凋机以及玩具等其它小型电器装置上也纷纷采用红外线遥控。工业设备中,在高压、辐射、有毒气体、粉尘等环境下,采用红外线遥控不仅完全可靠而且能有效地隔离电气干扰。

1 红外遥控系统

    通用红外遥控系统由发射和接收两大部分组成,应用编/解码专用集成电路芯片来进行控制操作,如图1所示。发射部分包括键盘矩阵、编码调制、LED红外发送器;接收部分包括光、电转换放大器、解调、解码电路。

2 遥控发射器及其编码

    遥控发射器专用芯片很多,根据编码格式可以分成两大类,这里我们以运用比较广泛,解码比较容易的一类来加以说明,现以日本NEC的uPD6121G组成发射电路为例说明编码原理。当发射器按键按下后,即有遥控码发出,所按的键不同遥控编码也不同。这种遥控码具有以下特征:

采用脉宽调制的串行码,以脉宽为0.565ms、间隔0.56ms、周期为1.125ms的组合表示二进制的“0”;以脉宽为0.565ms、间隔1.685ms、周期为2.25ms的组合表示二进制的“1”,其波形如图2所示。

    上述“0”和“1”组成的32位二进制码经38kHz的载频进行二次调制以提高发射效率,达到降低电源功耗的目的。然后再通过红外发射二极管产生红外线向空间发射,如图3所示。

    UPD6121G产生的遥控编码是连续的32位二进制码组,其中前16位为用户识别码,能区别不同的电器设备,防止不同机种遥控码互相干扰。该芯片的用户识别码固定为十六进制01H;后16位为8位操作码(功能码)及其反码。UPD6121G最多额128种不同组合的编码。

    遥控器在按键按下后,周期性地发出同一种32位二进制码,周期约为108ms。一组码本身的持续时间随它包含的二进制“0”和“1”的个数不同而不同,大约在45~63ms之间,图4为发射波形图。

    当一个键按下超过36ms,振荡器使芯片激活,将发射一组108ms的编码脉冲,这108ms发射代码由一个起始码(9ms),一个结果码(4.5ms),低8位地址码(9ms~18ms),高8位地址码(9ms~18ms),8位数据码(9ms~18ms)和这8位数据的反码(9ms~18ms)组成。如果键按下超过108ms仍未松开,接下来发射的代码(连发代码)将仅由起始码(9ms)和结束码(2.5ms)组成。

代码格式(以接收代码为准,接收代码与发射代码反向)
①位定义
        
②单发代码格式 
     
③连发代码格式

注:代码宽度算法:

16位地址码的最短宽度:1.12×16=18ms 16位地址码的最长宽度:2.24ms×16=36ms

易知8位数据代码及其8位反代码的宽度和不变:(1.12ms+2.24ms)×8=27ms

∴32位代码的宽度为(18ms+27ms)~(36ms+27ms)

1. 解码的关键是如何识别“0”和“1”,从位的定义我们可以发现“0”、“1”均以0.56ms的低电平开始,不同的是高电平的宽度不同,“0”为0.56ms,“1”为1.68ms,所以必须根据高电平的宽度区别“0”和“1”。如果从0.56ms低电平过后,开始延时,0.56ms以后,若读到的电平为低,说明该位为“0”,反之则为“1”,为了可靠起见,延时必须比0.56ms长些,但又不能超过1.12ms,否则如果该位为“0”,读到的已是下一位的高电平,因此取(1.12ms+0.56ms)/2=0.84ms最为可靠,一般取0.84ms左右均可。

2. 根据码的格式,应该等待9ms的起始码和4.5ms的结果码完成后才能读码。

接收器及解码

    一体化红外线接收器是一种集红外线接收和放大于一体,不需要任何外接元件,就能完成从红外线接收到输出与TTL电平信号兼容的所有工作,而体积和普通的塑封三极管大小一样,它适合于各种红外线遥控和红外线数据传输。



点击此处查看原文 >>

系统分类: 模拟技术   |    用户分类:    |    来源: 转贴

评论(1) | 阅读(2649)
发表于:2007-3-26 0:22:41
标签:AVR  

4

AVR中断应用设计要点

AVR的中断源比较多,尤其是ATmega128,一共有35个外部以及内部中断源。通常情况下,Flash程序存储器空间的最低位置(0x0000-0x0045)定义为复位和中断向量空间。完整的中断向量见第二章表2-23。在中断向量表中,处于低地址的中断向量所对应的中断拥有高优先级,所以,系统复位RESET拥有最高优先级。
http://images.51.com/a/200609/e0/e4/vickyguan888/d4d8a78b82d53db8c723e2b346e83b3f.gif

A.中断设计注意点:
1.具备Bootloader功能的AVR,其中断向量区可以在Flash程序存储器空间最低位置和Bootloader区的头部来回迁移,这主要用于配合Bootloader程序的应用。如果不使用Bootloader功能,一般不要中断向量区进行迁移。

2.Flash较小的AVR芯片,其一个中断向量占据1个字的空间,用于放置一条相对转移RJMP指令(范围-2K~+2K字),跳到中断服务程序。对于不使用的中断,在中断向量区中应放置1条中断返回指令RETI,增强程序的抗干扰性。

3.ATmega128的Flash空间为64K字节,因此它的一个中断向量占据2个字的空间,用于放置一条绝对转移JMP指令(指令长度为2个字),跳到中断服务程序。对于不使用的中断,在中断向量区中应连续放置2条中断返回指令RETI,增强程序的抗干扰性。当使用汇编语言编写系统程序时应注意。

4.当MCU响应一个中断时,其硬件系统会自动中断返回地址压入系统堆栈,并将关闭全局中断响应(硬件将中断标志I位清0),清除该中断的中断标志位;执行中断返回指令RETI时,硬件会先允许全局中断响应(硬件将中断标志I位置1),然后从系统堆栈中弹出返回地址到PC程序计数器中,继续执行被中断打断的程序。除此之外,MCU的硬件没有对中断保护做其他处理。

5.因此,用户在编写中断服务程序时,首先要编写中断现场保护程序,如保护MCU的状态寄存器等。在中断返回之前,不要忘记恢复中断现场。

6.如果设置和允许外部中断响应,即使是外部INT0..7引脚设置为输出方式,在引脚上的电平变化也会触发外部中断的发生,这一特性提供了使用软件产生中断的途径。

7.外部中断可选择采用上升沿触发、下降沿触发以及电平变化(由高变低或由低变高)和低电平触发等方式,无外部高电平触发方式。具体触发方式由外部中断控制寄存器EICRA(INT3:0)和EICRB(INT7:4)决定。

8.如果选择外部低电平方式触发中断时应特别注意:(1)引脚上的低电平必须一直保持到当前一条指令执行完成后才能触发中断;(2)低电平中断并不置位中断标志位,即外部低电平中断的触发不是由于中断标志位引起的,而是外部引脚上电平取反后直接触发中断(当然需要开放全局中断允许)。因此,在使用低电平触发方式时,中断请求将一直保持到引脚上的低电平消失为止。唤句话说,只要中断引脚的输入引脚保持低电平,那么将一直触发产生中断。所以,在低电平中断服务程序中,应有相应的操作命令,控制外部器件释放或取消加在外部引脚上的低电平。

B.中断优先级以及中断嵌套处理

1.AVR中断的优先级由该中断向量在中断向量区中的位置确定,处于低地址的中断向量所对应的中断拥有高优先级,所以,系统复位RESET拥有最高优先级。

2.当两个中断同时发生申请中断时,MCU先响应中断优先级高的中断。低优先级的中断一般将保持中断标志位的状态(外部低电平中断除外),等待MCU响应处理。

3.MCU响应一个中断后,在进入中断服务前已由硬件自动清零全局中断允许位。因此此时即使有更高优先级的中断请求发生,MCU也会不响应,要等执行到RETI指令,从本次中断返回,并执行了一条指令后,才能继续响应中断。所以,在缺省情况下,AVR的中断不能嵌套。AVR中断的优先级只是在有多个中断同时发生时才起作用,此时MCU将首先响应高优先级的中断。

4.AVR中断嵌套处理是通过软件方式实现的。如在B中断服务中,如需要MCU能及时的响应A中断(不是等本次中断返回后再响应),B中断的服务程序应这样设计:(1)B中断的现场保护;(2)屏蔽除A以外其它的中断允许标志;(3)用指令SEI开放允许全局中断;(4)B中断服务;(5)用指令CLI禁止全局中断(6)恢复在本中断程序被屏蔽的中断允许标志;(7)B中断现场恢复;(8)B中断返回。

5.采用软件方式实现中断嵌套处理的优点,是能够让程序员可以根据不同的实际情况和需要来决定中断的重要性,有更加灵活的手段处理中断响应和中断嵌套,如让低优先级的中断(此时很重要)打断高优先级中断的服务等,但同时也增加了编写中断服务程序的复杂性。

6.由于AVR的指令执行速度比较高,因此在一般情况下,不建议使用中断嵌套的处理方法。当然,这还需要用户在编写中断处理服务程序中,应遵循中断服务程序尽量要短的原则。 点击看大图

C.高级语言开发环境中中断服务程序的编写

1.在高级语言开发环境中,都扩展和提供了相应编写中断服务程序的方法,但不同高级语言开发环境中对编写中断服务程序的语法规则和处理方法是不同的。用户在编写中断服务程序前,应对所使用开发平台,中断程序的编写方法,中断的处理方法等有较好的了解。

2.使用ICCAVR、CVAVR、BASCOM-AVR等高级语言编写中断服务程序时,通常不必考虑中断现场保护和恢复的处理,因为编译器在编译中断服务程序的源代码时,会在生成的目标代码中自动加入相应的中断现场保护和恢复的指令。

3.如果用户要编写效率更高或特殊的中断服务程序,可以采用嵌入汇编、关闭编译系统的自动产生中断现场保护和恢复代码等措施,但程序员要对所使用的开发环境有更深的了解和掌握,并具备较高的软件设计能力。本人中给出的USART接收和发送中断服务程序(使用CVAVR开发平台)就是一个非常典型的示例。

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(942)
发表于:2007-3-25 23:59:45
标签:AVR  

3

avr单片机中断使用心得

中断响应后由硬件自动清零全局中断,任何中断都无法响应,在执行完中断程序后,全局中断打开.如果需要中断嵌套,则在中断程序里软件添加打开全局中断.就可以响应任何中断(包括比本中断优先级低的中断).以至可以中断自己嵌套自己(例如中断时间是每隔100ms一次,而中断执行时间是1s.那样中断就自己嵌套自己,程序就混乱了).中断响应后,全局中断被屏蔽,如果还有中断进入,那么无论优先级高低都无法响应,但响应的中断标志位置位,当中断执行完毕后,总中断打开,接着执行未响应的中断.  

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(752)
发表于:2007-3-23 13:41:21
标签:短信发错  

4

一条短信发错之后!!!!!!!

一条短信发错之后 !!!!!!!
故事发生在2006年1月6日.....

>这几天心情不好,晚上我呆在家里无聊,给我以前的一个女朋友发了一条短信,短信
内容如下:“宝贝,干什么呢,晚上出来陪陪我啊,虽然是冬天,但是我好热啊,我知
道你会给我解热的,我在凯宾美丽城等你啊。”但是由于本人精神不集中,按了群发键
,本人电话本C.P186人(亲人30人,朋友101人,战友16人,同事19人,人生知己3人同
学20人)..
>..
>10分钟后陆续接到信息....
>亲人:30人。
>老妈:“这个死孩子,胆子大了啊,给我发黄色信息...”
>老爸:“儿子啊,你又喝多了,是不是,又发错了吧?”
>表哥:“弟弟啊,你发错了吧?不许学坏啊,凯宾的房间不是很好,还是金帝的客房
好。
>”
>表姐:“????????”
>表嫂:“看完我就会删的,让你表哥看见就完了”
>表弟:“哥,你怎么了,我昨天刚去凯宾洗完澡,我不去了,你去吧”
>表妹:“哥哥,你是不可以喜欢我的,那就是乱伦了。”
>老婶:“我们医院有心理科,明天你给我打电话吧,我带你去看看。”
>老叔:“老叔这个人你还不了解吗?我是从不去那些地方找小姐的”(汗,太贵了)
>上海的舅舅:“孩子,你来上海了啊?”
>另一个表哥:“你是不是有病,发的什么信息?”
>另一个表姐:“我知道你小时我对你很好,给你洗脚,帮你洗衣服,交你背《沁园春
雪》,但是这么多年过去了,你现在和我说这些已经晚了,哎..(我倒)
>剩下的亲人都没有会。
>朋友:101人。
>3个小妹妹的回信:“哥哥,好长时间没上我们这做足疗了啊。”
>N个女网友基本这么回答:“我都还没见过你,叫我怎么好意思去啊,你好讨厌,你让
人家晚上睡不着了啊。”
>4个见过面的女网友一致回答:“不要把我想象那么随便,我不是那种人”
>2个在外地上班的女性朋友:“疯了吧,让我飞回去找你啊,莫名其妙。”
>4个在外地的哥们:兄弟,我知道你从不喝酒的,但我今天敢保证,你肯定喝多了。”

>2女性朋友:“虽然我很喜欢你,但是你要知道,我已经结婚了,等我家那个出差好吗
?你在约我。(哇,平时没看出来啊。)
>3女性朋友:“我和我男朋友和好了,谢谢你还记得我。”
>2个以前的对象:“死鬼,情人节为什么没找我,我不会在理你这种没良心的人了”。

>3个移动的女性朋友:“你要知道,我们经常联系是因为我们业务上的需要,你是不是
变态啊”
>2联通的女性朋友:“你是谁?”(想死)
>3个联通的女性朋友:“你啊你,说过你多少回了,不要在玩了,收收心吧,如果你真
的需要,我们先去吃饭好吗?
>1个网通的女性朋友:“我在阿尔山”
>我刚分手的对象:“我就知道你不会那么狠心,你不舍得我是吗?你等我,我马上
倒。”
>N通过我哥们认识的女性朋友:“没想到某某的朋友会是这样,以后不要说认识我。”

>3个女性朋友:“以后不要说认识我”
>2个比我大的姐姐:“好啊,你先把房间开好了啊,我回家换套衣服。”(换内衣吗?

>1个哥们:“交往这么久怎么没发现你是同性恋啊,以后我们不要联系了。”(冤枉啊

>N个哥们:“你怎么了啊?不行就去医院吧?”
>2个哥们:“老大,具我所知,你女人不断啊,现在怎么缺货了啊,好上这口了,想和
我???
>2个以前的情人:“我们不要在联系了,如果在联系的话,我怕我会舍不得你,虽然我
不是个好女孩,但是我也不想和你联系,因为你太乱糟了。”
>剩下的都没给我回。
>战友:16人。
>2个战友:“什么意思?”
>剩下的战友一致回答:“你他妈有病啊”
>同事:19人。
>一个已婚女同事:“我是他老公,你他妈是谁啊?”
>一个已婚女同事:“哎,我老了,眼看奔40的人了,但是我要感谢你这么直接,你来
我家吧,他没在家。”(平时没看出来啊)
>我的领导(我大队长):“明天上班时,带检讨来。”
>剩下的都没回。
>同学:20人。
>6个外地的女同学:“怎么回事啊?我没看懂。”(呵呵,还是我的同学纯啊,领悟能
力这么差)
>1个女同学:你还记得我啊,我今天来事了,改天吧。”
>3个女同学:“你好,你是??”
>1个女同学:“你是李明吧?好久不见你了,我也想你了,你打车来接我吧”(我晕,
这个
>同学,把我当成别人了)
>剩下都没回。
>人生知己:3个。
>都没给我回信息,马上都给打来电话问候,一个问是不是遇到什么困难了,一个问是
不是家里发生什么事了,一个问,我是不是已经提前进入更年期了?(还是我最好的三
个哥们啊,知道我总发错短信,能理解我啊)
>第二天我给我电话本所有人打电话进行解释,可是没有几个人能相信我发错了,我的
朋友们,我郁闷啊 !!!!........

点击此处查看原文 >>

系统分类: 自由话题   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(582)
发表于:2007-3-20 22:17:54
标签:AVR  

6

AVR外部SRAM

在实际AVR应用中很多朋友往往需要扩展external SRAM,首先我声明一点,AVR扩展SRAM的方法和51扩展的方法一样,在此不在累述。

语言写得非常土,高手可以不看。

下面主要讲ATmega162扩展SRAM的特点。

先摘录datasheet里面的一段:

An optional external data SRAM can be used with the ATmega162. This SRAM will
occupy an area in the remaining address locations in the 64K address space. This area
starts at the address following the internal SRAM. The Register File, I/O, Extended I/O
and Internal SRAM uses the occupies the lowest 1280 bytes in Normal mode, and the
lowest 1120 bytes in the ATmega161 compatibility mode (Extended I/O not present), so
when using 64KB (65,536 bytes) of External Memory, 64,256 Bytes of External Memory
are available in Normal mode, and 64,416 Bytes in ATmega161 compatibility mode. See
“External Memory Interface” on page 24 for details on how to take advantage of the
external memory map.

翻译:ATmega162可以选择使用外部SRAM。外部SRAM会占据64K中的一部分地址空间,这个地址紧接在内部SRAM的后面。内部Register,IO,扩展IO和内部SRAM占据了1280字节的空间,(略了161),所以当使用了全部的64KB的外部空间后,外部存储器只有64256Byte有效。


when the addresses accessing the SRAM memory space exceeds the internal data
memory locations, the external data SRAM is accessed using the same instructions as
for the internal data memory access. When the internal data memories are accessed,
the read and write strobe pins (PD7 and PD6) are inactive during the whole access
cycle. External SRAM operation is enabled by setting the SRE bit in the MCUCR
Register.

翻译:当存取SRAM的地址超出了内部数据存储器的地址的范围时,存取外部数据存储器的指令与存取内部数据存储器的指令相同(这点与51不同),当存取内部存储器时,RD和WR在整个存取期间处于非活动状态。如果你想对外部存储器进行操作,应该怎么办?你就要将MCUCR中的SRE位置位。(SRE: External SRAM/XMEM Enable)


Accessing external SRAM takes one additional clock cycle per byte compared to access
of the internal SRAM. This means that the commands LD, ST, LDS, STS, LDD, STD,
PUSH, and POP take one additional clock cycle. If the Stack is placed in external
SRAM, interrupts, subroutine calls and returns take three clock cycles extra because the
2-byte Program Counter is pushed and popped, and external memory access does not
take advantage of the internal pipeline memory access. When external SRAM interface
is used with wait-state, one-byte external access takes two, three, or four additional
clock cycles for one, two, and three wait-states respectively. Interrupt, subroutine calls
and returns will need five, seven, or nine clock cycles more than specified in the instruction
set manual for one, two, and three wait-states.

翻译:存取外部SRAM比存取内部SRAM每个字节要额外多一个时钟周期。这意味这那几个烦人的汇编指令的执行也需要额外的一个时钟周期。如果堆栈设定在外部SRAM,那么中断,子程序调用以及返回将要耗费三个额外的时钟周期,因为2字节的程序计数器必需要入栈和出栈,(加上那个额外的时钟,是不是三个?嘿嘿),所以外部SRAM的存取远没有内部SRAM的流水线操作来得高效。当外部SRAM接口使用的等待功能,每字节的存取将要花去2,3或4个额外的时钟周期。随即中断、子程序调用---大家不看也知道下面什么意思了,嘿嘿!

Using all Locations of
External Memory Smaller than
64 KB

Since the external memory is mapped after the internal memory as shown in Figure 11,
the external memory is not addressed when addressing the first 1,280 bytes of data
space. It may appear that the first 1,280 bytes of the external memory are inaccessible
(external memory addresses 0x0000 to 0x04FF). However, when connecting an external
memory smaller than 64 KB, for example 32 KB, these locations are easily accessed
simply by addressing from address 0x8000 to 0x84FF. Since the External Memory
Address bit A15 is not connected to the external memory, addresses 0x8000 to 0x84FF
will appear as addresses 0x0000 to 0x04FF for the external memory. Addressing above
address 0x84FF is not recommended, since this will address an external memory location
that is already accessed by another (lower) address. To the Application software,
the external 32 KB memory will appear as one linear 32 KB address space from 0x0500
to 0x84FF. This is illustrated in Figure 17. Memory configuration B refers to the
ATmega161 compatibility mode, configuration A to the non-compatible mode.

翻译:因为外部存储器在那个图中的内部存储器之后才被映射,所以呢,在外部存储器的头1280字节的空间是不可以寻址的,这就表现为不能存取外部存储器的0X0000-0X04FF。当然有个特殊的情况,当使用的外部存储器小于64K(典型值32K)时,外部存储器的0X0000-0X04FF范围可以通过访问0x8000 to 0x84FF进行存取(想一想为什么?)。因为高位地址线A15没有接入,外部寻址范围只有0X0000-0X7FFF,当访问0x8000 to 0x84FF时,低14位地址线定位在外部0X0000-0X04FF处(或许大家会疑惑,怎么不是访问的内部0X0000-0X04FF?请注意了,我们现在访问的是外部存储器,因为地址范围为0x8000 to 0x84FF,不是内部存储器,所以自然不是定位在内部0X0000-0X04FF范围)。不推荐大家对0x84FF以外的范围进行访问,因为这将改变0X04FF-0X7FFF的数据,因为低14位地址是重复的。在应用中,地址在0x0500 to 0x84FF范围的存取是连续的线性的,只有0X0000-0X04FF有写特殊。大家可以参考下图。

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 原创

评论(0) | 阅读(879)
发表于:2007-3-20 16:36:11
标签:AVR  

6

ATEMGA128-16读写外部32KRAM-70NS的完整测试程序

地址分配 
0X0000-0X10FF 内部4KRAM 
0X1100-0X7FFF 外部32KRAM 

系统频率16M ,BAUD=9600,下面对程序对0/1/2/2+1等待状态下,RAM进行测试,全部通过!! 

//ICC-AVR application builder : 2006-8-14 16:03:08
// Target : M128
// Crystal: 16.000Mhz

//1.debug rs232
//

#include<iom128v.h>
#include<macros.h>
#include<stdio.h>
#include<string.h>

//MCU时钟频率
#define F_CPU   16000000
//默认的系统BAUD
#define baud    115200
      
#define MCUBAUD9600 1  

//declare memory mapped variables
#define txbuf1_head 0x1100
//外部RAM大小0X7FFF-0X1100=0X6EFF=28415byte

extern volatile unsigned char txbuf1[28415];

//define mappings
void mapping_init(void)
{

 asm(
  ".area memory(abs)\n"
  ".org 0x1100\n"
  " _txbuf1:: .blkb 28415\n"
  ".text\n"
 );
 
}
//定义外部RAM地址
#define ext_PORT1 ((volatile unsigned char *)0x1100)
//定义一个指针指向外部RAM首地址
unsigned char *p=(unsigned char *)ext_PORT1;
//RAM测试的读写数据
unsigned char testramtable[4]={0x00,0x55,0xaa,0x00};

void Delay(void)
{
}
void Delay1ms(void)
{    
unsigned int  i;

for(i=0;i<=(unsigned int)(16*143-2);i++);
}

void Delayxms(unsigned char ms)
{   
unsigned char i;

for(i=0;i<=ms;i++)Delay1ms();

}


//unsigned char  readram(unsigned int iaddr);
void port_init(void);
void watchdog_init(void);
void uart1_init(void);
//void writeram(unsigned int iaddr, unsigned char ctemp);
void RAM_TEST(unsigned char );
void test_net(void);
//void sendstring1(unsigned int * txbuf);
char char2hex(char t1)
{
if((t1>=00) &&(t1<=0x09))t1=t1+0x30;//'0'--'9'
else 
{
 
 if((t1>=0x0a)&&(t1<=0x0f))//'A'--'F'
 t1=t1-0x0a+0x61;
}
return t1;
}

void sendinthex1(int c)
{
char temph=0,templ=0;
char t1=0,t2=0;

temph=c/256;
templ=c%256;

t1=(c/256)/16;
//t1=t1>>8;
UDR1 = char2hex(t1);
while(!(UCSR1A & 0x40));
UCSR1A |=0x40;

t1=(c/256)%16;
UDR1 = char2hex(t1);
while(!(UCSR1A & 0x40));
UCSR1A |=0x40;

t2=(c%256)/16;//templ&0xf0;
//t2=t2>>8;
UDR1 = char2hex(t2);
while(!(UCSR1A & 0x40));
UCSR1A |=0x40;

t2=(c%256)%16;//templ&0x0f;
UDR1 = char2hex(t2);
while(!(UCSR1A & 0x40));
UCSR1A |=0x40;

}

void sendchar1(char c) // 发送 
{
UDR1 = c;
while(!(UCSR1A & 0x40));
UCSR1A |=0x40;
}

void sendint1( int c) // 发送 
{
UDR1 = (c&0xff00)>>8;
while(!(UCSR1A & 0x40));
UCSR1A |=0x40;

UDR1 = c&0xff;
while(!(UCSR1A & 0x40));
UCSR1A |=0x40;


}


void sendstring1(unsigned char * txbuf) // 发送 
{
unsigned int j;
for (j = 0; *txbuf; j++, txbuf++)sendchar1(*txbuf);
//for(;*txbuf!='/0';txbuf++)

}

void port_init(void)
{
//PA AD0-AD7  地址
//PC AD8-AD15
 PORTA = 0xFF;
 DDRA  = 0xFF;

 PORTC = 0xFF; //m103 output only
 DDRC  = 0x00;

//PB4 NETRST O
 
 PORTB = 0xFF;
 DDRB  = 0x10;
 
 PORTD = 0xFF;
 DDRD  = 0x00;
// PE0 RXD0 
// PE1 TXD0
// PE4 NET_IRQ  i
// PE5 INFRA_IRQ  i
// 
 PORTE = 0xFF;
 DDRE  = 0x00;
 
 PORTF = 0xFF;
 DDRF  = 0x00;
 
 PORTG = 0x1F;
 DDRG  = 0x00;
}

//Watchdog initialisation
// prescale: 2048K cycles
void watchdog_init(void)
{
 WDR(); //this prevents a timout on enabling
 //WDTCR = 0x0F; //WATCHDOG ENABLED - dont forget to issue WDRs
 /* reset WDT */

/* Write logical one to WDTOE and WDE */
//WDTCR |= (1<<WDTOE) | (1<<WDE);
WDTCR=0X18;   //现在把WDTCH给关掉了
/* Turn off WDT */
WDTCR = 0x00;
//WDTCR=0X17;

}
//UART0 initialisation
// desired baud rate:115200
// actual baud rate:111111 (3.7%)
// char size: 8 bit
// parity: Disabled
/*
void uart0_init(void)
{
 UCSR0B = 0x00; //disable while setting baud rate
 UCSR0A = 0x00;
 UCSR0C = 0x06;

// UBRRL = (fosc / 16 / (baud + 1)) % 256; 
// UBRRH = (fosc / 16 / (baud + 1)) / 256; 

 UBRR0L = (F_CPU / 16 / (baud + 1)) % 256;//0x03;//0x08; //set baud rate lo
 UBRR0H = (F_CPU / 16 / (baud + 1)) / 256;//0x00; //set baud rate hi
 UCSR0B = 0x18;//0x98;
}
*/
//UART1 initialisation
// desired baud rate:115200
// actual baud rate:111111 (3.7%)
// char size: 8 bit
// parity: Disabled
void uart1_init(void)
{
 
#ifdef MCUBAUD9600
// UBRRL = (fosc / 16 / (baud + 1)) % 256; 
// UBRRH = (fosc / 16 / (baud + 1)) / 256; 
 UCSR1B = 0x00; //disable while setting baud rate
 UCSR1A = 0x00;
 UCSR1C = 0x06;
 UBRR1L = 0x67; //set baud rate lo
 UBRR1H = 0x00; //set baud rate hi
 UCSR1B = 0x18;
#else 
//baud115200
 UCSR1B = 0x00; //disable while setting baud rate
 UCSR1A = 0x00;
 UCSR1C = 0x06;
 UBRR1L = (F_CPU / 16 / (baud + 1)) % 256;//0x03;//0x08; //set baud rate lo
 UBRR1H = (F_CPU / 16 / (baud + 1)) / 256;//0x00; //set baud rate hi
 UCSR1B = 0x18;//0x98;
#endif 
}
/*
#pragma interrupt_handler int0_isr:2
void int0_isr(void)
{
 //external interupt on INT0
}
*/


//call this routine to initialise all peripherals
void init_devices(void)
{
 //stop errant interrupts until set up
 CLI(); //disable all interrupts
 XDIV  = 0x00; //xtal divider
 port_init();
  mapping_init();
 watchdog_init();
 uart1_init();

 //External RAM will reside between 8000h - FFFFh.
//There will be 2 wait states for both read and write.

// MCUCR = 0x80;
 //EICRA = 0x03; //extended ext ints
 //EICRB = 0x00; //extended ext ints
 //EIMSK = 0x01;
 //TIMSK = 0x00; //timer interrupt sources
 //ETIMSK = 0x00; //extended timer interrupt sources
 SEI(); //re-enable interrupts
 //all peripherals are now initialised
 

 
 
}



//测试RTL8019AS
void test_net(void)
{

}

//
void RAM_TEST(unsigned char umode)

 unsigned int k=0;
 unsigned int i=0,j=0;
 unsigned char DATA,u; 
// unsigned char *p=(unsigned char *)ext_PORT1;
// unsigned char *pointer=p;
 
 sendstring1("init system ok!\n");
 sendstring1("now test system-ram  all is 32k !\n");
for(u=0;u<4;u++)
{
   
   sendstring1("----now write  ram  ");
   sendinthex1(testramtable[u]);
   sendstring1("\n");
   
   i=0;
   do
   {   if(!umode)*(p+i)=testramtable[u];//testok
         else  txbuf1[i]=testramtable[u];
         i++;
   }while(i<0x6f00);//while(i<0x6eff);//while(i>0x6eff);
   
   sendstring1("----write ok\n");
   sendstring1("----now check write\n");
   
   
    k=0x1100;
      i=0;
      do
      { 
           if(!umode)DATA = *(p+i);//test ok
           else     DATA=txbuf1[i];
           if(DATA!=testramtable[u])
           {sendstring1("addr = ");
           sendinthex1(k);
        //sendstring1(" =");
        //sendinthex1(DATA);
           sendstring1("\n");
           }
        k++;i++; 
       }while(k<0x8000);//while(k<0x1110);
      //0x7fff);
      
 sendstring1("---- test system-ram  end!\n");
}
}

void main(void)
{

 init_devices();
 
 sendstring1("RAMTEST START !\n");
 sendstring1("-----POINTER  READ AND WRITE EXTERNAL 32K RAM----------\n");
 sendstring1("0 READ AND WRITE NO WAIT  PC7 RELEASED !\n");
 MCUCR = 0x80; // 允许外部并行扩展接口,忽略高位0X8000的等待时间
 XMCRA = 0x40; //0x00 external memory
 XMCRB = 0x01; // 释放PC7,作为通用I/O引脚使用 
 DDRC =  0xff; // PC7用于输出,(不影响PC0-PC6地址线) 
 PORTC = 0x00; // PC7输出0,(不影响PC0-PC6地址线) 
 RAM_TEST(0);

 sendstring1("1 READ AND WRITE 1 WAIT  PC7 RELEASED !\n");
 MCUCR = 0x80; // 允许外部并行扩展接口,忽略高位0X8000的等待时间
 XMCRA = 0x44; //0x00 external memory
 XMCRB = 0x01; // 释放PC7,作为通用I/O引脚使用 
 DDRC =  0xff; // PC7,PC6用于输出,(不影响PC0-PC5地址线) 
 PORTC = 0x00; // PC7,PC6输出0,(不影响PC0-PC5地址线) 
 RAM_TEST(0);


 sendstring1("2 READ AND WRITE 2 WAIT  PC7 RELEASED !\n");
 MCUCR = 0x80; // 允许外部并行扩展接口,忽略高位0X8000的等待时间
 XMCRA = 0x48; //0x00 external memory
 XMCRB = 0x01; // 释放PC7,作为通用I/O引脚使用 
 DDRC =  0xff; // PC7,PC6用于输出,(不影响PC0-PC5地址线) 
 PORTC = 0x00; // PC7,PC6输出0,(不影响PC0-PC5地址线) 
 RAM_TEST(0);

 
 sendstring1("3 READ AND WRITE 2+1 WAIT  PC7 RELEASED !\n");
 MCUCR = 0x80; // 允许外部并行扩展接口,忽略高位0X8000的等待时间
 XMCRA = 0x4C; //0x00 external memory
 XMCRB = 0x01; // 释放PC7,作为通用I/O引脚使用 
 DDRC =  0xff; // PC7,PC6用于输出,(不影响PC0-PC5地址线) 
 PORTC = 0x00; // PC7,PC6输出0,(不影响PC0-PC5地址线) 
 RAM_TEST(0);
 sendstring1("******POINTER  READ AND WRITE EXTERNAL 32K RAM*******\n");
 
 sendstring1("\n-----BUFFER READ AND WRITE EXTERNAL 32K RAM----------\n");
 sendstring1("4  READ AND WRITE  NOWAIT PC7  NO RELEASED !\n");
 MCUCR = 0x80; // 允许外部并行扩展接口,忽略高位0X8000的等待时间
 XMCRA = 0x40; //external memory
 RAM_TEST(1);

 sendstring1("5  READ AND WRITE  1 WAIT PC7  NO RELEASED !\n");
 MCUCR = 0x80; // 允许外部并行扩展接口,忽略高位0X8000的等待时间
 XMCRA = 0x44; //external memory
 RAM_TEST(1);

 sendstring1("6  READ AND WRITE  2WAIT PC7  NO RELEASED !\n");
 MCUCR = 0x80; // 允许外部并行扩展接口,忽略高位0X8000的等待时间
 XMCRA = 0x48; //external memory
 RAM_TEST(1);

 sendstring1("7  READ AND WRITE  2+1WAIT PC7  NO RELEASED !\n");
 MCUCR = 0x80; // 允许外部并行扩展接口,忽略高位0X8000的等待时间
 XMCRA = 0x4A; //external memory
 RAM_TEST(1);
 sendstring1("\n*******BUFFER READ AND WRITE EXTERNAL 32K RAM***********\n");
 
 sendstring1("---- RAM TEST OK!-----\n");

//while(1){}

// sendstring1("now test rtl8019as!\n");
// test_net();
//sendstring1("----test rtl8019as end!\n");

}

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(605)
发表于:2007-3-20 14:58:13
标签:AVR  C  VOLATILE  

5

volatile的使用

变量定位

 

普通变量的定义和访问同标准C语言,在HCS08 C语言中我们主要要解决映像寄存器变量和某些特殊变量的定位问题,即把这些变量存放在RAM中指定的位置。

1映像寄存器定位

映像寄存器单片机中跟硬件有关的寄存器,它们都有各自固定RAM地址,其定位有3种方法

1)宏定义

例如:#define PortA ( * ( volatile unsigned char * )  0x0000 )

这样 PortA 成为一个地址在0x0000的unsigned char类型变量。这个定义看起来很复杂,其实它也可以分解成几个很简单的部分来看。 ( volatile unsigned char * )是C语言中的强制类型转换,它的作用是把0x0000这个纯粹的十六进制数转换成为一个(地址)指针,其中volatile并不是必要的,它只是告诉编译器,这个值与外界环境有关,不要对它优化接下来在外面又加了一个*号,就表示0x0000内存单元中的内容了。经过这个宏定义之后,PortA就被可以做为一个普通的变量来操作,所有出现PortA的地方编译的时候都被替换成( * ( volatile unsigned char * )  0x0000 ),外面一层括号是为了保证里面的操作不会因为运算符优先级或者其它不可预测的原因被改变而无法得到预期的结果。

这种定义方法适合所有的C编译器,可移植性好,但PortA并不是一个真正的变量,只是一个宏名,当你调试一个程序的时候,无法在调试窗口观察它的值。另外连接器也失去了灵活性,它得防止其它变量跟此变量冲突。

2)使用@关键字

例如: volatile unsigned char PortA       @0x0000;

@是编译器扩展的一个特殊修饰符,其它编译器很可能并不认识。这种定义具有很好的可读性,失去了可移植性。

3)使用段定义

这种方法分为2个步骤

首先把变量定义在段中,其次在连接参数文件(*.prm)中把段定位在一个合适的位置

例如:第1步:在源程序文件中

#pragma DATA_SEG PORTB_SEG

volatile unsigned char PortA;

#pragma DATA_SEG DEFAULT

这样变量 PortA 定义在段 PORTB_SEG 中

第2步:在 prm 文件中

SECTIONS

PORTB_SEG = READ_WRITE 0x0000 SIZE 1;

这样段 PORTB_SEG 定位在地址0x0000上。

这种方法可移植性也很差,如果你要把它移植在别的编译器上,你不得不修改源程序。

2变量定义修饰符

变量定义有三个修饰符值得注意,虽然它们与标准C是相同的,但是在嵌入式C语言中又有不同的含义。

1) static

在子函数中static用声明的变量是局部变量,但是退出这个子函数后其值不消失。下一次调用这个函数时仍可以访问到原来的值。注意,在子函数中声明的static变量只对声明他的函数可见,别的函数是不可以使用的。如果static变量是在模块中声明的,那么只有本模块的函数可以使用它,别的模块中的函数是不能访问的。

void MyFunction (void)

  static char myVar = 0;  //用 static声明的局部变量

  myVar = myVar + 1;

}

void main (void)

{

   MyFunction();      //调用之前myVar = 0,调用之后myVar = 1

   MyFunction();      //调用之前myVar = 1,调用之后myVar = 2

}

 

2) volatile

如果一个变量的值可能会被程序操作之外的其它操作所改变,那么你必需用volatile 声明。在嵌入式系统中其它操作是:中断服务程序的操作、硬件动作的操作。

用volatile声明的变量是不会被编译器优化掉的,如:

volatile unsigned char PortA       @0x0000;

PORTA做为一个输入端口,其值是由外部设备决定的,由于外部设备的变化是随机的,因此第一次读取的值和第二次读取的值很可能不同,所以我们把它声明为volatile变量。

a = PORTA;  

a = PORTA;

由于PORTA是用volatile声明的变量,编译器不会把它优化成一句,而如果不是volatile声明的编译器就会将第二句优化掉,从而程序将会忽略输入端口的变化。

通常把嵌入式设备的所有外围器件寄存器都声明为volatile 的。

 

3) const

修饰符 const 可以用在任何变量之前, 告诉编译器把此变量存储在ROM中。ROM_VAR段是定位 const 变量的默认段

语法格式:#pragma CONST_SEG <段名>

 

例如:

#pragma DATA_SEG DEFAULT

#pragma CONST_SEG DEFAULT

static int a;//变量 a 存放在默认的 RAM 段 DEFAULT_RAM 中,DEFAULT_RAM是段名

static const int c0 = 10;//变量 c0 存放在默认的 ROM 段 ROM_VAR 中,ROM_VAR是段名

此时编译器选项-Cc必需是打开的。如果编译器选项-Cc必需是关闭的,则变量a和c0都定位在DEFAULT_RAM中。

例如:

#pragma DATA_SEG MyVarSeg

#pragma CONST_SEG MyConstSeg

static int a; //变量 a 存放在段MyVarSeg中,MyVarSeg是段名

static const int c0 = 10; //变量 c0 存放在段 MyConstSeg 中,MyConstSeg是段名

此时编译器选项-Cc必需是打开的。如果编译器选项-Cc必需是关闭的,则变量a和c0都定位在MyVarSeg中。

 

3全局变量和局部变量

 

全局变量为整个程序而定义,在整个程序运行期间。它们占用固定的RAM资源,因此除非在必需的情况,否则不要轻易使用。局部变量为某个函数而定义,只在此函数运行的时候,占用栈空间,局部变量实质上是函数运行所需要的一段RAM空间。因此函数不运行时,它们不占用RAM资源。全局变量通常是为了给中断服务函数传递参数定义的,建议定义时把它们定义在一个相对集中的RAM空间。

例如:

#pragma DATA_SEG SCI_DATA /* 这条预处理指令之后的所有变量定义在 SCI_DATA 段 */

char senderBuffer[50];

char receiverBuffer[100];

...

#pragma DATA_SEG DEFAULT /*这条预处理指令之后的所有变量定义在默认段*/

在参数文件中必需指定 SCI_DATA 段。

 

4位定义和访问

HCS08 C 语言采用直接位访问的方法来访问位,位的定义采用联合和结构数据类型来实现。

例如:

volatile union {

struct {

unsigned char MWPR:1; /* MWPR is bit 0 in FEETST */

unsigned char STRE:1; /* STRE is bit 1 in FEETST */

unsigned char VTCK:1; /* VTCK is bit 2 in FEETST */

unsigned char FDISVFP:1; /*FDISVFP is bit 3 in FEETST */

unsigned char FENLV:1;/* FENLV is bit 4 in FEETST */

unsigned char HVT:1; /* HVT is bit 5 in FEETST */

unsigned char GADR:1; /* GADR is bit 6 in FEETST */

unsigned char FSTE:1; /* FSTE is bit 7 in FEETST */

} FEETST_BITS;

unsigned char FEETST_BYTE; /* Alternate definition of the

port as a 8-bit variables. */

} FEETST_struct @0x00F6;

/* Define Symbol to access register FEETST */

 

#define FEETST FEETST_struct.FEETST_BYTE

/* Define Symbols to access single bits in FEETST */

 

#define MWPR FEETST_struct.FEETST_BITS.MWPR

#define STRE FEETST_struct.FEETST_BITS.STRE

#define VTCK FEETST_struct.FEETST_BITS.VTCK

#define FDISVFP FEETST_struct.FEETST_BITS.FDISVFP

#define FENLV FEETST_struct.FEETST_BITS.FENLV

#define HVT FEETST_struct.FEETST_BITS.HVT

#define GADR FEETST_struct.FEETST_BITS.GADR

#define FSTE FEETST_struct.FEETST_BITS.FSTE

这里的“:1”表示仅需要一个位,HCS08会把它们包装在一起形成一个字节。这样我们就可以以字节方式或位方式访问整个寄存器和位。

例如:

FEETST =0X80;//字节方式

MWPR = 1;//位方式

VTCK=1; // BSET 2,FEETST1

FDISVFP=0; // BCLR 4,FEETST1

有关映像寄存器和位定义可以参照具体芯片的头文件。

点击此处查看原文 >>

系统分类: 单片机   |    用户分类:    |    来源: 转贴

评论(0) | 阅读(925)
2345下一页总共 , 当前 /