STM32 中对GPIO的一点理解

GPIO

Created time: 2024年9月4日 15:03
Status: In progress
类型: 理论&实践

参考STM32F10xxx参考手册:Ch8(P105+)

STM32-GPIO介绍_stm32 gpio-CSDN博客

在学习GPIO之前,请复习STM32的时钟系统!


什么是GPIO?

GPIO : General Purpose Input/Output,通用输入输出端口.

GPIO最基本的输入功能是检测外部电平变化,比如把GPIO引脚连接到按键电路,通过电平的高低变化来识别按键是否被按下。输出功能同上.

STM32 GPIO简介

GPIO特点

  1. 不同型号GPIO数量不一样,请参阅选型手册;
  2. 每个GPIO都可以用作中断
  3. 快速翻转,每次翻转最快只需要2个周期(极限条件即超频条件下,官方给的F1的最高速度可以达到50MHz),F103系列(72MHz)翻转达到36MHz;
  4. 有八种工作特性(这个之后讲)

GPIO电气特性(比较重要)

  • STM32工作范围:2V≤VDD≤3.6V
  • GPIO识别电压的范围?
    • COMS(3.3V)端口: -0.3V≤ V I L V_{IL} VIL≤1.164V (在1.164~1.833V之间为不确定值) 1.833V≤ V I H V_{IH} VIH≤3.6V
    • TTL(5V&3.3V)端口(芯片手册上凡是标了FT的都是TTL端口)
  • GPIO输出电流:单个IO口最大输出25mA,然而F103系列最大输入输出电流为150mA,所以不可能每个IO口都输出25mA(e.g.STM32RCT6有51个GPIO,要是都输出25mA到1.7A了肯定不行)如果想要更大的输入输出电流的话,就需要想一些扩流的方案,比如加个三极管\MOS管\继电器.etc

GPIO引脚分布

在这里插入图片描述

电源引脚,晶振引脚,复位引脚,下载引脚,BOOT引脚,GPIO引脚

不同芯片有不同的引脚分布情况,以(Mini)RCT6为例,他有64个引脚,51个GPIO,其中GPIOAC分别有16个IO口,GPIOD有02共3个IO口,即48+3=51 个IO口.

GPIO基本结构介绍

在这里插入图片描述

摘于STM32F10xxx参考手册。这是GPIO的硬件结构框图,可以从这个框图中清晰的了解GPIO外设极其各种应用模式,最右端的I/O引脚就是STM32芯片引出的GPIO引脚,其它的部件都位于芯片内部.看不懂?你先别急…

施密特触发器

这是一个整形的电路,可以将非标准方波(如正选信号)整形成标准方波,原理很简单:当输入电压高于正向阈值电压,则输出为高;输出低于负向阈值电压,则输出为低;如果输出在正负向阈值之间,那么输出不改变.

P-MOS&N-MOS

复习下魔电,MOS压控元件,通过 V g s 栅源电压 V_{gs}栅源电压 Vgs栅源电压控制器件的导通或关闭

P-MOS: V g s < 0 V_{gs}<0 Vgs<0导通;

N-MOS: V g s > 0 V{gs}>0 Vgs>0导通.

简单来讲就是两个端不一样(1\0)就能导通.

GPIO的8种工作模式

输入

浮空输入

完全浮空,状态不定

  • 对应前面那张I/O端口位的基本结构里的橙色1~4:上下拉电阻关闭,TTL肖特基触发器打开(即施密特触发器),双MOS管不导通
  • 空闲状态(即外部高阻态时,IO状态不确定,由外部决定.

这里的高阻态,就是外部什么都没接,电阻很大的时候.(我的理解)

上拉输入

内部上拉,默认高电平

和浮空输入唯一的不同是使用了上拉电阻,空闲时(外部高阻态)IO呈现高电平.注意这是弱上拉(电流很小)

下拉输入

内部下拉,默认低电平

模拟输入

ADC/DAC

上下拉电阻&施密特&双MOS都不导通,那么只有走左上角的那一条路,到片上外设模拟信号的输入(之后会讲)

输出

开漏输出

软件IIC的SDL,SCL等

  • 上下拉电阻关闭,施密特触发器打开,这里可以发现输出是可以走到IDR(输入数据寄存器)中的,即配置为输出模式我们可以读取引脚的高低电平.
  • P-MOS始终不导通,即在输出控制模块接高) V D D V_{DD} VDD;
  • 往ODR对应位写0,N-MOS导通,写1则N-MOS不导通.
    • 那么怎么输出1呢?可以在外部(或内部如:F4 H7 H7)加一个上拉电阻(就是单单看内部是不能输出高电平…)

