STM32学习3--新建工程和LED点亮
参考江科大视频和其他博主,侵删!对应江科大视频P4讲。
1、STM32的3种开发方式
目前STM32的开发方式有:基于寄存器、基于标准库、基于HAL库。
1.1基于寄存器
与51单片机开发的方式一样,是用程序直接配置寄存器来达到想要的功能。这种方式最底层、最直接、效率更高。但STM32寄存器太多,结构复杂,该开发方式不推荐。
1.2基于标准库
使用ST官方封装好的库函数,来间接配置相关寄存器。这种方式既能满足对寄存器的配置,又能提高开发效率,且对开发人员友好。所以本次学习是库函数的开发方式。
1.3基于Hal库
Hal库可以使用图形化的界面快速配置STM32,比较适合快速上手STM32。该方式隐藏了底层逻辑,如果对STM32不熟悉,难以精通STM32,暂不推荐该方式。学完标准库,再学习Hal库比较好。
2、固件库介绍
打开配套资料并解压


解压打开,就可以看到两个文件,新建工程时会用到。
第三个文件project是官方提供的工程示例和模版,以后使用库函数的时候可以参考。
打开Project文件夹,可以看到两个文件

Utilities文件夹是STM32官方评估板的相关例程
打开可以看到一个文件,评估板就是官方用STM32做的一个小电路板,用来测评STM32的,
这个文件夹里面存的就是这个小电路板的测评程序。

最后的两个文件,一个是库函数的发布文档,另一个是使用手册,发布文档里有一些版本的说明,使用手册里有教怎么使用这个库函数的。
3、新建工程
首先,我们需要先建立一个存放工程的文件夹,以后的工程都放在该文件夹里。在该文件夹里新建一个文件夹,名字叫2-1 STM32工程模板


打开Keil5软件, 点击Project,新建的工程放在 2-1 STM32工程模板 文件夹里


然后点进去,接下来给工程文件起个通用一点的名字:Project
注意:需要说明这个工程是什么样的,可以在文件夹名称说明, 因为文件夹的名称好改的,而这个工程名称以后不太方便改,所以就起project,然后点击保存。

接下来选择芯片型号:STM32F103C8T6,所以这里选择STM32F103C8,点击OK。

这里弹出一个新建工程小助手,它可帮助我们快速新建工程,暂时不用这个小助手,关掉即可。

工程就建好了,但是这里的工程文件是空的,不能直接用的。

需要给它添加一些工程的必要文件,才能使用该工程,依次打开固件库下面的文件夹。









就可以看到这些文件,是STM32的启动文件,STM32的程序就是从启动文件开始执行的。全部复制。

回到工程模板文件夹:
新建一个文件夹,可以叫做start,把刚复制的启动文件,全部粘贴在该文件夹里。


再回到刚刚固件库的STM32F10X文件夹,打开后,可以看到STM32F10X.h和两个system开头的文件。

这个STM32F10X.h就是STM32的外设寄存器描述文件,它的作用就跟51单片机的头文件regx52.h一样,是用来描述STM32有哪些寄存器和它对应的地址的。 那两个system文件主要是用来配置时钟的。STM32,主频72MHz,就是system文件里的函数配置的。
将3个文件复制,也粘贴到start文件夹下。


因为这个STM32是内核和内核外围的设备组成的,而且这个内核的寄存器描述和外围设备的描述文件不是在一起的,所以我们还需要添加一个内核寄存器的描述文件,打开CM3及下面的文件夹


打开后,看到2个文件,这两个CM3文件就是内核的寄存器描述。还带了一些内核的配置函数,所以多了个点C文件,全部复制,粘贴到start文件夹下。


到此为止,工程的必要文件全部完成。
回到keil软件,把刚才复制的那些文件添加到工程里来。
将这个source Group1改一下名字,也叫start


右键选择添加已经存在的文件到组里来

