当前位置:   article > 正文

STM32学习笔记【江科协】【2-2】新建工程_江科协指针

江科协指针

STM32的三种开发方式:

  • 基于寄存器的开发:与51单片机类似,用程序直接配置寄存器。最底层,最直接,效率更高。但STM32结构复杂,寄存器太多,不推荐
  • 基于标准库(库函数)的开发:使用ST公司已封装好的函数,通过调用这些函数来间接控制寄存器。由于ST对寄存器的封装比较好,既能满足对寄存器的配置,对开发人员更友好
  • 基于HAL库的开发:这种方式是图形化界面快速开发,,但缺乏对STM32的底层逻辑理解,很难深入学习

Libraries :库函数的文件,新建工程时会用到

Project:官方提供的工程示例和工程模板,在使用库函数时可以参考

Utilities:STM32官方评估板的相关例程,此文件存储测评程序

 *评估板就是官方做的小电路板,用来测评STM32

Release_Notes:库函数的发布文档,有版本的说明

stm32f10x_stdperiph_lib_um:库函数的使用手册,教大家如何使用库函数


新建一个有关标准库的工程

新建一个文件夹,用来存储后续相关的工程

打开Keil

这里是新建文件夹,再把工程存在新建文件夹里

文件夹名是很容易更改的,所以可以在名称上起到说明的作用,工程名不方便更改

选择对应芯片型号,这里应选择C8那一项

弹出的新建工程小助手,可以帮助我们快速新建工程

 在新建工程设立的文件夹里开始搭配环境

  •  新建一个start文件
    注意根目录的操作顺序,来找到指定文件

 这些是STM32的启动文件,STM32的程序就是从启动文件开始运行的

  •  这个stm32f10x.h是STM32外设寄存器描述文件,作用与52单片机REGX52.H头文件作用一样,用来描述STM32有哪些寄存器和它们对应的位置
  • 两个system文件是用来配置时钟的,STM32主频72MHz就是由system文件里面的函数配置的
  • STM32是由内核和内核外围设备组成的,而且这个内核寄存器描述和外围设备描述不是在一起的,所以我们还需要添加内核寄存器描述文件
    这两个cm3(cortex-m)文件就是内核寄存器的描述,.c是内核的配置函数

 将上述文件粘贴至start里

改名

注意是在第几个目录下,一开始错误改了Target
右键Source Group1,选择Add Exiting Files

后缀md.s作为启动文件即可,启动文件有很多分类,但只需按型号选择一个

后面选择.c和.h文件都要选择进来

  • 到这里STM32的start文件已经配置好了,这些是STM32最基本的文件不需要修改 ,带黄色小钥匙的意思就是只读文件
  • 还需在工程选项中添加头文件路径,不然软件是无法找到.h文件的

 点击魔术棒,选择

点击Include Paths的一栏的三个小点

新建一个main函数,打开工程文件夹,新建一个用来保存main函数文件夹,叫做user

这里是新的item

选择创造.c的main函数,选择user路径否则是默认在文件夹user外的

 操作main.c文件

加入头文件

0错误0警告代表建立的工程没有问题

  1. #include "stm32f10x.h" // Device header
  2. int main(void){
  3. while(1){
  4. }
  5. }

一定要在末尾多一行空格,否则程序就会报错

到目前为止没有添加过STM32的库函数,所以还是一个基于寄存器开发的工程,如果使用寄存器开发,那么工程建到这里就足够了


以下,是关于如何用配置寄存器的方式完成点灯操作

小tip:点击扳手图标,再选择ASM和C/C++编辑器用来调节字体,在Courier New里面选择字号

同样是扳手工具,选择UTF-8选项,可以防止中文乱码问题,打开别人的工程中文是乱码时也要修改这个编码格式

点击模式棒,选择调试器默认是ULINK,改为STLINK

点击setting

勾上Reset and Run,然后点击确定,这个确保每次下载后程序会立马复位并执行

 只需配置三个寄存器就可以点灯了

寄存器①:RCC,用来使能GPIOC的时钟,GPIO都是APB2的外设,所以在这个APB2外设时钟使能寄存器RCC_APB2AENR里

