本文主要介绍STM32F103系列芯片的地址映射和寄存器映射原理,以及分析GPIO端口的初始化设置(时钟配置、输入输出模式设置、最大速率设置)。
一、寄存器简介
1、定义
寄存器是 CPU内部 用来 存放数据 的一些 小型存储区域 ,用来暂时存放参与运算的数据和运算结果 。寄存器的功能是存储二进制代码,它是由具有存储功能的触发器组合起来构成的。其实寄存器就是一种常用的时序逻辑电路,但这种时序逻辑电路只包含存储电路。寄存器的存储电路是由锁存器或触发器构成的,因为一个锁存器或触发器能存储1位二进制数,所以由N个锁存器或触发器可以构成N位寄存器。寄存器是中央处理器内的组成部分。寄存器是有限存储容量的高速存储部件,它们可用来 暂存指令、数据和位址 。 简单来说,寄存器就是存放东西的东西。从名字来看,跟超市寄存物品的地方相似。只不过超市的物品寄存柜,存放的是物品;寄存器可能存放的是 指令、数据或地址。
存放数据的寄存器 是最好理解的,如果你需要读取一个数据,直接到这个寄存器所在的地方来问问他,数据是多少就行了。问寄存器这个动作,叫做 访问寄存器。不同的数据会存放在不同的寄存器,例如引脚PA2与PB8的高低电平数据(1或0)肯定放在不同的寄存器里,那么怎么区分不同的寄存器呢?通过 地址 ,不同的寄存器有不同的地址,就像老张的物品寄存在25号柜子,老王的物品寄存在34号柜子。 指令、地址寄存器 与数据寄存器类似,里边存放的都是0和1,毕竟单片机也只认识机器码,机器码都是0或1,只是特别的规定下,数据寄存器里面存放的0和1表示数据,指令寄存器里存放的表示指令。
2、分类
按照功能的不同,可将寄存器分为 基本寄存器 和 移位寄存器 两大类。
基本寄存器: 只能并行送入数据,也只能并行输出。 移位寄存器: 移位寄存器中的数据可以在移位脉冲作用下依次逐位右移或左移,数据既可以 并行输入、并行输出,也可以 串行输入、串行输出,还可以 并行输入、串行输出,或 串行输入、并行输出,十分灵活,用途也很广。
3、功能
寄存器最起码具备以下4种功能。
①清除数码: 将寄存器里的原有数码清除。 ②接收数码: 在接收脉冲作用下,将外输入数码存入寄存器中。 ③存储数码: 在没有新的写入脉冲来之前,寄存器能保存原有数码不变。 ④输出数码: 在输出脉冲作用下,才通过电路输出数码。 仅具有以上功能的寄存器称为 数码寄存器 ;有的寄存器还具有移位功能,称为 移位寄存器 。
4、数码存取方式
寄存器有串行和并行两种数码存取方式。
并行方式: 将n位二进制数一次存入寄存器或从寄存器中读出的方式称为 并行方式。 串行方式: 将n位二进制数以每次1位,分成n次存入寄存器并从寄存器读出,这种方式称为 串行方式。 对比: 并行方式只需一个时钟脉冲就可以完成数据操作,工作速度快,但需要n根输入和输出数据线。 串行方式要使用几个时钟脉冲完成输入或输出操作,工作速度慢,但只需要一根输入或输出数据线,传输线少,适用于远距离传输。
二、STM32F103系列芯片的地址映射和寄存器映射原理
1、STM32F103C8T6芯片介绍
STM32F103C8T6 是一款基于ARM Cortex-M 内核 STM32系列 的 32位 的微控制器,程序存储器容量是 64KB,需要电压 2V~3.6V,工作温度为 -40°C ~ 85°C。具体参数如下:
2、地址映射
为了保证 CPU 执行指令时可正确访问存储单元,需将用户程序中的逻辑地址转换为运行时由机器直接寻址的物理地址,这一过程称为 地址映射
3、寄存器映射
在存储器的区域单元中,每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。我们可以找到每个单元的起始地址,然后通过 C 语言指针的操作方式来访问这些单元,如果每次都是通过这种地址的方式来访问,不仅不好记忆还容易出错,这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫 寄存器映射
4、根据数据手册查找寄存器的地址
手册中没有直接给出所有的寄存器的地址,需要读者稍加计算。STM32 给不同的寄存器分配了不同的地址,有点像划分了片区。在《STM32中文参考手册_V10》的第28页,有不同寄存器的地址范围。 现在,假如我们想读取 PB3 引脚的电平,该怎么找到相关的寄存器?
-
第一步,找到 GPIOB 的基地址 也就是找到 GPIOB 的小区。结论是,所有 GPIOB 相关的寄存器,都住在 0x4001 0C00~0x4001 0FFF 范围内。 -
第二步,找到端口输入寄存器的地址偏移 找到存储数据的那个屋子,结论是 0x4001 0C00+0x08 = 0x4001 0C08 -
第三步,找到知道数据的那个人 PB3 的数据位于从右往左数第4个。
而这个寄存器的位数是 32位(虽然 高16位 没有用到),这就是 32位的单片机的意思。每个寄存器都占据4字节,32位。而CPU的总线一次可以操作32位,所以比8位单片机厉害一点。 经过这三步查找,我们可以做出以下结论: PB3 的输入数据位于 0x4001 0C08 这个地址上,这个地址上存放数据的右起第4个位就是 PB3 引脚对应的高低电平。 我们可以直接访问这个地址:
unsigned int *pGPIOB_IDR = (unsigned int *)0x40010C08;
unsigned char PB3 = *pGPIOB_IDR & 0x8;
但是,直接访问的操作并不好用,每操作一个寄存器就必须去查看数据手册,然后找找这个寄存器的地址。 STM 公司为了方便大家使用,就把这些寄存器都起了一目了然的名字,并把寄存器与地址映射关系放在他们提供的头文件 stm32f10x.h 里。
三、GPIO端口的初始化设置
1、GPIO简介
GPIO 是通用输入输出端口的简称,简单来说就是 STM32 可控制的引脚,STM32 芯片的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。STM32 芯片的 GPIO 被分成很多组,每组有 16 个引脚。
如型号为 STM32F103VET6 型号的芯片有 GPIOA、GPIOB、GPIOC至 GPIOE 共 5组 GPIO,芯片一共 100个引脚,其中 GPIO 就占了一大部分,所有的 GPIO 引脚都有基本的输入输出功能。
GPIO的内部结构:
GPIO 结构里有三个重要组成部分:
-
保护二极管 引脚内部加上这两个保护二级管可以防止引脚外部过高或过低的电压输入,当引脚电压高于 VDD_FT 或 VDD 时,上方的二极管导通吸收这个高电压,当引脚电压低于 VSS 时,下方的二极管导通,防止不正常电压引入芯片导致芯片烧毁。 尽管 STM32 芯片内部有这样的保护,但并不意味着 STM32 的引脚就无所不能,如果直接将引脚连接大功率器件,比如电机,那么要么电机不转,要么烧坏芯片。如果要驱动一些大功率器件,必须要加大功率及隔离电路驱动。也可以说 STM32 引脚是用来做控制,而不是做驱动使用的。 -
上下拉电阻 从图中可以看到,上拉和下拉电阻上都有一个开关,通过配置上下拉电阻开关,可以控制引脚的默认状态电平。当开启上拉时引脚默认电压为高电平,开启下拉时,引脚默认电压为低电平,这样就可以消除引脚不定状态的影响。当然也可以将上拉和下拉的开关都关断,这种状态我们称为 浮空模式,一旦配置成这个模式,引脚的电压是不确定的,如果用万用表测量此模式下管脚电压时会发现只有 1 点几伏,而且还不时改变,所以一般情况下我们都会给引脚设置成上拉或者下拉模式,使它有一个默认状态。STM32 上下拉及浮空模式的配置是通过 GPIOx_CRL 和 GPIOx_CRH 寄存器控制的,大家在《STM32F1xx中文参考手册》查阅。STM32 内部的上拉其实是一个 弱上拉,也就是说通过此上拉电阻输出的电流很小,如果想要输出一个大电流,那么就需要外接上拉电阻了。 -
P-MOS和N-MOS管 GPIO 引脚经过两个保护二极管后就分成两路,上面一路是“输入模式”,下面一路是“输出模式”。我们先讲输出模式,线路经过一个由 P-MOS 和N-MOS 管组成的单元电路,这让 GPIO 引脚具有了推挽和开漏两种输出模式。所谓推挽输出模式,是根据 P-MOS 和 N-MOS 管的工作方式命名的。在该结构单元输入一个高电平时,P-MOS 管导通,N-MOS管截止(可以将 P-MOS 当作 NPN 三极管,N-MOS 当作PNP 三极管来看就非常清楚),对外输出高电平(3.3V)。 在该单元输入一个低电平时,P-MOS 管截止,N-MOS 管导通, 对外输出低电平 (0V) 。如果当切换输入高低电平时,两个MOS 管将轮流导通,一个负责灌电流(电流输出到负载),一个负责拉电流(负载电流流向芯片),使其负载能力和开关速度都比普通的方式有很大的提高。
2、时钟配置
(1)什么是时钟 stm32 的时钟是由内部或外部振荡器产生的“频率”,而被人们形象的称为“系统时钟”。最大为 72MHz 换成周期T为:1/72MHz≈13.9ns。 时钟就是单片机的心脏。每跳动一下。整个单片机的各个电路就同步的动作一下。就好像我们做广播体操的时候 广播上喊的节拍1234 2234 3234。。。。然后我们全部的同学就按照这个节奏进行一个个动作。节拍越快我们动作越快。节拍越慢我们动作的越慢。 (2)为什么要用时钟配置 因为耗电量,stm32 功能强大,能做很多事,但与之同时带来的消耗也越严重,当 stm32 不引入时钟的话,就像51一样外设全开,相应耗电就很严重了,所以厂家(st公司)为了解决这个问题,引入了“时钟概念”,即使用哪个外设就给哪个外设时钟(频率),不使用的就关掉(不震荡)。此做法大大降低了功耗,续航持久。
在51单片机中一个时钟把所有的都包了,而 stm32 的时钟是有分工的,并且每类时钟的频率不一样,因为没必要所有的时钟都是最高频率,只要够用就行,好比一个门出来水流大小,如果只要洗脸,但是出来的是和洪水一样涌出来的水,那就没必要了,消耗能源也多,所以不同的时钟也会有频率差别,或者在配置的时候可以配置时钟分频。
3、输入输出模式设置
GPIO 支持4种输入模式( 浮空输入、上拉输入、下拉输入、模拟输入 )和4种输出模式(开漏输出、开漏复用输出、推挽输出、推挽复用输出),每个 I/O 口可以自由编程,但 I/O 口寄存器必须按 32位 字被访问。
输入: (1)GPIO_Mode_AIN 模拟输入 (应用ADC模拟输入,或者低功耗下省电) (2)GPIO_Mode_IN_FLOATING 浮空输入 (浮空就是浮在半空,可以被其他物体拉上或者拉下,可以用于按键输入) (3)GPIO_Mode_IPD 下拉输入 (IO内部下拉电阻输入) (4)GPIO_Mode_IPU 上拉输入 (IO内部上拉电阻输入)
输出: (1)GPIO_Mode_Out_OD 开漏输出(开漏输出:输出端相当于三极管的集电极. 要得到高电平状态需要上拉电阻才行) (2)GPIO_Mode_Out_PP 推挽输出 (推挽就是有推有拉电平都是确定的,不需要上拉和下拉,IO输出0-接GND, IO输出1 -接VCC,读输入值是未知的 ) (3)GPIO_Mode_AF_OD 复用开漏输出(片内外设功能(I2C的SCL,SDA)) (4)GPIO_Mode_AF_PP 复用推挽输出 (片内外设功能TX1,MOSI,MISO.SCK.SS)
-
1.GPIO浮空输入_IN_FLOATING模式工作原理 数据通道中仅接入TTL触发器(作用是将相对缓慢变化的模拟信号变成矩形信号)整形,随后输入输入数据寄存器,该种工作模式未接入任何上拉/下拉电阻。 模式特点:在该引脚悬空(无信号输入)的情况下,读取该端口的电平是不确定的。 适用场合:外部按键输入/USART RX引脚。 -
2.GPIO带上拉输入_IPU 模式工作原理 与浮空输入模式相比,仅仅是在数据通道前端接入了一个上拉电阻,其余无变化。 模式特点:在无信号输入时端口电位受上拉电阻钳制,I/O端口输入电平始终保持为高电平;而当端口输入电平为低电平时,I/O端口输入电平为低电平。 适用场合:需要IO内部上拉电阻输入时,器件的外部中断(IRQ)引脚触发中断条件为下降沿触发/低电平触发,这样在无信号输入时始终保持高电平,如果有事件触发中断IRQ可以输出一个低电平,进而可产生(下降沿/低电平)中断。 -
3.GPIO带下拉输入_IPD 模式工作原理 与浮空输入模式相比,仅仅是在数据通道前端接入了一个下拉电阻,其余无变化。 模式特点:在无信号输入时端口电位受下拉电阻钳制,I/O端口输入电平始终保持为低电平;而当端口输入电平为高电平时,I/O端口输入电平为高电平。 适用场合:需要IO内部下拉电阻输入时,器件的外部中断(IRQ)引脚触发中断条件为上升沿触发/高电平触发时,该端口可以选择下拉输入模式。 -
4.GPIO模拟输入_AIN 模式工作原理 数据通道不接入任何处理单元(TTL触发器/钳制电阻),直接输入MCU内部的处理单元。 模式特点:相较于其他输入模式只能读取到逻辑高/低电平(数字量),该模式能读取到细微变化的值(模拟量)。 适用场合:ADC模拟输入/低功耗下省电。 -
5.GPIO开漏输出_OUT_OD 模式工作原理 输出具有驱动能力,当CPU输出逻辑’0’时,I/O端口输出低电平,而当CPU输出逻辑’1’时,I/O端口输出高电平,通常作为普通的GPIO用于驱动LED、数码管等电子元器件或输出控制某个信号。 -
6.GPIO推挽输出_OUT_PP模式工作原理 适合做电流型的驱动,其吸收电流能力较强。当CPU输出逻辑’0’时,I/O端口输出低电平,而当CPU输出逻辑’1’时,该引脚处于开漏,也就是浮空状态(高阻态),如果想输出高电平则必须接入上拉电阻。同时IO口可以由外部电路改变为低电平或不变,即可读IO输入电平变化,实现了I/O端口的双向功能;此外,可以将多路开漏输出的引脚连接到一条线上,通过一个上拉电阻,在不增加任何器件的情况下,形成“与逻辑”关系。 -
7.GPIO开漏复用输出_AF_OD模式工作原理 在STM32中,一个引脚通常可作为普通GPIO来使用,但通常有多个复用模块对应着同一个引脚,那么当这个GPIO作为内置外设引脚时,就叫做复用模式。 适用场合:常见片内外设(USART TX引脚/SPI/PWM输出等等) -
8.GPIO推挽复用输出_AF_PP模式工作原理 与开漏输出特性一致,只不过引脚选择了复用功能。 适用场合:常见片内外设(I2C/SMBus等等)
GPIO的8种工作状态:
typedef enum
{
GPIO_Mode_AIN = 0x0,
GPIO_Mode_IN_FLOATING = 0x04,
GPIO_Mode_IPD = 0x28,
GPIO_Mode_IPU = 0x48,
GPIO_Mode_Out_OD = 0x14,
GPIO_Mode_Out_PP = 0x10,
GPIO_Mode_AF_OD = 0x1C,
GPIO_Mode_AF_PP = 0x18
} GPIOMode_TypeDef;
4、最大速率设置
GPIO的输出速率: GPIO电平每秒切换的最大次数, 单纯GPIO意义不大,不过在通讯方面对于GPIO是有要求的。GPIO口的驱动电路响应速度,不是输出信号的速度。输出信号的速度与程序有关,通过选择速度来选择不同的驱动电路,降低功耗控制噪声。 这个输出速率主要体现I/O驱动电路的输出反应能力,通过选择不同的输出驱动速率,实现最佳的噪声与和功耗控制。不难理解,选择输出驱动速率越高,噪声也越大,相应的芯片功耗也会越大。所以对于这个输出频率的选择,不要太随意,合适就好。在满足应用的需求的前提下,就不要随意往高端速率选择。 当STM32的GPIO端口设置为输出形式时,有三种速度能够挑选:2MHz、10MHz和50MHz,这个速度是指I/O口驱动电路的速度,是用来挑选不同的输出驱动模块,到达最佳的噪声控制和降低功耗的意图。
5、GPIO初始化步骤
第一步: 使能GPIOx口的时钟 第二步: 指明GPIOx口的哪一位,这一位的速度大小以及模式 第三步: 调用GPIOx初始化函数进行初始化 第四步: 调用GPIO-SetBits函数,进行相应位的置位
对单个GPIO口的初始化:
GPIO_InitTypeDef GPIO_InitStructure;
第一步:使能GPIOA的时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
第二步:设置GPIOA参数:输出OR输入,工作模式,端口翻转速率
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_6| GPIO_Pin_7| GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
第三步:调用GPIOA口初始化函数,进行初始化。
GPIO_Init(GPIOA, &GPIO_InitStructure);
第四步:调用GPIO-SetBits函数,进行相应为的置位。
GPIO_SetBits(GPIOA,GPIO_Pin_0);
对于多个GPIO口的初始化
GPIO_InitTypeDef GPIO_InitStructure;
第一步:使能GPIOA,GPIOE的时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
第二步:设置GPIOA,GPIOE参数:输出OR输入,工作模式,端口翻转速率
第三步:调用GPIOA口初始化函数,进行初始化。
第四步:调用GPIO-SetBits函数,进行相应为的置位。
把第二、三、四步合并分别设置GPIOA和GPIOE
先设置GPIOA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; // 第四个口,PA4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz
GPIO_Init(GPIOA,&GPIO-InitST); //根据设定参数初始化GPIOA
GPIO_SetBits(GPIOA,GPIO_Pin_4); //输出高
再设置GPIOE
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; // 第三个口,PE3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // IO口速度为50MHz
GPIO_Init(GPIOE,&GPIO-InitST); //根据设定参数初始化GPIOE
GPIO_SetBits(GPIOE,GPIO_Pin_3); //输出高电平
四、总结
通过本次学习,我基本上了解了STM32F103系列芯片的地址映射和寄存器映射原理,以及GPIO端口的初始化设置(时钟配置、输入输出模式设置、最大速率设置),明白了要想学好嵌入式,还有很长一段路要走。
参考列表: 1.寄存器_百度百科 2.STM32寄存器的简介、地址查找,与直接操作寄存器 3.STM32从地址到寄存器 4.STM32 GPIO的8种工作模式与应用场合 5.寄存器映射原理详解,GPIO端口的初始化设置步骤
|