打开start文件夹,把下面这个文件过滤器选择all files, 就能看到文件夹里的所有文件。

首先添加一下启动文件,这个启动文件有很多分类,但只能添加一个。 我们当下学习的所用型号需要选择这个后缀为md.s的启动文件。我们选中它,点击add。启动文件选择哪一个,后面会有。

剩下的.c和.h文件都要添加进来,这些文件都是STM32里最基本的文件,是不需要修改的,添加进来即可,另外可以看到这个文件图标上带了个小钥匙,表示它是个只读文件。

最后,我们还需要在工程选项里添加上这个文件夹的头文件路径。
点击魔术棒按钮,打开工程选项:
在C/C++里找到这个include passes栏,然后点击右边三个点的按钮。

在这里新建路径,然后再点3个点的按钮,

把start的路径添加进来,点击OK,这样就把这个文件夹的头文件路径添加进来了。


我们再新建一个main函数,测试这个工程是否可行。 打开工程文件夹,然后新建一个文件夹,叫做user,我们的main函数就放在这个文件夹里。

回到Keil,在target这里右键点击添加组,名字叫user。


在User右键点击添加新文件

选择C文件,名字叫main。 路径注意一下,要选择User文件夹,要不然默认是放在文件夹外面的。点击add,这样新建了main.c文件。

打开main.c,我们先右键插入头文件,选择STM32F10X.H,

写一个main函数。

注意:main函数是一个int型返回值,void参数的函数,还有最后一行必须要是空行,要不然会报警告。
编译后,可以看到下面提示的是0错误,0警告,那这就说明我们建立的工程是没问题的


这个工程目前还没有添加STM32的库函数,所以它还是一个基于寄存器开发的工程。 如果你想用寄存器开发STM32,那工程建到这里就可以了。
4、配置寄存器点亮LED
配置寄存器,了解即可。
按照下图,将STM32最小系统板与STLINK连接好,然后把STLINK插在电脑上。

插上后,这个板子上的LED灯应该会常亮。另一个连接在PC13口上的LED灯应该是闪烁的,这是芯片里的一个测试程序。

接下来配置寄存器
点击魔术棒按钮,选择debug。这个调试器默认是ULINK,改成STLINK debug(按照实际选择)

点击右边的Setting按钮
在flash下载这一项,把这个reset and run这一项勾上,这样下载程序后会立马复位并执行,否则每次下载之后还需要按一下板子上的复位按键才能执行程序。

配置好调试器之后,点击确认OK,然后重新编译一下,没有错误。

点击这个Dowdload的按钮,将程序下载到STM32里面。

下载后,这个灯已经不闪了,因为是空程序。

打开STM32的参考手册,
第1步:配置第一个寄存器:首先是RCC的一个寄存器来使能GPIOC的时钟。
RCC:Reset and Clock Control

GPIO都是APB2的外设,所以在这个APB2外设时钟使能寄存器RCC APB2ENR里面配置。

可以看到这里有个IOPCEN, 这一位就是使能GPIOC的时钟的。

这一位写1,就是打开GPIOC的时钟。

那这一位写1,其他的先都给0,那整个寄存器的二进制数据换成16进制就是四个一分组,也就是00000010。
回到keil,在while死循环之前,写上RCC的APB2ENR寄存器=0X00000010,打开GPIOC的时钟。

第2步:配置第二个寄存器,我们需要配置一下PC13口的模式 。找到端口配置高寄存器GPIOx_CRH,这个x可以是A到E的任意一个字母。

右边的CNF13和MODE13就是用来配置13号口的

这个CNF我们需要配置为通用推挽输出模式,也就是这两位为00,MODE要配置为输出模式,最大速度可以给50MHz,也就是这两位为11。

最后我们对照上面的寄存器,这四位为0011,其他的我们也都给它配置为0,这样整个寄存器的值换算成16进制,就是00300000。

回到keil,在这里写上GPIOC的CRH=0x00300000;

