最近要用STC单片机写个程序,但STC在KEIL的单片机库中没有,就随便找了个代替,但是刚好找到的keil没有添加StartUp.A51文件,刚开始时候写程序调程序也没什么,挺正常。但后来越来越奇怪,经常上电时出错,找了很久才发现有个变量没有初始化为0。忽然发觉是不是keil上电时没有帮我清空内存空间!一看才知道没有StartUp.A51文件。加上后,设置内部空间及外部空间地址,一切正常。足足浪费了我一天的时间。 由于CPU和程序启动代码文件STARTUP.a51的重要性,一些8051派生的CPU产品要求初始化CPU来满足设计中的相应的硬件,因此,有时候用户需要对STARTUP.a51进行修改,所以进行注释一下: ;--------------------------------------------------- ;startup.A51: 用户上电初始化程序 ;---------------------------------------------------- ; ;使用以下EQU命令可定义在CPU复位时需要用0进行初始化的内存空间 ; ;IDATA存储器的空间的绝对起始地址总是零 IDATALEN EQU 80H ;需用0进行初始化的IDATA存储器空间的字节数 ; XDATASTART EQU 0H ;XDATA存储器空间的绝对起始地址 XDATALEN EQU 0H ;需用0进行初始化的XDATA存储器的空间字节数 ; PDATASTART EQU 0H ;PDATA存储器的空间的绝对起始地址 PDATALEN EQU 0H ;需用0进行初始化的PDATA存储器的空间字节数 ;注意:IDATA存储器的空间在物理上包括了8051单片机的DATA和BIT存储空间 ;至少要保证与C51编译器运行库有关的存储器的空间进行0初始化 ; ;再入函数模拟初始化 ;----------------------------------------------------------- ;以下用EQU指令定义了再入函数模拟堆栈指针的初始化 ; ;使用SMALL存储器模式时再入函数的堆栈空间 IBPSACK EQU 0 ;使用SMALL存储器模式再入函数时将其设置成1 IBPSTACKTOP EQU 0FFH+1 ;将堆栈顶设置为最高地址加1 ; ;使用LARGE存储器模式时再入函数的堆栈空间 XBPSTACK EQU 0 ;使用LARGE存储器模式再入函数时将其设置成1 XBPSTACKTOP WQU 0FFFFH+1 ;将堆栈顶设置为最高地址加1 ; ;使用COMPACT存储器模式时再入函数的堆栈空间 PBPSTACK EQU 0 ; 使用COMPACT存储器模式再入函数时将其设置成1 PBPSTACKTOP WQU 0FFFFH+1 ;将堆栈顶设置为最高地址加1 ;;---------------------------------------------------- ;使用COMPACT存储器模式时,64KB X DATA存储器空间的分页定义 ; ;以下用EQU指令定义PDATA类型变量在XDATA存储器空间的页地址 ;使用EQU指令定义PFAGE时必须与L51连接定位器PDATA指令的控制参数一致
; PPAGEENABLE EQU 0 ;使用PDATA类型变量时将其设置成1 PPAGE EQU 0 ;定义页号 ; ;------------------------------------------------ NAME ? C_STARTUP ;模块名为 ? C_STARTUP ? C_51STARTUP SEGMENT CODE ;代码段 ? STACK SEGMENT IDATA ;堆栈段 RSEG ? STACK ;堆栈 DS 1 EXTRN COE(? C_START) ;程序开始地址 PUBLIC ? C_STARTUP CSEG AT 0x8000 ;定义用户程序的起始地址,用MON51仿真器时可能有用 ? C_STARTUP: LFMP STARTUP1 RSEG ? C_51STARTUP STARTUP1: ; ;初始化串口 MOV SCOM, #40H MOV TMOD, #20H MOV TH1, #0FDH SETB TR1 CLR T1 ;单片机上电IDATA内存清零,如果不需要上电清零IDATA,可以注销IF到IFEDN之间的 ;语句,或者修改IDTALEN的长度,为了让CPU具有掉电保护功能,需要确定IDTALEN的长度 IF IDATALEN <> 0 MOV R0, # IDATALEN-1 CLR A IDATALOOP: MOV @R0,A DJNZ R0,IDATALOOP ENDIF ; ;单片机上电XDATA内存清零,如果不需要上电清零XDATA,可以注销IF到IFEDN之间的 ;语句,或者修改XDTALEN的长度 IF XDATALEN <> 0 MOV DPTR, #XDATASTART MOV R7,#LOW (XDATALEN) IF (LOW(XDATALEN)) <> 0 MOV R6, #(HIGH(XDATALEN))+1 ELSE MOV R6, #HIGH (XDATALEN) ENDIF CLR A XDATALOOP: MOVX @DPTR, A
INC DPTR DJNZ R7, XDATALOOP DJNZ R6, XDATALOOP END IF ; ;送PDATA存储器页面高位地址 IF PPAGEENABLE <> 0 MOV P2, #PPAGE ENDIF ; ;单片机上电PDATA内存清零,如果不需要上电清零XDATA,可注销IF到IFEDN之 ;间的语句或者修改PDATALEN的长度 IF PDATALEN <> 0 MOV R0, #PDATASTART MOV R7, #LOW (PDATALEN) CLR A PDATALOOP: MOV @R0, A INC R0 DJNZ R7,PDATALOOP ENDIF ; ;设置使用SMALL存储器模式时再入函数的堆栈空间 IF IBPSTACK <> 0 EXTRN DATA(? C_IBP) MOV ? C_IBP, #LOW IBPSTACKTOP ENDIF ; ;设置使用LARGE存储器模式时再入函数的堆栈空间 IF XBPSTACK <> 0 EXTRN DATA (? C_XBP) MOV ? C_XBP, #HIGH XBPSTACKTOP MOV ? C_XBP +1, #LOW XBPSTACKTOP ENDIF ; ;设置使用COMPACT存储器模式时再入函数的堆栈空间 IF PBPSTACK <> 0 EXTRN DATA(? C_PBP) MOV ? C_PBP, #LOW PBPSTACKTOP END IF ; ;设置堆栈的起始地址 MOV SP, #? STACK-1 ;例如 MOV SP, #4FH ; ;如果程序超过64K,则使用程序分组技术,启动下面的程序
;EXTRN CODE(? B_SWITCH0) ;CALL ? B_SWITCH0 ;程序从第一组bank 0 块开始执行 ;跳转到用户程序MAIN函数 LJMP ? C_START END startup.a51的作用和汇编一样,在C中定义的那些变量和数组的初始化就在startup.a51中进行,如果你在定义全局变量时带有数值,如unsigned char data xxx="100";,那startup.a51 中就会有相关的赋值。如果没有=100,startup.a51就会把他清0。(startup.a51==变量的初始化)。 这些初始化完毕后,还会设置SP指针。对非变量区域,如堆栈区,将不会有赋值或清零动作。 有人喜欢改startup.a51,为了满足自己一些想当然的爱好,这是不必要的,有可能错误的。比如掉电保护的时候想保存一些变量, 但改startup.a51来实现是很笨的方法,实际只要利用非变量区域的特性,定义一个指针变量指向堆栈低部:0xff处就可实现。, 为什么还要去改? 可以这么说:任何时候都可以不需要改startup.a51,如果你明白它的特性