当前位置: 首页 > article >正文

第28讲 程序是如何控制寄存器的

寄存器是程序与外设之间的桥梁,这一讲我们来研究程序是怎么操作寄存器的。

注意我们讨论的外设是指片上外设,如下图所示的这些:

查阅手册可得GPIOA/B/C/D/E都有一套这样的寄存器:

以ODR寄存器为例:

如手册截图所示,STM32拥有32位的数据处理位宽,所以GPIOx_ODR寄存器有32位;其中16到31位是保留位,第0~15位分别代表了GPIO PA0~PA15是输出高电平还是低电平。

如上图所示,如果我们先通过对其他寄存器的设置使得GPIOA7处于推挽输出模式,那么当ODR的第7位被设置为1时,输出控制电路就会根据此信号讲P-MOS激活,N-MOS断开,宏观上单片机的引脚将会输出推挽的高电平。

反之,如若ODR寄存器被清0,那么N-MOS就会被激活,GPIO会输出低电平。

那么程序是如何控制寄存器的呢?

STM32的内部,有4GB的地址空间(0x00000000~0xFFFFFFFF),这段地址空间内存储着大量的地址数据,指向STM32内部的一小段存储空间。注意,这里说的存储空间不仅仅指的是内存空间,CortexM内核对这些地址进行了划分:

如果我们让指针指向一个外设寄存器的地址,就可以通过读取或者修改此地址存储大的数据,获取或者修改外设的状态。

以  HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_RESET)为例,点进GPIOA可以发现,GPIOx就是对GPIOx_BASE进行了类型强转,强转成为GPIO_TypeDef指针类型。

再次跳转定义可以发现GPIOx_BASE的地址是在APB2PERIPH总线的基地址上+若干位。

最后看到总线地址相当于外设基地址加若干位。

通过运算可以得知各个GPIOx的地址是多少,以GPIOA为例,它的地址就是0x4000000+0x10000+0x800=0x400010800。与2.3节存储器映像表格中记录的一致。

再来看GPIO_PIN_7的宏定义,是十六进制的0x0080,转换为二进制是1000 0000,也就是第七位为1(从0开始数)。

接下来讨论HAL_GPIO_WritePin的内部实现:

void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
{
  /* Check the parameters */
  assert_param(IS_GPIO_PIN(GPIO_Pin));
  assert_param(IS_GPIO_PIN_ACTION(PinState));

  if (PinState != GPIO_PIN_RESET)
  {
    GPIOx->BSRR = GPIO_Pin;
  }
  else
  {
    GPIOx->BSRR = (uint32_t)GPIO_Pin << 16u;
  }
}

如果传入的PinState不是低电平,就将GPIOx结构体指针指向的BSRR修改为GPIO_Pin这个数值。

继续沿用上例PA7,此时BSRR的数值被修改为:

如果是低电平就左移16位,再赋值给BSRR:

点进BSRR可以发现,BSRR是结构体内第5个32位成员变量。

typedef struct
{
  __IO uint32_t CRL;
  __IO uint32_t CRH;
  __IO uint32_t IDR;
  __IO uint32_t ODR;
  __IO uint32_t BSRR;
  __IO uint32_t BRR;
  __IO uint32_t LCKR;
} GPIO_TypeDef;

由此得出这7个寄存器的位置如下所示:

与手册上说明的地址是一致的,七个寄存器地址由低到高排布:

找到关于BSRR寄存器的描述:

第0~15位被置为1就可以将ODR寄存器的对应位置为1,但不影响ODR寄存器上的其他位置。第16~32位如果将其中的某一位请0,就可以将ODR寄存器清0而不影响其他位。BSRR寄存器的作用就是用来辅助ODR寄存器的修改,因为stm32数据处理的位宽为32位。因此如果需要直接修改ODR寄存器,那么就需要先读取ODR的状态再将修改后的数据整个写入。但是BSRR寄存器就支持我们对ODR寄存器进行直接修改了。


http://www.kler.cn/a/520969.html

相关文章:

  • JavaScript正则表达式
  • TikTok 推出了一款 IDE,用于快速构建 AI 应用
  • Linux——rzsz工具
  • 如何解压7z文件?8种方法(Win/Mac/手机/网页端)
  • PCIE模式配置
  • 006 mybatis关联查询(一对一、一对多)
  • 从零到全栈开发
  • 在深度Linux (Deepin) 20中安装Nvidia驱动
  • MiniMax-01中Lightning Attention的由来(线性注意力进化史)
  • API接口设计模板
  • Zotero中使用Deepseek翻译
  • 基于Python的哔哩哔哩综合热门数据分析系统的设计与实现
  • 小程序开发实战:记录一天的 Bug 修复历程
  • 绘制决策树尝试2 内含添加环境变量步骤
  • AIGC时代下的Vue组件开发深度探索
  • Centos7系统php8编译安装ImageMagick/Imagick扩展教程整理
  • 数据结构课设——模糊查询汉字和其位置
  • 机器学习2 (笔记)(朴素贝叶斯,集成学习,KNN和matlab运用)
  • 推箱子游戏
  • 第04章 17 实现一个逐步收缩球体的视觉效果
  • 分布式系统学习:小结
  • 从项目复查做一些TypeScript使用上的总结
  • 多模态论文笔记——VDT
  • ZooKeeper 数据模型
  • react-native网络调试工具Reactotron保姆级教程
  • java8-日期时间Api