第3步: 给PC3口输出数据
手册上,端口输出数据寄存器GPIOx_ODR

有一位ODR13,这一位写1,13号口就是高电平,写0就是低电平。写1的话,ODR的值就是00002000。

回到Keil,写上GPIOC的ODR=0X00002000;

LED灯是低电平点亮的,ODR全给0就亮,而给ODR=0X00002000(高电平)就会灭。

编译后下载程序到STM32系统板,PC13的灯被点亮。

如果给ODR=0X00002000,PC13熄灭。

以上就是通过 配置寄存器的方式进行点灯的操作。
这种方式需要不断的查手册,来了解每个寄存器的每一位的功能。弊端就是:PC13之外的位都配置成了0,影响PC13的原有配置。虽然可以&=和|=进行位操作,代码简洁但很麻烦、不方便。
5、添加库函数实现点灯
打开工程文件,新建文件夹Library,存放库函数。

打开固件库的文件夹,


STM32标准外设驱动:
打开src,是库函数的原文件,


这个misc.c是内核的库函数,其他的就是内核外的外设库函数了,misc:混杂的意思。

全选复制,粘贴到刚创建的Library文件夹里。

再打开固件库的inc文件夹,这是库函数的头文件,也全选复制到library文件夹下。


回到Keil软件,同样在target处右键,然后添加组,起个名字叫library


再右键添加已经存在的文件,将刚刚创建的Library文件夹里的文件全部添加,这样就把所有的库函数文件都添加进来了。


但是对于这个库函数来说,还不能直接使用,还需要再添加一个文件。
打开固件库文件夹,打开project,再打开stm32 template,



可以看到STM32f10x_conf.h和两个it结尾的文件。这个conf.h文件是用来配置库函数头文件的包含关系的。另外这里面还有一个用来参数检查的函数定义,这是所有库函数都需要的。 2个it.c文件是用来存放中断函数的。将这3个文件复制,然后粘贴到工程的User目录下。


回到keil软件,在User组里把刚才那3个文件添加进来。


最后还需要一个宏定义。
在这个头文件右键打开文件,然后滑到最下面,有这个语句,


这个是条件编译,意思是如果你定义了使用标准外设驱动(USE_STDPERIPH_DRIVER)这个字符串,下面这个#include "stm32f10x_conf.h"语句才有效,所以我们还需要复制一下这个字符串

打开工程选项,在C/C++的define栏目粘贴这个字符串。这样才能包含标准外设库,也就是库函数。

还有下面的头文件路径,把这个user和library目录的路径也都添加上,然后OK


这样我们基于库函数的工程就建好了。
回到Keil,这个library里面的库函数也都带了钥匙,不需要更改。唯一需要更改的就是user组里面的这些文件


来编译看一下。 这个第一次编译会比较慢,以后就快一些了。 可以看到是0错误,0警告,这说明我们的工程建立是成功的。

开始点亮LED灯
使用库函数来实现点灯的操作。
第1步:使能时钟
库函数也是间接配置寄存器,同寄存器的配置是一样的。首先是使能时钟。库函数有这样函数来开启时钟。叫RCC_APB2PeriphClockCmd外设时钟控制。 然后这里提示有两个参数,第一个是选择外设,第二个是选择新的状态。

右键跳转到函数定义,有函数的简介和参数说明:
简介说这个函数是用来使能或者失能APB2的外设时钟。 第1、2个参数可以是下面这些值。

找到APB2外设GPIOC,作为第一个参数。第二个参数new state的值可以是enable或者disable。


这样GPIOC的外设时钟就配置好。可以看下这个外设时钟函数,其内部还是配置了RCC_APB2ERNR这个寄存器,但是经过该函数的封装,不需要查RCC_APB2ERNR这个寄存器的功能,且用 或等于、与等于对该寄存器进行了操作,不会影响其他位的功能。这就是库函数与寄存器的区别。使用时,只需要调用库函数,按照提示填写相关参数就可以了。
第2步:配置端口模式
配置端口模式需要用到GPIO_Init函数,包含2个参数:第一个选择哪个GPIO,第二个是参数的结构体。

