STM32F103系列芯片的地址映射和寄存器映射原理&&GPIO端口的初始化设置

一.STM32F103系列芯片的地址映射和寄存器映射原理

(一)什么是寄存器

1. 寄存器映射

提到单片机,就不得不提到寄存器。根据百度百科介绍,寄存器是中央处理器内的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。简单来说,寄存器就是存放东西的东西。从名字来看,跟火车站寄存行李的地方好像是有关系的。只不过火车站行李寄存处,存放的行李;寄存器可能存放的是指令、数据或地址。
  存放数据的寄存器是最好理解的,如果你需要读取一个数据,直接到这个寄存器所在的地方来问问他,数据是多少就行了。问寄存器这个动作,叫做访问寄存器。不同的数据会存放在不同的寄存器,例如引脚PA2与PB8的高低电平数据(1或0)肯定放在不同的寄存器里,那么怎么区分不同的寄存器呢?通过地址,不同的寄存器有不同的地址,就像老张行李寄存处在101号店铺,老王行李寄存处在258号店铺。
  指令、地址寄存器与数据寄存器类似,里边存放的都是0和1,毕竟单片机也只认识机器码,机器码都是0或1,只是特别的规定下,数据寄存器里面存放的0和1表示数据,指令寄存器里存放的表示指令。

2. 举例说明

比如,我们找到 GPIOB 端口的输出数据寄存器 ODR 的地址是 0x4001 0C0C(至于这个地址如何找到可以先跳过,后面我们会有详细的讲解),ODR 寄存器是 32bit,低 16bit有效,对应着 16 个外部 IO,写 0/1 对应的的 IO 则输出低/高电平。现在我们通过 C 语言指
针的操作方式,让 GPIOB 的 16 个 IO 都输出高电平,具体见代码

通过绝对地址访问内存单元

1 // GPIOB 端口全部输出 高电平
2 *(unsigned int*)(0x4001 0C0C) = 0xFFFF;

0x4001 0C0C在我们看来是 GPIOB端口 ODR的地址,但是在编译器看来,这只是一个普通的变量,是一个立即数,要想让编译器也认为是指针,我们得进行强制类型转换,把它转换成指针,即(unsigned int *)0x4001 0C0C,然后再对这个指针进行 * 操作。刚刚我们说了,通过绝对地址访问内存单元不好记忆且容易出错,我们可以通过寄存器的方式来操作,具体见代码

通过寄存器别名方式访问内存单元

1 // GPIOB 端口全部输出 高电平
2 #define GPIOB_ODR (unsigned int*)(GPIOB_BASE+0x0C)
3 * GPIOB_ODR = 0xFF;

为了方便操作,我们干脆把指针操作“*”也定义到寄存器别名里面,具体见代码

通过寄存器别名访问内存单元

1 // GPIOB 端口全部输出 高电平
2 #define GPIOB_ODR *(unsigned int*)(GPIOB_BASE+0x0C)
3 GPIOB_ODR = 0xFF

3. 地址映射

为了保证CPU执行指令时可正确访问存储单元,需将用户程序中的逻辑地址转换为运行时由机器直接寻址的物理地址,这一过程称为地址映射。

(二)什么是存储器映射

1. 存储器映射

存储器本身不具备地址,所以把芯片内核所预先设定好的地址分配给寄存器,就是存储器映射,具体见下图。

在这里插入图片描述

2.存储器区域功能划分

在这 4GB 的地址空间中,ARM 已经粗线条的平均分成了 8 个块,每块 512MB,每个
块也都规定了用途,具体分类见表格 6-1。每个块的大小都有 512MB,显然这是非常大的,芯片厂商在每个块的范围内设计各具特色的外设时并不一定都用得完,都是只用了其中的一部分而已。
存储器功能分类表
在这里插入图片描述

在这 8个 Block里面,有 3个块非常重要,也是我们最关心的三个块。Block0用来设计成内部 FLASH,Block1 用来设计成内部 RAM,Block2 用来设计成片上的外设。

二.GPIO端口的初始化设置三步骤

(一)GPIO 简介

GPIO 是通用输入输出端口的简称,简单来说就是 STM32 可控制的引脚,STM32 芯片的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。STM32 芯片的 GPIO 被分成很多组,每组有 16 个引脚,如型号为 STM32F103VET6 型号芯片有 GPIOA、GPIOB、GPIOC至 GPIOE共 5组 GPIO,芯片一共 100个引脚,其中 GPIO就占了一大部分,所有的 GPIO 引脚都有基本的输入输出功能。
最基本的输出功能是由 STM32 控制引脚输出高、低电平,实现开关控制,如把 GPIO引脚接入到 LED灯,那就可以控制 LED灯的亮灭,引脚接入到继电器或三极管,那就可以通过继电器或三极管控制外部大功率电路的通断。
最基本的输入功能是检测外部输入电平,如把 GPIO 引脚连接到按键,通过电平高低区分按键是否被按下。
这里我们以 GPIOB 端口为例,来说明 GPIO 都有哪些寄存器,具体见表在这里插入图片描述

