关于单片机全局变量初始化的问题

时间:2022-09-09 14:41:44

  假如说在keil中定义了一个全局变量int i = 0x1234;这个i的初始化肯定是在上电之后,main函数之前。编译完之后debug,从地址0开始执行,怎么没看见对i的初始化呢?有的说是在init.a51文件之中。但是一直没有找到明确的解释。

  请高手明示!最后能帖段代码,谢谢了!

19 个解决方案

#1


楼主的意思我没太看明白,暂时按照我的理解解释:
这个变量的初始化跟上电没关系, 编译完成后就完成了对全局变量的初始化,这个初始化的全局变量被放在数据段。单片机要做的只是顺着地址执行代码。并不是说 i的初始化写在代码的前面 烧录时就放在低地址处 ,这个变量的初始化由编译器完成,并把它放到数据段 ,你看不到它执行初始化的过程

#2


;-------------------------------------------------------------------------
; STRUCTURE OF THE INITIALIZATION INFORMATION
; -------------------------------------------
; This section describes the initialization data generated by C51 for
; explicit variable initializations (in segment ?C_INITSEC).
;
; Explicit variable initilizations at C source level are stored by C51 in
; the segment ?C_INITSEC.  All partial segments are combined at linker level
; to one segment.  The segment end value DB 0 is taken from this library module
; INIT.A51.
;
; Structure of the ?C_INITSEC information:
;     <Info> (see below) [BYTE]                      ----+  repeated
;     <additional info>  [BYTES depend on Info]      ----+  repeated
;     0x00               [BYTE]   <end of list mark>
;
;  <Info> has the following format:
;
;  Bit      7  6  5  4  3  2  1  0
;  <Info>   T  T  B  L  L  L  L  L    T=Type  B=BIGBIT  L=LENGTH
;
;  If BIGBIT is set, another LENGTH BYTE FOLLOWS.  The LENGHT
;  info of the first byte is then the HIGH part.
;
;  Typ is one of the following:
;  0  := IDATA init values;  the following bytes follow:
;        -  1 byte address
;        -  init data bytes according LENGTH specification
;
;  1  := XDATA init values;  the following bytes follow:
;        -  2 byte address (high byte first)
;        -  init data bytes according LENGTH specification
;
;  2  := PDATA init values;  the following bytes follow:
;        -  1 byte address
;        -  init data bytes according LENGTH specification
;
;  3, BIGBIT=0  := BIT init values; the followign bytes follow:
;        -  1 byte for each bit according LENGTH specification
;           this byte has the following format:
;
;           Bit    7  6  5  4  3  2  1  0
;                  I  B  B  B  B  B  B  B   I := state of the bit
;                                           B := bit address
;
;  3, BIGBIT=1  := HDATA init values;   the following bytes follow:
;        -  another LENGTH byte (since BIGBIT is always 1)
;        -  3 byte address  (MSB first)
;        -  data bytes according LENGTH specification
;
;----------------------------------------------------------------------

#3


51我用的不多,AVR常用,现在大部分编译器都会在Main之前插入一段代码,用于初始化,包括全局变量赋值等。编译完后,你Main函数对应的入口地址并不在程序存储器的0地址处,因为那里是初始化代码(其实还有一段中断向量跳转代码)

#4


引用 1 楼 liukun321 的回复:
楼主的意思我没太看明白,暂时按照我的理解解释:
这个变量的初始化跟上电没关系, 编译完成后就完成了对全局变量的初始化,这个初始化的全局变量被放在数据段。单片机要做的只是顺着地址执行代码。并不是说 i的初始化写在代码的前面 烧录时就放在低地址处 ,这个变量的初始化由编译器完成,并把它放到数据段 ,你看不到它执行初始化的过程


代码都是烧写在ROM中的,而全局之类的变量都是在RAM中,所以上电的时候肯定要初始化的。我知道编译器肯定要在main之前加入初始化代码的,但是我不知道加在哪儿了?在keil 中debug后的汇编后的汇编中似乎看不见呢。

#5


引用 2 楼 schlafenhamster 的回复:
;-------------------------------------------------------------------------
; STRUCTURE OF THE INITIALIZATION INFORMATION
; -------------------------------------------
; This section describes the i……



这个文件我知道,我想知道的后编译后这段代码插在生成汇编代码的哪个地方了。

