当前位置:首页 > 单片机 > 单片机
[导读] (1)最常用的PAGE和BANKEMC的IC是分几个page和几个bank的,低端的EM78P156等只有一个bank和一个page,所以不用切换,新一点的IC基本都要切换的了,这个经常用的冬冬,做成宏就最合适,代码如下:/****

(1)最常用的PAGE和BANK
EMC的IC是分几个page和几个bank的,低端的EM78P156等只有一个bank和一个page,所以不用切换,新
一点的IC基本都要切换的了,这个经常用的冬冬,做成宏就最合适,代码如下:

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






*BANKSELECTION*
*****************************************************/
BANKmacronum
ifnum==0
bcR4,6
bcR4,7
elseifnum==1
bsR4,6
bcR4,7
elseifnum==2
bcR4,6
bsR4,7
elseifnum==3
bsR4,6
bsR4,7
else
message"warring!"
endif
endm

/*****************************************************
*PAGESELECTION*
*****************************************************/
PAGEmacronum
ifnum==0

bcpsw,5
bcpsw,6
elseifnum==1
bspsw,5
bcpsw,6
elseifnum==2
bcpsw,5
bspsw,6
elseifnum==3
bspsw,5
bspsw,6
else
message"warring!"
endif
endm

调用格式是
BANKnum(num是0~3代表4个BANK)
PAGEnum(num是0~3代表4个PAGE)
这样方便多了,而且不会出错

(2)带参数的宏
作为例子,我们假定定义一个宏“FUNC”,带两个参数,功能是单纯的将传进来的数据传到PORT5和
PORT6而已,演示用法。
首先看定义:

FUNCMACROARG1,ARG2
MOV A,@ARG1
MOV PORT5,A
MOV A,ARG2
MOV PORT6,A
ENDM

注意到,为什么ARG1前面有个@的符号的呢?这个代表的是宏接收的第一个参数是一个立即数,而AR
G2没有那个符号,代表宏接收的第二个参数是一个寄存器的地址。
好了,看在主程序怎么用:

FUNC0X10,0X20

这样就OK了,编辑器编译的时候,会自动进行宏替换,将0X10这个立即数作为第一个参数传递进去,而
将0X20寄存器的内容,作为第二个参数传递进去,进行宏替换之后的结果,等效于:
MOV A,@0x10
MOV PORT5,A
MOV A,0x20
MOV PORT6,A
(3)说一点C语言的一种良好风格
C语言上面有一种比较好的编程风格,给个C51的例子:
我们想设置TIMER0在模式1,TIMER1在模式2
一般教程的思维和代码就是:
翻资料看看TMOD的位的定义,然后慢慢算,模式1和模式2该给什么值,最后写指令:
TMOD = 0x21;
完工…..
其实我们还可以有另外一种办法,那就是这样写:

TMOD = CT0_MODE1 | CT1_MODE2 ;

其中里面用到一些宏,具体定义是:
#define CT0_MODE0 0x00 // Timer0/Counter0 Mode
#define CT0_MODE1 0x01
#define CT0_MODE2 0x02
#define CT0_MODE3 0x03

#define CT1_MODE0 0x00 // Timer1/Counter1 Mode
#define CT1_MODE1 0x10
#define CT1_MODE2 0x20
#define CT1_MODE3 0x30

TMOD = CT0_MODE1 | CT1_MODE2 ;
这个应该很容易看的懂吧?中间的 “|”是或运算,这个就是编译器在编译之前先做的运算了,具体CT
0_MODE1 代表 0X01 CT1_MODE2 代表0x20,然后“与运算”之后结果就是0X21 了,跟上面一样。但是老
实说,大家愿意用哪个办法去做呢?我会毫不犹豫的选择第二种。

(4)用我们的EMC的汇编编译器模仿这种风格
我们的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_DISABLE|TCCA_SRC_INT|TCCA_EDGE_RISE
看到了吧?
(TCCA_DISABLE|TCCA_SRC_INT|TCCA_EDGE_RISE)一堆有意义的参数,异或之后作为一个参数传递给宏
TCCA_SETUP ,修改的时候我们很简单就能搞定,甚至绝对不需要查资料,例如,我们想改成外部TCCA
脉冲计数,只需要简单的修改

TCCA_SETUP TCCA_DISABLE|TCCA_SRC_EXT|TCCA_EDGE_RISE

完工了,想禁止TCCA的话,改成 TCCA_DISABLE 就OK了


(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了。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