可以看到这一位是使能GPIOC的时钟的,上面解释是这一位写1就是打开GPIOC的时钟

 将整个寄存器的2进制转换为16进制,4个一分组就是00000010

RCC->APB2ENR = 0X00000010;

在keil里写入,这样可以打开GPIOC的时钟

寄存器②:配置PC13口的模式

可以看到CNF13和MODE13就是用来配置13号口的

 同样换算成16进制是00300000

回到keil

GPIOC-> CRH = 0X00300000;

接下来要给PB13口输出数据了

 ODR13写0就是低电平,写1就是高电平

这里需要高电平,所以是00002000

GPIOC—>ODR = 0X00002000;

灯是低电平点亮的,所以给ODR全是0便点亮,给ODR0X00002000就是灭

有个弊端是将除了PC13都设置成了0,会影响其他端口的原有配置,如果要做到只配置PC13而不影响其他端口,这还需要&=和|=的操作

所以

  1. #include "stm32f10x.h" // Device header
  2. int main(void){
  3. RCC->APB2ENR = 0X00000010;
  4. GPIOC->CRH = 0X03000000;
  5. GPIOC->ODR = 0X00000000;
  6. while(1){
  7. }
  8. }

此代码下,灯点亮

  1. #include "stm32f10x.h" // Device header
  2. int main(void){
  3. RCC->APB2ENR = 0X00000010;
  4. GPIOC->CRH = 0X03000000;
  5. GPIOC->ODR = 0X00002000;
  6. while(1){
  7. }
  8. }

此代码下,灯熄灭

以上是配置寄存器的点灯方式,这种方式需要不断地查手册来知道每个寄存器每一位是用来干什么的


接下来添加库函数

打开工程文件夹,再创立一个文件夹Library,用来存放库函数

这些是库函数的源文件

 这个misc是内核的库函数,其他的是内核外的外设库函数

全选复制到Library文件夹下

库函数的头文件

Ctrl + A 全选复制到Library文件夹下

回到keil软件,在Target1右键添加组改个名字叫Library

再右键加入已存在的Library文件,全选加入进去

 这样便添加了所有库函数文件

但对于这个库函数来说,还不能直接使用,还需添加

 这个conf(configuration)文件是用来配置库函数头文件包含关系的,还有所有函数都需要的用来参数检查的函数定义

两个it(interupt)文件是用来存放中断函数的

这三个文件需要复制下来,粘贴到user目录下

再回到keil软件在use组里把三个文件添加进来

 最后,我们还需要一个宏定义

点击头文件右键,打开文件

划到最下面 看到这条语句,这是一个条件编译,意思是只有你定义了USE_STDPERIPH_DRIVER这个字串,下面这个stm32f10x_conf.h语句才会有效,所以需要复制下来USE_STDPERIPH_DRIVER,点击魔术棒按钮再到C/C++,粘贴到define这栏

 这样才能包含标准外设库,也就是库函数

还有头文件路径,点击Include Paths

 加入user和Library

这样基于库函数的工程已经建立好了

Library组的文件也全都带了钥匙,不需要我们修改,唯一需要我们修改的是user组里的文件

 

 可以点三个箱子的图标,把Library往上挪,让页面看起来整齐一些


接下来使用库函数来实现点灯操作

首先是使能时钟,库函数有这样一个函数来开启时钟

RCC_APB2PeriphClockCmd,接下来提示两个参数,第一个是选择外设,第二个是选择新的状态

 可以点击右键跳转到函数定义*这里一开始无法跳转,因为没有编译一直显示no browse

这上面有函数的简介和参数说明

 简介说,这个函数是用来使能或者失能APB2外设时钟,第一个参数可以是下面的这些值,可以找到APB2外设GPIOC这一项,然后复制作为第一个参数即可,在看第二个参数,NewState的值可以是ENABLE或者DISABLE,那我们复制ENABLE放在第二个参数的位置

这样GPIOC的外设时钟就配置好了

可以看到这个函数,它的内部其实还是配置RCC_APB2ENR这个寄存器,但是经过函数的包装,不需要再去查手册,去确认哪一位是干什么 ,而且这里应用了&=和|=来操作,所以这个库函数配置是不会影响到寄存器的其他位的

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);

