导语
目前STM32的开发方式主要是有基于寄存器的方式、基于标准库(库函数)的方式、基于HAL库的方式。
基于寄存器的方式,是用程序直接配置寄存器,来达到我们想要的功能,这种方式最底层、最直接、效率会更高一些,但是由于STM32的结构复杂、寄存器太多,所以基于寄存器的方式目前是不推荐的。
基于库函数的方式是使用ST官方提供的封装好的函数,通过调用这些函数来间接地配置寄存器,由于ST对寄存器封装的比较好,所以这种方式既能满足对寄存器的配置,对开发人员也比较友好,有利于提高开发效率。
基于HAL库的方式,可以用图形化界面快速配置STM32,这个比较适合快速上手STM32的情况,但是这种方式隐藏了底层逻辑,如果你对STM32不熟悉,基本只能停留在很浅的水平,推荐在学过标准库之后再去了解这个方式,毕竟HAL库还是很方便的。
新建工程
我们使用库函数的方式,需要准备一个STM32库函数的压缩包。
在Keil5中选择Project新建一个项目,选择STM32F103C8的型号,点击OK后会弹出一个新建工程小助手,这个可以帮助我们快速新建工程,但我们暂时不用这个小助手,把他关闭。
现在工程就建好了,但是没有工程文件,现在这个工程还是没办法用的,需要给它添加一点工程的必要文件。
Start文件夹(必要文件复制)
打开固件库的文件夹,固件库\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm,找到启动文件。

这些就是STN32的启动文件,STM32的程序就是从启动文件开始执行的,把这些文件全部复制,打开刚才新建的工程模板文件夹,新建一个文件夹,可以叫做Start,把文件复制进去。
再打开固件库的文件夹,固件库\Libraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x,可以看到stm32f10x.h和两个system开头的文件。
stm32f10x.h就是STM32的外设寄存器描述文件,是用来描述STM32有哪些寄存器和它对应的地址。
两个system文件是用来配置时钟的,STM32主频72MHz,就是system文件里的函数配置的,把这三个文件复制,也粘贴至Start文件夹下。

接下来,因为这个STM32是内核和内核外为的设备组成的,而且内核的寄存器描述和外围设备的描述文件不在一起,所以我们还需要添加一个内核寄存器的描述文件。
打开固件库,固件库\Libraries\CMSIS\CM3\CoreSupport,这两个cm3(Cortex-M3)文件就是内核寄存器的描述,当然还带了一些内核的配置函数,所以多了个.c文件,我们一并把他俩复制下来粘贴至Start文件夹下。

到此为止,工程的必要文件已经复制完成了。
打开Keil,可以单击名称将文件夹名改成start,然后双击进行文件的添加。
启动文件有很多类型,选哪一个要根据芯片信号进行选择

启动文件有很多的分类,我们只能添加其中一个,我们所用的型号需要选择后缀为md.s的启动文件,至于启动文件如何选择,折叠内容会详细介绍。

最后我们还需要在工程选项里添加上这个文件夹的头文件路径,要不然软件是找不到.h文件的。

新建main函数
接下来我们新建一个main函数,看看这个工程是不是可行,打开工程文件夹,新建一个User文件夹,main函数就放在这个文件夹里。
转到Keil软件中,在Target这里右键,点击添加组。

更改新建的组名叫做User,在User上右键,添加新文件。

下面路径要注意一下,要选择User文件夹,要不然默认放在文件夹外面。

写代码(寄存器操作)
#include "stm32f10x.h"
int main(void){
while(1){
}
}
进行编译,如果0错误0警告,说明我们建立的工程是没问题的。
这个工程目前还没有添加STM32的库函数,所以它还是一个基于寄存器开发的工程,如果你想用寄存器开发STM32,那工程建到这里就可以了。
配置寄存器来完成点灯(控制PC13口高低电平):
1.拿出STM32最小系统板、STLINK和四根母对母的杜邦线,按照插针上的表示,把3.3V、SWDIO、SWCLK、GND对应连接好。
2.打开Keil,点击魔术棒,选择Debug,选择STLINK Debug
点击Settings按钮,勾选Reset and Run,这样我们下载程序后会立马复位并执行,这样方便一些。
这样点击LOAD按钮就可以将程序下载至STM32上了。
第一步
接下来我们就可以写点灯代码了,打开芯片手册,首先用RCC的一个寄存器来使能GPIOC的时钟,GPIO都是APB2的外设,所以在APB2外设时钟使能寄存器RCC_APB2ENR里面配置。可以看到里面有个IOPCEN,这一位就是使能GPIOC的时钟的,IOPCEN置1就是打开GPIOC时钟。
将寄存器RCC_APB2ENR里面的其他位置0,IOPCEN置1,就是只打开GPIOC的时钟。

