目录
32学习可以看江科大野火和原子的视频
在最开始接触32的时候看江科大的视频,了解了一点寄存器之后,就直接用标准库函数了。一直是知道怎么用函数,但对这个函数是如何实现的不是太了解。前段时间重新看了,野火的视频,火哥讲的比较详细。把这一部分搞明白了。
寄存器和库函数
在用寄存器开发时,我们要查表然后对寄存器的地址进行操作。而标准库函数直接就把它封装成一个函数了。
举个例子。我们用寄存器电灯时,需要打开时钟,然后选择gpio对其端口配置寄存器进行位操作。配置其模式,然后对ODR进行写1或0来实现灯的亮灭。对于这样的操作来讲,如果要配置多个的话会很麻烦要一个一个的查手册,配置寄存器。
而库函数就是把它寄存器给封装成函数来使用。
对于一个工程来说最重要的是启动文件。当有了启动文件其实程序就可以运行了;
对于下面的文件,最下面的三个文件包括头文件都是自己写的。用的不是官方的。由此可以看出这些并不是必不可少的。
构建一个简单库函数
自己构建一个库函数是学习库函数的最好方法。
对寄存器点灯的代码进行封装
其中systemInit(void)函数是对时钟进行初始化,在启动文件中被调用,正常写代码官方都会有
1.外设寄存器结构体定义
在操作寄存器时,我们操作的都是寄存器的绝对地址。每个都这样操作会很麻烦。其实外设寄存器的地址都是基于外设基地址的偏移地址,都是在外设基地址上逐个连续递增的,每个寄存器占32个字节,跟结构体成员类似。所以可以定义一种外设结构体,结构体的地址就是外设的基地址,其成员就与寄存器一样。这样操作寄存器的时候直接对结构体成员操作就行了;
2.外设存储器映射
外设寄存器结构体只是一个定义,想要让这个结构体和寄存器对应起来,达到给寄存器赋值就可以操作寄存器的话,还需要找到寄存器的地址。我们可以找到外设的地址,将其定义成宏,实现外设寄存器的映射。

3.外设声明
定义好结构体,实现映射之后,再把外设的基地址强制转换为相应的外设寄存器结构体指针,再把指针声明为外设名。这样外设名就和外设的地址对应起来了。而且这个外设名还是一个该外设类型的寄存器结构体指针,通过该指针可以直接操作该外设的全部寄存器。


4.定义位操作函数
比如我们最开始接触到的
就是把引脚和gpio的宏定义好之后实现的
这里只声明了GPIOB,不过同理可以得到其他的。
5.定义初始化结构体
这里就是最常见的初始化函数的结构体配置了
我们在写代码的时候是要对结构体的参数进行写值,选择引脚,模式等等,这里就需要定义其枚举类型了
6.定义引脚模式的枚举类型
上面的结构体虽然很直接但在对结构体赋值实现功能时,还需要查手册的寄存器说明,我们可以直接使用C语言中的枚举定义功能,根据手册把每个成员的所有取值定义好,这样就不用再去看手册了
比如下图
7.定义初始化函数
按照上面的思路对结构体赋值后将他输入GPIO初始化函数,由他实现寄存器配置,即我们常用的GPIO_Init(GPIOx,&GPIO_InitStruct)函数
下图是官方的函数一部分,感兴趣的可以在官方库函数里面查看
8.使用库函数
这样一个简单的库函数就写好了可以运行程序
总结
一个库函数是这样构成的。这只是一个简单的库函数,官方的比这个复杂的多,不过大概了解其流程就可以搞明白库函数的构成。对理解程序更有帮助,知其然知其所以然。
参考文档:
野火零死角教程
官方手册