- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
1、前言
在之前的STM32的GPIO理论基础知识中,分别对基本结构和工作模式进行了详细的介绍。GPIO基本结构中主要对GPIO内部的各个功能电路逐一的进行的分析;GPIO工作模式中主要介绍GPIO应用在不同的使用场景下,GPIO端口的静态特征配置和动态的工作模式,同时对信号的工作流进行了分析.
这一篇主要对GPIO模块使用到的寄存器进行详细的分析介绍,适当了解GPIO寄存器的相关知识,可以对GPIO最底层的一些配置和工作原理有更好的认识,有助于加深对GPIO基本结构及工作模式的理解,同时对后续介绍到的GPIO在应用设计中有较好的帮助.
图1为STM32的GPIO模块中寄存器的概述,总共有5种类型的寄存器。这里需要了解的是GPIO模块的port和pin的概念。其中寄存器名称中GPIOx的x表示不同的GPIO端口port,比如STM32芯片支持的port可以从A到I,GPIOA,GPIOB就表示了不同的端口;pin就是不同的port下支持的引脚,比如GPIOA下的引脚数从pin0到pin15。因此port就是pin的集合,不同的port都有它自己的如下图列出来的寄存器.
图1 GPIO寄存器概述 。
本节对寄存器位、寄存器偏移地址、复位值、寄存器功能定义进行介绍。可通过字节(8 位)、半字(16 位)或字(32 位)对 GPIO 寄存器进行访问.
(1)端口模式寄存器GPIOx_MODER 。
本寄存器的功能为设置GPIO端口的方向和模式,总共0到32位,每两位就是该port下的pin值,例如将GPIOA_MODER的MODER0[1:0]配置为00,就是将GPIOA的pin0管脚功能配置为输入类型的管脚,将GPIOA_MODER的MODER1[1:0]配置为00,就是将GPIOA的pin1管脚功能配置为输入类型的管脚,以此类推。 。
图2 GPIOx_MODER寄存器定义 。
(2)端口输出类型寄存器GPIOx_OTYPER 。
本寄存器设置GPIO端口的输出类型,前提是该端口中的pin已经配置成输出功能。该寄存器只有0到15位有效,每一位就是对应的pin值,例如将GPIOA_OTYPER的OT0设置为1,就是将GPIOA的pin0管脚设置为输出开漏的类型.
(3)端口输出速度寄存器GPIOx_OSPEEDR 。
本寄存器设置GPIO的输出速度频率,前提是该端口中的pin已经应用作为输出功能管脚.
这个速度是指输出驱动电路的响应速度:(芯片内部在I/O口的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路,通过选择速度来选择不同的输出驱动模块,达到最佳的噪声控制和降低功耗的目的。可理解为输出驱动电路的带宽:即一个驱动电路可以不失真地通过信号的最大频率.
速度高的IO耗电大、噪声也大,速度低的IO耗电小、噪声也小。使用合适的速度可以降低功耗和噪声。高频的驱动电路,噪声也高,当不需要高的输出频率时,请选用低频驱动电路,这样非常有利于提高系统的EMI性能,也可以降低功耗。当然如果要输出较高频率的信号,但却选用了较低频率的速度,很可能会得到失真的输出信号。关键是GPIO的引脚速度跟应用匹配.
比如:
①USART串口,若最大波特率只需115.2k,那用2M的速度就够了,既省电也噪声小.
②I2C接口,若使用400k波特率,若想把余量留大些,可以选用10M的GPIO引脚速度.
③SPI接口,若使用18M或9M波特率,需要选用50M的GPIO的引脚速度.
当为该端口下寄存器值的pin配置为11时,输出速度和电容C有关,这是指对于CMOS工艺的集成电路而言,输入阻抗是非常高的,主要功耗来自于绝缘栅等效的电容充放电效应。既然是电容的充放电,考虑信号源的内阻(基于标准CMOS电路的输出),根据RC充电常数和逻辑门限电平就能得出一个最小周期,其对应一个最高IO频率。 。
(4)端口上拉/下拉寄存器GPIOx_PUPDR 。
该寄存器是配置端口对应的pin上是否需要配置芯片内部的上拉或者下拉电阻.
图5 GPIOx_PUPDR寄存器定义 。
STM32芯片GPIO的上拉电阻和下拉电阻最小值,典型值和最大值如下:
(5)端口输入数据寄存器 GPIOx_IDR 。
本寄存器读取GPIO端口引脚的信号电平值。该寄存器只有0到15位有效,每一位就是对应的pin值,例如GPIOA_OTYPER的IDR00值为1,就是此时读到GPIOA的pin0管脚值为1高电平信号.
(6)GPIO 端口输出数据寄存器 GPIOx_ODR 。
本寄存器可以设置GPIO端口引脚的信号值。前提是该引脚为普通的IO输出引脚。该寄存器只有0到15位有效,每一位就是对应的pin值,例如设置GPIOA_OTYPER的ODR0值为1,就是此时输出GPIOA的pin0管脚值为1高电平信号.
(7)GPIO 端口置位/复位寄存器GPIOx_BSRR 。
本寄存器可以通过写入GPIOx_BSRR寄存器值,可以对GPIOx_ODR的对应位进行置位和复位。既然GPIOx_ODR 能控制管脚高低电平,为什么还需要GPIOx_BSRR寄存器?
原因是GPIOx_BSRR去改变管脚状态的时候是原子操作置位/复位,没有被中断打断的风险。也就不需要关闭中断,关闭中断明显会延迟或丢失一事件的捕获,所以控制GPIO的状态最好可以用GPIOx_BSRR.
该寄存器的0到15位为置位功能,16到31位为复位功能。例如设置GPIOA_BSRR的BS0值为1,相当于输出GPIOA的pin0管脚值为1高电平信号;设置GPIOA_BSRR的BR0值为1,相当于输出GPIOA的pin0管脚值为0低电平信号.
(8)GPIO 端口配置锁定寄存器GPIOx_LCKR 。
本寄存器用于锁定当前管脚的配置,可以保持管脚当前的状态,保护管脚不受干扰,要使用该寄存器,需要先激活“锁定”功能。当执行正确的写序列设置了位16(LCKK)时,锁定功能被激活,LCKK位的写序列为:写1 -> 写0 -> 写1 -> 读0 -> 读1。最后一个读可省略,但可以用来确认锁键已被激活。被锁定的管脚pin只有等到下次MCU复位才能被解锁.
LCK0到LCK15为对应的pin0到pin15的锁定配置,当需要锁定对应的管脚pin时,在执行LCKK写序列操作时,将对应的LCK位写1.
(9)GPIO 复用功能低位 寄存器GPIOx_AFRL 。
本寄存器可以设置GPIO端口引脚的复用功能,比如将该引脚设置成USART或者SPI类型的功能管脚,本寄存器AFRL0~AFRL7分别对应引脚pin0~pin7,每个引脚又有4位可选,因此一个引脚可以在16中复用功能中选择,例如将GPIOA_AFRL的AFRL0[3:0]=0001,就是将GPIOA的pin0管脚应用成第2种复用功能AF1.
(10)GPIO 复用功能高位寄存器GPIOx_AFRH 。
本寄存器可以设置GPIO端口引脚的复用功能,本寄存器AFRL0~AFRL7分别对应引脚pin0~pin7,功能上和复用功能低位寄存器GPIOx_AFRL一样.
本篇对STM32的GPIO对应的寄存器分别进行了介绍,了解了各个寄存器的功能和对应寄存器位的定义可以更方便的去理解在实际使用GPIO时的配置功能,后续篇章将对GPIO在实际开发中的设计配置及应用进行详细的分析.
更多技术内容和书籍资料获取,入群技术交流敬请关注公众号“明解嵌入式” 。
最后此篇关于明解STM32—GPIO理论基础知识篇之寄存器原理的文章就讲到这里了,如果你想了解更多关于明解STM32—GPIO理论基础知识篇之寄存器原理的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在对 JVM 上的 STM 技术进行一些研究。阅读了一些文档后,我对 Multiverse 的实现有些困惑。 根据 the Multiverse FAQ , Multiverse 不支持检测。然而
我想知道 Clojure 怎么可能已经实现了软件事务内存并且没有发现任何问题,而微软没有完成它的 C# 工作并注意到一些问题使得实现这里描述的 STM 不切实际: http://www.bluebyt
最后,我有以下设置 C:>哪里玩 C:\apps\play-2.2.0\play C:\apps\play-2.2.0\play.bat C:> 哪里 scala C:\apps\scala\bin\
我试图找出 Clojure 所称的 STM 与 Haskell 中实现的 STM 之间的区别。撇开实际的语言语义差异不谈,正如 Rich Hickey 在他的演讲中所说,Clojure 的 STM 实
阅读 Bartosz Milewski 的精彩作品 blog post在 STM 上,我很兴奋地阅读了以下内容: But take into account an important fact: ST
大家好, 在某些时候,我认为这些 stm 实现(我使用过一点点的多元宇宙......),被过度宣传了。因为在某些时候他们使用 CAS 来为他们提供操作的原子性。如果我直接使用 CAS 而不是使用这些实
haskell 的 stm 库中有一个函数,其类型签名如下: alwaysSucceeds :: STM a -> STM () 根据我对 Haskell 中 STM 的了解,在执行 STM 计算时,
在 Clojure 中,我们使用 STM 来实现并发。 我的问题是STM使用数据的时间点值,这是否会带来歧义? 我们如何知道访问了什么值? 最佳答案 Clojure 中的 STM 提供了(通过 ref
我需要有关用作原子更改日志的数据结构的建议。 我正在尝试实现以下算法。有流量传入更改更新内存中的映射。在类似 Haskell 的伪代码中它是 update :: DataSet -> Some
我正在尝试对这两个(软件事务内存和原子操作,我想两者不一样)进行一些基准测试,尽管我没有使用STM做太多事情(它似乎很难使用),但我成功地尝试了对基准测试进行计数,即所有线程将共享计数器递增 5000
我能够使用 STM 初始化状态并将其打印出来: module Main where import Control.Concurrent.STM data State = State {name ::
我读过两个关于 STM 如何实现的完全不同的描述。也许两者都是正确的,或者一个是错误的,我希望有人能阐明这一点。 Take 1(维基百科):允许所有线程修改共享内存,但事务中的每次读写都会被记录下来。
我知道将具有副作用的函数放在 STM 事务中通常是不好的做法,因为它们可能会被重试和调用多次。 然而,在我看来,您可以使用代理来确保只有在事务成功完成后才会执行副作用。 例如 (dosync //
我正在编写一个程序,其中大量代理监听事件并对其使用react。由于Control.Concurrent.Chan.dupChan已弃用我决定使用 TChan 的广告。 TChan 的表现比我预想的差很
我正在研究 Clojure 中的并发编程。 http://clojure.org/concurrent_programming 我了解到atom、ref和agent形式是用来维护程序状态的。 仅ref
你好,我正在阅读《clojure 的乐趣》这本书,在关于 STM 的部分中,他们有一个 2 个事务的图像,其中 A 最初从引用中检索与 B 相同的值,然后事务 A 和 B 都进行计算但 A 首先完成并
我熟悉Database transactions ,并花费了大量的时间调整isolation levels 。我从未在代码中实现过自己的事务模型。 我已通读 the source code对于 Clo
我有一个事务由于某种原因无限期失败,我想在内部使用跟踪指令。例如,要在执行此片段中的事务之前打印 MVar 的状态: data_out do putTMVar
当我们运行 STM 表达式时,它命中了 retry,线程被阻塞,如果条目被修改,事务将再次运行。 但我想知道: 如果我们读取一个 STM 变量,但在导致重试的特定分支中实际未使用该变量,更新它是否会尝
我正在研究 Clojure 中的并发编程。 http://clojure.org/concurrent_programming 我了解到atom、ref 和agent 表单用于维护程序状态。 只有 r
我是一名优秀的程序员,十分优秀!