新建工程时的文件及常见错误

新建工程时的文件及常见错误

大纲

  1. 启动文件
  2. stm32f10x.h 文件
  3. core_cm3.c

具体案例

启动文件

这里只是简单介绍启动文件,具体的内容在后面会详细分析

名为“startup_stm32f10x_hd.s”的文件,它里边使用汇编语言写好了基本程序,当 STM32 芯片上电启动的时候,首先会执行这里的汇编程序,从而建立起 C 语言的运行环境,所以我们把这个文
件称为启动文件。该文件使用的汇编指令是 Cortex-M3 内核支持的指令,可参考《Cortex-M3 权威指南》中指令集章节。

当然在这个文件的基础上,在以后的工作需求上进行适量的更改

其主要的功能有(后面会单独分析代码):
• 初始化堆栈指针 SP;
• 初始化程序计数器指针 PC;
• 设置堆、栈的大小;
• 初始化中断向量表;
• 配置外部 SRAM 作为数据存储器(这个由用户配置,一般的开发板可没有外部 SRAM);
• 调用 SystemIni() 函数配置 STM32 的系统时钟。
• 设置 C 库的分支入口“__main”(最终用来调用 main 函数);

在启动文件中有一段复位后立即执行的程序,Reset_Handler

;Reset handler
 Reset_Handler PROC
 EXPORT Reset_Handler [WEAK]
 IMPORT SystemInit
 IMPORT __main

 LDR R0, =SystemInit
 BLX R0
LDR R0, =__main
BX R0
ENDP

这里简单解释一下(当然后面也会讲这一段)

开头的是程序注释,在汇编里面注释用的是“;”,相当于 C 语言的
“//”注释符

第二行是定义了一个子程序:Reset_Handler。PROC 是子程序定义伪指令。这里就相当于 C 语言里定义了一个函数,函数名为 Reset_Handler。

第三行 EXPORT 表示 Reset_Handler 这个子程序可供其他模块调用。相当于 C 语言的函数声明。关键字 [WEAK] 表示弱定义,如果编译器发现在别处定义了同名的函数,则在链接时用别处的地址进行链接,如果其它地方没有定义,编译器也不报错,以此处地址进行链接。

第四行和第五行 IMPORT 说明 SystemInit 和 __main 这两个标号在其他文件,在链接的时候需要到其他文件去寻找。相当于 C 语言中,从其它文件引入函数声明。以便下面对外部函数进行调用。

SystemInit 需要由我们自己实现,即我们要编写一个具有该名称的函数,用来初始化 STM32 芯片的时钟,一般包括初始化 AHB、APB 等各总线的时钟,需要经过一系列的配置 STM32 才能达到稳定运行的状态。其实这个函数在固件库里面有提供,官方已经为我们写好。

__main 其实不是我们定义的 (不要与 C 语言中的 main 函数混淆),这是一个 C 库函数,当编译器编译时,只要遇到这个标号就会定义这个函数,该函数的主要功能是:负责初始化栈、堆,配置系统环境,并在函数的最后调用用户编写的 main 函数,从此来到 C 的世界。

第六行把 SystemInit 的地址加载到寄存器 R0。

第七行程序跳转到 R0 中的地址执行程序,即执行 SystemInit 函数的内容。

第八行把 __main 的地址加载到寄存器 R0。

第九行程序跳转到 R0 中的地址执行程序,即执行 __main 函数,执行完毕之后就去到我们熟知的
C 世界,进入 main 函数。

第十行表示子程序的结束。

启动文件的选择

在这里插入图片描述
不同芯片的FLASH容量请自行查阅芯片手册

stm32f10x.h 文件

在编程之前我们要先实现寄存器映射,有关寄存器映射的代码都统一写在 stm32f10x.h 文件中,除此之外还有很多其它的定义,可自行观看

core_cm3.c

在 CoreSupport 文件夹中有 core_cm3.c 和 core_cm3.h 两个文件。Core_cm3.h 头文件里面实现了内核的寄存器映射,对应外设头文件 stm32f10x.h,区别就是一个针对内核的外设,一个针对片上(内核之外)的外设。core_cm3.c 文件实现了一下操作内核外设寄存器的函数,用的比较少。

