⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 prg3.asm

📁 单片机对FLASH芯片的烧写,源程序,原理图,PCB图
💻 ASM
📖 第 1 页 / 共 2 页
字号:
 	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 + -