STM32 初学者问题

.c文件和.h文件之间的联系

.c文件与.h文件

.C:写具体函数(函数体)
.H:是.C的头文件,里面包含函数的定义,可以让其他.C函数调用。(函数声明,结构体,头文件等)

一般都在头文件中进行函数,变量声明,宏声明,结构体声明,而在C文件中去进行变量定义,函数实现。

所以,.h文件可以被多个.c文件引用(头文件),可以一改全改。

include的过程完全可以"看成"是一个文件拼接的过程。

  • 在h文件中可以写函数体,只要在任何一个C文件包含此.h文件就可以将这个函数编译成目标文件的一部分(但编译是以C文件为单位的,如果不在任何C文件中包含此.h文件的话,这段代码就形同虚设)
  • 一般都在h文件中进行函数,变量声明,宏声明,结构体声明,在C文件中去进行变量定义,函数实现
  • 声明告诉编译器这些符号的含义
  • 声明在回答who的问题,定义回答how的问题
  • “定义”兼具“声明”的功能,任何变量、函数必须先声明后使用
  • 编译是以c文件为单位的,编译器是不会编译h文件的
  • #include本身只是一个简单的文件包含预处理命令,即用include的文件的内容代替该行语句

ifndef,define,endif

作用:防止重复定义产生错误

#ifndef _feed_dog_h //如果到目前为止还没有定义过“_feed_dog_h”这个宏
#define _feed_dog_h //则定义“_feed_dog_h”这个宏

extern void feed_dog(void); //声明一个外部函数

#endif //“#ifndef”到此结束

.h文件编译

在一个项目中,会有.h文件被多次引用,这样.h文件就会被放到多个.c文件中被多次编译,我们要尽量避免这样的多次声明.从而提高效率.
在这里插入图片描述
上面的D.h文件中就会重复出现两个int a();的声明,这样就有点重复了,这时条件编译宏就派上了用场
在这里插入图片描述

这样就不会重复定义了.

部分名词解释

总线:信息的传递通道,连接各种外设和芯片,详细的介绍可以看stm32的总线AMBA、AHB、APB
一般说来,有系统总线AHB和外设总线APB

时钟系统:做个不严谨的比喻,我们可以认为时钟源就是一个大的水源,外设时钟是一个个小水库,有的水库可以有多个水源的水补充(比如系统时钟),水库周围的人(外设)要用水,就要打开水库(使能外设时钟),想喝多少(分频因子设置函数),喝哪里的水(时钟源选择函数)都可以选择。
我们不可能一直开着水闸(浪费,所以设置一堆使能函数);
不同的人不同用途对水的要求不一样(所以可以选择水库的水的来源,给你一堆时钟源配置函数)。
现在你在回头看看这三个函数类别,是不是有点理解了?
挨着顺序举个例:
我们使用串口1,首先就要打开时钟:RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //串口1挂载在APB2总线,函数使用要对应其挂载的总线。
然后再对串口1做相关的初始化参数配置就可以使用串口1了(不做展开)。

变量声明和变量定义

变量定义:用于为变量分配存储空间,还可为变量指定初始值。程序中,变量有且仅有一个定义。

变量声明:用于向程序表明变量的类型和名字(这句话可以理解成,变量声明告诉编译器某个符号的类型)。

定义也是声明:当定义变量时我们声明了它的类型和名字。

extern是声明不是定义:通过使用extern关键字声明变量名而不定义它,表示extern变量的定义不在这个文件中,请到其它.c文件中寻找。

变量在使用前必须被被定义或者声明。

在一个程序中,变量只能定义一次,却可以声明多次。

定义分配存储空间,而声明不会。

函数的声明与定义

函数定义的时候自带声明的性质

函数的声明告诉编译器,函数有哪些传入参数,分别是什么类型,函数有返回值吗,是什么类型。函数的定义告诉编译器函数如何实现

两者区别起来比较简单,带有{ }的就是定义,否则就是声明。

结构体

声明结构体类型格式

格式:
struct 结构体名
{
	成员列表;
}变量名列表;

实例:
struct _GPIO
{
	int TMODER;
	int Tser;
}
**注:变量名列表结构体声明的结构体变量,可不写,以后再定义**
例如:struct _GPIO  age,number;//就定义了两个结构体变量age和number

定义结构体变量后,结构体成员变量的引用方法是

例如我们上面定义了的age结构体变量,我要输出他的成员变量Tser
那么应该写为
printf("%d",age.Tser);//也就是 结构体变量名.成员变量名,没什么特殊的

