0

关于投票
EMC指令版本SLE4428卡读写程序
SLE4428卡读写程序。这个EMC指令版本是根据C51程序改写的。已经通过了调试。
;============================
;发送数据子程序
;入口: DBUF_24 =要发送的数据(8_BIT)
;============================
ic_send_data:
MOV A,@8 ;循环次数=8
MOV COUNT_24,A
TXLP:
RRC DBUF_24 ;左移(带C)
CALL ic_BITOUT ;输出1_BIT
DJZ COUNT_24 ;循环结束?
JMP TXLP
RET
;=================
;位输入子程序
;说明: 当SCL=1时,从SDA上读电平
;出口: C="从SDA上读入的位值"
;=================
ic_BITIN:
set_io_in ;设置i/o为输入口
set_clk_out
bc 0x05,0
bs port6,icclk ;clk=1
call delay ;延时
BC R3,0
JBC port6,icio
BS R3,0 ;C=io
call delay ;延时0.6US
BC port6,icclk ;clk=0
call delay ;延时0.6US
RET
;=================
;位输出子程序
;说明: 每当SCL=0时,改写SDA上的电平
;入口: C="要写到SDA上的位值"
;=================
ic_BITOUT:
;SDA_OUT ;设置SDA为输出口
set_io_out
set_clk_out

JBS R3,0
JMP BIT0
BS port6,icio ;io=C=1
JMP io1
BIT0:
BC port6,icio ;io=C=0
io1:
call delay ;延时0.6US
bs port6,icclk ;clk=1
BIT2:
call delay
call delay
bc port6,icclk ;clk=0
RET
;============================
;接收数据子程序
;入口: TT_24.REND_24 =读完毕标志
;出口: DBUF_24 =接受到的数据(8_BIT)
;============================
ic_receive_data:
MOV A,@8 ;循环次数=8
MOV COUNT_24,A
CLR DBUF_24
RXLP:
CALL ic_BITIN ;输入1_BIT
RRC DBUF_24 ;左移(带C)
DJZ COUNT_24 ;循环结束?
JMP RXLP
RET


;===========================
;复位操作
;============================
ic_reset:
set_clk_out
set_io_out
set_rst_out

bc port6,icclk ;clk=0
call delay10
bc port6,icrst ;rst=0
call delay10
bs port6,icio ;i/o=1
call delay10
bs port6,icrst ;rst=1
call delay10
bs port6,icclk ;clk=1
call delay10
bc port6,icclk ;clk=0
call delay10
bc port6,icrst ;rst=0
call delay10

call ic_receive_data
mov ic_buffer1,dbuf_24
call ic_receive_data
;mov ic_buffer2,dbuf_24
call ic_receive_data
;mov ic_buffer3,dbuf_24
call ic_receive_data
;mov ic_buffer4,dbuf_24
ret

;============================延时子程序====================================
;功能:短延时 入口:NONE 出口:NONE
;影响资源:A,TEMP ,STATUS
;==========================================================================
DELAY:
MOV A,@0X05
MOV TEMP,A
DJZ TEMP
JMP $-1
RET
;============================延时子程序10MS================================
;功能:延时 入口:NONE 出口:NONE
;影响资源:A,TEMP ,STATUS
;==========================================================================
DELAY10:
MOV A,@0x10
MOV TEMP,A
MOV A,@0xff
MOV TEMP1,A
DJZ TEMP1
JMP $-1
DJZ TEMP
JMP $-5
RET

DELAY100:
mov a, @0x36
mov delay_time1, a
delay51:
mov a, @0x25
mov delay_time2,a
delay52:
mov a, @0x42
mov flag, a
delay53:
djz flag
jmp delay53
djz delay_time2
jmp delay52
djz delay_time1
jmp delay51
RET

;=========发送命令=========
;send command
;==========================
ic_sendcommand:
;start condition
set_clk_out
set_io_out
bc port6,icclk
bs port6,icio
call delay
bs port6,icclk
call delay
bc port6,icio
call delay
bc port6,icclk
call delay

