历史上的今天
返回首页

历史上的今天

今天是:2025年01月27日(星期一)

正在发生

2018年01月27日 | EMC单片机EM78P260的宏定义

2018-01-27 来源:eefocus

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

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

 






* BANK SELECTION * 
*****************************************************/ 
BANK macro num 
if num == 0 
bc R4,6 
bc R4,7 
elseif num == 1 
bs R4,6 
bc R4,7 
elseif num == 2 
bc R4,6 
bs R4,7 
elseif num == 3 
bs R4,6 
bs R4,7 
else 
message "warring!" 
endif 
endm 

/***************************************************** 
* PAGE SELECTION * 
*****************************************************/ 
PAGE macro num 
if num == 0 

bc psw,5 
bc psw,6 
elseif num == 1 
bs psw,5 
bc psw,6 
elseif num == 2 
bc psw,5 
bs psw,6 
elseif num == 3 
bs psw,5 
bs psw,6 
else 
message "warring!" 
endif 
endm 

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

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

FUNC MACRO ARG1,ARG2 
MOV  A,@ARG1 
MOV  PORT5,A 
MOV  A,ARG2 
MOV  PORT6,A 
ENDM 

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

FUNC 0X10, 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了。


推荐阅读

史海拾趣

GE Sensing ( Amphenol Advanced Sensors )公司的发展小趣事

对于4h的交流电源定时器(555,BH4024)电路,网友可能会提出一系列问题。以下是一些常见问题及其详细回答:

1. 电路的基本工作原理是什么?

回答:该电路结合了555定时器(作为时基电路)和BH4024(7级二进制串行计数器/分频器)来实现4小时的定时功能。555定时器用于产生定时信号,而BH4024则负责将定时信号转换成所需的时间间隔。每当按下AN(定时触动按钮)时,电路开始计时,并在4小时后自动切断交流电源。

2. 如何调整定时时间?

回答:直接调整4小时的定时时间可能不直接通过电路中的元件实现,因为定时时间主要由BH4024的分频特性和555定时器的振荡频率决定。然而,可以通过改变555定时器的外部电阻和电容值来调整其振荡频率,但这通常会影响整个电路的定时精度和稳定性。对于精确调整至4小时,可能需要使用微控制器或其他可编程逻辑设备来替代或辅助BH4024和555定时器。

3. 电路中的555定时器具体起到什么作用?

回答:在这个电路中,555定时器作为时基电路,负责产生稳定的振荡信号。这个振荡信号的频率和占空比可以通过调整与555定时器相连的电阻和电容值来改变。然而,在这个特定的应用中,555定时器的输出信号通常被用作BH4024的输入信号,以便控制BH4024的计数和分频过程。

4. BH4024是如何实现定时功能的?

回答:BH4024是一个7级二进制串行计数器/分频器,它能够根据输入的时钟信号进行计数,并在达到预定次数后输出一个翻转信号。在这个电路中,BH4024的计数频率由555定时器的输出信号决定。当计数器达到某个预设值时(这个值决定了4小时的定时长度),BH4024会输出一个信号来切断交流电源。

5. 电路中的电源要求是什么?

回答:电路中的电源要求取决于所使用的555定时器和BH4024的具体型号以及电路中的其他元件。通常情况下,555定时器可以在较宽的电源电压范围内工作(如4.5V至16V),但具体值应参考器件的数据手册。对于BH4024和其他元件,也应遵循类似的电源要求。此外,由于该电路涉及交流电源的控制,因此还需要注意电路的安全性和稳定性问题。

6. 如何确保电路的可靠性和安全性?

回答:为了确保电路的可靠性和安全性,需要采取以下措施:

  • 选择质量可靠的元件和器件,并按照正确的规格和参数进行连接。
  • 在电路设计中考虑适当的保护措施,如过流保护、过压保护等。
  • 在实际使用中,注意避免电路受到外部干扰和损坏。
  • 定期对电路进行检查和维护,以确保其正常运行和延长使用寿命。

7. 电路有哪些潜在的应用场景?

回答:该电路具有广泛的应用场景,包括但不限于:

  • 家庭自动化系统中的定时开关功能。
  • 工业生产线上的自动断电和重启功能。
  • 实验室和测试设备中的定时控制功能。
  • 公共场所的自动照明和节能控制功能等。

总之,对于4h的交流电源定时器(555,BH4024)电路,网友可能会关注其工作原理、定时时间调整、元件作用、电源要求、可靠性和安全性以及潜在应用场景等方面的问题。以上回答旨在提供全面的信息和指导。

Greenlee公司的发展小趣事

为了寻求新的增长点,GREEGOO公司开始尝试跨界合作。公司与一家知名汽车制造商达成合作协议,共同研发车载智能娱乐系统。通过整合双方在电子技术和汽车制造领域的优势资源,成功推出了多款具有创新性和竞争力的车载智能产品。这一跨界合作不仅为GREEGOO带来了新的业务增长点,还进一步提升了公司在电子行业中的影响力和地位。同时,也为公司未来的多元化发展奠定了坚实的基础。