定义结构体指针变量

依然基于上面的_GPIO结构体
定义结构体指针变量:struct _GPIO  *age;
是的,只是结构体变量名前面加了*,但是要访问结构体变量成员时应该这样写
printf("%d",age->Tser);

初始化一个外设

这里 PPP 代表任意外设。

  1. 在主应用文件中,声明一个结构 PPP_InitTypeDef,例如:
PPP_InitTypeDef PPP_InitStructure;

这里 PPP_InitStructure 是一个位于内存中的工作变量,用来初始化一个或者多个外设 PPP。

  1. 为变量 PPP_InitStructure 的各个结构成员填入允许的值。可以采用以下 2 种方式:
    a)按照如下程序设置整个结构体
PPP_InitStructure.member1 = val1;
PPP_InitStructure.member2 = val2;
PPP_InitStructure.memberN = valN;
/* where N is the number of the structure members */

以上步骤可以合并在同一行里,用以优化代码大小:PPP_InitTypeDef PPP_InitStructure = { val1, val2,.., valN}

b)仅设置结构体中的部分成员:这种情况下,用户应当首先调用函数 PPP_SturcInit(…)来初始化变量PPP_InitStructure,然后再修改其中需要修改的成员。这样可以保证其他成员的值(多为缺省值)被正确填入。

PPP_StructInit(&PPP_InitStructure);
PP_InitStructure.memberX = valX;
PPP_InitStructure.memberY = valY;
/*where X and Y are the members the user wants to configure*/
  1. 调用函数 PPP_Init(…)来初始化外设 PPP。

  2. 在这一步,外设 PPP 已被初始化。可以调用函数 PPP_Cmd(…)来使能之。

PPP_Cmd(PPP, ENABLE);

可以通过调用一系列函数来使用外设。每个外设都拥有各自的功能函数。更多细节参阅 Section3 外设固
件概述。
注:1. 在设置一个外设前,必须调用以下一个函数来使能它的时钟:

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_PPPx, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_PPPx, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PPPx, ENABLE);
  1. 可以调用函数 PPP_Deinit(…)来把外设 PPP 的所有寄存器复位为缺省值:
    PPP_DeInit(PPP)
  2. 在外设设置完成以后,继续修改它的一些参数,可以参照如下步骤:
PPP_InitStucture.memberX = valX;
PPP_InitStructure.memberY = valY; /* where X and Y are the only
members that user wants to modify*/
PPP_Init(PPP, &PPP_InitStructure);

工程模板

1、core_cm4.h	//内核功能的定义,比如NVIC相关寄存器的结构体和Systick配置;
2、core_cm4_simd.h	//包含与编译器相关的处理
3、core_cmFunc.h	//内核核心功能接口头文件
4、core_cmInstr.h	//包含一些内核核心专用指令

5、startup_stm32f40_41xxx.s	//devices vector table for MDK-ARM toolchain
6、stm32f4xx.h	//contains all the peripheral register's definitions, bits definitions 
				//and memory mapping for STM32F4xx devices
7、system_stm32f4xx.c	//contains the system clock configuration for STM32F4xx devices,
						//关键函数SystemInit(),系统启动文件startup_stm32f40_41xxx.s里面调用
8、stm32f4xx_conf.h	//里面包含了我们需要使用的标准库,对于需要使用的库需要在其中加以说明include,		
					//stm32f4xx.h里面可以看到对其include
					
9、stm32f4xx_it.c	//provides template for all exceptions handler and 
          			// peripherals interrupt service routine.
10、main.c		//主程序
11、led.c 	//对于关键使用硬件的驱动配置文件

在这里插入图片描述

新建一个固件库

新建一个固件库模板

1.新建工程模板文件夹,如“Fwlib-Template”,下面新建如下文件夹:
在这里插入图片描述
2.新建工程,选择相应芯片型号(这是需要提前在st官网下载相应芯片包并安装的)。
3.在工程中target文件夹下新建相应group
在这里插入图片描述
4.将官方库的相应文件拷贝到自己的工程模板目录中

  • libraries:(将官方库的libraries拷贝过来之后调整目录结构)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • user:(这个是从官方库的例程里面拷贝过来的,除了main.c)
    在这里插入图片描述
    在这里插入图片描述
  • 添加include path

在这里插入图片描述

  • 定义宏
    在这里插入图片描述

未完待续(也可能已经完了)

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值