首先转到函数定义,可以看到,这个函数是根据GPIO_Init结构体的参数来配置GPIO。

参数GPIOx,其中X可以是A到G,来选择你要配置哪个GPIO。我们使用的是PC13口,所以第一个参数就写GPIOC。


第二个参数是一个GPIO_InitTypeDef的结构体,所以要先定义一个结构体。

定义结构体并起名字GPIO_InitStructure(名字可以随意起,但最好起与功能相关的)

用”.”来引出结构体的参数,可以看到这个结构体有3个参数,分别是GPIO模式,GPIO端口、GPIO速度,将3个参数都罗列出来。


转到定义,可以看出,这个参数是GPIOMode_TypeDef里的一个值


通过CTRL+F查找

可以看到,是枚举,GPIOMode是其中的一个值。选择GPIO_MODE_Out_PP,推挽输出。该参数配置完毕。


同理,GPIO_Pin和GPIO_Speed。需要注意的是,GPIO_Pin时,选择member这一项

结构体参数配置完毕。

结构体变量有了,填写GPIO_Init第2个参数,第2个参数是指向结构体的指针。所以要传结构体的地址,结构体变量前 加上取地址符:&


GPIO模式配置就完成了。
第三步:配置端口的高低电平
设置高低电平点亮LED。
库函数GPIO_SetBits,将指定端口设为高电平。函数GPIO_ResteBits,将指定端口设为低电平。可以右击查看定义,填写参数。第一个参数是:GPIO端口:GPIOC,第二个参数:GPIO_Pin_13。两个函数的参数都一样的


首先将端口置为低电平,将GPIO_SetBits函数注释掉,然后编译下载:

LED被点亮
将端口置为高电平,将GPIO_ResetBits函数注释掉,然后编译下载:


实验完成,这就是使用库函数的基本操作。
6、新建工程的启动文件选择
新建工程第一个加的就是启动文件。

启动文件有很多类型,要根据芯片型号选择,见下表:

STM32F1系列中的型号分类,其中根据flash的大小分:小容量产品flash为16~32K,简写为LD,中容量产品flash为16~128K,简写为MD,大容量产品flash为256~512K,减小为HD,加大容量产品flash>512K,简写为XL。
STM3F100的系列,ST把它叫做超值系列,简写为VL(Value Line)。
STM32F105和107系列,ST把它叫做互联型产品,不再根据flash大小再分类。 如果使用STM32F100的型号,就选择带VL的启动文件,然后再根据flash的大小选择LD、MD还是HD;如果你使用STM32F101/102/103的型号,就选择不带VL的,然后根据flash的大小选择LD/MD/HD还是XL。如果你使用STM3F105/107的型号,直接选择CL的启动文件即可。
回到本实验,因为C8T6的flash是64K,所以选择MD的启动文件。

