新闻中心

EEPW首页>模拟技术>牛人业话> 单片机宏定义学习手记

单片机宏定义学习手记

作者: 时间:2016-09-26 来源:网络 收藏

  (4)用我们的EMC的汇编编译器模仿这种风格

本文引用地址://m.amcfsurvey.com/article/201609/310319.htm

  我们的EMC汇编编译器同样支持这种编译时候的运算,让编译器帮我们先处理一些基本的运算,虽然面对C编译器这个小功能真是见惯不怪,但是原来汇编编译器也能,颇有点小

  小的有点意外。EMC的芯片的功能寄存器分配,真有点乱七八糟,唉,看着吐血,用定一种型号的IC那还好,如果用了几种IC的话,那个叫郁闷,一个例子就是EM78P447 和

  EM78P156,本来前者是升级版,但是为啥有些控制差别会那么大呢,每次都要疯狂的查DATASHEET,为了缓慢脑细胞的死亡速度,俺决定用宏……

  例如: 我们需要开启EM78P260的TCCA计数器来用,初始化时候的工作,我们用带参数的宏来实现。分几步走

  1 首先定义一个宏,以后可以用这个宏来初始化了

  TCCA_SETUP MACRO TCCACNT

  clr 0x04 ; 0x04 是用来做临时寄存器用的

  ior 0x08 ; 0x08是控制TCCA的寄存器

  and a,@0xf8 ; 屏蔽掉TCCA相关的

  mov 0x04,a

  mov a,@TCCACNT ; 读取传递进来的参数

  or a,0x04

  iow 0x08

  mov a,@TCCACNT ; 如果允许TCCA的话,开TCCA的中断

  and a,@0x04 ; 否则直接跳出

  jbc 0x03,2

  jmp $+4

  ior 0x0f

  or a,@0x08

  iow 0x0f

  ENDM

  (因为这个程序在初始化阶段,所以改变0x04寄存器没有所谓,不过在正常跑的时候千万不要乱来,那个是会切换BANK的,跑飞了可不是说着玩,当然,这里可以在RAM开辟一

  个寄存器来用,那就没事了。喜欢的自己改)

  2 第二部就是定义一些宏的具体数值了(跟C类似)

  TCCA_ENABLE == 0X04

  TCCA_DISABLE == 0X00

  TCCA_SRC_INT == 0X00

  TCCA_SRC_EXT == 0X02

  TCCA_EDGE_RISE == 0X00

  TCCA_EDGE_FALL == 0X01

  3 第三步就是华丽的开始用了,在主程序里面,

  /*****************************************************************************

  TCCA_SETUP setup MACRO

  argument : TCCA_ENABLE / TCCA_DISABLE 是否允许

  TCCA_SRC_INT / TCCA_SRC_EXT 计数源选择

  TCCA_EDGE_RISE / TCCA_EDGE_FALL 出发弦选择

  ****************************************************************************/

  TCCA_SETUP TCCA_ENABLE|TCCA_SRC_INT|TCCA_EDGE_RISE

  看到了吧?

  (TCCA_DISABLE|TCCA_SRC_INT|TCCA_EDGE_RISE)一堆有意义的参数,或运算之后作为一个参数传递给宏 TCCA_SETUP ,修改的时候我们很简单就能搞定,甚至绝对

  不需要查资料,例如,我们想改成外部TCCA脉冲计数,只需要简单的修改

  TCCA_SETUP TCCA_ENABLE|TCCA_SRC_EXT|TCCA_EDGE_RISE

  完工了,想禁止TCCA的话,改成 TCCA_DISABLE 就OK了,是不是很简单?很方便? 当然,方便的代价就是增加程序代码,不过就多那么10来行,没有哈大问题的,重要是不

  要过多的抹煞脑细胞~~hoho~ 可持续发展啊~~~

  (5)寄存器自动分配

  终于到了尾声,到了最BT的地方了,也是最有成就感的东西,怎么让寄存器自动分配空间,汇编跟C一个很大的区别就是,C的变量是自动分配,看着都眼红,那是多少好的东西

  啊,被汇编虐待了好些日子,突然发现,原来咱们EMC的汇编编译器也有这个功能,大喜!可能已经有前辈懂得怎么用了,那就算在下班门弄斧好,拍拍砖~~~

  平时写程序的习惯就是,定义一个有意义,容易记的名字去代替抽象的寄存器名,例如定义一个临时变量用的寄存器

  TEMP EQU 0X10

  这样,我们定义了TEMP,以后都用 TEMP 来代替 0X10 寄存器,这是最最常规的办法。但是,问题是,我们必须每次写程序之前都重新定义一次TEMP EQU 0X10 ,当然,也不是说很烦,但是我们都有一些常用功能的子程序,子程序里面用到寄存器的话,也需要定义,然后做项目的时候,这里copy一个子程序,那里copy一个子程序,好了,一大堆冲突的寄存器定义,必须慢慢仔细的检查,如果不走运,有两个名字定义到同一个寄存器上面,好,惨了,很隐蔽的逻辑错误就出现了,那是恶梦。但是用宏可以做到自动分配用到的是变量宏,WICE手册里面也有说,用法是

  TEST VAR 1

  MOV A,@TEST

  TEST VAR TEST+1

  MOV A,@TEST

  对比两次的A值,我们发现,第一个A值为1,第二个A值为2 !!这个就是变量宏的基本原理,编译器当它是一个变量,可以改变的,不过这个改变,只发生在编译的时候,生成代码之后就没有用的了。

  好了,下面说说我们的核心,具体怎么分配。

  首先定义个分配变量的宏,代码如下

  ADDR_ASSIGN MACRO REGISTER

  REGISTER EQU ADDRESS

  ADDRESS VAR ADDRESS+1

  ENDM

  用了一个参数,传递进来的变量的名字。例如我们在主程序里面写了

  ADDRESS VAR 0X10

  (首先定义开始分配的地址,我们是由 0X10 开始)

  ADDR_ASSIGN Temp0

  Temp0 作为参数传递进来,实际上就是执行了

  Temp EQU 0X10

  ADDRESS = ADDRESS+1 (现在的ADDRESS已经是 0X11了!因为它是一个变量宏!)

  下次如果我们继续定义

  ADDR_ASSIGN Temp1

  现在 Temp1 已经自动被定义为 0X11 了,然后ADDRESS滚到0X12为下个寄存器定义用。

  这样就方便了,例如我们定义一堆寄存器

  ADDR_ASSIGN Temp0

  ADDR_ASSIGN Temp1

  ADDR_ASSIGN Temp2

  ADDR_ASSIGN Temp3

  天啊,这实在是太好用了!!!我们完全不用关心具体分配到哪个寄存器上面,反正就是分配了,反正就是可以用了,哈~~TEST一下就知道。

  牵涉的问题1

  越界问题,当分配到 0X3F 的时候一个页面结束了,但是ADDRESS还是继续加上去,怕不怕?不怕,编译器已经报错了,不能编译,这样就不怕越界,可以放心的定义了

  牵涉的问题2

  多个bank的怎么分配?其实可以在定义宏的时候加多一个参数,通过条件宏来跳转定义就OK了,不过我怕麻烦,用了一下的办法:

  /*---------------------------BANK 0 入口地址-------------------------------------*/

  ADDRESS VAR 0X10 ; 可分配 0x10 ~ 0x3f

  /*--------------------------- BANK 0 ----------------------------------------*/

  这里就是我们需要定义的寄存器的

  /*---------------------------BANK0 调试信息输出----------------------------------*/

  MESSAGE "Bank0最大分配RAM:"

  ADDR_DISP ADDRESS-1

  /*-------------------------------------------------------------------------------*/

  /*---------------------------BANK 1 入口地址-------------------------------------*/

  ADDRESS VAR 0X20 ; 可分配 0x20 ~ 0x3f

  /*--------------------------- BANK 1 ----------------------------------------*/

  这里我门需要定义的bank 1 的寄存器

  /*---------------------------BANK1 调试信息输出----------------------------------*/

  MESSAGE "Bank 1 最大分配RAM:"

  ADDR_DISP ADDRESS-1

  /*-------------------------------------------------------------------------------*/

  怎么样?和谐了吧? 将变量严格分开,你需要放在 bank0 的就填到 bank0 的区域,需要分到bank1 的就填到bank1那里,因为在bank1开头,重新定义了 ADDRESS 为 0X20 ,那样就可以继续从 0X20开始分配,如果有多个page的,按照同样的办法。在每个bank结束的时候,我还放了两个宏,他们是

  MESSAGE "Bank0最大分配RAM:"

  ADDR_DISP ADDRESS-1

  第一个,简单的显示文字而已,第二个 ADDR_DISP 是用来显示一共最大分配到哪个寄存器,这个宏的原型是:

  ADDR_DISP macro reg

  IF reg==0x10

  MESSAGE "0x10"

  ELSEIF reg==0x11

  MESSAGE "0x11"

  ELSEIF reg==0x12

  MESSAGE "0x12"

  ELSEIF reg==0x13

  ……

  ……

  (下面的自己写了….)

  ENDM

  很简单,将ADDRESS最后的地址传进去,现实一下而已,因为ADDRESS执行多了一条自加指令的,所以我们减回,那就OK了。

  需要注意的地方,这个方法分配的全部都是全局变量,当做小项目寄存器极其紧缺,需要将某个寄存器复用的时候,这办法就见鬼了。注意一下就是了。


上一页 1 2 下一页

关键词:单片机宏定义

评论


相关推荐

技术专区

关闭