mov dbuf_24,ic_command1
call ic_send_data
mov dbuf_24,ic_command2
call ic_send_data
mov dbuf_24,ic_command3
call ic_send_data

;stop condition
bc port6,icio
call delay
bs port6,icclk
call delay
bs port6,icio
call delay
ret

;process
ic_process:
bc port6,icclk
call delay
bc port6,icio
mov process_temp,@254
puls:
bs port6,icclk
call delay
bc port6,icclk
djz process_temp
jmp puls
ret

/*================读主存储器==================
入口:rmm_address 读取的地址
rmm_len 读取的长度
出口:ic_buffer1
;============================================*/
ic_readmainmemory:
bank 0
mov ic_command1,@0x30
mov ic_command2,rmm_address
mov ic_command3,@0
call ic_sendcommand

bc port6,icclk
call delay
mov len,@0 ;0x10为私有要保护
mov rmm_temp,@255
mov a,rmm_address
sub rmm_temp,a
inc rmm_temp ;rmm_temp=256-address
goto_readdata:
CJL len,rmm_temp,readdata
;COMPARE AND JUMP IF REG1 jmp exit_readdata
readdata:
CJL len,rmm_len,save_data
call ic_receive_data
jmp drop_data
save_data:
call ic_receive_data
mov a,dbuf_24
mov ic_buffer1,a
drop_data:
inc len
jmp goto_readdata
exit_readdata:
bs port6,icclk
call delay
bc port6,icclk
call delay
ret

/*================写主存储器==================
入口:wmm_address 写主存的地址
wmm_value 写主存的数据
出口:
;============================================*/
ic_writemainmemory:
set_io_out
set_clk_out
mov ic_command1,@0x38
mov ic_command2,wmm_address
mov ic_command3,wmm_data
call ic_sendcommand
bc port6,icclk
call delay
bc port6,icio
call delay
mov len,@0 ;0x10为私有要保护
goto_writedata:
CJL len,@254,writedata
jmp exit_writedata
writedata:
bs port6,icclk
call delay
bc port6,icclk
call delay
inc len
jmp goto_writedata
exit_writedata:
bs port6,icio
call delay
bs port6,icclk ;stop condition
call delay
bc port6,icclk
call delay
ret
/*================读安全储区=================
入口:
出口:rsm_data1、rsm_data2、rsm_data3、rsm_data4读取的数据
;============================================*/
ic_readsecmemory:
set_io_out
set_clk_out
mov ic_command1,@0x31
;mov a,@0xff
mov ic_command2,@0xff
mov ic_command3,@0xff
call ic_sendcommand
bc port6,icclk
call delay

call ic_receive_data
mov rsm_data1,dbuf_24
call ic_receive_data
mov rsm_data2,dbuf_24
call ic_receive_data
mov rsm_data3,dbuf_24
call ic_receive_data
mov rsm_data4,dbuf_24
set_io_out
set_clk_out
bs port6,icio
call delay
bs port6,icclk ;stop condition
call delay
bc port6,icclk
call delay
ret
/*================比较密码 =================
入口:
出口:
;============================================*/
ic_compareverifdata:
set_io_out
set_clk_out
call ic_readsecmemory
nop
nop
;mov a,rsm_data1
;and a,@0x07
;mov rsm_data1,a
mov rsm_data1,rsm_data1
jbc 0x03,2
jmp fail_exit

nop
CJE rsm_data1,@0x07,setbit1
CJE rsm_data1,@0x06,setbit2
CJE rsm_data1,@0x04,setbit3
jmp fail_exit
setbit1:
mov wsm_data,@0x06
nop
jmp endcomp
setbit2:
mov wsm_data,@0x04
nop
jmp endcomp
setbit3:
mov wsm_data,@0x00
nop
endcomp:
mov wsm_address,@0
call ic_writesecmemory

;mov len,@0
;CJL len,@3,writedata
;mov password_data,@0xff
mov ic_command1,@0x33
mov ic_command2,@1
mov ic_command3,@0xff
call ic_sendcommand
set_io_out
set_clk_out
bc port6,icclk
call delay
bc port6,icio
call delay
bs port6,icclk ;stop condition
call delay
bc port6,icclk
call delay
bs port6,icclk ;stop condition
call delay
bc port6,icclk
call delay
bs port6,icio
call delay
bs port6,icclk ;stop condition
call delay
bc port6,icclk
call delay

