尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

重温STM32基础:关于GPIO(1)

重温STM32基础:关于GPIO(1) 文章目录引脚电平输出模式输入模式STM32中的GPIOGPIO端口位的基本结构输入保护二极管4种输入模式施密特触发器输出3种设置输出值的操作方式读-改-写通过bit set/reset registerBSRR位带操作三种方法总结4种输出模式开漏和推挽的选择输入输出电路同时工作最近借着江科大课程梳理了一下GPIO。引脚电平0~3.3V部分可容忍5V。容忍5V的意思是可以容忍5V输入。下图中的表格截图来自于STM32F103的datasheet。FT代表能够容忍5V的电压没有FT的就只能3.3V输出最多只能是3.3V因为电源电压就是3.3V注表格中的“主功能”是指引脚默认功能。通常和引脚名称一样。如果不一样引脚的实际功能是主功能而不是引脚名称说的功能。输出模式输入模式控制端口输出高低电平驱动LED控制蜂鸣器模拟通信协议输出时序等如果控制的是功率比较大的设备只需要加入驱动电路即可输入模式读取端口的高低电平或电压读取按键输入外接模块电平信号输入ADC电压采集GPIO配置成模拟输入并配合ADC外设模拟通信协议接收数据STM32中的GPIO都是挂在APB2总线上。所以如果要使用GPIO都需要通过RCC使能APB2的外设时钟主要就是调用库函数中的“RCC_APB2PeriphClockCmd”寄存器每一位都对应一个引脚STM32的寄存器都是32位的但是GPIO端口只有16位。所以图中的”寄存器“只有低16位对应有端口寄存器只负责存储数据驱动器来增加驱动能力。GPIO端口位的基本结构输入输入信号会经过的特殊部分保护二极管 -上拉/下拉电阻 -施密特触发器 -寄存器保护二极管保护二极管的工作机制以标准GPIO为例FT的GPIO类似目的是对输入电压限幅上面的二极管提供过压保护如果输入电压大于3.3V则上面的二极管会被导通这个大电流就会从上面出去而不是进入芯片内部从而保护芯片内部电路不受大电流的伤害。下面的二极管提供负压保护如果输入电压为负低于VSS则下面连着VSS的二极管会被导通。VSS通常接地则这个时候电流会从地流到外部设备而不是从芯片内部流到外部设备。如果没有保护内部电流会面临过流烧毁和电场击穿的风险要注意的是这两个保护二极管是为了防止瞬态冲击不能承受持续的大电流。如果外部长期存在负压或者大电流需要靠其他器件来保护。4种输入模式上拉/下拉/浮空的本质是给输入提供一个默认的输入电平。当没有人没有外部设备明确告诉引脚你是高电平或你是低电平的时候引脚自己应该处于什么状态上拉输入默认为高电平的模式。没有外部设备的时候MCU读到的是高电平。当外部设备拉到低电平比如接GND的按键按下MCU可以读到低电平。这个模式是在检测外部”接地“作为有用信号的时候使用。下拉输入默认为低电平的模式。没有外部设备的时候MCU读到的是低电平。当外部设备拉到高电平时比如接VCC的按键按下MCU可以读到高电平。浮空输入默认电平不确定。设置这个模式的时候外部设备必须有一个连续的驱动源不能出现悬空的状态。模拟输入配置成这个模式时施密特触发器等全部断开。相当于从引脚直接接入片上外设也就是ADC。所以当我们用ADC的时候把引脚配置成模拟输入就可以了。其他时候一般用不到这个模式。施密特触发器它的目的是对输入电压整形效果是”迟滞“只有高于高电平和低于低电平时施密特触发器的输出才会变化。它的前后信号分别被接入其他外设它的前面是模拟输入接到用模拟量的外设主要是ADC它的后面是数字量接到用数字量的外设输出3种设置输出值的操作方式关注两个寄存器bit set/reset register 和 output data register(ODR)。ODR同时控制16个端口且这个寄存器只能整体读写。所以如果需要单独控制其中某个端口而不影响其他就需要一些特殊的操作方式。读-改-写读出寄存器的值 - 按位或/与的方式更改某一位 - 写回寄存器。对应C代码中的 |和的操作。这种操作比较麻烦。这种读-改-写的步骤还会有问题这不是原子操作会造成”竞争问题“。如果在第二步和第三步的时候中断突然发生另一个代码也改写了这个ODR的其他位那我们”写“的操作会把这另一个代码的修改覆盖。通过bit set/reset registerBSRR对某一位进行置1操作在位设置的对应位写1即可其他不需要操作的位写0。芯片内部电路自动讲ODR对应位置1ODR的其他位BSR里0的位置保持不变。对某一位清零操作在位清除的寄存器里对应位写1。这样内部电路就会把ODR的某一位清零。位域作用BR[15:0]高 16 位Bit Reset写 1 → 把 ODR 对应位清 0写 0 → 无影响BS[15:0]低 16 位Bit Set写 1 → 把 ODR 对应位置 1写 0 → 无影响这个方法是基于硬件的整个过程是单周期、原子操作所以不会有竞态。可以发现我们是可以同时向指向同一个Port的BR和BS写1的同时让它set和reset但硬件规定是BS优先所以结果确定不会混乱。位带操作这是Cortex-M3/M4内核的一个硬件特性。STM32继承了这个特性。STM32专门分配有一段地址区域这段地址隐射了RAM和外设寄存器所有的位。读写这段地址中的数据就相当于读写所映射位置的某一位。具体来说位带给每个位单独分配了一个 32 位的替身地址。比如以下为假设ODR 寄存器的第 0 位 → 映射到地址 0x4001 1400ODR 寄存器的第 1 位 → 映射到地址 0x4001 1404通过位带方式写ODR的第0位*(volatileuint32_t*)0x400114001;// 向位带别名区写 1硬件直接把这个值写进 ODR 的第 0 位其他 31 个位完全不受影响。整个过程是原子的不可中断不存在读-改-写的竞态问题。但是比较麻烦的是需要计算别名地址。但是现在的一些HAL库可能已经做了封装。三种方法总结第二和第三种方法都不会有竞态问题。第二种方法只能用于GPIO而第三种方法可以用于所有外设。可以把第二种方法看成GPIO外设的”专用位带“。特性BSRR位带操作对象只能改 GPIO 的 ODR可以改任何支持的寄存器/内存操作方向只能写置 1 或清 0可读可写写 0 的影响写 0 无影响不会误改其他位写 0 就是把该位清 0使用方式向 32 位寄存器写值向映射的 32 位地址写值本质外设硬件机制Cortex-M 内核总线机制库函数用的是第二种方法。4种输出模式推挽输出配置成这个模式的时候ODR配置成1时P-MOS导通N-MOS断开外部接收3.3VODR配置成0时P-MOS断开N-MOS导通外部接收低电平N-MOS和P-MOS是“互斥的上关下开是连通3.3v给外部设备推上开下关就是把0V给外部设备挽。这种模式一般是驱动能够使用3.3V的外部设备而配置的。这个模式也叫”强推输出模式“高低电平由STM32说了算。开漏输出上面的P-MOS无效。只有N-MOS工作。ODR配置成1时N-MOS断开输出线相当于断开是高阻模式ODR配置成0时N-MOS导通输出线接到VSS即输出低电平这种情况只有低电平由驱动能力高电平没有驱动能力推挽输出模式是高低电平都有驱动能力。可以作为通信协议的驱动模式比如I2C的驱动引脚。开漏模式可以用于输出5V的电平信号用于兼容一个5V的设备比如在IO口外接一个上拉电阻到5V的电源。ODR配置成1时IO引脚由外部电阻拉高至5VODR配置成0时IO引脚直接接到VSS复用推挽输出类似于普通的推挽输出只是引脚电平时由片上外设控制的而不是ODR如下图红圈是断开的复用开漏输出类似于普通的开漏输出只是引脚电平时由片上外设控制的而不是ODR如下图红圈是断开的可以发现4种模式其实涉及两个维度的分类复用和无复用决定谁控制引脚CPU 还是硬件外设开漏和推挽两种输出的物理结构。开漏和推挽的选择必须开漏I2C总线I2C总线设计成高电平靠外部上拉电阻统一提供所有设备只能拉低总线。如果用推挽输出那么如果总线上一个设备输出高电平一个输出低电平就会造成短路。需要电平转换一个FT的引脚去驱动外部5V的设备配置为开漏输出 外部 5V 上拉电阻必须推挽一般数字输出LED、蜂鸣器控制等推挽输出高低电平都有驱动能力高速通信(SPI或I2C)推挽输出的上升沿和下降沿都很陡峭纳秒级适合高速信号传输。如果用开漏 上拉电阻RC 充电会让上升沿变得很慢限制通信速率。需要强高低电平驱动的场景:比如驱动 MOSFET 栅极、高速 CMOS 逻辑门等推挽能提供更快的充放电能力。功耗考虑静态功耗开漏输出高电平时STM32引脚处于高阻态设备引脚CMOS阻抗很高但不是断开但是此时上拉电阻还是会有微小的电流漏电流。如果总线上挂了很多设备漏电流就会累计变得较大。当然这还是很小的漏电流当开漏输出低电平时上拉电阻会持续耗电功耗会非常高相比之下推挽输出没有持续的电阻通路功耗较低。瞬态电流推完结构在电平翻转期间可能会有一个短暂的PMOS和NMOS都导通的情况。这会在 VDD 和 GND 之间形成一个低阻通路产生一个纳秒级的浪涌电流。单个引脚切换的时候不成问题但是如果多个GPIO同时翻转会产生多个这种瞬态电流会有芯片功耗上升的情况。但开漏输出不会有这种GPIO电平翻转导通的问题。上升沿功耗开漏输出从低变高时NMOS 截止电容负载通过上拉电阻充电这个充电电流持续流过电阻单位时间内充电次数越多动态功耗越大而推挽输出是PMOS直接给电容负载充电虽然也有功耗但充电速度快、效率高整体动态功耗通常更低。实际功耗考量场景推荐模式原因电池供电引脚长期输出高电平推挽开漏上拉电阻会持续耗电电池供电引脚长期输出低电平开漏或推挽都可以开漏 NMOS 导通时功耗也很低高速通信推挽边沿快动态功耗效率更高I2C 等必须开漏的总线开漏无法选择外部上拉电阻的功耗是必要代价输入输出电路同时工作配置成输入模式的电路可以发现这个时候输出部分的电路断开配置成输出模式的电路可以发现这个时候输如部分的电路还在施密特触发器是on的所以GPIO并不是只能作为输入或者只能作为输出。STM32的GPIO电路里输入检测电路和输出驱动电路是并行的不是互斥的。至少当配置成输出模式的时候它还能读取。总结来说配成输入时输出端被强制断开你无法驱动引脚。配成输出时输入端并没有被断开它一直挂在引脚上监听。此时不用配置”输出模式“仍然可以读取 IDR 寄存器读到引脚上的实际电平其实把”输入电路“理解成”引脚电压检测/监听“电路就很好理解了。在输出模式下使用“输入”的作用推挽输出时验证输出是否真的出去了。比如你让引脚输出高电平然后读 IDR如果读到 1则正常。如果读到 0那么引脚可能被外部短路到地了或者负载太大被拉低了。开漏输出模式下引脚状态读取重要应用比如I2C 的 SDA 就是开漏输出 外部上拉。我们往ODR里写1时是N-MOS断开期望引脚靠外部上拉电阻变高我们往ODR里写0时N-MOS导通通常时把引脚拉到GND但是我们如何知道实际引脚到底时高还是低此时可以读IDR。在开漏模式下总线上可能有其他设备把线拉低。你虽然想输出高电平释放但如果另一个设备把线拉低了你读 IDR 就会读到 0。所以在把GPIO配置成输出模式的时候可以通过读取IDR来得到引脚的真实电平状态。当配置成“复用开漏/推挽输出”的时候输入部分电路也是有效的此时其他片上外设以及IDR也都是可以读取到引脚电平的如“复用功能配置电路”图的绿圈所示总结只有当把GPIO配置成模拟输入的时候输入模式部分电路会被关闭其他7个模式中输入部分电路一直是有效的。还没完且听下回继续补充
返回列表