#6


有没有被优化掉?

#7


一般来说,全局变量如果有初始值,它们会被存放在ROM的某个区域,上电后会执行一段从ROM到RAM复制的过程.....这就是全局变量的初始化.

#8



很简单,汇编是从0地址开始,而c的main函数不是从0地址开始的

初始化在main之前,因为在main之前有启动代码和初始化代码



#9


支持8楼!

#10


在startup.a51的最后,有这么一句 LJMP    ?C_START,单步过去....
C:0x0626    020664   LJMP     C:0664
C:0x0664    90099D   MOV      DPTR,#0x099D
C:0x0667    E4       CLR      A
C:0x0668    7E01     MOV      R6,#0x01
C:0x066A    93       MOVC     A,@A+DPTR
C:0x066B    60BC     JZ       C:0629
C:0x066D    A3       INC      DPTR
C:0x066E    FF       MOV      R7,A
C:0x066F    543F     ANL      A,#vbatt(0x3F)
C:0x0671    30E509   JNB      0xE0.5,C:067D
C:0x0674    541F     ANL      A,#0x1F
C:0x0676    FE       MOV      R6,A
C:0x0677    E4       CLR      A
C:0x0678    93       MOVC     A,@A+DPTR
C:0x0679    A3       INC      DPTR
C:0x067A    6001     JZ       C:067D
C:0x067C    0E       INC      R6
C:0x067D    CF       XCH      A,R7
C:0x067E    54C0     ANL      A,#0xC0
C:0x0680    25E0     ADD      A,ACC(0xE0)
C:0x0682    60A8     JZ       C:062C
C:0x0684    40B8     JC       C:063E
C:0x0686    E4       CLR      A
C:0x0687    93       MOVC     A,@A+DPTR
C:0x0688    A3       INC      DPTR
C:0x0689    FA       MOV      R2,A
C:0x068A    E4       CLR      A
C:0x068B    93       MOVC     A,@A+DPTR
C:0x068C    A3       INC      DPTR
C:0x068D    F8       MOV      R0,A
C:0x068E    E4       CLR      A
C:0x068F    93       MOVC     A,@A+DPTR
C:0x0690    A3       INC      DPTR
C:0x0691    C8       XCH      A,R0
C:0x0692    C582     XCH      A,DPL(0x82)
C:0x0694    C8       XCH      A,R0
C:0x0695    CA       XCH      A,R2
C:0x0696    C583     XCH      A,DPH(0x83)
C:0x0698    CA       XCH      A,R2
C:0x0699    F0       MOVX     @DPTR,A
C:0x069A    A3       INC      DPTR
C:0x069B    C8       XCH      A,R0
C:0x069C    C582     XCH      A,DPL(0x82)
C:0x069E    C8       XCH      A,R0
C:0x069F    CA       XCH      A,R2
C:0x06A0    C583     XCH      A,DPH(0x83)
C:0x06A2    CA       XCH      A,R2
C:0x06A3    DFE9     DJNZ     R7,C:068E
C:0x06A5    DEE7     DJNZ     R6,C:068E
C:0x06A7    80BE     SJMP     C:0667........然后就跳到main了....
全局变量初始化代码就在这里面......

#11


你还记得用keil建工程的时候,有个提示:Copy Standard 8051 Startup Code to project folder and add file to project ?" 

这个提示就是说,是否添加Startup code 到工程 ,Startup code 是cpu复位或上电启动后立即运行的一段启动代码。
c编程的时候cpu先找到Startup code 代码,在跳到main函数入口  所以不是从rom 0地址开始的

而Startup code 代码的作用是:

1:清除片内外RAM PDATA  堆栈和指针
2:如果有全局变量,则初始化,如果无全局变量,则直接进入main函数

#12


其实选不选这个Startup code   程序都会自动加入Startup code 执行

#13


昨天已经找到了,谢谢大家了,
如Great_Bug所说,在startup.a51后面的那句 LJMP ?C_START是关键,而 C_START是在init.a51中定义的,init.a51主要就是全局变量的初始化,然后init.a51又调用了main函数。

在http://www.keil.com/support/man/docs/c51/c51_ap_startup.htm上有说明
Startup code is executed immediately upon reset of the target system. The Keil startup code performs (optionally) the following operations in order:

Clears internal data memory
Clears external data memory
Clears paged external data memory
Initializes the small model reentrant stack and pointer
Initializes the large model reentrant stack and pointer
Initializes the compact model reentrant stack and pointer
Initializes the 8051 hardware stack pointer
Transfers control to code that initializes global variables or to the main C function if there are no initialized global variables

#14


STARTUP.A51,这个感觉像是“标准”51的初始化。根据你OPTION里选择的芯片和设备相关

而全局变量应该是编译,变量所在文件,进行链接的时候统一到main()前面进行初始化的

#15


仔细读keil的相关文档,就会找到答案的。用一个编译器首先了解编译器。

#16


应该查看Keil编译器的代码

#17


引用 10 楼 great_bug 的回复:
在startup.a51的最后,有这么一句 LJMP ?C_START,单步过去....
C:0x0626 020664 LJMP C:0664
C:0x0664 90099D MOV DPTR,#0x099D
C:0x0667 E4 CLR A
C:0x0668 7E01 MOV R6,#0x01
C:0x066A 93 MOVC A,@A+DPTR
C:0x066B 60BC JZ……

弱弱的问一下,这里所说的初始化是指的把数据段从ROM搬到RAM吗?

#18


来迟了,呵呵,我是过来总结下大家的意思的:
startup.a51---》init.a51---》main()
初始化全局变量在init.a51中,,,

#19


51平台下,全局变量初始化问题?? 


问题描述: 
typedef xdata unsigned char xBYTE; //1字节 

在文件test.c里这样定义并初始化一个全局数组: 
static xBYTE uploadList_test[10] = { 
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,  
}; 
然后在上电进入mian函数(main函数和test.c不是同一个文件)的时候调用test.c里的打印函数打印出变量uploadList_test的值,发现uploadList_test没有值。 

51扩成了5个bank的,keil编译器中当把test.c放在comment区和bank4的时候用上述操作打出来是有值的,但是test.c放在bank0~bank3的时候打出来发现没有值!!!但是查看编译后的编译文件uploadList_test是已经有值了,是STARTUP.A51这个文件有问题吗?? 

问题补充:上述定义改成static code xBYTE uploadList_test[10]={........}直接从rom里面读数据打出来是有值的,但是改成 static const xBYTE uploadList_test[10]={........}打出来也没有值!! 

这是怎么回事呢??? 

#1


楼主的意思我没太看明白,暂时按照我的理解解释:
这个变量的初始化跟上电没关系, 编译完成后就完成了对全局变量的初始化,这个初始化的全局变量被放在数据段。单片机要做的只是顺着地址执行代码。并不是说 i的初始化写在代码的前面 烧录时就放在低地址处 ,这个变量的初始化由编译器完成,并把它放到数据段 ,你看不到它执行初始化的过程

#2


;-------------------------------------------------------------------------
; STRUCTURE OF THE INITIALIZATION INFORMATION
; -------------------------------------------
; This section describes the initialization data generated by C51 for
; explicit variable initializations (in segment ?C_INITSEC).
;
; Explicit variable initilizations at C source level are stored by C51 in
; the segment ?C_INITSEC.  All partial segments are combined at linker level
; to one segment.  The segment end value DB 0 is taken from this library module
; INIT.A51.
;
; Structure of the ?C_INITSEC information:
;     <Info> (see below) [BYTE]                      ----+  repeated
;     <additional info>  [BYTES depend on Info]      ----+  repeated
;     0x00               [BYTE]   <end of list mark>
;
;  <Info> has the following format:
;
;  Bit      7  6  5  4  3  2  1  0
;  <Info>   T  T  B  L  L  L  L  L    T=Type  B=BIGBIT  L=LENGTH
;
;  If BIGBIT is set, another LENGTH BYTE FOLLOWS.  The LENGHT
;  info of the first byte is then the HIGH part.
;
;  Typ is one of the following:
;  0  := IDATA init values;  the following bytes follow:
;        -  1 byte address
;        -  init data bytes according LENGTH specification
;
;  1  := XDATA init values;  the following bytes follow:
;        -  2 byte address (high byte first)
;        -  init data bytes according LENGTH specification
;
;  2  := PDATA init values;  the following bytes follow:
;        -  1 byte address
;        -  init data bytes according LENGTH specification
;
;  3, BIGBIT=0  := BIT init values; the followign bytes follow:
;        -  1 byte for each bit according LENGTH specification
;           this byte has the following format:
;
;           Bit    7  6  5  4  3  2  1  0
;                  I  B  B  B  B  B  B  B   I := state of the bit
;                                           B := bit address
;
;  3, BIGBIT=1  := HDATA init values;   the following bytes follow:
;        -  another LENGTH byte (since BIGBIT is always 1)
;        -  3 byte address  (MSB first)
;        -  data bytes according LENGTH specification
;
;----------------------------------------------------------------------

#3


51我用的不多,AVR常用,现在大部分编译器都会在Main之前插入一段代码,用于初始化,包括全局变量赋值等。编译完后,你Main函数对应的入口地址并不在程序存储器的0地址处,因为那里是初始化代码(其实还有一段中断向量跳转代码)

#4


引用 1 楼 liukun321 的回复:
楼主的意思我没太看明白,暂时按照我的理解解释:
这个变量的初始化跟上电没关系, 编译完成后就完成了对全局变量的初始化,这个初始化的全局变量被放在数据段。单片机要做的只是顺着地址执行代码。并不是说 i的初始化写在代码的前面 烧录时就放在低地址处 ,这个变量的初始化由编译器完成,并把它放到数据段 ,你看不到它执行初始化的过程


代码都是烧写在ROM中的,而全局之类的变量都是在RAM中,所以上电的时候肯定要初始化的。我知道编译器肯定要在main之前加入初始化代码的,但是我不知道加在哪儿了?在keil 中debug后的汇编后的汇编中似乎看不见呢。

#5


引用 2 楼 schlafenhamster 的回复:
;-------------------------------------------------------------------------
; STRUCTURE OF THE INITIALIZATION INFORMATION
; -------------------------------------------
; This section describes the i……



这个文件我知道,我想知道的后编译后这段代码插在生成汇编代码的哪个地方了。

#6


有没有被优化掉?

#7


一般来说,全局变量如果有初始值,它们会被存放在ROM的某个区域,上电后会执行一段从ROM到RAM复制的过程.....这就是全局变量的初始化.

#8



很简单,汇编是从0地址开始,而c的main函数不是从0地址开始的

初始化在main之前,因为在main之前有启动代码和初始化代码



#9


支持8楼!

#10


在startup.a51的最后,有这么一句 LJMP    ?C_START,单步过去....
C:0x0626    020664   LJMP     C:0664
C:0x0664    90099D   MOV      DPTR,#0x099D
C:0x0667    E4       CLR      A
C:0x0668    7E01     MOV      R6,#0x01
C:0x066A    93       MOVC     A,@A+DPTR
C:0x066B    60BC     JZ       C:0629
C:0x066D    A3       INC      DPTR
C:0x066E    FF       MOV      R7,A
C:0x066F    543F     ANL      A,#vbatt(0x3F)
C:0x0671    30E509   JNB      0xE0.5,C:067D
C:0x0674    541F     ANL      A,#0x1F
C:0x0676    FE       MOV      R6,A
C:0x0677    E4       CLR      A
C:0x0678    93       MOVC     A,@A+DPTR
C:0x0679    A3       INC      DPTR
C:0x067A    6001     JZ       C:067D
C:0x067C    0E       INC      R6
C:0x067D    CF       XCH      A,R7
C:0x067E    54C0     ANL      A,#0xC0
C:0x0680    25E0     ADD      A,ACC(0xE0)
C:0x0682    60A8     JZ       C:062C
C:0x0684    40B8     JC       C:063E
C:0x0686    E4       CLR      A
C:0x0687    93       MOVC     A,@A+DPTR
C:0x0688    A3       INC      DPTR
C:0x0689    FA       MOV      R2,A
C:0x068A    E4       CLR      A
C:0x068B    93       MOVC     A,@A+DPTR
C:0x068C    A3       INC      DPTR
C:0x068D    F8       MOV      R0,A
C:0x068E    E4       CLR      A
C:0x068F    93       MOVC     A,@A+DPTR
C:0x0690    A3       INC      DPTR
C:0x0691    C8       XCH      A,R0
C:0x0692    C582     XCH      A,DPL(0x82)
C:0x0694    C8       XCH      A,R0
C:0x0695    CA       XCH      A,R2
C:0x0696    C583     XCH      A,DPH(0x83)
C:0x0698    CA       XCH      A,R2
C:0x0699    F0       MOVX     @DPTR,A
C:0x069A    A3       INC      DPTR
C:0x069B    C8       XCH      A,R0
C:0x069C    C582     XCH      A,DPL(0x82)
C:0x069E    C8       XCH      A,R0
C:0x069F    CA       XCH      A,R2
C:0x06A0    C583     XCH      A,DPH(0x83)
C:0x06A2    CA       XCH      A,R2
C:0x06A3    DFE9     DJNZ     R7,C:068E
C:0x06A5    DEE7     DJNZ     R6,C:068E
C:0x06A7    80BE     SJMP     C:0667........然后就跳到main了....
全局变量初始化代码就在这里面......

#11


你还记得用keil建工程的时候,有个提示:Copy Standard 8051 Startup Code to project folder and add file to project ?" 

这个提示就是说,是否添加Startup code 到工程 ,Startup code 是cpu复位或上电启动后立即运行的一段启动代码。
c编程的时候cpu先找到Startup code 代码,在跳到main函数入口  所以不是从rom 0地址开始的

而Startup code 代码的作用是:

1:清除片内外RAM PDATA  堆栈和指针
2:如果有全局变量,则初始化,如果无全局变量,则直接进入main函数

#12


其实选不选这个Startup code   程序都会自动加入Startup code 执行

#13


昨天已经找到了,谢谢大家了,
如Great_Bug所说,在startup.a51后面的那句 LJMP ?C_START是关键,而 C_START是在init.a51中定义的,init.a51主要就是全局变量的初始化,然后init.a51又调用了main函数。

在http://www.keil.com/support/man/docs/c51/c51_ap_startup.htm上有说明
Startup code is executed immediately upon reset of the target system. The Keil startup code performs (optionally) the following operations in order:

Clears internal data memory
Clears external data memory
Clears paged external data memory
Initializes the small model reentrant stack and pointer
Initializes the large model reentrant stack and pointer
Initializes the compact model reentrant stack and pointer
Initializes the 8051 hardware stack pointer
Transfers control to code that initializes global variables or to the main C function if there are no initialized global variables

#14


STARTUP.A51,这个感觉像是“标准”51的初始化。根据你OPTION里选择的芯片和设备相关

而全局变量应该是编译,变量所在文件,进行链接的时候统一到main()前面进行初始化的

#15


仔细读keil的相关文档,就会找到答案的。用一个编译器首先了解编译器。

#16


应该查看Keil编译器的代码

#17


引用 10 楼 great_bug 的回复:
在startup.a51的最后,有这么一句 LJMP ?C_START,单步过去....
C:0x0626 020664 LJMP C:0664
C:0x0664 90099D MOV DPTR,#0x099D
C:0x0667 E4 CLR A
C:0x0668 7E01 MOV R6,#0x01
C:0x066A 93 MOVC A,@A+DPTR
C:0x066B 60BC JZ……

弱弱的问一下,这里所说的初始化是指的把数据段从ROM搬到RAM吗?

#18


来迟了,呵呵,我是过来总结下大家的意思的:
startup.a51---》init.a51---》main()
初始化全局变量在init.a51中,,,

#19


51平台下,全局变量初始化问题?? 


问题描述: 
typedef xdata unsigned char xBYTE; //1字节 

在文件test.c里这样定义并初始化一个全局数组: 
static xBYTE uploadList_test[10] = { 
0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,  
}; 
然后在上电进入mian函数(main函数和test.c不是同一个文件)的时候调用test.c里的打印函数打印出变量uploadList_test的值,发现uploadList_test没有值。 

51扩成了5个bank的,keil编译器中当把test.c放在comment区和bank4的时候用上述操作打出来是有值的,但是test.c放在bank0~bank3的时候打出来发现没有值!!!但是查看编译后的编译文件uploadList_test是已经有值了,是STARTUP.A51这个文件有问题吗?? 

问题补充:上述定义改成static code xBYTE uploadList_test[10]={........}直接从rom里面读数据打出来是有值的,但是改成 static const xBYTE uploadList_test[10]={........}打出来也没有值!! 

这是怎么回事呢??? 

#20