STM32F1系列的型号分类和启动文件的选取。
7、新建工程总结
新建工程步骤:
第1步:新建文件夹,在keil里新建工程,选择芯片型号;
第2步:在工程文件夹里,新建Start、User、Library等文件夹,复制固件库文件到工程文件夹。
这一步是为了添加工程文件准备的,因为文件比较多,需要建立文件夹分类管理。 这个文件夹的名称和数量没有限制,可以根据自己的需求来建。另外,需要用的文件一定要复制到工程文件夹里,不要添加工程文件夹外面的文件。要不然你外面的文件一旦挪位置,工程里就找不到文件了,所以我们要复制文件到工程里来,保持工程的独立性。
第3步:在工程里对应新建Start、User、Library等同名称的分组,然后将文件夹里的文件添加到工程分组里,原因是在keil里方便管理文件,因为keil没法直接添加文件夹,所以还得重复一下,在keil里建立分组,然后添加文件。这个添加文件,建议所有的.h文件和.c文件都添加进来。因为.h文件是不参与编译的,所以一些工程都是不添加.h文件的。但把.h文件加进来比较方便打开查看,建议把所有的文件都添加进来。
第4步:工程选项C/C++,Define内定义USE_STDPERIPH_DRIVER(使用标准外设驱动)这个字符串。
这是使用库函数的条件编译,使用库函数就必须定义这个。另外,其他的工程在这个位置还声明了一个STM32F10X_MD的字符串,由于Keil在新建工程后自动就帮我们声明好了,这个不需要再额外声明了。所以在这个位置只需要声明使用标准外设驱动的字符串即可。
工程选项debug,下拉列表选择对应调试器,再点击settings →flash download →勾选reset and run(勾选就不要复位就可以程序运行了), 这个就是选择调试器来进行下载的选项,我们用STLINK, 就选择STLINK的那一项即可,如果用DAP,就选择DAP即可。
这就是新建工程的基本步骤,新建工程也是很灵活的,大家只要符合要求都可以编译通过。
8、工程架构解析
了解工程的每个文件都是干啥的,为啥需要这些文件。

首先是startup启动文件,这是程序执行最基本的文件。 我们可以看到,keil中启动文件是用汇编写的。

启动文件里定义了中断向量表、中断服务函数等。中断服务函数里有一个复位中断,是整个程序的入口。当STM32上电复位或者按下这个按键后,程序就会进入复位中断函数执行。复位中断函数就执行2个:第一个调用SystemInit函数,第二个调用main函数。然后就结束了。

实际上单片机的程序永远也不会结束,所以在main函数的最后一定是一个死循环。

SystemInit函数就是定义在这个System开头的.c文件里的。 在keil里我们也可以看到这个函数的定义。这个函数的作用:设置微控制器的启动、初始化嵌入式闪存接口、锁相环、更新系统内核的时钟变量。note:这个函数仅在复位后需要调用。

那下面这些就是用来配置这些东西的,这个也不需要更改,我们只需要知道在main函数之前,单片机就已经执行了一堆东西了,把这个闪存接口、时钟等都配置好了。
另外在启动文件还定义了STM32所有的其他中断,这些中断达到触发条件后就会自动执行。

在启动文件下面都是其他的中断调用了。

中断函数的定义就是在STM32Fx_it里面的。我们打开keil可以看到这些就是中断函数的定义。

ST建议我们把自己的中断写在这个位置,也可以在哪用中断就写在哪里,写在别的地方也是可以的。

以上就是中断部分的执行逻辑了,另外也可以自己定义一些用户文件来封装一些模块供主函数和中断调用,这样有利于程序结构的模块化。要不然所有的程序都堆在主函数里,那主函数就太长了。

到此为止,以上就是工程结构主动执行的部分,剩下右边的就是被动执行的东西了,相当于STM32的资源,我们在主函数或者中断函数里就可以调用这些资源。

右上角这两个STM32F10x.h和core_cm3,是外设和内核外设的寄存器描述。 在keil中,可以看到这里面都是寄存器和寄存器每一位的名字,还有地址信息等。

如果直接调用这些寄存器来使用STM32,那就是寄存器的开发方式,这种方式会有一些弊端,也比较麻烦。 所以ST公司就提供了下面这两个文件,这个就是库函数的文件。在keil中可以看到这每个外设都提供了函数。这些函数封装了寄存器的操作,给我们提供更加人性化的函数调用方式,学会操作套路即可。


这个conf文件就是用来配置头文件的包含关系的。在这个conf文件,include了所有的库函数头文件。


同时,在STM32F10x.h的最后,又包含了conf.h,所以在使用这些库函数时,只需要包含STM32F10x.h这一个头文件,就相当于包含了所有的库函数头文件,这样就可以调用库函数了。

本篇结束!
更多推荐


所有评论(0)