这个代码虽然比寄存器长,但是语义更加明确其,也不需要查表计算值,只需要调用库函数,按照它的提示,把参数填好就行了

2.接下来是配置端口模式,我们需要用到GPIO_Init这个函数

 两个参数,选择哪个GPIO和参数的结构体(这里用到了结构体配置参数)

首先还是去到函数的定义

是PC13口的LED,所以第一个参数就写GPIOC,第二个参数是一个GPIO_InitTypeDef的结构体,首先需定义一个结构体,先把结构体的类型写上GPIO_InitTypeDef,这个名字可以随便起,但根据官方推荐最好叫作GPIO_InitStructure,然后把结构体的每个参数写上,复制粘贴结构体的名字,然后用点 . 来引出结构体的参数,先把参数罗列出来,可以看到结构体有三个参数,分别是GPIO模式、GPIO端口、GPIO速度

 右键转到Mode的定义

 右边介绍说,参数可以是GPIOMode_TypeDef里面的一个值

注释里的内容无法右键跳转了,所以可以选中GPIOMode_TypeDef这个字符,按下Ctrl+F,搜索这个定义的位置点击Find Next,可以看到这是个枚举

选择GPIO_Mode_Out_PP这一项复制,这一项就是通用推挽输出

回来,点击下一个Pin

 出现的这个框代表,可以跳转的定义有很多

选择member这一项双击跳转,还是刚刚那个位置,选中Ctrl+F、Find Next然后跳转,这里是个宏定义的列表

 选中GPIO_Pin_13复制,填在第二个位置上

第三个参数也是一样,跳转定义,选中,Ctrl+F、Find Next,选中GPIO_Speed_50MHz复制,填在第三个参数上

这样结构体变量就有了,就可以填写GPIO_Init的第二个参数了

  1. GPIO_InitTypeDef GPIO_InitStructure;
  2. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  3. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  4. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

可以回到之前的定义里说明,第二个参数是指向结构体的指针,所以这里需要传输结构体的地址

复制结构体的名字,加上&取地址,&GPIO_InitStructure作为第二个参数

最后来设置端口的高低电平来进行点灯,这里有个函数GPIO_SetBits这个就可以把指定端口设置为高电平

也有函数将端口配置为低电平,GPIO_ResetBits,参数与SetBits一样,GPIO_ResetBits(GPIOC, GPIO_Pin_13);这句便可将PC13号端口设置为低电平

整个代码是

  1. #include "stm32f10x.h" // Device header
  2. int main(void){
  3. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
  4. GPIO_InitTypeDef GPIO_InitStructure;
  5. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  6. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  7. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  8. GPIO_Init(GPIOC, &GPIO_InitStructure);
  9. //GPIO_SetBits(GPIOC, GPIO_Pin_13);
  10. GPIO_ResetBits(GPIOC, GPIO_Pin_13);
  11. while(1){
  12. }
  13. }

灯亮

  1. #include "stm32f10x.h" // Device header
  2. int main(void){
  3. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
  4. GPIO_InitTypeDef GPIO_InitStructure;
  5. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  6. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  7. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  8. GPIO_Init(GPIOC, &GPIO_InitStructure);
  9. GPIO_SetBits(GPIOC, GPIO_Pin_13);
  10. //GPIO_ResetBits(GPIOC, GPIO_Pin_13);
  11. while(1){
  12. }
  13. }

灯灭

以上是学习库函数的基本操作


新建工程里启动文件的选择

新建工程一个要添加的就是启动文件,启动文件有很多类型,至于选择哪个,需要根据芯片的型号来确定

STM32F1系列中型号分布

 如何判断?当选择STM32F100的产品时,就选择带VL的启动文件,然后再根据Flash的大小来确定LD、MD、HD、XL

当选择STM32F101/102/103的型号,就选择不带VL的启动文件,根据Flash的大小来确定LD、MD、HD、XL

当选择STM32F105/107的型号,就直接选择CL即可

eg:用到的STM32F103C8T6是F103,直接看LD、MD、HD、XL,可知C8T6是64K的Flash,所以选择后缀带有md的启动文件

