📄 prg3.asm
字号:
LCALL CLR_INTERFACE
SETB ERR_IC_READY
SETB _FLASH_PWR
SETB CALL_RET
RET
RST_F0: CLR ERR_IC_READY
SETB _DX_EN
CLR _FLASH_PWR ;POWER THE FLASH
MOV R7,#50 ;DELAY 50ms AFTER POWER
LCALL DELAY
SETB _DX_RD
SETB _FLASH_OE
SETB _FLASH_WE
CLR _FLASH_RST
MOV R7,#1 ;DELAY 1ms
SETB _FLASH_RST
LCALL DELAY
RET
;芯片复位(HARDWARE)、读取ID、芯片再复位(HARDWARE)
RST_RDID_RST:
CLR IN_READ ;执行复位指令后,停止正在进行的操作
CLR IN_PROG ;执行复位指令后,停止正在进行的操作
; CLR CALL_RET
LCALL RST_FLASH
JNB CALL_RET,R_R_R1
RET
R_R_R1:
LCALL RD_ID
JNB CALL_RET,R_R_R2
RET
R_R_R2:
LCALL RST_FLASH
RET
;芯片擦除/扇区擦除指令的共同部分
ERASE_CMDX:
CLR IN_READ ;执行擦除指令后,停止正在进行的操作
CLR IN_PROG ;执行擦除指令后,停止正在进行的操作
LCALL WRITE_CMD_HEAD
SETB _DX_RD ;数据线方向:FLASH <-- HOST
CLR _DX_EN ;数据线使能
MOV DXL,#80H ;ERASE CMD
MOV DXH,#0 ;SET THE DATA: 80
CLR _FLASH_WE
CLR _FLASH_CE ;LATCH THE ADDR
SETB _FLASH_CE ;LATCH THE DATA
SETB _FLASH_WE ;
LCALL WRITE_CMD_HEAD
RET
;芯片擦除
CHIP_ERASE:
LCALL RST_RDID_RST
JNB CALL_RET,C_E1
RET
C_E1: LCALL RET_ID
CLR ERR_TIMEOUT
CLR ERR_ERASE
LCALL ERASE_CMDX
SETB _DX_RD ;数据线方向:FLASH <-- HOST
CLR _DX_EN ;数据线使能
; MOV CB2,#0 ;三字节地址(20BITS)
; MOV CB1,#5H
; MOV CB0,#55H
; LCALL SETADDR
MOV DXH,#0
MOV DXL,#10H ;CHIP ERASE CMD
CLR _FLASH_CE
CLR _FLASH_WE
SETB _FLASH_CE
SETB _FLASH_WE
SETB _DX_EN ;关闭数据线
;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
;www: jb TX_FLAG,www
; LCALL RETOK
;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
MOV R5,#150 ;DELAY 14s: WAIT TO FINISH ERASING
C_E_DLY:
MOV R7,#0
JB _FLASH_BUSY,C_E2
LCALL DELAY ;200ms
DJNZ R5,C_E_DLY
SETB ERR_TIMEOUT
SETB CALL_RET
RET
C_E2: LCALL VERIFY_ERASE
; JNB CALL_RET,C_E3 ;回复PC
; LCALL RETERR
; RET
;C_E3: MOV A,#CMD_CHIP_ERASE
;C_EE: LCALL RETX1
RET
;检查擦除结果
VERIFY_ERASE:
MOV DXL,#0FFH
MOV DXH,#0FFH
CLR _DX_RD ;数据线方向:FLASH --> HOST
CLR _DX_EN ;数据线使能
CLR _FLASH_CE
CLR _FLASH_OE
MOV DPL,DXL
MOV DPH,DXH
SETB _DX_EN ;关闭数据线
SETB _FLASH_CE
SETB _FLASH_OE
MOV A,#0FFH
CJNE A,DXL,V_E3
CJNE A,DXH,V_E3
RET
V_E3:
SETB ERR_ERASE
SETB CALL_RET
RET
;扇区擦除
SECT_ERASE:
MOV ADDR2,@R0 ;SAVE THE ADDR
INC R0
MOV ADDR1,@R0 ;SAVE THE ADDR
INC R0
MOV ADDR0,@R0 ;SAVE THE ADDR
LCALL RST_RDID_RST
JNB CALL_RET,S_E1
RET
S_E1: LCALL RET_ID
CLR ERR_TIMEOUT
CLR ERR_ERASE
LCALL ERASE_CMDX
SETB _DX_RD ;数据线方向:FLASH <-- HOST
CLR _DX_EN ;数据线使能
MOV CB0,ADDR0 ;三字节扇区地址(20BITS)
MOV CB1,ADDR1
MOV CB2,ADDR2
LCALL SETADDR
MOV DXH,#0
MOV DXL,#30H ;扇区 ERASE CMD
CLR _FLASH_CE
CLR _FLASH_WE
SETB _FLASH_CE
SETB _FLASH_WE
SETB _DX_EN ;关闭数据线
MOV DXL,#0FFH
MOV DXH,#0FFH
MOV R5,#50 ;DELAY 6s: WAIT TO FINISH ERASING
S_E_DLY:
MOV R7,#0
JB _FLASH_BUSY,S_E2
LCALL DELAY ;200ms
DJNZ R5,S_E_DLY
SETB ERR_TIMEOUT
SETB CALL_RET
RET
S_E2: LCALL VERIFY_ERASE
; JNB CALL_RET,S_E3 ;回复PC
; LCALL RETERR
; RET
;S_E3: MOV A,#CMD_SECT_ERASE;
;S_EE: LCALL RETX1
RET
;接收/发送: 地址(高4位=低4位=1~6), 数据长度(高4位=低4位=1~15), 数据((长度-1)字节), 累加和(1字节)(数据字节数+累加和字节数=数据长度)
TX_RX: MOV ABAK,A ;SAVE A
MOV CBAK,C ;SAVE C
SETB RS0 ;SELECT WORK REGS 1
TX_RX0: JB TI,TX ;发送/接收? 发送->TX
RX: CLR RI ;接收
JB RX_END,TRXEND ;
MOV A,SBUF ;奇偶校验
JB P,RX_P
JNB RB8,RX_0 ;OK
AJMP RX_PE
RX_P: JB RB8,RX_0 ;OK
RX_PE: JNB IN_RX,RX12 ;是否在接收过程中?
SETB ERR_PERITY
SETB RET_ERR ;是: 置回答错误标志
AJMP RX12
RX_0: JB RX_FLAG,RX1 ;是否已经收到通讯起始标识?
CJNE A,#COMM_START,TRXEND ;是否为通讯起始标识,否->END
SETB RX_FLAG ;是: 准备接收数据长度
RX0: MOV TL0,#0H ;T0置初值(12M,8.191ms): 设置接收超时--超时后停止接收,清除接收标志
MOV TH0,#0H ;
SETB TR0 ;启动T0
SETB ET0 ;允许T0中断
AJMP TRXEND
RX1: MOV TL0,#0H ;T0置初值(12M,8.191ms): 设置接收超时--超时后停止接收,清除接收标志
MOV TH0,#0H ;
JB IN_RX,RX11
JZ RX12; ;长度=0 -> ERROR
JB ACC.7,RX12 ;长度>63 -> ERROR, END
JB ACC.6,RX12 ;长度>63 -> ERROR, END
MOV RX_LEN,A ;取接收数据长度
ANL A,#0FEH
JZ RX12; ;长度<2 -> ERROR
MOV RX_COUNT,#0; ;
MOV R0,RX_ADDRC ;接收数据缓存地址->R0
SETB IN_RX
AJMP TRXEND
RX11: MOV @R0,A ;SBUF ;缓存接收数据
INC RX_COUNT ;接收计数加1
INC R0 ;缓存地址加1
MOV A,RX_COUNT
CJNE A,RX_LEN,TRXEND ;是否接收到了所有的数据?
SETB RX_END
RX12: CLR TR0 ;YES, 停止T0计数
CLR ET0 ;关T0中断
CLR RX_FLAG
CLR IN_RX
RX2: AJMP TRXEND
TX: CLR TI
JNB TX_FLAG,TX0 ;TXFLAG=0: 发送长度
DJNZ TX_COUNT,TX1 ;数据是否发送完,发送完-->结束
CLR TX_FLAG
AJMP TRXEND
TX0: MOV A,TX_LEN ;发送长度
SETB TX_FLAG ;置发送中标志
AJMP TX2
TX1: MOV A,@R1 ;发送数据
INC R1 ;缓存地址加1
TX2: MOV C,P ;奇偶校验位
MOV TB8,C
MOV SBUF,A ;发送数据
TRXEND: MOV A,ABAK
MOV C,CBAK
CLR RS0 ;SELECT WORK REGS 0
RETI
;TRXERR: CLR RX_FLAG
; CLR RX_END
; CLR IN_RX
; AJMP TRXEND
;定时器T0中断服务程序
TIMER:
; DJNZ TIMERX,TRET ;
CLR RX_FLAG
CLR RX_END
CLR IN_RX
CLR TR0
CLR ET0
; LCALL INITX
; SETB FTIMER
TRET: RETI
DELAY: ;delay N ms: 由A中的数据决定
; MOV R7,A ;A=0: 200ms
L0X: MOV R6,#0FFH
L1X: DJNZ R6,L1X ;3us*256*N
DJNZ R7,L0X
RET
;检查地址、长度: 如果地址超出范围或长度=0/长度超出范围,则置相应标志及CALL_RET
CHK_ADD_LEN:
CLR CALL_RET
MOV A,LEN2 ;TO CHECK THE LEN
JB ACC.7,C_A_LL ;len>200000H
JB ACC.6,C_A_LL ;len>200000H
JNB ACC.5,C_A_L0 ;len>200000H
MOV A,LEN1
ORL A,LEN0
JNZ C_A_LL ;len>200000H
C_A_L0: MOV A,LEN2
ORL A,LEN1
ORL A,LEN0
JZ C_A_LL ;len=0
MOV A,#0F0H ;TO CHECK THE ADDR: 0--0FFFFFH
ANL A,ADDR2
JNZ C_A_LA ;addr>0FFFFFH
RET
C_A_LL:
SETB ERR_LEN
AJMP C_A_LE
C_A_LA:
SETB ERR_ADDR ;ADDR ERROR
C_A_LE:
SETB CALL_RET
RET
;收到读FLASH命令后:先读取ID,发送给PC,然后再读取FLASH数据,并设置有关标志
RD_PREPARE:
MOV RX_ADDRC,#80H ;串行接收首字节的存放地址:80h
MOV ADDR2,@R0 ;SAVE THE ADDR
INC R0
MOV ADDR1,@R0 ;SAVE THE ADDR
INC R0
MOV ADDR0,@R0 ;SAVE THE ADDR
INC R0
MOV LEN2,@R0 ;SAVE THE LEN
INC R0
MOV LEN1,@R0 ;SAVE THE LEN
INC R0
MOV LEN0,@R0 ;SAVE THE LEN
INC R0
LCALL CHK_ADD_LEN ;检查地址、长度
JB CALL_RET,RD_PE ;ERROR
LCALL RST_RDID_RST ;芯片复位、读取ID
JB CALL_RET,RD_PE
LCALL RET_ID ;将ID送给PC
;RD_P0: JNB TX_FLAG,RD_P0 ;等待发送
MOV CB2,ADDR2 ;设置起始地址
MOV CB1,ADDR1
MOV CB0,ADDR0
LCALL SETADDR
MOV CB2,LEN2 ;设置字节计数
MOV CB1,LEN1
MOV CB0,LEN0
SETB RD_FLAG ;READ DATA TO ADDR 'C0H'
LCALL RDTX2 ;
RD_P1: JB TX_FLAG,RD_P1 ;等待发送完毕
SETB IN_READ
LCALL RDTX0 ;发送缓冲区40H中的数据,读数据到缓冲区C0H中
RET
RD_PE: LCALL RETERR
RD_PX: RET
;在读FLASH过程中:发送缓冲区1数据, 将FLASH数据读入发送缓冲区2: 发送: CMD+数据+SUM
READTX:
JB IC_READY,RDTX0 ;$$$$$$$$$$$$$$$$$$$$$????????????
LCALL CLR_INTERFACE
SETB ERR_IC_READY
SETB _FLASH_PWR
; SETB CALL_RET
SETB RET_ERR
RDTX: CLR IN_READ ;结束READ
RET
RDTX0: ; CLR TX_FLAG
JNB RD_FLAG,RDTX01 ;$$$$$$$$$$$$$$?????????????
MOV R0,TX_ADDRC ;#40H-->R0
AJMP RDTX02
RDTX01:
MOV R0,#0C0H
RDTX02:
MOV A,@R0 ;LENGTH=0?
JZ RDTX ;YES --> RET
MOV TX_LEN,A
MOV TX_COUNT,A
INC TX_COUNT
INC R0 ;
MOV TX_INDEX,R0 ;发送缓冲区地址
LCALL TX_COMM_START ;发送 通讯起始标识
RDTX1: JNB TX_FLAG,RDTX1
RDTX2: JB RD_FLAG,RDTX3 ;$$$$$$$$$$$$$$?????????????
MOV R0,#42H
MOV R1,#40H ;40H-LENGTH, 41H--CMD
AJMP RDTX4
RDTX3: MOV R0,#0C2H
MOV R1,#0C0H ;0C0H--LENGTH, 0C1H--CMD
RDTX4: LCALL ISZERO ;检查要读取的字节数是否为零
JNZ RDTX5
MOV A,#2
CJNE A,TX_LEN,RDTX40
MOV @R1,#0 ;END READ: LEN
AJMP RDTX41
RDTX40:
MOV @R1,#2 ;END READ: LEN
INC R1
MOV @R1,#CMD_END ;CMD
INC R1
MOV @R1,#CMD_END ;SUM
RDTX41: CPL RD_FLAG
RET
RDTX5: LCALL RD_FLASH
MOV A,R3 ;累加和
MOV @R0,A ;
MOV A,R4 ;LENGTH
MOV @R1,A
INC R1
MOV @R1,#CMD_READ
CPL RD_FLAG
RET
;RD_FLAG: IN READING: 0--TRANSMITTING ADDR=40H; 1--TRANSMITTING ADDR=C0H; R3--累加和
RD_FLASH:
MOV DXL,#0FFH
MOV DXH,#0FFH
; CLR A ;累加和
MOV A,#CMD_READ
MOV R4,#2 ;LENGTH: 读的数据个数+CMD+SUM
MOV R2,#RD_BYTES ;READ 60 BYTES
SETB _FLASH_WE
SETB _ADDR_INC
CLR _DX_RD ;数据线方向:FLASH --> HOST
CLR _DX_EN ;数据线使能
CLR _FLASH_OE
RD_F3: CLR _FLASH_CE
DEC R2
MOV @R0,DXH
INC R0
INC R4
ADD A,DXH
MOV @R0,DXL
INC R0
INC R4
ADD A,DXL
MOV R3,A
; SETB _FLASH_OE
SETB _FLASH_CE
LCALL COUNT_DOWN ;字节数-1
JZ RD_F4
LCALL COUNT_DOWN ;字节数-1
JZ RD_F4
CLR _ADDR_INC ;INC ADDR
SETB _ADDR_INC
MOV A,R3
DJNZ R2,RD_F3
RD_F4: SETB _DX_EN ;关闭数据线
RET
;COUNTING DOWN : RET -- A=0 --> CB0=CB1=CB2=0
COUNT_DOWN: CLR A
DJNZ CB0,C_D1
ORL A,CB1
ORL A,CB2
C_DRET: RET
C_D1: MOV A,#0FFH
CJNE A,CB0,C_DRET
DEC CB1
CJNE A,CB1,C_DRET
DEC CB2
RET
;设置地址
SETADDR:
SETB ADDR_CLR ;CLR THE ADDR TO ZERO
SETB _ADDR_INC ;
CLR ADDR_CLR ;
LCALL ISZERO ;
SETA_0: JZ SETA_X
CLR _ADDR_INC ;ADDR INC
LCALL COUNT_DOWN ;COUNT DOWN
SETB _ADDR_INC ;
AJMP SETA_0
SETA_X: RET
;TO SEE IF THE NUMBER IS ZERO: RET -- THE NUMBER=0 --> A=0
ISZERO: MOV A,CB0
ORL A,CB1
ORL A,CB2
RET
;READ THE ID: ID_MC, ID_DC; 应首先调用RST_FLASH,
RD_ID:
CLR CALL_RET
JB IC_READY,RD_ID0 ;33333333333333333333#############????/
LCALL CLR_INTERFACE
SETB ERR_IC_READY
SETB _FLASH_PWR
SETB CALL_RET
RET
RD_ID0: CLR ERR_IC_READY
CLR ERR_ID
; CLR _FLASH_PWR ;POWER THE FLASH
SETB _FLASH_WE
SETB _FLASH_CE
SETB _FLASH_BYTE ;WORD MODE
; CLR _FLASH_RST ;RESET THE FLASH
SETB _FLASH_OE
; SETB _FLASH_RST
LCALL WRITE_CMD_HEAD
LCALL WRITE_ID_CMD
SETB ADDR_CLR ;CLR THE ADDR TO ZERO: SET THE ADDR: 00 FOR ID_MC
SETB _ADDR_INC ;
CLR ADDR_CLR ;
MOV DXL,#0FFH
MOV DXH,#0FFH
CLR _DX_RD ;数据线方向:FLASH --> HOST
CLR _DX_EN ;数据线使能
CLR _FLASH_CE ;LATCH THE ADDR
CLR _FLASH_OE
MOV ID_MCL,DXL
MOV ID_MCH,DXH
SETB _FLASH_CE ;LATCH THE ADDR
SETB _FLASH_OE
; SETB ADDR_CLR ;CLR THE ADDR TO ZERO: SET THE ADDR: 01 FOR ID_DC
; SETB _ADDR_INC ;
; CLR ADDR_CLR ;
CLR _ADDR_INC ;ADDR=1
SETB _ADDR_INC ;
CLR _FLASH_CE ;LATCH THE ADDR
CLR _FLASH_OE
MOV ID_DCL,DXL
MOV ID_DCH,DXH
SETB _DX_EN ;关闭数据线
SETB _DX_RD ;数据线方向:FLASH <-- HOST
SETB _FLASH_CE ;LATCH THE ADDR
SETB _FLASH_OE
MOV A,ID_DCH ;CHECK THE ID
JNZ RD_ID2
RD_ID1: SETB ERR_ID
SETB CALL_RET
RD_ID3: RET
RD_ID2:
CJNE A,#0FFH,RD_ID3
AJMP RD_ID1
;
WRITE_CMD_HEAD:
SETB _DX_RD ;数据线方向:FLASH <-- HOST
CLR _DX_EN ;数据线使能
MOV CB2,#0 ;SET THE ADDR: 555
MOV CB1,#5
MOV CB0,#55H
LCALL SETADDR
MOV DXL,#0AAH
MOV DXH,#0 ;SET THE DATA: AA
CLR _FLASH_WE
CLR _FLASH_CE ;LATCH THE ADDR
SETB _FLASH_CE ;LATCH THE DATA
MOV CB2,#0 ;SET THE ADDR: 2AA
MOV CB1,#2
MOV CB0,#0AAH
LCALL SETADDR
MOV DXL,#55H
MOV DXH,#0 ;SET THE DATA: 55
; CLR _FLASH_WE
CLR _FLASH_CE ;LATCH THE ADDR
SETB _FLASH_CE ;LATCH THE DATA
SETB _FLASH_WE ;
SETB _DX_EN ;关闭数据线
MOV CB2,#0 ;SET THE ADDR: 555
MOV CB1,#5
MOV CB0,#55H
LCALL SETADDR
RET
WRITE_ID_CMD:
SETB _DX_RD ;数据线方向:FLASH <-- HOST
CLR _DX_EN ;数据线使能
MOV DXL,#90H
MOV DXH,#0 ;SET THE DATA: AA
CLR _FLASH_WE
CLR _FLASH_CE ;LATCH THE ADDR
SETB _FLASH_CE ;LATCH THE DATA
SETB _FLASH_WE ;
SETB _DX_EN ;关闭数据线
RET
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -