800027a: 681b ldr r3, [r3, #0]
800027c: 3301 adds r3, #1
800027e: 4a01 ldr r2, [pc, #4] ; (8000284
8000280: 6013 str r3, [r2, #0]
8000282: e7f9 b.n 8000278
8000284: 20000000 .word 0x20000000
再来分析下汇编。
- 在地址8000278处,指令ldr r3, [pc, #8]意味着将PC+8处的数据加载到r3寄存器,从汇编可以看出PC+8=8000284,即将20000000加载到r3寄存器。
- 然后CPU继续运行来到800027a处,指令ldr r3, [r3, #0]意味着将r3+0处的数据加载到r3,而这时候r3的内容是20000000,也就是将20000000里面的数据加载到r3寄存器里面,这时候r3寄存器里面才是变量gvar_x的值。
- 在地址800027c处,指令adds r3, #1意味着对r3寄存器加1,也就是gvar_x+1。
- 到这一步就完成了,先取变量gvar_x的值,然后对变量gvar_x加1。
- 在地址800027e处,指令ldr r2, [pc, #4]意味着将PC+4,也就是8000284处的数据加载到r2寄存器里面,这里和第1步一样,先拿到变量gvar_x的地址。只不过r3已经被占用了,所以使用了r2寄存器,这里CPU自有一套标准选择使用的寄存器。
- 来到8000280处,指令str r3, [r2, #0]意味着将r3寄存器里的值设置到r2+0地址处,也就是20000000这个地址里面。
所以这就是单片机里面为什么要有只读的FLASH和可读可写的RAM。
从上面分析也可以看出,CPU执行代码指令是直接从FLASH里面直接取代码指令去执行。
RAM扩展
RAM里面有全局变量、静态变量、堆、栈。
当你编译完后,你写的代码指令和数据都在一个hex文件里面,而这个hex的起始地址是80000000开始的,也就是当你烧录程序时候,不会把变量烧录到20000000后面的地址。
那变量是什么时候到20000000里面的呢?
就在程序启动之前,CPU会先把属于RAM的数据变量都加载到RAM里面。
这就涉及VMA、LMA。也就是运行内存地址和加载内存地址。
这就是为什么当你的单片机掉电后,运行数据都丢失的原因。
如果你想保存这些数据,就需要单片机的外设FLASH模块了。而CPU是不能直接将数据写入到FLASH里面的。
栈
_Min_Stack_Size = 0x400 ; /* required amount of stack */栈里面就是存储的局部变量,当然栈是有大小的,这里最小设置的1KBytes。
假如堆+全局变量+静态变量使用了63K,那你栈只能使用1K空间,如果这时候你有个局部变量数据,大小是2K,那你就去HardFault里面呆着吧。
堆
_Min_Heap_Size = 0x200 ; /* required amount of heap */堆就是你程序在跑的过程中使用malloc开辟的空间。
假如栈+全局变量+静态变量使用了63K,而你又要开辟了一个2K的堆空间,那这时候就会内存泄漏。程序跑哪我也不知道了。