一、前言
使用c语言时,要用到的一个很重要的就是栈,所以我们要在汇编中就设置好栈;
而对于当下的stm32f103来说,我们可以在0x08000000处写入栈顶地址,也可以在汇编程序中使用指令设置SP
二、在MDK中实现
修改start.s,在0x08000000处写入栈顶地址,如下所示:
- Stack_Size EQU 0x00000400 ;定义堆栈大小为1024byte
- AREA STACK, NOINIT, READWRITE, ALIGN=3 ;定义一个数据段,标记为STACK,即栈,不写入初始值初,对RAM来说,即初始化为0,8字节对齐
- Stack_Mem SPACE Stack_Size ;保留Stack_Size大小的栈空间
- __initial_sp ;标号,代表堆栈顶部地址,后面有用
- PRESERVE8 ;指示编译器8字节对齐
- THUMB ;指示编译器以后的指令为THUMB指令
- ; Vector Table Mapped to Address 0 at Reset
- AREA RESET, CODE, READONLY ;定义只读数据段,标记为RESET,其实放在CODE区,位于0地址
- EXPORT __Vectors ;在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用
-
- __Vectors DCD __initial_sp ;当前地址写入一个字(32bit)数据,值为__initial_sp指向的地址值,即栈顶地址
- DCD Reset_Handler ;当前地址写入一个字(32bit)数据,值为Reset_Handler指向的地址值,即程序入口地址
- AREA |.text|, CODE, READONLY ;定义代码段,标记为.text
- ; Reset handler ;利用PROC、ENDP这一对伪指令把程序段分为若干个过程,使程序的结构加清晰
- Reset_Handler PROC ;过程的开始
- EXPORT Reset_Handler [WEAK] ;[WEAK] 弱定义,意思是如果在别处也定义该标号(函数),在链接时用别处的地址。
- IMPORT led ;通知编译器要使用的标号在其他文件
- BL led ;跳转去执行led函数
- B . ;原地跳转,即处于循环状态
- ENDP
- ALIGN ;填充字节使地址对齐
- END ;整个汇编文件结束
复制代码
在汇编程序中使用指令设置SP,如下所示:
- PRESERVE8 ;指示编译器8字节对齐
- THUMB ;指示编译器以后的指令为THUMB指令
- ; Vector Table Mapped to Address 0 at Reset
- AREA RESET, CODE, READONLY ;定义只读数据段,标记为RESET,其实放在CODE区,位于0地址
- EXPORT __Vectors ;在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用
-
- __Vectors DCD 0 ;当前地址写入一个字(32bit)数据,值应该为栈顶地址
- DCD Reset_Handler ;当前地址写入一个字(32bit)数据,值为Reset_Handler指向的地址值,即程序入口地址
- AREA |.text|, CODE, READONLY ;定义代码段,标记为.text
- ; Reset handler ;利用PROC、ENDP这一对伪指令把程序段分为若干个过程,使程序的结构加清晰
- Reset_Handler PROC ;过程的开始
- EXPORT Reset_Handler [WEAK] ;[WEAK] 弱定义,意思是如果在别处也定义该标号(函数),在链接时用别处的地址。
- IMPORT led ;通知编译器要使用的标号在其他文件
- LDR SP, =(0x20000000+0x400) ;设置栈顶地址为0x20000400
- BL led ;跳转去执行led函数
- B . ;原地跳转,即处于循环状态
- ENDP
- ALIGN ;填充字节使地址对齐
- END ;整个汇编文件结束
复制代码
然后新建led.c文件,如下所示
- int delay(int ndelay)
- {
- volatile int n = ndelay;
- while(n--);
-
- return 0;
- }
- int led(void)
- {
- unsigned int *pReg;
-
- /* 1、使能GPIOB */
- pReg = (unsigned int *)(0x40021000 + 0x18);
- *pReg |= (1<<3);
-
- /* 2、设置GPIOB5为输出引脚 */
- pReg = (unsigned int *)(0x40010C00 + 0x00);
- *pReg |= (1<<20);
- pReg = (unsigned int *)(0x40010C00 + 0x0C);
-
- while (1)
- {
- /* 3、设置GPIOB5输出1 */
- *pReg |= (1<<5);
-
- delay(1000000);
- /* 4、设置GPIOB5输出0 */
- *pReg &= ~(1<<5);
-
- delay(1000000);
- }
- }
复制代码
编译链接烧写到开发板,可以看到LED闪烁
三、在GCC中实现
修改start.s如下所示:
- .syntax unified /* 指明当前汇编文件的指令是ARM和THUMB通用格式 */
- .cpu cortex-m3 /* 指明cpu核为cortex-m3 */
- .fpu softvfp /* 软浮点 */
- .thumb /* thumb指令 */
- .global _start /* .global表示Reset_Handler是一个全局符号 */
- .word 0x00000000 /* 当前地址写入一个字(32bit)数据,值为0x00000000,实际上应为栈顶地址 */
- .word _start+1 /* 当前地址写入一个字(32bit)数据, 值为_reset标号代表的地址+1,即程序入口地址*/
- _start: /* 标签_start,汇编程序的默认入口是_start */
- /* 1、设置栈 */
- LDR SP, =(0x20000000+0x400)
- /* 2、跳转到led函数 */
- BL led
- /* 3、原地循环 */
- B .
复制代码
使用同样的led.c文件,如下所示
- int delay(int ndelay)
- {
- volatile int n = ndelay;
- while(n--);
-
- return 0;
- }
- int led(void)
- {
- unsigned int *pReg;
-
- /* 1、使能GPIOB */
- pReg = (unsigned int *)(0x40021000 + 0x18);
- *pReg |= (1<<3);
-
- /* 2、设置GPIOB5为输出引脚 */
- pReg = (unsigned int *)(0x40010C00 + 0x00);
- *pReg |= (1<<20);
- pReg = (unsigned int *)(0x40010C00 + 0x0C);
-
- while (1)
- {
- /* 3、设置GPIOB5输出1 */
- *pReg |= (1<<5);
-
- delay(1000000);
- /* 4、设置GPIOB5输出0 */
- *pReg &= ~(1<<5);
-
- delay(1000000);
- }
- }
复制代码
再修改Makefile如下,注意要有-mcpu=cortex-m3 -mthumb参数,这个很重要
- all : start.S led.c
- arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -c start.s -o start.o
- arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -c led.c -o led.o
- arm-none-eabi-ld start.o led.o -Ttext 0X8000000 -o led.elf
- arm-none-eabi-objcopy led.elf -O ihex led.hex
- arm-none-eabi-objcopy led.elf -O binary -S led.bin
- arm-none-eabi-objdump -D -m cortex-m3 led.elf > led.dis
- clean:
- rm -rf *.o led.elf led.hex led.bin led.dis
复制代码
使用make执行后如下
编译烧录后可以看到LED闪烁
四、优化Makefile
可以将Makefile优化为如下所示
- TARGET = led
- OBJECTS = start.o led.o
- CPU = -mcpu=cortex-m3
- MCU = $(CPU) -mthumb
- CFLAGS = $(MCU) -Wall
- all : $(TARGET).elf $(TARGET).hex $(TARGET).bin $(TARGET).dis
- arm-none-eabi-size [ DISCUZ_CODE_6 ]lt;
- %.o: %.c
- arm-none-eabi-gcc -c $(CFLAGS) [ DISCUZ_CODE_6 ]lt; -o $@
- %.o: %.s
- arm-none-eabi-gcc -c $(CFLAGS) [ DISCUZ_CODE_6 ]lt; -o $@
- $(TARGET).elf: $(OBJECTS)
- arm-none-eabi-ld $(OBJECTS) -Ttext 0X8000000 -o $@
- %.hex: %.elf
- arm-none-eabi-objcopy -O ihex [ DISCUZ_CODE_6 ]lt; $@
- %.bin: %.elf
- arm-none-eabi-objcopy -O binary -S [ DISCUZ_CODE_6 ]lt; $@
- %.dis: %.elf
- arm-none-eabi-objdump -D -m cortex-m3 [ DISCUZ_CODE_6 ]lt; > $@
- clean:
- rm -rf *.o led.elf led.hex led.bin led.dis
复制代码
————————————————
转载:Willliam_william
|