自古逢秋悲寂寥,我言秋日胜春朝。
晴空一鹤排云上,便引诗情到碧霄。——刘禹锡《秋词二首·其一》
一、新建工程
- 芯片型号:
STM32F103C8T6
(SMT32最小系统开发版) - 新建工程后需要添加一些必要文件:(将里面的文件全部复制,并粘贴到新建工程的Start文件中)
stm32f10x.h
:就是STM32
的外设寄存器描述文件,它的作用与51单片机
的头文件REGX52.H
一样,是用来描述STM32
有哪些寄存器和它对应的地址的;- 下面两个
system
文件主要是用来配置时钟的,STM32主频72MHz,就是system
文件里的函数配置的:- system_stm32f10x.c:
- system_stm32f10x.h:
- 将这三个文件也复制下来,并粘贴到Start文件中;
- STM32是内核和内核外围的设备组成的,而且内核的寄存器和外围设备的描述文件不是在一起的,因此我们还需要添加一个内核寄存器的描述文件;
- 两个
cm3(Cortex-M3)
文件就是内核的寄存器描,还带了一些内核的配置函数,将其全部复制下来到Start文件下;
- 必要文件就此准备完成了,回到
keil
软件,将刚才复制的文件添加到工程中去, - 添加下面文件到工程中,最基本的文件,不需要我们进行修改的,是只读文件;
- 最后我们还需要在工程选项里添加上这个文件夹的头文件路径,不然软件是无法找到.h文件的;
- 打开工程文件夹:新建一个
User
文件夹,存放我们的main
函数;
二、点灯
1. 通过配置寄存器来点亮灯:
- 首先是
RCC
这个寄存器,来使能GPIOC
的时钟,GPIO
都是APB2的外设,所以在这个APB2
外设时钟使能寄存器RCC_APB2ENR
里面配置;IOPCEN
:这一位就是使能GPIO
的时钟,该位写1
,就是打开GPIOC
的时钟;
- 第二个寄存器,需要配置一下
PC13口
的模式,找到端口配置高寄存器GPIOx_CRH
(这个x可以是A到E的任意一个字母),CNF13
和MODE13
就是用来配置13号口
的,CNFy[1:0]
:端口x
配置位 (y=8……15)- 在输入模式
(MODE[1:0] = 00)
:00
:模拟输入模式;01
:浮空输入模式(复位后的状态);10
:上拉/下拉输入模式;11
:保留;
- 在输出模式
(MODE[1:0] > 00)
:00
:通用推挽输出模式;01
:通用开漏输出模式;10
:复用功能推挽输出模式;11
:复用功能开漏输出模式;
- 在输入模式
- 端口输出数据寄存器
(GPIOx_ODR)
(x = A…E)ODR13
:这一位写1,13号口就是高电平,写0就是低电平;- 如果写
1
:ODR
的值就是0000 2000
;
- 如果写
注:使用寄存器的操作方式,虽然代码简洁,但操作起来还是不够方便;
2. 为工程添加库函数
比较库函数和寄存器的操作方式有哪些区别:
- 库函数是把应用的寄存器编辑封装好,应用相应的函数名就可以实现相应的功能,不用再一个个的设置单片机的寄存器,初学者还是先用寄存器开始好,弄懂寄存器再使用函数编程;
- 二者没有本质区别,仅仅是封装层级不同。因为所有的库函数本质都是为了编程方便对寄存器读写调用的封装。而且二者在一定程度上可以混用(只要不造成冲突)。一般来说库函数开发要快很多,寄存器开发需要较高资源管理,开发难度很大,也容易出错,不过正确开发后因为少了一层调用,程序效率更高(但这点在大多数时候意义不大)。
- 在工程中新建一个文件夹
Library
用来存放库函数; misc
是内核的库函数,其他的就是内核外的外设库函数;
- 要想能够直接使用库函数,我们需要再添加一个文件;
conf(configuration)
文件是用来配置库函数头文件的包含关系的,其中里面还有一个用来检查的函数定义,这是所有库函数都需要的;- 两个
it(interrupt)
文件是用来存放中断函数的;
- 将这三个文件复制下来,粘贴到工程中的
User
文件中;
- 完成之后,我们将进行使用库函数做点灯的操作,库函数其实就是间接地配置寄存器;
- 库函数是间接地配置寄存器,因此与寄存器的步骤一样的:
- 首先是使能时钟,库函数就有这样一个函数来开启时钟,叫做
RCC_APB2PeriphClockCmd()
(RCC_APB2外设时钟控制);- 其中有两个参数,第一个是选择外设;第二个是选择新的状态;
- 这个函数是用来使能或者失能APB2的外设时钟;
- 第一个参数 可以是这些值:(可以复制以下参数直接使用)
RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB, RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE,RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1,RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3,RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17,RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11
- 第二个参数 :
NewState
的值可以是ENABLE
或者DISABLE
;(同样可以复制使用)
- 第二步:配置端口模式,需要使用
GPIO_Init()
这个函数;- 其中有两个参数:第一个是选择那个GPIO,第二个参数是一个指向结构体的指针;
- 第一个参数:
GPIOx
,其中x
可以是A到G
,来选择需要配置哪个GPIO
,选择的是PC13口
的LED
,所以第一个参数就写GPIOC
; - 第二个参数: 是一个
GPIO_InitTypeDef
的结构体,需要先定义一个结构体,需要先写上结构体的类型,然后给结构体取个名字,名字最好叫GPIO_InitStruct
,然后填上结构体的每个参数; - 复制结构体的名字,然后用点来引出结构体的参数:
- 这个结构体有三个参数,分别是:GPIO
模式(GPIO_Mode) :可以看到这个结构体是个枚举的类型,GPIO_Mode就是其中的一个值,选择Out_PP这一项,意思就是通用推挽输出;GPIO
端口(GPIO_Pin):这个参数是在GPIO_pins_define
中定义的,采用注中的方式,可以看到一个宏定义的列表,选择GPIO_Pin_13,然后复制到第二个位置;GPIO
速度(GPIO_Speed):也是如上操作,跳到定义,然后注操作,选中50MHz的速度,然后赋值过去;
- 注:在注释里的东西,无法使用右键进行跳转,可以进行选中这个字符,然后按下Ctrl+F,搜索这个字符的位置 ,点击Find Next,可以看到这个结构体是个枚举的类型,GPIO_Mode就是其中的一个值,选择Out_PP这一项,意思就是通用推挽输出 ; **
- GPIO_Init()这个函数的第二个参数是一个指向结构体的指针,因此我们需要传递结构体的地址,复制结构体的名字,粘贴到函数的第二个参数的位置,然后在前面加上一个取地址符(&);
- 第一个参数:
- 这样就完成了GPIO模式的配置;
- 其中有两个参数:第一个是选择那个GPIO,第二个参数是一个指向结构体的指针;
- 配置的操作方式虽然看上去比较难,但是STM32的这种方式都是固定的;
- 最后一步:来设置端口的高低电平进行点灯,
- 函数GPIO_SetBits():该函数可以把指定端口设置为高电平;
- 第一个参数:GPIOC;
- 第二个参数:GPIO_Pin_13;(即可将PC13号口置为高电平)
- 高电平熄灭;
- 函数GPIO_ResetBits():该函数可以将指定端口设置为低电平;
- 第一个参数:GPIOC;
- 第二个参数:GPIO_Pin_13;(即可将PC13号口置为低电平)
- 低电平点亮;
- 函数GPIO_SetBits():该函数可以把指定端口设置为高电平;
- 最后一步:来设置端口的高低电平进行点灯,
- 首先是使能时钟,库函数就有这样一个函数来开启时钟,叫做
三、强调点
1、首先是新建工程里的启动文件选择,启动文件有很多类型,至于选择哪一个,我们需要根据芯片的型号来选择;
STM32F1
系列中的型号分类:- 根据
Flash
的大小:- 小容量产品,Flash为
16~32K
,简写为LD(Low Density)
; - 中容量产品,Flash为
64~128K
,简写为MD(Medium Density)
; - 大容量产品,Flash为
256~512K
,简写为HD(High Denisty)
;
- 小容量产品,Flash为
四、GPIO
GPIO(General Purpose Input Output)
:通用输入输出口,可配置为8种输入模式;
- 引脚电平:
0V~3.3V
,部分引脚可容忍5V
;- 输出模式 下可控制端口输出高低电平,用以
驱动LED
、控制蜂鸣器
、模拟通信协议输出时序
等;- 输入模式 下可读取端口的高低电平或电压,用于
读取按键输入
。外接模块电平信号输入
、ADC电压采集
、模拟通信协议接收数据
等;
- 输入模式最常用的就是读取按键,用来捕获按键按下的事件;另外也可以读取带有数字输出的一些模块;比如
光敏电阻模块
、热敏电阻模块
等;- 如果这个模块输出的是模拟量,那
GPIO
还可以配置成模拟输入的模式,再配合内部的ADC外设,就能直接读取端口的模拟电压了;
4.1 GPIO
基本结构
4.1 GPIO
位结构
- 第三种操作方式:就是读写STM32中的“位带”区域,这个位带的作用:和51单片机的位寻址作用差不多,在STM32中,专门分配的有一段地址区域,这段地址区域映射了RAM(随机存取存储器)和外设寄存器所有的位,读写这段地址中的数据,就相当于读写映射位置的某一位;
- 但我们主要是使用库函数来操作的,库函数使用的就是读写位设置和位清除寄存器的方法;
GPIO
模式
- 通过配置
GPIO
的端口配置寄存器,端口可以配置成以下8种模式
;
- 这三个模式的电路结构基本是一样的,区别就是:上拉电阻和下拉电阻的连接;
- 它们都属于 数字的输入口,特征就是:都可以读取端口的高低电平;
- 因为在浮空输入在引脚悬空时,电平是不确定的,所以在使用浮空输入时,端口一定要接上一个连续的驱动源,不能出现悬空的状态;
模拟输入
模拟输入是ADC模数转换器的专属配置了,模拟输入的结构:
注:在GPIO的这8种模式中,除了模拟输入这个模式会关闭数字的输入功能,在其他的7个模式中,所有的输入都是有效的。
六、操作STM32的GPIO的三个步骤
- 使用RCC开启GPIO时钟;
- 使用GPIO_Init()函数初始化GPIO;
- 使用输出或者输入的函数控制GPIO口;
七、RCC的库函数
八、GPIO的库函数