用SST单片机做自己的ISP在线下载程序!!下面是源代码,结合VB或VC编程PC端的下载窗 口,就是自己的ISP!
;******************************************* ;* SST FlashFlex51系列单片机在线下载程序示例 * ;* (对应SST89E58RD2单片机 - 器件代码: E2h) * ;* (11.0592MHz的外部晶振/38.4Kbps波特率) ;* ;* 1. 在软件中,程序设内部看门狗的时间为50ms, 发送一个询问命令(F7h)给主 * ;* PC,等待PC来的握手命令(05h和55h)直到WDT溢出. 探测到握手命令后软件 * ;* 发出器件ID和软件版本号给主PC, 在两秒的时间内等待PC的伪IAP命令. * ;* 2. WDT溢出后程序将运行在0000H的用户程序. ;* 3. 在主PC, 用户可以发出运行用户代码命令(62h和62h)停止下载模式和运行 * ;* 用户程序. * ;* 4. 软件支持12MHz晶振时38.4Kbps串口波特率. ;* 5. 本程序是放在块1存储器内,所以需要把FLASH进行重映射,使单片机在复 * ;* 位后从块1启动,详细请参考SST单片机的器件资料. * ;* 6. 软件使用了下面的资源: * ;* 寄存器R0-R6; 内部RAM 08h-0Fh; 看门狗(WDT); A, B, DPTR, SFCF寄存器.* ;* 7. 只需要把SST单片机的串口通过232电平转换连到PC的串口. * ;* ;************************************************************************
;************************************************************************ ;* * ;* 8052系列特殊功能寄存器地址 * ;* * ;************************************************************************
T2CON DATA 0C8H RCAP2L DATA 0CAH RCAP2H DATA 0CBH TL2 DATA 0CCH TH2 DATA 0CDH
;************************************************************************ ;* * ;* SST 51 MCU SST89E52RD2/54RD2/58RD2特殊功能寄存器地址 ;* * ;************************************************************************
SFCF DATA 0B1H ; Flash配置位 SFCM DATA 0B2H ; Flash指令位 SFAL DATA 0B3H ; Flash地址低位 SFAH DATA 0B4H ; Flash地址高位 SFDT DATA 0B5H ; Flash数据位 SFST DATA 0B6H ; Flash状态位 WDTC DATA 0C0H ; 看门狗定时器控制 WDTD DATA 86H ; 看门狗定时器数据/重装
;************************************************************************ ;* * ;* SST 51 MCU SST89E52RD2/54RD2/58RD2 IAP命令 ;* * ;************************************************************************
SFCM_SE EQU 0BH ; 扇区擦除(Sector Erase)命令 SFCM_PB EQU 0EH ; 字节编程(Program byte)命令 SFCM_VB EQU 0CH ; 字节校验(Verify byte)命令
;************************************************************************ ;* * ;* 定义变量 ;* * ;************************************************************************
CMD EQU R2 ; PC命令 PCDATA EQU R3 ; PC数据 ADRHI EQU R4 ; 开始地址高位 ADRLO EQU R5 ; 开始地址低位 COUNT EQU R6 ; 字节数或大小
STR1 DATA 08h ; 内部RAM 08h - 0Bh用来存STRG STR2 DATA 09h STR3 DATA 0Ah STR4 DATA 0Bh
;************************************************************************ ;* 定义常量 * ;************************************************************************ SST89E52RD_ID EQU 9Dh ; SST89E52RD2的器件代码 SST89E54RD_ID EQU 9Fh ; SST89E54RD2的器件代码 SST89E58RD_ID EQU 9Bh ; SST89E58RD2的器件代码 FW_Ver EQU 11h ; 软件版本1.1 ;************************************************************************ ;* 复位和中断矢量(在块1 FLASH的扇区0) * ;************************************************************************ org 0E000h ; 影射后的复位矢量 ljmp start ; 跳到开始执行的代码
org 0E003h ; 外部中断0矢量
org 0E00Bh ; 定时器0溢出矢量
org 0E013h ; 外部中断1矢量
org 0E01Bh ; 定时器1溢出矢量 org 0E023h ; 串行I/O中断矢量
org 0E02Bh ; 定时器2溢出矢量
;************************************************************************ ;* 运行下载代码或用户代码? ;************************************************************************ ;* 下载程序开始后检查WDTC.2 (看门狗定时器复位标记),如果WDTC.2 = 0跳到 * ;* poweron程序;如果WDTC.2 = 1,把STR1-STR4与字符串"POWR"或"USER"做比较 * ;* 当WDT超时溢出,程序做下面动作: ;* 1. 如果WDT是在下载程序终止的,则清WDT复位标记. * ;* 2. 跳到resetval恢复SFR的初始值. ;************************************************************************
org 0E040h
start: mov a, SFCF ; 如果重映射,跳到chkwdtc anl a, #00000011b jz chkwdtc mov STR1, #"R" ; 重映射没有设,置"RMAP"标志 mov STR2, #"M" mov STR3, #"A" mov STR4, #"P"
mov WDTD, #-2 ; 等10ms(典型值)后复位MCU mov WDTC, #0fh ; sjmp $ ; 软件陷阱
chkwdtc:jnb WDTC.2, poweron ; 上电复位后做初始化
mov a, STR1 cjne a, #'P', others mov a, STR2 cjne a, #'O', others mov a, STR3 cjne a, #'W', others mov a, STR4 cjne a, #'R', others
orl WDTC, #00000100b ; 清除复位标记(WDTS, 就是WDTC.2 ) ljmp resetval ; 如果标记是"POWR",跳到resetval
others: mov a, STR1 cjne a, #'U', rmap mov a, STR2 cjne a, #'S', rmap mov a, STR3 cjne a, #'E', rmap mov a, STR4 cjne a, #'R', rmap ; 如果flag="USER"和WDTC.2=1,跳到resetval ljmp resetval ; 但不要清除WDT复位标记(WDTS) !!
rmap: mov a, STR1 cjne a, #'R', user mov a, STR2 cjne a, #'M', user mov a, STR3 cjne a, #'A', user mov a, STR4 cjne a, #'P', user orl WDTC, #00000100b ; 清复位标记 sjmp poweron
user: mov STR1, #'U' ; 设置标记"USER" mov STR2, #'S' mov STR3, #'E' mov STR4, #'R' sjmp init
;************************************************************************ ;* 下载程序初始化程序 * ;************************************************************************ ;* 1. 初始化SFR, 建立串口连接和开动WDT. * ;* 2. MCU发送询问命令(F7h)给主PC,等待PC来的握手命令,报告状态. * ;* 3. MCU发送命令F7h给PC,等待命令60h,再报告器件ID和软件版本. * ;* 4. 软件继续在循环程序运行: MCU发送命令F7h给PC,等待PC来的伪IAP指令. * ;* 5. 要退出循环程序,可以做复位或PC发一个运行用户代码命令(62h)给. * ;************************************************************************ poweron: ; 设"POWR"标记 mov STR1, #'P' mov STR2, #'O' mov STR3, #'W' mov STR4, #'R'
init: clr a ; 清除A mov PSW, a ; 清除程序状态字 mov IE, a ; 清除中断使能位 mov SP, #0Bh ; 0Ch到0Fh做为Stack! anl SFCF, #10111111b ; IAPEN=0 mov SFDT, #0 ; mov SFAH, #0abh ; 指向片外FLASH mov SFAL, #0cdh mov RCAP2H, #high(-9) ; 11.0592MHz晶振, 38.4Kbps mov RCAP2L, #low(-9) ; 11.0592MHz晶振, 38.4Kbps
mov T2CON, #00110100b ; Timer2作为波特率发生器
mov SCON, #01010010b ; 模式1, 8位UART, 无奇偶, REN=1, TI=1 mov WDTD, #-5 ; 5 x 7.7ms=38ms(最小), 50ms(典型) mov WDTC, #00001111b
;************************************************************************ ;* 循环程序loop ;************************************************************************ ;* MCU发一个询问命令(F7h),告诉主PC已经准备好接收伪IAP指令 * ;************************************************************************
loop: mov a, #0F7h ; 把询问命令(0F7H )存在ACC jnb TI, $ ; 等到最后字节发送完 mov SBUF, a ; 发询问命令到串口 clr TI ;
mov B, #0 ; 无效的IAP命令
waitpc: jnb RI, waitpc ; 等输入字节准备好 mov a, SBUF ; 把接收到的数传给ACC clr RI ; 准备接收下一个字节
mov CMD, a ; 复制ACC到CMD setb WDTC.1 ; 刷新看门狗定时器!
;************************************************************************ ;* 握手程序(伪IAP命令: 05h和55h) ;************************************************************************ ;* 1. 检查握手命令顺序(05h和55h)和向主PC报告状态 * ;* 2. 如果检查到非法命令,继续执行BSL循环程序 ;************************************************************************
cjne a, #05h, cmd60 ; 如果cmd不等于05h,跳到cmd60 setb WDTC.1 ; 刷新看门狗定时器! lcall INBYTE ; 从串口读一个数 cjne a, #55h, loop ; 如果数据非法,继续循环程序
mov a, SFCF ; 读SFCF的BSEL(bit0)状态 anl a, #00000001b ; 把SECD(bit 7,6,5)和BSEL(bit0)合成一个 orl a, SFST ; 数送给主PC lcall OUTBYTE ; 把状态数送到串口
clr WDTC.0 ; 停止WDT,准备做合法命令 mov WDTD, #-200 ; 看门狗定时器改为2秒 mov WDTC, #00001111b ; 使能复位reset, 清标志, 刷新和启动WDT sjmp loop ; 继续BSL循环程序
;************************************************************************ ;* 报告芯片ID和软件ID程序(伪IAP命令: 60h) * ;************************************************************************ ;* 主PC要MCU报告芯片ID和软件ID: * ;* 1. 发送器件代码: SST89E52RD2是9Dh,SST89E54RD2是9Fh,SST89E58RD2是9Bh* ;* 2. 发送软件版本号: 软件v1.1则是11h ;************************************************************************ cmd60: cjne a, #60h, cmd62 setb WDTC.1 mov a, #SST89E58RD_ID lcall OUTBYTE mov a, #FW_Ver lcall OUTBYTE sjmp loop
;************************************************************************ ;* 运行用户程序(伪IAP CMD: 62h和62h) * ;************************************************************************ ;* 主PC发送这个命令来运行用户代码: ;* 1. MCU要接收两个连续的数: 62h和62h. ;* 2. 调到重置值程序resetval,把SFR恢复成初始值,然后 ;************************************************************************ cmd62: cjne a, #62h, nop_cmd ; 如果不是62h则跳到nop_cmd lcall INBYTE ; 从串口在读一个数 cjne a, #62h, loop ; 如果第二个数不是62h,那不是合法的顺序
jnb TI,$ ; 等到最后字节发送完成 ljmp resetval ; 跳到resetval程序和运行用户代码
;************************************************************************ ;* 到其它伪IAP命令程序 ;************************************************************************
nop_cmd:cjne a, #61h, cmd2 setb WDTC.1 ; 刷新看门狗定时器! ljmp loop ; CMD 61H = NOP cmd
cmd2: cjne a, #SFCM_SE, cmd3 lcall byte3 mov SFDT, #55h lcall sector_e ; 扇区擦除 ljmp loop
cmd3: cjne a, #SFCM_PB, cmd4 lcall byte3 lcall program_b ; 编程字节 ljmp loop
cmd4: cjne a, #SFCM_VB, wrongcmd lcall byte3 lcall verify_b ; 校验字节 ljmp loop
wrongcmd: ljmp loop ; 跳到BSL循环程序loop nop nop nop sjmp $ ; ;************************************************************************ byte3: lcall INBYTE ; 从PC读3个字节 mov ADRHI, a ; 1) 输入地址高位 mov DPH, a lcall INBYTE ; 2) 输入地址底位 mov ADRLO, a mov DPL, a lcall INBYTE ; 3) 输入数值 mov COUNT, a
mov r0, #0 ret ;************************************************************************ nop nop nop sjmp $
;************************************************************************ ;* 串口通讯子程序 * ;************************************************************************ OUTBYTE: ; 从串口发送一个字节 jnb TI, $ ; 等最后的字节发送完成 mov SBUF, a ; 把数据存入SBUF clr TI ; setb WDTC.1 ; 刷新看门狗定时器! ret ;======================================================================== nop nop nop sjmp $ ; 软件陷阱 ;======================================================================== INBYTE: ; 从串口接收一个字节 jnb RI,$ ; 等上一个字节接收完成 mov a, SBUF ; 把接收到的数据放到ACC clr RI ; 准备接收下一个字节
setb WDTC.1 ; 刷新看门狗定时器! ret ;======================================================================== nop nop nop sjmp $ ; 软件陷阱 ;========================================================================
;************************************************************************ ; 扇区擦除程序(IAP CMD: 0Bh) ; 输入项: (1) 开始地址: R4 = 地址高位, R5 = 地址低位 * ; (2) 扇区数 (R6) ; 返回: ACC * ; 使用的寄存器: ACC,B,R0,R1,R2,R3,R4,R5,R6 * ; 这个程序擦除给定的扇区,从提供的开始地址。程序返回一个值给PC, * ; 表示操作成功(ACC.2 = 0)或失败(ACC.2 = 1) * ;************************************************************************ sector_e: mov B, #SFCM_SE mov a, CMD cjne a, #SFCM_SE, error1 mov a, SFDT cjne a, #55h, error2
nxtsctr:mov a, ADRHI clr c subb a, #0e0h jnc error3 orl SFCF, #040h ; IAP使能 mov SFAH, ADRHI ; 存入地址高位 mov SFAL, ADRLO ; 存入地址低位 mov SFCM, B ; 发出扇区擦除命令 mov CMD, #04h ; lcall done? ; 等扇区擦除完成 jb acc.2, exit2 ; 如果发生溢时就终止 djnz COUNT, newaddr
exit2: lcall OUTBYTE anl SFCF, #10111111b ; IAPEN=0 mov SFDT, #0 ; mov SFAH, #0abh ; 指向片外存储器 mov SFAL, #0cdh mov B, #0 ; 非法IAP命令 ret
error1: mov a, #0C1h ; cmd不是合法扇区擦除命令(0Bh) sjmp exit2
error2: mov a, #0C2h ; SFDT不合法的55h sjmp exit2
error3: mov a, #0C3h ; 扇区地址指向块1 sjmp exit2
newaddr:mov a, ADRLO add a, #128 ; 块0扇区大小是128字节 mov ADRLO, a ; 下一个扇区的低位地址 mov a, ADRHI addc a, #0 mov ADRHI, a ; 下一个扇区的高位地址 sjmp nxtsctr ;======================================================================== nop nop nop sjmp $ ; 软件陷阱 ;========================================================================
;************************************************************************ ; 编程字节(IAP CMD: 0Eh) * ; 输入项: (1) 开始地址: DPH = 地址高位, DPL = 地址低位 * ; (2) 字节数(在R6) * ; 返回值: 无 * ; 使用的寄存器: ACC,B,R0,R1,R2,R3,R6,DPTR * ; 程序接收开始地址和字节数,然后写入选定的地址 * ;************************************************************************ program_b: mov B, #SFCM_PB mov a, DPH clr c subb a, #0e0h jnc exit3
lcall INBYTE ; 从串口接收一位 orl SFCF, #040h ; IAP使能 mov SFAH, DPH ; 放入准备写的地址 mov SFAL, DPL mov SFDT, A ; 放入数据 mov SFCM, B ; 发出字节编程命令 mov CMD, #04h ; done?中屏蔽Flash_Busy位 lcall done? ; 等待命令完成
anl SFCF, #0BFh ; 禁止IAP inc DPTR ; 地址指向下一个要写的地址 djnz COUNT, program_b ; 重复写,直到所有数据写完
exit3: anl SFCF, #10111111b ; IAPEN=0 mov SFDT, #0 ; mov SFAH, #0abh ; 指向片外存储器 mov SFAL, #0cdh mov B, #0 ; 非法IAP命令 ret ;======================================================================== nop nop nop sjmp $ ; 软件陷阱 ;======================================================================== ;************************************************************************ ; 字节校验程序(IAP CMD: 0Ch) * ; 输入项: (1) 开始地址: DPH = 地址高位, DPL = 地址低位 * ; (2) 扇区长度(在R6) * ; 返回: ACC和SFDT存有最后读的数据 * ; 使用的寄存器: ACC,DPTR,R6 * ; 程序从要求的位置读数据,然后把数据传回PC. &n, bsp; * ;************************************************************************
verify_b: mov a, DPH ; 块1的程序不能用IAP访问自己 clr c subb a, #0e0h jc block0
clr a movc a, @a+dptr ; 用movc来读块1的内容 sjmp tellpc
block0: orl SFCF, #040h ; IAP使能 mov SFAH, DPH ; 存入高位地址 mov SFAL, DPL ; 存入低位地址 mov SFCM, #SFCM_VB ; 发出字节校对命令 nop nop nop mov a, SFDT tellpc: lcall OUTBYTE ; 数据发送到PC
inc DPTR ; 指向下一个数据地址 djnz COUNT, verify_b ; 读下一个字节,直到计数为零
anl SFCF, #00111111b ; 禁止IAP mov SFDT, #0 ; mov SFAH, #0abh &, ;nbs, p; ; 指向片外存储器 mov SFAL, #0cdh mov B, #0 ; 非法IAP命令 ret ;======================================================================== nop nop nop sjmp $ ; 软件陷阱 ;======================================================================== ;************************************************************************ ;* 检查SFST.2位可以确定IAP操作是否完成 * ;************************************************************************ done?: mov a, SFST jb acc.2, done? ; 等FLASH操作完成. ret ;======================================================================== nop nop nop sjmp $ ; 软件陷阱 ;======================================================================== ;************************************************************************ ;* 重新置值程序 * ;************************************************************************ ;* 1. 恢复SFR的初始值. * ;* 2. 执行在块0 0000H地址的用户代码 * ;************************************************************************ resetval: CLR A MOV B, A MOV PSW, A MOV SP, #07H MOV DPTR, #0 MOV IE, #40H MOV IP, A MOV PCON, A ANL SFST, #11100000B MOV SFCM, A MOV SFDT, A MOV SFAL, A MOV SFAH, A MOV RCAP2L, A MOV RCAP2H, A MOV TL2, A MOV TH2, A MOV T2CON,A MOV SCON, A MOV TCON, A MOV TMOD, A MOV TL0, A MOV TH0, A MOV TL1, A MOV TH1, A mov STR1, #'D' ; 破坏SRAM中08h,09h,0Ah,0Bh的数据 mov STR2, #'O' mov STR3, #'N' mov STR4, #'E' anl SFCF, #10111100b ; VIS=1, IAPEN=0, REMAP=0KB ljmp 0000h ; 执行在块0 0000H地址的用户代码 ;===================================================================== nop nop nop sjmp $ END
, p; ; 指向片外存储器 mov SFAL, #0cdh mov B, #0 ; 非法IAP命令 ret ;======================================================================== nop nop nop sjmp $ ; 软件陷阱 ;======================================================================== ;************************************************************************ ;* 检查SFST.2位可以确定IAP操作是否完成 * ;************************************************************************ done?: mov a, SFST jb acc.2, done? ; 等FLASH操作完成. ret ;======================================================================== nop nop nop sjmp $ ; 软件陷阱 ;======================================================================== ;************************************************************************ ;* 重新置值程序 * ;************************************************************************ ;* 1. 恢复SFR的初始值. * ;* 2. 执行在块0 0000H地址的用户代码 * ;************************************************************************ resetval: CLR A MOV B, A MOV PSW, A MOV SP, #07H MOV DPTR, #0 MOV IE, #40H MOV IP, A MOV PCON, A ANL SFST, #11100000B MOV SFCM, A MOV SFDT, A MOV SFAL, A MOV SFAH, A MOV RCAP2L, A MOV RCAP2H, A MOV TL2, A MOV TH2, A MOV T2CON,A MOV SCON, A MOV TCON, A MOV TMOD, A MOV TL0, A MOV TH0, A MOV TL1, A MOV TH1, A mov STR1, #'D' ; 破坏SRAM中08h,09h,0Ah,0Bh的数据 mov STR2, #'O' mov STR3, #'N' mov STR4, #'E' anl SFCF, #10111100b ; VIS=1, IAPEN=0, REMAP=0KB ljmp 0000h ; 执行在块0 0000H地址的用户代码 ;===================================================================== nop nop nop sjmp $ END
, p; ; 指向片外存储器 mov SFAL, #0cdh mov B, #0 ; 非法IAP命令 ret ;======================================================================== nop nop nop sjmp $ ; 软件陷阱 ;======================================================================== ;************************************************************************ ;* 检查SFST.2位可以确定IAP操作是否完成 * ;************************************************************************ done?: mov a, SFST jb acc.2, done? ; 等FLASH操作完成. ret ;======================================================================== nop nop nop sjmp $ ; 软件陷阱 ;======================================================================== ;************************************************************************ ;* 重新置值程序 * ;************************************************************************ ;* 1. 恢复SFR的初始值. * ;* 2. 执行在块0 0000H地址的用户代码 * ;************************************************************************ resetval: CLR A MOV B, A MOV PSW, A MOV SP, #07H MOV DPTR, #0 MOV IE, #40H MOV IP, A MOV PCON, A ANL SFST, #11100000B MOV SFCM, A MOV SFDT, A MOV SFAL, A MOV SFAH, A MOV RCAP2L, A MOV RCAP2H, A MOV TL2, A MOV TH2, A MOV T2CON,A MOV SCON, A MOV TCON, A MOV TMOD, A MOV TL0, A MOV TH0, A MOV TL1, A MOV TH1, A mov STR1, #'D' ; 破坏SRAM中08h,09h,0Ah,0Bh的数据 mov STR2, #'O' mov STR3, #'N' mov STR4, #'E' anl SFCF, #10111100b ; VIS=1, IAPEN=0, REMAP=0KB ljmp 0000h ; 执行在块0 0000H地址的用户代码 ;===================================================================== nop nop nop sjmp $ END
|