这就是STM32F10系列的型号分类和启动文件选取


总结新建工程的顺序

建立工程文件夹, Keil 中新建工程,选择型号
工程文件夹里建立 Start Library User 等文件夹,复制固件库里面的文件到工程文件夹
*一定要将需要的文件加入到工程文件夹里面来,不要添加工程文件夹外面的文件,否则文件一旦挪位置,工程就找不到文件了,保持工程的独立性
工程里对应建立 Start Library User 等同名称的分组,然后将文件夹内的文件添加到工程分组里
*这一步是为了方便管理keil的文件,因为keil里面无法直接添加文件夹
*.h文件不参与编译,但UP主添加进来为了方便查看
工程选项, C/C++ Include Paths 内声明所有包含头文件的文件夹
*start、library等文件夹是自己建的,keil软件并不知道,所以要用自己文件夹里面的.h文件,就必须声明一下路径,最好是把所有自己建的文件夹都声明,这样就不会出现.h文件找不到的问题了
工程选项, C/C++ Define 内定义 USE_STDPERIPH_DRIVER
*这是使用库函数的条件编译,使用库函数就必须定义这个
工程选项, Debug ,下拉列表选择对应调试器, Settings Flash Download 里勾选 Reset and Run
*选择调试器下载的选项,选择STLINK那一项即可

工程架构

                主动执行部分                                                                 被动执行部分

 首先start up启动文件,这个是程序执行最基本的文件

keil中启动文件是用汇编写的,启动文件内部定义了中断向量表、中断服务函数等,中断服务函数中有一个复位中断,这是整个程序的入口

当STM32上电复位或者按下复位键时,程序就会进入复位中断函数的执行,复位中断函数主要做两件事情,一个是调用SystemInit函数,第二个是调用main函数,对应启动文件这里

 然后程序就结束了,事实上单片机由于while的循环程序永远不会结束

SystemInit的文件就是定义在这个system_xx.c/.h文件里的

 可以在keil中看到这个函数的定义,brief简介中写了函数的作用,是设置微控制处理器的启动,初始化嵌入式闪存接口、锁相环、更新系统内核的时钟变量,note写得是这个函数仅在复位后需要调用

 下面这些是用来配置这些东西的,不需要修改,在main函数之前,单片机已经执行了一堆东西了,帮把这个闪存接口、时钟等一系列杂碎的东西都配置好了

另外在启动文件还定义了STM32所有的其他中断,这些中断达到条件后会自动执行

启动文件下面就是其他文件的中断调用了 ,这个中断函数定义就是在stm32fx_it里面

打开keil可以看到中断函数的定义

ST还建议我们将中断写在这个位置,当然我们还是习惯在哪里用就写在哪里 这些就是中断部分的执行逻辑了,另外可以自己定义一些用户文件,来封装一些模块来供主函数和模块中断调用,这有利于我们程序结构模块化,不然所有结构都堆在主函数里面,主函数会非常长

*目前我还不明白封装具体用法和整体概念

 以上是工程主动执行部分内容,剩下的是被动执行的东西了,相当于STM32的资源

在主函数或者中断函数里面就可以调用这些资源

右上角是stm32f10x.h和core_cm3.c / .h分别是外设寄存器描述内核寄存器描述

打开keil可以看到

 寄存器和寄存器每一位的名字和对应的地址信息,直接调用寄存器来使用STM32(有些麻烦),这是寄存器的开发方式

所以ST公司提供了库函数文件misc.c / .h、stm32f10x_adc.c / .h库函数

 在keil中可以看到,每个外设都提供有一大堆函数,这些函数封装了寄存器的操作,提供了函数调用的方式

stm32f10x_conf.h库函数配置这个conf文件就是用来配置头文件的包含关系的

可以看到conf文件include所有库函数的头文件

 同时在是stm32f10x.h最后又包含了stm32f10x_conf.h,所以在使用这些库函数是只需要包括stm32f10x.h这一个头文件即可,就相当于包含了所有库函数的头文件,这样我们就可以任意调用库函数了

这些就是工程的结构和每个文件的作用

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/676745
推荐阅读
相关标签
  

闽ICP备14008679号