本文目的主要是学习和理解STM32F103系列芯片的地址映射和寄存器映射原理;了解GPIO端口的初始化设置三步骤(时钟配置、输入输出模式设置、最大速率设置)。
文章目录
前言
※ 单片机的本质其实就是在操作寄存器,让单片机完成我们想要的动作例如点亮一个LED灯,stm32的库函数开发也不例外它只不过是将操作寄存器封装成一个个函数,我们只要配置指定函数的参数,再调用该函数自动把对应的寄存器配置好,其实本质还是操作寄存器,更加方便快捷,如果你只学库函数的话后期就有种空中阁楼的感觉,知其然不知其所以然,使用我们需要好好掌握底层原理。
(一)STM32F103系列芯片的地址映射及寄存器映射原理
1.STM32F103C8T6简要介绍
● STM32F103C8T6是一款由意法半导体公司(ST)推出的基于Cortex-M3内核的32位微控制器,硬件采用LQFP48封装,属于ST公司微控制器中的STM32系列。除了被我们熟知的STM32,ST公司还有SPC5X系列、STM8系列等,具体参数如下:
内核 | Cortex-M3 |
---|---|
Flash | 64K x 8bit |
SRAM | 20K x 8bit |
GPIO | 37个GPIO,分别为PA0-PA15、PB0-PB15、PC13-PC15、PD0-PD1 |
ADC | 2个12bit ADC合计12路通道,外部通道:PA0到PA7+PB0到PB1,内部通道:温度传感器通道ADC_Channel_16和内部参考电压通道ADC_Channel_17 |
Timers | 4个16bit定时器/计数器,分别为TIM1、TIM2、TIM3、TIM4,TM1带死区插入,常用于产生PWM控制电机 |
工作电压、温度 | 2V~3.6V、-40°C ~ 85°C |
通信串口 | 2IIC,2SPI,3USART,1CAN |
系统时钟 | 内部8MHz时钟HSI最高可倍频到64MHz,外部8MHz时钟HSE最高可倍频到72MHz |
![](https://i-blog.csdnimg.cn/blog_migrate/9ca321cdba935627ae3e244734f978a4.png)
2.什么是寄存器?
● 寄存器
是中央处理器内的组成部分
。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和位址。在中央处理器的控制部件中,包含的寄存器有指令寄存器(IR)和程序计数器(PC)。在中央处理器的算术及逻辑部件中,包含的寄存器有累加器(ACC)。
● 寄存器
是内存阶层中的最顶端
,也是系统获得操作资料的最快速途径
。寄存器通常都是以他们可以保存的位元数量来估量,举例来说,一个 “8 位元寄存器”或 “32 位元寄存器”。寄存器现在都以寄存器档案的方式来实作,但是他们也可能使用单独的正反器、高速的核心内存、薄膜内存以及在数种机器上的其他方式来实作出来。
●寄存器
又分为内部寄存器
与外部寄存器
,所谓内部寄存器,其实也是一些小的存储单元,也能存储数据。但同存储器相比,寄存器又有自己独有的特点:
①寄存器位于CPU内部,数量很少,仅十四个;
②寄存器所能存储的数据不一定是8bit,有一些寄存器可以存储16bit数据,对于386/486处理器中的一些寄存器则能存储32bit数据;
③每个内部寄存器都有一个名字,而没有类似存储器的地址编号。
● 寄存器的功能十分重要,CPU对存储器中的数据进行处理时,往往先把数据取到内部寄存器中,而后再作处理。外部寄存器是计算机中其它一些部件上用于暂存数据的寄存器,它与CPU之间通过“端口”交换数据,外部寄存器具有寄存器和内存储器双重特点。
3. 地址映射
● 地址映射这个过程是在设计芯片的时候就要进行考虑的,地址总线接口如果是32位,则内核可访问的外设空间最大就是4G,芯片设计者为每一个外设会映射一段地址空间,比如GPIOA映射到0x0000000-0x0000FFFF,则CPU在访问0x0000000-0x0000FFFF地址空间时会被GPIOA外设捕获到,至于外设想做什么由外设的硬件设计者来决定。如果地址总线接口如果是64位,则内核可访问外设的地址空间为2^64bit。
● STM32地址总线接口为32位,则可以访问4Gbit的外设空间,下面为STM32F10X外设地址映射表。有很多还没有被映射的地址空间,ST公司后期可能用来扩展新外设,而扩展过程Cortex内核是不需要进行任何修改的。
4.寄存器映射原理
※存储器在产家制作完成后是一片没有任何信息的物理存储器,而CPU要进行访存就涉及到内存地址的概念,因此存储器映射就是为物理内存按一定编码规则分配地址的行为。值得注意,存储器映射一般是由产家规定,用户不能随意更改。
注意:寄存器映射是在存储器映射的基础上进行的。
● STM32,操作硬件本质上就是操作寄存器。在存储器片上外设区域,四字节为一个单元,每个单元对应不同的功能。当我们控制这些单元时就可以驱动外设工作,我们可以找到每个单元的起始地址,然后通过C 语言指针的操作方式来访问这些单元。但若每次都是通过这种方式访问地址,不好记忆且易出错。这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名实质上就是寄存器名字。给已分配好地址(通过存储器映射实现)的有特定功能的内存单元取别名的过程就叫寄存器映射。
(二)GPIO端口的初始化设置三步骤(时钟配置、输入输出模式设置、最大速率设置)
1.什么是GPIO
● GPIO(general porpose intput output):通用输入输出端口的简称。可以通过软件控制其输出和输入。stm32芯片的GPIO引脚与外部设备连接起来,从而实现与外部通信,控制以及数据采集的功能。
图中最右端 I/O 端口是STM32 芯片的引脚,其它部分都在 STM32 芯片内部。
IO端口位基本结构
①保护二极管。
②上/下拉电阻。
③施密特触发器:整形作用,使不规则波形成为规则方波。
④ P/N mos管。
MOS是压控型元件,通过控制Vgs来实现导通或关闭。
2.STM32时钟设置
2.1 什么是时钟?
● 单片机如果要正常运行,时钟信号是必不可少的。作为CPU的脉搏,时钟的快慢决定了CPU的运行速率,执行指令的速度。一般时钟源会被分频器或倍频器分成多种频率的时钟,以满足系统的不同应用。
● 在STM32中,有五个时钟源,为HSI、HSE、LSI、LSE、PLL。
时钟源 | 介绍 |
---|---|
HSI | 高速内部时钟,RC振荡器,频率为8MHz |
HSE | 高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz |
LSI | 低速内部时钟,RC振荡器,频率为40kHz |
LSE | 低速外部时钟,接频率为32.768kHz的石英晶体 |
PLL | 锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz |
2.2 为什么进行时钟配置?
● stm32配置时钟,就可以把不需要那些功能的功耗去掉
。当你想关闭某个IO的时候,关闭它相对应的时钟使能就是了,不过在51里面,在使用IO的时候是没有设置IO的时钟的,还有在STM32中,有外部和内部时钟之分。ARM的芯片都是这样,外设通常都是给了时钟后,才能设置它的寄存器(即才能使用这个外设)。STM32、LPC1XXX等等都是这样。这么做的目的是为了省电
,使用了所谓时钟门控的技术。这也属于电路里同步电路的范畴:同步电路总是需要1个时钟。
※ 总而言之,就是减少耗能
。
(三)GPIO输入输出模式设置
3.1GPIO输入输出模式简介
● GPIO支持4种输入模式(浮空输入、上拉输入、下拉输入、模拟输入)和4种输出模式(开漏输出、开漏复用输出、推挽输出、推挽复用输出)。同时,GPIO还支持三种最大翻转速度(2MHz、10MHz、50MHz)。
注意:每个I/O口可以自由编程,但I/O口寄存器必须按32位字被访问。
程序中标识 | 模式 |
---|---|
GPIO_Mode_AIN | 模拟输入 |
GPIO_Mode_IN_FLOATING | 浮空输入 |
GPIO_Mode_IPD | 下拉输入 |
GPIO_Mode_IPU | 上拉输入 |
GPIO_Mode_Out_OD | 开漏输出 |
GPIO_Mode_Out_PP | 推挽输出 |
GPIO_Mode_AF_OD | 复用开漏输出 |
GPIO_Mode_AF_PP | 复用推挽输出 |
3.2上拉输入模式
※ 默认情况下输入引脚数据为1,高电平。
● 上拉输入模式下,I/O端口的电平信号直接进入输入数据寄存器。但是在I/O端口悬空(在无信号输入)的情况下,输入端的电平保持在高电平(自己理解:上拉电阻连接电压);并且在I/O端口输入为低电平的时候,输入端的电平也是低电平(自己理解:上拉电阻上的电压和端口导通)。
施密特触发器:
施密特就是为了防止在某一个临界电平的情况出现各种情况的抖动出现,为了稳定我们的输出而设计的。
施密特触发器采用电位触发方式
,其状态由输入信号电位维持;对于负向递减和正向递增两种不同变化方向的输入信号,施密特触发器有不同的阈值电压。
3.3下拉输入模式
※ 默认情况下输入引脚为0,低电平。
● 下拉输入模式下,I/O端口的电平信号直接进入输入数据寄存器。但是在I/O端口悬空(在无信号输入)的情况下,输入端的电平保持在低电平;并且在I/O端口输入为高电平的时候,输入端的电平也是高电平。
3.4浮空输入模式
※ 通常用于IIC、USART。
● 浮空输入模式下,I/O端口的电平信号直接进入输入数据寄存器。
也就是说,I/O的电平状态是不确定的,完全由外部输入决定;如果在该引脚悬空(在无信号输入)的情况下,读取该端口的电平是不确定的。
3.5模拟输入模式
● 模拟输入模式下,I/O端口的模拟信号(电压信号,而非电平信号)直接模拟输入到片上外设模块
,比如ADC模块等。模拟信号一般:3.3v 5v 9v。
3.6开漏输出模式
※ 可以输出0和1,适用于电平不匹配场合,要得到高电平需要上拉电阻才行。
● 开漏输出模式下(上拉电阻+N-MOS管),通过设置位设置/清除寄存器或者输出数据寄存器的值,途经N-MOS管,最终输出到I/O端口。这里要注意N-MOS管,当设置输出的值为高电平的时候,N-MOS管处于关闭状态,此时I/O端口的电平就不会由输出的高低电平决定,而是由I/O端口外部的上拉或者下拉决定;当设置输出的值为低电平的时候,N-MOS管处于开启状态,此时I/O端口的电平就是低电平
。同时,I/O端口的电平也可以通过输入电路进行读取;注意,I/O端口的电平不一定是输出的电平。
3.7开漏复用输出模式
※ 片内外设功能:TX1,MOSI,MISO,SCK,SS
● 开漏复用输出模式,与开漏输出模式很是类似。只是输出的高低电平的来源,不是让CPU直接写输出数据寄存器,取而代之利用片上外设模块的复用功能输出来决定的。
3.8推挽输出模式
※ 可以输出高低电平0和1,适用于双向IO使用。
推挽输出模式下(P-MOS管+N-MOS管),通过设置位设置/清除寄存器或者输出数据寄存器的值,途经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端口的电平一定是输出的电平。
3.9推挽复用输出模式
※ 片内外设功能IIC的SCL、SDL
推挽复用输出模式,与推挽输出模式很是类似。只是输出的高低电平的来源,不是让CPU直接写输出数据寄存器,取而代之利用片上外设模块的复用功能输出来决定的。
(四)在STM32中选用怎样选择I/O模式
● 浮空输入_IN_FLOATING ——浮空输入,可以做KEY识别,RX1
● 带上拉输入_IPU——IO内部上拉电阻输入
● 带下拉输入_IPD—— IO内部下拉电阻输入
● 模拟输入_AIN ——应用ADC模拟输入,或者低功耗下省电
● 开漏输出_OUT_OD ——IO输出0接GND,IO输出1,悬空,需要外接上拉电阻,才能实现输出高电平。当输出为1时,IO口的状态由上拉电阻拉高电平,但由于是开漏输出模式,这样IO口也就可以由外部电路改变为低电平或不变。可以读IO输入电平变化,实现C51的IO双向功能
● 推挽输出_OUT_PP ——IO输出0-接GND, IO输出1 -接VCC,读输入值是未知的
● 复用功能的推挽输出_AF_PP ——片内外设功能(I2C的SCL、SDA)
● 复用功能的开漏输出_AF_OD——片内外设功能(TX1、MOSI、MISO.SCK.SS)
(五)GPIO初始化步骤
步骤 | 操作 |
---|---|
A | 使能GPIOx口的时钟 |
B | 指明GPIOx口的哪一位,这一位的速度大小以及模式 |
C | 调用GPIOx初始化函数进行初始化 |
D | 调用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; // IO口速度为50MHz
第三步:调用GPIOA口初始化函数,进行初始化。
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA
第四步:调用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端口的初始化设置三步骤。细心耐心,乃是学习的最好态度。
寄语:吸一缕新鲜的空气
摘一捧鲜花
予生活热爱
![](https://i-blog.csdnimg.cn/blog_migrate/3c5f47e47fd5a8ccbd00cbee7a26cdca.jpeg)
参考文献:
https://blog.csdn.net/geek_monkey/article/details/86291377
https://blog.csdn.net/geek_monkey/article/details/86291377
https://blog.csdn.net/k666499436/article/details/123800095
https://blog.csdn.net/zhuguanlin121/article/details/118489092