mov ic_command1,@0x33
mov ic_command2,@2
mov ic_command3,@0xff
call ic_sendcommand

bc port6,icclk
call delay
bc port6,icio
call delay
bs port6,icclk ;stop condition
call delay
bc port6,icclk
call delay
bs port6,icclk ;stop condition
call delay
bc port6,icclk
call delay
bs port6,icio
call delay
bs port6,icclk ;stop condition
call delay
bc port6,icclk
call delay

mov ic_command1,@0x33
mov ic_command2,@3
mov ic_command3,@0xff
call ic_sendcommand

bc port6,icclk
call delay
bc port6,icio
call delay
bs port6,icclk ;stop condition
call delay
bc port6,icclk
call delay
bs port6,icclk ;stop condition
call delay
bc port6,icclk
call delay
bs port6,icio
call delay
bs port6,icclk ;stop condition
call delay
bc port6,icclk
call delay
nop
fail_exit:
mov wsm_address,@0
mov wsm_data,@0xff
call ic_writesecmemory
call delay
call ic_readsecmemory
CJE rsm_data1,@0x07,success
mov ic_compare_password_flag,@0
jmp failed
success:
mov ic_compare_password_flag,@1
failed:
nop
nop
ret
/*================读保护储器=================
出口:rpm_data 读取的数据
;============================================*/
ic_readprotectmemory:
set_io_out
set_clk_out
mov ic_command1,@0x34
mov a,@0
mov ic_command2,a
mov ic_command3,a
call ic_sendcommand

bc p6cr,icclk
call delay
call ic_receive_data
mov rpm_data1,dbuf_24
call ic_receive_data
mov rpm_data2,dbuf_24
call ic_receive_data
mov rpm_data3,dbuf_24
call ic_receive_data
mov rpm_data4,dbuf_24
set_io_out
set_clk_out
bs p6cr,icclk ;stop condition
call delay
bc p6cr,icclk
call delay
ret

/*================写保护储器=================
入口:wpm_address 写的地址
出口:wpm_data 写的数据
;============================================*/
ic_writeprotectmemory:
set_io_out
set_clk_out
mov ic_command1,@0x3c
mov ic_command2,wpm_address
mov ic_command3,wpm_data
call ic_sendcommand
bc p6cr,icclk
call delay
bc p6cr,icio
call delay

mov len,@0
goto_writeprotectdata:
CJL len,@254,writeprotectdata
jmp exit_writeprotectdata
writeprotectdata:
bs p6cr,icclk
call delay
bc p6cr,icclk
call delay
inc len
jmp goto_writeprotectdata
exit_writeprotectdata:

bs p6cr,icio
call delay
bs p6cr,icclk ;stop condition
call delay
bc p6cr,icclk
call delay
ret


/*================写安全储区=================
入口:wsm_address 写的地址
出口:wsm_data 写的数据
;============================================*/
ic_writesecmemory:
set_io_out
set_clk_out
mov ic_command1,@0x39
mov ic_command2,wsm_address
mov ic_command3,wsm_data
call ic_sendcommand
bc port6,icclk
call delay
bc port6,icio
call delay

mov len,@0
goto_writesecdata:
CJL len,@254,writesecdata
jmp exit_writesecdata
writesecdata:
bs port6,icclk
call delay
bc port6,icclk
call delay
inc len
jmp goto_writesecdata
exit_writesecdata:

bs port6,icio
call delay
bs port6,icclk ;stop condition
call delay
bc port6,icclk
call delay
ret
系统分类: 单片机
用户分类: emc单片机
标签: EMC SLE4428 读写程序
来源: 原创
发表评论 阅读全文(413) | 回复(0)

0

关于投票
法宝级的EMC单片机编程技巧集锦
法宝级的EMC单片机编程技巧集锦