在这里插入图片描述

开漏复用输出

片上外设功能(硬件IIC的SDL,SCL等)

  • 上下拉电阻关闭,施密特触发器打开,P-MOS管始终不导通(和开漏输出一样的,也是不能自己输出高电平(F1))
  • 注意这里的控制是上面那张图的左下角(片上外设)控制的,就不用寄存器控制了

推挽输出

驱动能力强,25mA(max),通用输出(高低电平都能输出)

  • 上下拉电阻关闭,施密特触发器打开,往ODR(就是输出数据寄存器)(走中间那条道)对应位写0的时候,N-MOS导通,写一则P-MOS导通.
  • 当然,我们先前说想要让P/N-MOS管导通,要和他们不一样才能导通,那么像输出0,进入输出驱动器时候得有一个反相器,反一下就能输出了,看眼这张图:

在这里插入图片描述

推挽复用输出

片上外设功能(SPI的SCK,MISO,MOSI引脚等)

  • 上下拉电阻关闭,施密特触发器打开,P/N-MOS可开可关.
  • 通过片上外设 (左下角)控制

总结一下:

  1. F1是不使用内部上下拉电阻的,其他(F4,F7,H7)可以使用
  2. 不同系列IO翻转速度不同

Q:STM32能输出5V电平嘛?——————————结论是可以,但是得加外部上拉(翻)

GPIO的寄存器介绍

有同学说,寄存器这玩意好枯燥不想看啊,这东西学了有啥用??告诉你哦,想学单片机确实需要了解一个个寄存器的,这和Python或者Java不一样(这其实也是对我自己说的,因为以前学的感觉都是顶层或者偏上位机),在这里初学者可能会有些痛苦,但耐心学你会知道这些有啥用的(doge)

看眼参考手册8.2(F1系列通用寄存器GPIO通用寄存器GPIOx_yyy)(x:A~E)

CRLCRHIDRODRBSRRBRRLCKR
配置工作速度,输出速度同CRL输入数据输出数据设置ODR寄存器的值F4之后没有这个寄存器配置锁定,用的不多(把CRL&CRH锁定)

CRL有32位+CRH有32位=64个位,而每个组(AE)有16个引脚(GPIOA0A15),∴4个位控制一个IO引脚的工作模式.接下来来看这俩寄存器(注意结合**参考手册(F1)**这玩意太他妈重要了):

端口配置低寄存器(GPIOx_CRL)(x=A…E)

在这里插入图片描述

CRL寄存器控制的是GPIOx0~7的工作模式(就对应着上文8个工作模式),然后CRH就是GPIOx8~15 的工作模式.

端口配置高寄存器(GPIOx_CRH)(x=A…E)

在这里插入图片描述

端口输入数据寄存器(GPIOx_IDR)(x=A…E)

在这里插入图片描述

0~15位分别控制GPIOx_0~15 注意这个寄存器是只读的,也就是只能判断引脚电平

端口输出数据寄存器(GPIOx_ODR)(x=A…E)

在这里插入图片描述

这个寄存器有俩功能:

  1. 设置上下拉(这个功能是补充CRL&CRH中设置上下拉模式不知道是上拉还是下拉的时候确定的,看这个表:)

    在这里插入图片描述

  2. 第二个功能就顾名思义,设置引脚输出的电平

端口位设置/清除寄存器(GPIOx_BSRR)(x=A…E)

间接控制ODR,注意这个寄存器只能操作,并且写1才有用.

在这里插入图片描述

  • 0~15 位写1:将ODR寄存器设置为1;
  • 16~31 位写1:清ODR寄存器为0.

ODR&BSRR有啥区别?
使用ODR在读和修改访问之间产生中断时,可能会发生风险;BSRR则无风险.

啥风险??

比如我想操作GPIOB3置高:

GPIOB->ODR |= 1<<3;
GPIOB->BSRR = Ox00000008;

