赞
踩
使用c语言时,要用到的一个很重要的就是栈,所以我们要在汇编中就设置好栈;
而对于当下的stm32f103来说,我们可以在0x08000000处写入栈顶地址,也可以在汇编程序中使用指令设置SP
修改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闪烁
修改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优化为如下所示
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 $< %.o: %.c arm-none-eabi-gcc -c $(CFLAGS) $< -o $@ %.o: %.s arm-none-eabi-gcc -c $(CFLAGS) $< -o $@ $(TARGET).elf: $(OBJECTS) arm-none-eabi-ld $(OBJECTS) -Ttext 0X8000000 -o $@ %.hex: %.elf arm-none-eabi-objcopy -O ihex $< $@ %.bin: %.elf arm-none-eabi-objcopy -O binary -S $< $@ %.dis: %.elf arm-none-eabi-objdump -D -m cortex-m3 $< > $@ clean: rm -rf *.o led.elf led.hex led.bin led.dis
上一篇:STM32裸机开发(3) — 使用汇编点亮LED灯
下一篇:STM32裸机开发(5) — 在Keil-MDK下编写uart串口打印程序
代码存放:https://gitee.com/william_william/stm32f103_noos.git
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。