我们还需要了解的是 core_cm3.h 头文件中包含了“stdint.h”这个头文件,这是一个 ANSI C 文件,是独立于处理器之外的,就像我们熟知的 C 语言头文件“stdio.h”文件一样。位于 RVMDK 这个软件的安装目录下,主要作用是提供一些类型定义

而在stdint.h文件里,实现对数据类型的定义,如下

/* exact-width signed integer types */
 typedef signed char int8_t;
 typedef signed short int int16_t;
 typedef signed int int32_t;
 typedef signed __int64 int64_t;

 /* exact-width unsigned integer types */
 typedef unsigned char uint8_t;
 typedef unsigned short int uint16_t;
 typedef unsigned int uint32_t;
 typedef unsigned __int64 uint64_t;

这些新类型定义屏蔽了在不同芯片平台时,出现的诸如 int 的大小是 16 位,还是 32 位的差异。所以在我们以后的程序中,都将使用新类型如 uint8_t 、uint16_t 等。

stm32f10x_conf.h

stm32f10x_conf.h:这个文件被包含进 stm32f10x.h 文件。当我们使用固件库编程的时候,如果需要某个外设的驱动库,就需要包含该外设的头文件:stm32f10x_ppp.h,包含一个还好,如果是用了多外设,就需要包含多个头文件,这不仅影响代码美观也不好管理
现我们用一个头文件stm32f10x_conf.h 把这些外设的头文件都包含在里面,让这个配置头文件统一管理这些外设的头文件,我们在应用程序中只需要包含这个配置头文件即可,我们又知道这个头文件在stm32f10x.h 的最后被包含,所以最终我们只需要包含 stm32f10x.h 这个头文件即可,非常方便

简而言之:这个是所有外设头文件的头文件
如下:

 #include "stm32f10x_adc.h"
 #include "stm32f10x_bkp.h"
 #include "stm32f10x_can.h"
 #include "stm32f10x_cec.h"
 #include "stm32f10x_crc.h"
 #include "stm32f10x_dac.h"
 #include "stm32f10x_dbgmcu.h"
 #include "stm32f10x_dma.h"
 #include "stm32f10x_exti.h"
 #include "stm32f10x_flash.h"
 #include "stm32f10x_fsmc.h"
 #include "stm32f10x_gpio.h"
 #include "stm32f10x_i2c.h"
 #include "stm32f10x_iwdg.h"
 #include "stm32f10x_pwr.h"
 #include "stm32f10x_rcc.h"
 #include "stm32f10x_rtc.h"
 #include "stm32f10x_sdio.h"
 #include "stm32f10x_spi.h"
 #include "stm32f10x_tim.h"
 #include "stm32f10x_usart.h"
 #include "stm32f10x_wwdg.h"
 #include "misc.h"

stm32f10x_conf.h 这个文件还可配置是否使用“断言”编译选项

#ifdef USE_FULL_ASSERT

 /**
 * @brief The assert_param macro is used for parameters check.
 * @param expr: If expr is false, it calls assert_failed function
 * which reports the name of the source file and the source
 * line number of the call that failed.
 * If expr is true, it returns no value.
 * @retval None
 */
 #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t
,*)__FILE__, __LINE__))
 /* Exported functions ---------------------------------- */
 void assert_failed(uint8_t* file, uint32_t line);

在 ST 标准库的函数中,一般会包含输入参数检查,即上述代码中的“assert_param”宏,当参数不符合要求时,会调用“assert_failed”函数,这个函数默认是空的。

实际开发中使用断言时,先通过定义 USE_FULL_ASSERT 宏来使能断言,然后定义“assert_failed”函数,通常我们会让它调用 printf 函数输出错误说明。使能断言后,程序运行时会检查函数的输入参数,当软件经过测试,可发布时,会取消USE_FULL_ASSERT 宏来去掉断言功能,使程序全
速运行。
下面是各个文件之间关系的图
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

挽天技术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值