(二)GPIO的八种工作模式

  1. GPIO支持4种输入模式(浮空输入、上拉输入、下拉输入、模拟输入)和4种输出模式(开漏输出、开漏复用输出、推挽输出、推挽复用输出)
  2. 每个I/O口可以自由编程,但I/O口寄存器必须按32位字被访问
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;


1. 模拟输入模式

I/O端口的模拟信号(电压信号,而非电平信号)直接模拟输入到片上外设模块,比如ADC模块等等

 GPIO_Mode_AIN 

在这里插入图片描述

2. 浮空输入模式

I/O端口的电平信号直接进入输入数据寄存器:也就是说,I/O的电平状态是不确定的,完全由外部输入决定;如果在该引脚悬空(在无信号输入)的情况下,读取该端口的电平是不确定的

GPIO_Mode_IN_FLOATING 

在这里插入图片描述

3. 下拉输入模式

I/O端口的电平信号直接进入输入数据寄存器。但是在I/O端口悬空(在无信号输入)的情况下,输入端的电平可以保持在低电平;并且在I/O端口输入为高电平的时候,输入端的电平也还是高电平

GPIO_Mode_IPD 

在这里插入图片描述

4. 上拉输入模式

I/O端口的电平信号直接进入输入数据寄存器:但是在I/O端口悬空(在无信号输入)的情况下,输入端的电平可以保持在高电平;并且在I/O端口输入为低电平的时候,输入端的电平也还是低电平

 GPIO_Mode_IPU 

在这里插入图片描述

5. 开漏输出模式

通过设置位设置/清除寄存器或者输出数据寄存器的值,途经N-MOS管,最终输出到I/O端口。这里要注意N-MOS管,当设置输出的值为高电平的时候,N-MOS管处于关闭状态,此时I/O端口的电平就不会由输出的高低电平决定,而是由I/O端口外部的上拉或者下拉决定;当设置输出的值为低电平的时候,N-MOS管处于开启状态,此时I/O端口的电平就是低电平。同时,I/O端口的电平也可以通过输入电路进行读取;注意,I/O端口的电平不一定是输出的电平

 GPIO_Mode_Out_OD

在这里插入图片描述

6. 推挽输出模式

通过设置位设置/清除寄存器或者输出数据寄存器的值,途经P-MOS管和N-MOS管,最终输出到I/O端口。这里要注意P-MOS管和N-MOS管,当设置输出的值为高电平的时候,P-MOS管处于开启状态,N-MOS管处于关闭状态,此时I/O端口的电平就由P-MOS管决定:高电平;当设置输出的值为低电平的时候,P-MOS管处于关闭状态,N-MOS管处于开启状态,此时I/O端口的电平就由N-MOS管决定:低电平。同时,I/O端口的电平也可以通过输入电路进行读取;注意,此时I/O端口的电平一定是输出的电平

 GPIO_Mode_Out_PP

在这里插入图片描述

7. 复用开漏输出模式

与开漏输出模式很是类似。只是输出的高低电平的来源,不是让CPU直接写输出数据寄存器,取而代之利用片上外设模块的复用功能输出来决定的

 GPIO_Mode_AF_OD

在这里插入图片描述

8.复用推挽输出

与推挽输出模式很是类似。只是输出的高低电平的来源,不是让CPU直接写输出数据寄存器,取而代之利用片上外设模块的复用功能输出来决定的

GPIO_Mode_AF_PP 

在这里插入图片描述

(三)时钟配置

1. 时钟的作用

决定了程序执行的速度,给芯片提供一个稳定的执行频率

2.STM32时钟的配置

PLL的倍频因子:HSE * PLLMUL = 72M Hz
AHB的频率:72M Hz
APB2的频率:72M Hz
APB1的频率:36M Hz

(四)GPIO初始化步骤

第一步:使能GPIOx口的时钟
第二步:指明GPIOx口的哪一位,这一位的速度大小以及模式
第三步:调用GPIOx初始化函数进行初始化
第四步:调用GPIO-SetBits函数,进行相应位的置位

1.单个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; // IO口速度为50MHz

第三步:调用GPIOA口初始化函数,进行初始化。
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA

第四步:调用GPIO-SetBits函数,进行相应为的置位。
GPIO_SetBits(GPIOA,GPIO_Pin_0); //输出高



2.多个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端口的初始化设置。如有错误,请各位指出,多谢。

四. 参考链接

https://blog.csdn.net/geek_monkey/article/details/86291377
https://blog.csdn.net/weixin_42506096/article/details/123625114
https://blog.csdn.net/qq_46467126/article/details/120737655

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值