你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F0系列之编写C语言点亮LED灯

[复制链接]
STMCU小助手 发布时间:2022-8-25 22:07
一、前言
使用c语言时,要用到的一个很重要的就是栈,所以我们要在汇编中就设置好栈;
而对于当下的stm32f103来说,我们可以在0x08000000处写入栈顶地址,也可以在汇编程序中使用指令设置SP

二、在MDK中实现
修改start.s,在0x08000000处写入栈顶地址,如下所示:

  1. Stack_Size      EQU     0x00000400                                  ;定义堆栈大小为1024byte
  2.                                 AREA    STACK, NOINIT, READWRITE, ALIGN=3  ;定义一个数据段,标记为STACK,即栈,不写入初始值初,对RAM来说,即初始化为0,8字节对齐
  3. Stack_Mem                SPACE        Stack_Size                                    ;保留Stack_Size大小的栈空间
  4. __initial_sp                                                                                  ;标号,代表堆栈顶部地址,后面有用

  5.                 PRESERVE8                                                        ;指示编译器8字节对齐
  6.                 THUMB                                                                ;指示编译器以后的指令为THUMB指令                                                               


  7. ; Vector Table Mapped to Address 0 at Reset
  8.                                 AREA    RESET, CODE, READONLY                ;定义只读数据段,标记为RESET,其实放在CODE区,位于0地址
  9.                                 EXPORT  __Vectors                                        ;在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用
  10.                                        
  11. __Vectors       DCD     __initial_sp                            ;当前地址写入一个字(32bit)数据,值为__initial_sp指向的地址值,即栈顶地址
  12.                 DCD     Reset_Handler                      ;当前地址写入一个字(32bit)数据,值为Reset_Handler指向的地址值,即程序入口地址

  13.                                 AREA    |.text|, CODE, READONLY                ;定义代码段,标记为.text

  14. ; Reset handler        ;利用PROC、ENDP这一对伪指令把程序段分为若干个过程,使程序的结构加清晰
  15. Reset_Handler   PROC                                                                ;过程的开始
  16.                                 EXPORT  Reset_Handler        [WEAK]                ;[WEAK] 弱定义,意思是如果在别处也定义该标号(函数),在链接时用别处的地址。
  17.                                 IMPORT  led                                                        ;通知编译器要使用的标号在其他文件
  18.                                 BL                led                                                 ;跳转去执行led函数
  19.                                 B                .                                                        ;原地跳转,即处于循环状态
  20.                                 ENDP

  21.                 ALIGN                                                                 ;填充字节使地址对齐
  22.                 END                                                                        ;整个汇编文件结束
复制代码

在汇编程序中使用指令设置SP,如下所示:

  1.                PRESERVE8                                                        ;指示编译器8字节对齐
  2.                 THUMB                                                                ;指示编译器以后的指令为THUMB指令                                                               


  3. ; Vector Table Mapped to Address 0 at Reset
  4.                                 AREA    RESET, CODE, READONLY                ;定义只读数据段,标记为RESET,其实放在CODE区,位于0地址
  5.                                 EXPORT  __Vectors                                        ;在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用
  6.                                        
  7. __Vectors       DCD     0                                                    ;当前地址写入一个字(32bit)数据,值应该为栈顶地址
  8.                 DCD     Reset_Handler                      ;当前地址写入一个字(32bit)数据,值为Reset_Handler指向的地址值,即程序入口地址

  9.                                 AREA    |.text|, CODE, READONLY                ;定义代码段,标记为.text

  10. ; Reset handler        ;利用PROC、ENDP这一对伪指令把程序段分为若干个过程,使程序的结构加清晰
  11. Reset_Handler   PROC                                                                ;过程的开始
  12.                                 EXPORT  Reset_Handler        [WEAK]                ;[WEAK] 弱定义,意思是如果在别处也定义该标号(函数),在链接时用别处的地址。
  13.                                 IMPORT  led                                                        ;通知编译器要使用的标号在其他文件
  14.                                 LDR SP, =(0x20000000+0x400)                        ;设置栈顶地址为0x20000400
  15.                                 BL                led                                                 ;跳转去执行led函数
  16.                                 B                .                                                        ;原地跳转,即处于循环状态
  17.                                 ENDP

  18.                 ALIGN                                                                 ;填充字节使地址对齐
  19.                 END                                                                        ;整个汇编文件结束
复制代码

然后新建led.c文件,如下所示

  1. int delay(int ndelay)
  2. {
  3.         volatile int n = ndelay;
  4.         while(n--);
  5.         
  6.         return 0;
  7. }

  8. int led(void)
  9. {
  10.         unsigned int *pReg;
  11.         
  12.         /* 1、使能GPIOB */
  13.         pReg = (unsigned int *)(0x40021000 + 0x18);
  14.         *pReg |= (1<<3);
  15.         
  16.         /* 2、设置GPIOB5为输出引脚 */
  17.         pReg = (unsigned int *)(0x40010C00 + 0x00);
  18.         *pReg |= (1<<20);

  19.         pReg = (unsigned int *)(0x40010C00 + 0x0C);
  20.         
  21.         while (1)
  22.         {
  23.                 /* 3、设置GPIOB5输出1 */
  24.                 *pReg |= (1<<5);
  25.                
  26.                 delay(1000000);

  27.                 /* 4、设置GPIOB5输出0 */
  28.                 *pReg &= ~(1<<5);
  29.                
  30.                 delay(1000000);               
  31.         }
  32. }
复制代码

编译链接烧写到开发板,可以看到LED闪烁

20210102162522474.gif

三、在GCC中实现

修改start.s如下所示:

  1.   .syntax unified                   /* 指明当前汇编文件的指令是ARM和THUMB通用格式 */
  2.   .cpu cortex-m3                    /* 指明cpu核为cortex-m3 */
  3.   .fpu softvfp                      /* 软浮点 */
  4.   .thumb                            /* thumb指令 */

  5. .global  _start                     /* .global表示Reset_Handler是一个全局符号 */

  6. .word 0x00000000                    /* 当前地址写入一个字(32bit)数据,值为0x00000000,实际上应为栈顶地址 */
  7. .word _start+1                      /* 当前地址写入一个字(32bit)数据, 值为_reset标号代表的地址+1,即程序入口地址*/

  8. _start:                             /* 标签_start,汇编程序的默认入口是_start */
  9.     /* 1、设置栈 */
  10.     LDR SP, =(0x20000000+0x400)
  11.     /* 2、跳转到led函数 */
  12.     BL led
  13.     /* 3、原地循环 */
  14.     B .
复制代码

使用同样的led.c文件,如下所示

  1. int delay(int ndelay)
  2. {
  3.         volatile int n = ndelay;
  4.         while(n--);
  5.         
  6.         return 0;
  7. }

  8. int led(void)
  9. {
  10.         unsigned int *pReg;
  11.         
  12.         /* 1、使能GPIOB */
  13.         pReg = (unsigned int *)(0x40021000 + 0x18);
  14.         *pReg |= (1<<3);
  15.         
  16.         /* 2、设置GPIOB5为输出引脚 */
  17.         pReg = (unsigned int *)(0x40010C00 + 0x00);
  18.         *pReg |= (1<<20);

  19.         pReg = (unsigned int *)(0x40010C00 + 0x0C);
  20.         
  21.         while (1)
  22.         {
  23.                 /* 3、设置GPIOB5输出1 */
  24.                 *pReg |= (1<<5);
  25.                
  26.                 delay(1000000);

  27.                 /* 4、设置GPIOB5输出0 */
  28.                 *pReg &= ~(1<<5);
  29.                
  30.                 delay(1000000);               
  31.         }
  32. }
复制代码

再修改Makefile如下,注意要有-mcpu=cortex-m3 -mthumb参数,这个很重要

  1. all : start.S led.c
  2.         arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -c start.s -o start.o
  3.         arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -c led.c -o led.o
  4.         arm-none-eabi-ld  start.o led.o -Ttext 0X8000000 -o led.elf
  5.         arm-none-eabi-objcopy led.elf -O ihex led.hex
  6.         arm-none-eabi-objcopy led.elf -O binary -S led.bin
  7.         arm-none-eabi-objdump -D -m cortex-m3 led.elf > led.dis

  8. clean:
  9.         rm -rf *.o led.elf led.hex led.bin led.dis
复制代码

使用make执行后如下
20210102175418537.png

编译烧录后可以看到LED闪烁

20210102175449422.gif

四、优化Makefile
可以将Makefile优化为如下所示

  1. TARGET = led

  2. OBJECTS = start.o led.o

  3. CPU = -mcpu=cortex-m3
  4. MCU = $(CPU) -mthumb

  5. CFLAGS = $(MCU) -Wall

  6. all : $(TARGET).elf $(TARGET).hex $(TARGET).bin $(TARGET).dis
  7.         arm-none-eabi-size [        DISCUZ_CODE_6        ]lt;

  8. %.o: %.c
  9.         arm-none-eabi-gcc -c $(CFLAGS)  [        DISCUZ_CODE_6        ]lt; -o $@

  10. %.o: %.s
  11.         arm-none-eabi-gcc -c $(CFLAGS)  [        DISCUZ_CODE_6        ]lt; -o $@

  12. $(TARGET).elf: $(OBJECTS)
  13.         arm-none-eabi-ld  $(OBJECTS) -Ttext 0X8000000 -o $@

  14. %.hex: %.elf
  15.         arm-none-eabi-objcopy -O ihex [        DISCUZ_CODE_6        ]lt; $@

  16. %.bin: %.elf
  17.         arm-none-eabi-objcopy -O binary -S [        DISCUZ_CODE_6        ]lt; $@

  18. %.dis: %.elf
  19.         arm-none-eabi-objdump -D -m cortex-m3 [        DISCUZ_CODE_6        ]lt; > $@

  20. clean:
  21.         rm -rf *.o led.elf led.hex led.bin led.dis
复制代码

————————————————
转载:Willliam_william


收藏 评论0 发布时间:2022-8-25 22:07

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版