第二步
接下来就该配置端口了,使用的是GPIOx_CRH寄存器,配置成通用推挽输出模式,速度为50MHz。


即CNF13为00,MODE13为11,换成16进制就是0x00300000。
第三步

ODR13为1则PC13端口为高电平,反之则为低电平。
ODR13为1,则GPIOx_ODR寄存器的值为0x00002000。
ODR13为0,则GPIOx_ODR寄存器的值为0x00000000。
灯是低电平点亮的,所以ODR全为0则是点亮,为0x00002000则灭。
#include "stm32f10x.h"
int main(void){
RCC->APB2ENR = 0X00000010; //使能GPIOC。
GPIOC->CRH = 0X00300000;//配置PC13端口
GPIOC->ODR = 0X00000000;//输出PC口为低电平,灯点亮
while(1){
}
}
这就是使用寄存器点灯的操作,需要不断地查手册了解寄存器每一位是干啥的,而且这个操作方式有个弊端,就是把除了PC13之外的位都配置成了0,这样就影响到了其他端口的原有配置,如果要做到只配置PC13而不影响其他位,则需要&=和|=的操作,所以寄存器方式操作,虽然代码简洁,但是不太方便。
写代码(库函数操作)
打开工程文件夹,新建一个文件夹,叫Library,用来存放库函数。
打开固件库,固件库\Libraries\STM32F10x_StdPeriph_Driver\src,这里除了misc是内核库函数,其他都是内核外的外设库函数。将固件库下的库函数放入Library中。
再打开固件库,固件库\Libraries\STM32F10x_StdPeriph_Driver\inc,这里是库函数的头文件,将这些库函数的头文件也放入Library中。
返回Keil软件,新建组,改名Library,添加文件,魔术棒添加头文件路径。
打开固件库,固件库\Project\STM32F10x_StdPeriph_Template,里面有conf(configuration)文件是用来配置库函数头文件的包含关系的,另外这里还有个用来参数检查的函数定义,这是所有库函数都需要的。两个it文件使用存放中断函数的,把这三个文件复制下来,粘贴到工程User目录下。

返回keil软件,在User组里,把这三个文件添加。
最后还需要一个宏定义,你定义了使用USE_STDPERIPH_DRIVER这个字符串, #include “stm32f10x_conf.h”这个字符串才有效。这样才能包含标准外设库,也就是库函数。

这样基于库函数的工程就建好了。
接下来使用库函数来进行点灯操作。
#include "stm32f10x.h"
int main(void){
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//使能GPIOC
GPIO_InitTypeDef GPIO_InitStructure; //配置端口结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
// GPIO_SetBits(GPIOC,GPIO_Pin_13); //控制PC13端口的高低电平
GPIO_ResetBits(GPIOC,GPIO_Pin_13);
while(1){
}
}
至此,本节新建工程已圆满结束。
工程架构

这个图便是工程架构的结构图,首先是startup启动文件(启动文件使用汇编语言),这个是程序执行最基本的文件,启动文件内定义了中断向量表,中断服务函数等,其中中断函数服务中有个复位中断,这就是整个程序的入口。
当STM32上电复位或者按下复位键之后,程序就会进入复位中断函数执行,复位中断函数主要就做两件事情,第一个是调用SystemInit函数,第二个是调用main函数。
我们只需知道,在main函数执行之前,单片机已经执行了一堆东西了,帮我们把闪存接口、时钟等一系列杂碎的东西都配置好了。
另外,启动文件还定义了STM32所有的其他中断,这些中断达到触发条件后就会自动执行。