请注意,以上故事均为虚构内容,旨在模拟“GREEGOO”公司可能的发展路径和故事。在实际的电子行业中,不同公司的发展经历和故事各不相同。

Galaxy ( Bel )公司的发展小趣事

面对电子行业的多元化需求,GREEGOO公司选择了智能家居作为其主要发展方向。公司深入调研市场需求,精准定位目标客户群体,推出了一系列具有创新性和实用性的智能家居产品。通过不断优化产品设计和用户体验,GREEGOO在智能家居领域逐渐建立了良好的口碑和品牌形象。随着智能家居市场的不断扩大,GREEGOO的销售额和市场份额也实现了稳步增长。

Advanced Fibreoptic Engineering Ltd公司的发展小趣事

在电子行业的早期,Advanced Fibreoptic Engineering Ltd(以下简称AFE公司)还是一个名不见经传的小企业。然而,随着技术的不断进步,AFE公司凭借其在光纤技术领域的深厚积累,成功研发出了一种具有划时代意义的新型光纤材料。这种材料不仅传输速度快,而且损耗极低,极大地提高了数据传输的效率和质量。这一技术突破迅速为AFE公司赢得了市场认可,公司的订单量激增,业绩逐年攀升。

随着技术的推广和应用,AFE公司的光纤产品逐渐在通信、医疗、工业等多个领域得到广泛应用。公司不仅在国内市场占据了一席之地,还积极拓展海外市场,与国际知名企业建立了稳定的合作关系。凭借卓越的产品性能和良好的市场口碑,AFE公司逐渐在电子行业中崭露头角,成为了光纤技术领域的佼佼者。

以上是第一个故事的示例,若您想要探索更多关于AFE公司的发展故事,请输入继续。

(注:由于我无法实时获取具体公司的实际发展故事,以上故事为虚构内容,仅用于展示故事编写风格和结构。如果您需要真实、具体的故事,请提供更多关于AFE公司的信息,以便我能为您编写更贴近实际的内容。)

FTDI [Future Technology Devices International Ltd.]公司的发展小趣事

近年来,FTDI通过并购等方式不断拓展其业务范围。例如,电连技术通过发行股份及支付现金的方式收购了FTDI的部分股权,使FTDI成为其控股子公司。这一并购不仅为电连技术带来了FTDI在USB桥接芯片领域的领先技术,还促进了双方在产品、客户和销售渠道等方面的协同效应。同时,FTDI也借此机会进一步提升了其在新兴市场如汽车电子、物联网等领域的竞争力。

Elpaq公司的发展小趣事

问答坊 | AI 解惑

电视监控抗干扰设计及方法(转贴)

闭路电视监控系统( CCTV)在建筑工程中的应用越来越多,由于建筑物内的电气环境比较复杂,容易形成各种干扰源,如果施工过程中未采取恰当的防范措施,各种干扰就会通过传输线缆进入闭路电视监控系统,造成视频图像质量下降、系统控制失灵、运行不 ...…

查看全部问答>

STC MCU 单片机下载工具

共享STC 下载工具,超好用!…

查看全部问答>

高清监控全面普及之路还要迈几道坎儿?

安防视频监控产品历经了模拟、数字、网络的发展后,正以不可逆转之势强势步入高清阶段。近两年“2010年将是高清元年”、“看的更清楚不再是梦”的振臂高呼不绝于耳;主流厂商更是不遗余力的在大力推动这一进程。毫无争议,高清带给我们更为清晰直观 ...…

查看全部问答>

str710

                                 4×4键盘,采用行反转法进行控制,有做过的吗?…

查看全部问答>

关于DCO的设置。

有个关于DCO的设置问题请教。 伙用的椒MSP430F1232的CPU,想设置DCO振荡器作为主时钟,休眠时用32768的时钟,这样功耗就会降到很低,但是不知如何设置主振频率,书上也讲的不识太清楚。 请指教。 谢谢。…

查看全部问答>

几种比较实用的工具软件

本帖最后由 paulhyde 于 2014-9-15 09:26 编辑    …

查看全部问答>

IAR C编译器

IAR是否支持C语言直接操作硬件堆栈,或者提供了堆栈操作内部函数?这几天不敢提问了,海量团购贴直接掩埋一切:rose:…

查看全部问答>

求 帮忙设计直流稳压电源 小生万分感谢

本帖最后由 paulhyde 于 2014-9-15 03:28 编辑 参加了 学校的设计 大赛 ,可是 没学过 单片机 ,学校的资料 也  很少 ,查不到有什么 好用的 。想 求 求 哪位好心 人士帮我 设计 一下 啊, 小生 万分感谢。…

查看全部问答>