EM78系列单芯片-提升软件效率的小程序谭振文分享
笔者闲暇时总喜欢一个人窝在房里拿烙铁 ,焊电路板,在网络上游走,看到喜欢的DIY也一定仔细端详,即使按图施工也可以得到不少的乐趣,相信酷爱此道的人应该也不少 ,除了喜欢看看别人的作品,也可以互相比较一下看谁用的零件少,谁提供的功能强,谁的速度最快,所以经常很容易就搜集到一些不错的电路,日子久了就像堆积木一样,可以一个方块一个方块的拿来用,吾人戏称为积木设计法。将许多有用的电路组合在一起,又是一个新的东西。这种方式的确又快又经济,符合现代人快餐的观念。不仅是硬件可以像堆积木一样的收集起来,软件当然也可以适用于积木法则,于是在不少有心人的努力之下,笔者也收集了EM78系列单芯片一些很好的链接库,所以说麻雀虽小,五脏俱全。也因为这些链接库极具参考价值,笔者不忍独享,故决定将紊乱的笔记重新整理后
公开出来,与热爱此系列单芯片的朋友们一同分享。
EM78XXX单芯片自从问世以来已经陆续推出十余种不同等级的单芯片,小到8Pin的78P152,大到100Pin
OTP的78P860,其汇编语言指令都是一样的,仅有57个,所以反复练习几次就能熟悉指令的用法。汇编语言用在I/O控制非常容易,也有很高的效率,所以坊间的书籍大部份以讨论控制为主显,显少专门探讨软件技巧的篇幅,其实老手都知道,关于芯片之控制往往用到时再去翻一翻DATA
BOOK,注意一下TIMING,然后准备一部示波器,三两下就可以搞定。反倒是算法用的好不好会大大影响产品的稳定度,所以有经验的程序设计师通常都有自己的一套葵花秘笈,所以要提升自己的功力最好的方式除了多练习之外,看看别人的程序也会使你进步很快。
BCD转换成Binary
由于EM78XXX是8位的微控器,因此为了节省内存,我们的范例仅以一个BYTE存放两位BCD数为例,数字的范围在0~99之间,转换后的结果放在ACC,如果您需要更多的位数,相信您在看完之后应该不难自行修改才是。
程序一
这个范例程序共花费13个指令CYCLE,需要两个变量空间,执行后会影响到原BCD的内容。
MOV A,BCD
MOV TMP,A
MOV A,@0x0F
AND TMP,A
SWAP BCD
AND BCD,A
BC PSW,0
RLC BCD ; *2
MOV A,BCD
ADD TMP,A
RLC BCD
RLCA BCD ; *8
ADD A,TMP
说明
在程序一中所采用的方式应该算是最多人知道的方式,也是一种最直觉的方法,先将BCD个位数保存起来,因为十位数必须要乘以10,所以利用移位的技巧乘以10再加上个位数,所得的答案放入ACC。
程序二
在程序一的缺点,就是在执行程序以后,原本BCD的内容已经在移位的过程中被破坏掉了,为了改善这项缺失,我们换一种方式看看。下面这个程序,我们企图改善前面的缺失,共花费11个指令CYCLE,仍需要两个变量空间,但是执行后不会破坏原来BCD的内容。
SWAPA BCD
MOV TMP,A
MOV A,@0x0F
AND BCD,A
AND TMP,A
BC PSW,0
RLCA TMP
SWAP TMP
RRC TMP
ADD A,TMP
ADD A,BCD
程序三
对于程序二的结果我们仍然不满意,似乎稍嫌复杂,虽然速度有所改善,但在内存的分配上仍有余地,所以我们再改善成程序三的型态。转换过程只花费10个指令CYCLE,而且只需要一个变量空间,执行之后也不会改变原来BCD的内容。
MOV A,@0x0f
AND A,BCD
JBC BCD,4
ADD A,@10
JBC BCD,5
ADD A,@20
JBC BCD,6
ADD A,@40
JBC BCD,7
ADD A,@80
说明
看过以上三个范例,您是否觉得程序三最简洁而且容易了解?写程序的确是一项极具挑战性的工作,而且还可以找到很多灵感及乐趣,想不到吧!
Binary转换成BCD码
下面的范例程序会将存放在ACC内的二进制数转换成两位BCD码(Compacted BCD Code),可转换最大的BCD码是99。
CLR BCD
DIGIT_HI:
ADD A,@256-10
JBS PSW,FC
JMP DIGIT_LO
INC BCD
JMP DIGIT_HI
DIGIT_LO:
ADD A,@10
SWAP BCD
OR BCD,A
减法的陷阱
EM78系列汇编语言的减法指令是SUB,使用这个指令时您得特别注意,因为ACC永远都是减数,不可为被减数。SUB指令的语法有以下三种:
SUB A,R (R-A→A)
SUB R,A (R-A→R)
SUB A,K (K-A→A)
也就是说如果我们想计算A-2的值,如果写成:
SUB A,@2
其实是执行2-A,解决方法如下:
ADD A,@256-2 或
ADD A,@254
交换两组缓存器的内容
如果你觉得要交换两组内存的内容一定要借用第三组变量,那么您可以参考以下的方式,只是用了一些数学技巧就变得又快又简单。
MOV A,REG1
SUB A,REG2
ADD REG1,A
SUB REG2,A
原理说明
A=REG1
A=REG2-REG1
REG1=REG1+A
=REG1+(REG2-REG1)
=REG2
REG2=REG2-(REG2-REG1)
=REG1
若X>Y就交换...
延续上一个例子,此法用应用在Bubble Sort特别管用。
MOV A,X
SUB A,Y
JBC PSW,FC
JMP NO_CHANGE
ADD X,A
SUB Y,A
2补码
2补码加法经常代替减法,传统上的做法是先取1补码,然后加1。
COM REG
INC REG
或是可以利用另一种方式求得,所不同的是第二种方式会影响PSW缓存器。
ADD A,REG
SUB A,REG
如果您所要求的数已经放在ACC里面,那只要一行就能解决了。
SUB A,@0
旋转字节运算
在8051指令中位左旋有RLC与RL两种指令区分,RLC在ACC左旋时会连带将CY一并旋转,而RL只会将ACC的MSB旋入LSB。EM78XXX指令只有RLC,那么要如何才能做到不带CY旋转呢?答案是旋转两次:
RLCA REG1
RLC REG1
如图1所示,第一次位旋转并没有真正改变REG1的内容,目的是将REG1的MSB先放入FC,第二次位旋转才将刚刚放在FC内的MSB旋入LSB。同理,两个BYTES不经FC的位旋转也是相同的原理。
RLCA HI_BYTE
RLC LO_BYTE
RLC HI_BYTE
范围判断
写程序免不了会碰到IF..THEN..的场合,有些人觉得EM78XXX的条件判断式太过繁琐,所以笔者也将它们整理归纳一下。条件判断式可分为开放区间条件式与封闭区间条件式来讨论,以图2来表示。
开放条件式是以N点为出发点,当待测值大于N或是小于等于N时的条件判断,以C的语法描述如下:
if(number>n)
... /* number大于N */
else
... /* number小于等于N */
EM78XXX汇编语言写法如下:
MOV A,@N+1
SUB A,Number
JBC PSW,FC
JMP LABEL_1 ; 大于N
JMP LABEL_2 ; 小于等于N
封闭式条件判断是指待测值N是否在X与Y的范围之内,若以C的语法描述:
if((number>=x) && (number<=y))
.... /* in range */
else
.... /* False */
如何以EM78汇编语言做到呢?一般做法是以减法后的PSW做条件判断,程序如下:
MOV A,@2
SUB A,number
JBS PSW,FC
JMP FALSE
MOV A,@y+1
SUB A,SI
JBC PSW,FC
JMP FALSE
IN_RANGE:
; ....
FALSE:
; ....
这个IF条件式要花费8个指令Cycle,还不算太复杂。但是还有个更简洁的方法,以下用加法后的PSW(R3)做条件判断,一共只要5行就清洁溜溜了。
MOV A,Number
ADD A,@255-y
ADD A,@y-x+1
JBC PSW,FC
JMP IN_RANGE
FALSE:
; ....
IN_RANGE:
; ....
说明
关键就在前三行,x表示条件式的下限值,y表示条件式的上限值,可以看得出仍是利用CY旗标制造的特效,不但精简而且有点小聪明,许多老手都爱用,这也是他们口袋里的秘密武器之一。如果您觉得不错,不妨也收入锦囊中,尔后就可以依样画葫芦了。
ACC与缓存器内容交换
这理我们要介绍一种快速的逻辑算法,只需要3个指令CYCLE,就可以将ACC的内容与缓存器的内容交换,不拖泥带水,Very cute!
XOR Number,A
XOR A,Number
XOR Number,A
请读者自行在纸上推算一次,就知道答案了。
交换多组缓存器内容
利用上面介绍的方法,可以推广到多组缓存器交换的例子上,下面的程序将5组DATA内容移位,第一笔缓存器的数据传到第二笔缓存器内,第二缓存器的数据再传送到第三笔缓存器内,依此类推,最后一笔数据则传给第一个缓存器,形成一种字节数据旋转。
MOV A,@5
MOV COUNT,A
MOV A,@DATA1
MOV RSR,A
MOV A,DATA5
NEXT:
XOR INDIR,A
XOR A,INDIR
XOR INDIR,A
INC RSR
DJZ COUNT
JMP NEXT
计算MOD 2N
假如你刚好需要计算ACC MOD X,且X刚好是2的N次方,使用ACC AND
(X-1)是最快的方法了。例如要判断YEAR是否为闰年,有个简单的方法,可以排除一些非闰年的条件,只要不能被4整除者就不是闰年。所以可以用YEAR
AND 3解决。
MOV A,@4-1
AND A,YEAR
JBS PSW,FZ
JMP NOLEAP
清除一段连续的内存
对于连续一段内存做读写最好的方式就是使用间接寻址法,但是要注意在一些如M78447/811/860等高阶MCU,内存20H~
3FH又可以分成4组BANK,如果之前没有切换到正确的BANK会造成读写错误。下面的范例程序会将BANK1内的32个BYTES全部清为0。
INDIR == 0x00
RSR == 0x04
COUNT == 0x10
REG == 0x20
BANK1 == 0x40
BANK2 == 0x80
BANK3 == 0xC0
MOV A,@32
MOV COUNT,A
MOV A,@REG|BANK1
MOV RSR,A
NEXT:
CLR INDIR
INC RSR
DJZ COUNT
JMP NEXT
计算一个BYTE中有多少个"1"
这个小程序可以检查出在某个BYTE中共有几个1,在某些算法的过程可能会用得到,计算的结果放在ACC。
RRCA DATA
AND A,@0x55
SUB DATA,A
MOV A,DATA
AND A,@0x33
ADD DATA,A
RRC DATA
ADD DATA,A
RRC DATA
SWAPA DATA
ADD A,DATA
AND A,@0x0F
节省NOP指令的方法
您还在为程序挤不下伤脑筋吗?NOP指令有时候在延迟指令时间很有用,假如你有连续两个NOP指令可以用JMP到下一个指令的方式代替,因为这样可以减少一个指令BYTE,又可以达到相同的效果。
例如:
NOP
NOP
可以写成:
JMP NEXT_INST
NEXT_INST:
;....
因为一个NOP花费一个指令Cycle,但是一个JMP指令就需要2个指令Cycle,虽然有时候会抱怨JMP指令会多花一点时间,但是想不到它也有如此妙用吧。
LABEL太多?
写汇编语言最令人伤脑筋的问题之一就是程序中到处是label,这有两个坏处,第一就是不小心就会造成label重复的问题,第二就是想不出适当的label名称。如果您已经为label的命名问题肠枯思竭,给您提供一个小方法,程序中如果用「$」可以表示目前PC的地址,依此推论「$+2」表示PC+2,「$-4」表示PC-4,看看底下的例子您立刻就明白:
MOV R,R
JBS PSW,FZ
JMP $+