可见,ODR修改:读→改→写而BSRR是直接写,而操作ODR时需要中断,而中断恰好要用到这个寄存器,这样就很容易产生覆盖值的问题.当然还会有操作系统中的线程(任务调度)的先后,所以选择BSRR会降低所谓的风险.建议大家使用BSRR控制输出哈,.

通用外设驱动模型(四步法)

这一个小点是对于STM32所有外设的驱动模型:

  1. 初始化
    1. 时钟设置
      1. 给外设选择时钟源(有默认时钟源的话就不用动了哈)
      2. 开启时钟源
    2. 参数设置
      1. 比如说GPIO有8种工作模式,那想要其工作在其中一种模式下就需要对其参数进行设置(寄存器.etc)
    3. IO设置,中断设置:这俩都是可选的,像GPIO就不需要设置IO,但是像串口(USART/UART)就需要设置IO(设置为复用功能);也是串口,他需要设置接收中断&发送中断,而在中断设置中我们也有开中断,设置NVIC等步骤(先别急之后会讲)
  2. 读函数(可选):就是从外设读取数据(串口)
  3. 写函数(可选):从外设写数据(串口)
  4. 中断服务函数(可选):根据中断标志,处理外设各种中断事务

GPIO配置步骤

接下来来看看具体的GPIO是怎么设置的:

  1. 使能时钟:__HAL_RCC_GPIOx_CLK_ENABLE()(??为啥这里没有选择时钟源?因为GPIO是挂载在总线时钟上的,具体哪个总线得看不同的系列)
  2. 设置工作模式(也就是八种工作模式的设置):HAL_GPIO_Init()
  3. 设置输出状态(可选)(写函数):有HAL_GPIO_WritePin()和HAL_GPIO_TogglePin()
  4. 设置输入状态(可选(读函数):HAL_GPIO_ReadPin()

相关HAL库函数简介

HAL库相关函数主要寄存器功能
__HAL_RCC_GPIOx_CLK_ENABLEF1:RCC_APB2ENR
F4:RCC_AHB1ENR
F7:RCC_AHB1ENR
H7:RCC_AHB4ENR开启GPIO时钟
HAL_GPIO_Init()F1:CRL,CRH,ODR初始化GPIO
HAL_GPIO_WritePin()BSRR控制IO输出高/低电平
HAL_GPIO_TogglePin()BSRR每次调用IO输出电平翻转一次
HAL_GPIO_ReadPin()IDR读IO电平

这里以__HAL_RCC_GPIOA_CLK_ENABLE() 为例:

__HAL_RCC_GPIOx_CLK_ENABLE

在这里插入图片描述

这边主要看蓝色那一行,自己把这些参数都跳转一遍,可以得出结论:这一句就是把1<<2(1左移2位)再对RCC_APB2ENR做或运算.那么RCC_APB2ENR 是啥呢?看眼参考手册:

在这里插入图片描述

我们现在是对位2进行写1的操作,再看眼位2:

在这里插入图片描述

破案了,就是将GPIOA的时钟开启,和我们要做的事情一致,.

HAL_GPIO_Init

举一反三,现在你已经会自己找到相关函数的定义了,所以我就解释一下帮助你理解:

void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) 看一眼函数形参:

  1. 第一个:GPIO_TypeDef 是各种寄存器的声明:

在这里插入图片描述

GPIOx 是寄存器基地址,以GPIOA 为例,它在\USER\stm32f103xe.h 下:

在这里插入图片描述

我们把这些都称作xx外设寄存器基地址.

  1. GPIO_InitTypeDef :
typedef struct
{
  uint32_t Pin;      /*引脚号*/ 
  uint32_t Mode;     /*模式设置(8)*/
  uint32_t Pull;     /*上拉下拉设置*/
  uint32_t Speed;    /*速度设置*/
}GPIO_InitTypeDef;

这个Ctrl+F就可以找到.看到后面注释有个@ref 的宏,Ctrl+C&Ctrl+F 进去就可以找到宏定义了,之后每查阅一些需要的函数或者变量都记得这个方法.

HAL_GPIO_WritePin()

HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState) 3个参数分别是GPIO组别(A~G),引脚号,状态(0/1)

HAL_GPIO_TogglePin**()**

void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

HAL_GPIO_ReadPin()

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin) //返回0/1

编程实战:点亮一个LED灯

Do It Yourself !

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值