Skip to main content

31.一节课讲明白STM32寄存器(下)

Hello,小伙伴们,大家好,这里是左左右,在上期视频中我们通过修改ODR这个寄存器中的值也同样实现了小灯闪烁的功能,这样的写法在这个案例中是没什么问题的,但他其实是存在一定的隐患的,我们在给寄存器中PA15这一位置1和置0时,也同时把PA0到PA15的位也置零了。 Docusaurus logo 我们在做一个完整的项目时,前面的代码可能已经对PA0到PA15中的某些引脚置1了,我们在这时将他们全部置0,程序不就乱套了?那么有没有什么办法将PA15这一位单独置零或者置1呢?答案肯定是有的,首先我们来尝试一下将PA15这一位单独置1,其实也很简单,我们都知道1与任意值做或运算都等于1,而0与任意值做或运算都等于这个值本身。 Docusaurus logo 基于这一原理,我们将GPIOA ODR这个指针指向的值与这个数做或运算,这样我们就实现了将PA15这一位单独置1,而不影响其他位的值。 Docusaurus logo 在代码中我们要将它转换为16进制的数,那么每次都要将2进制的数转换为16进制的数 是不是很容易出错? 那么有什么更简单的方法呢 其实我们只要将16进制的0x1向左移动15位就可以了 Docusaurus logo 接下来我们要将PA15这一位单独置0 我们都知道0与任意值做与运算都等于0 而1与任意值做与运算都等于这个值本身 这时将GPIO A ODR这个指针指向的值与这个数做与运算 我们就实现了将PA15这一位单独置0 而不影响其他位的值 Docusaurus logo 我们要将这个2进制的数转换为16进制数是不是更容易出错啊? 其实我们只要将另外一个2进制数取反就等价与这个2进制的数 这么看是不是就很眼熟了? 我们只要将16进制的0x1向左移动15位就可以了 Docusaurus logo 在STM 3 2 GPIO寄存器中除了ODR寄存器还有一个非常重要的寄存器 那就是BSRR寄存器 这是它的偏移量 一会会用到 Docusaurus logo STM 3 2将32比特的BSRR寄存器分为高16位和低16位 高16位是用来清除ODR中0到15位的值 命名为BR位 这里的R就是RESET 设置为1会将ODR对应的位的值置为0,设置为0不影响 Docusaurus logo 而低16位是用来设置ODR中0到15位的值 命名为BS位 这里的S就是SET 设置为1会将ODR对应的位的值置为1,设置为0不影响 Docusaurus logo 也就是说我们只需通过在BSSR这个寄存器中置1的操作 就可以实现ODR对应位置1或置0的操作 同样我们通过改变BSRR这个寄存器中的值也可以间接实现对小灯亮灭的控制 那么当高16位和低16位都同时置1该怎么办? 在文档中也有说明 当高16位和低16位都同时置1时 BS位起作用 Docusaurus logo 接下来我们打开STM 32 cube IDE来试一下 点击运行,小灯同样实现了亮灭的功能

main.c
  while (1)
{

uint32_t *GPIOA_ODR = (uint32_t*)(0x40010800 + 0x0000000C);
*GPIOA_ODR |= 0x1 << 15;
HAL_Delay(500);
*GPIOA_ODR &= ~(0x1 << 15);
HAL_Delay(500);

/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}

接着我们通过改变BSSR这个寄存器中值来实现小灯的亮灭 点击运行,是不是也没有问题?

main.c
  while (1)
{

uint32_t *GPIOA_BSRR = (uint32_t*)(0x40010800 + 0x00000010);
*GPIOA_BSRR |= 0x1 << 15;
HAL_Delay(500);
*GPIOA_BSRR |= 0x1 << 31;
/ HAL_Delay(500);

/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}

接下来我们看看hal库具体是怎么操作寄存器的 我们按下Ctrl点击HAL_GPIO_WritePin这个函数 接着顺藤摸瓜找到和它同名的.c文件 这两行代码作用是判断我们输入的这两个参数是否合法 不用管他

在这个函数中我们传入的PinState的值是GPIO_PIN_RESET 所以程序会跳转到这里 当我们看到这个符号 是不是就瞬间想到结构体指针了? 这是因为HAL_GPIO_WritePin这个函数传入的第一个参数就是结构体指针 我们这里传入的GPIOA 所以GPIOA就是就是指向GPIO_TypeDef这个结构体的指针 指针的两个功能分别是指向功能和存放地址的功能 指向的功能在传参时已经赋予了 Docusaurus logo 接着来找一下GPIOA中存放的地址 顺藤摸瓜我们可以找到GPIOA中存放的就是手册中GPIOA的基地址0x40010800 Docusaurus logo 接着我们找到定义GPIO_TypeDef这个结构体的地方 由于GPIOA的地址是0x40010800 由此就可推出ODR和BSRR的地址 是不是很眼熟 Docusaurus logo 这不就是手册中ODR和BSRR寄存器的地址嘛 Docusaurus logo 接着找到GPIO_PIN_15对应的值 此时的1处于BSRR寄存器低16位的最高位 Docusaurus logo 将它左移16位 对应BSRR寄存器高16位的最高位置1 此时ODR PA15的值置0 Docusaurus logo 所以hal库源码做的事和我们前面操作寄存器是一模一样的 那么 ODR和 BSSR到底是什么呢 他们对应的就是前面讲过的位设置清除寄存器 和输出数据寄存器 这里有两条路可以控制IO口输出高低电平 一条是通过改变BSRR中值来改变ODR 另一条就是直接改变ODR中的值 和输出数据寄存器 这就将前面视频的知识串在一起了 Docusaurus logo 通过这两期视频我们完成了ODR和 BSSR两个寄存器的讲解 同时也完成了HAL_GPIO_WritePin这个函数的源码讲解 其他内容我也会在后面的HAL库源码解析的课程中陆续讲解到的 Docusaurus logo 好的,今天的视频就到这里了 为了能让大家高效、易懂的学习 每期视频我都倾注了大量的时间和心血在里面 您的关注,点赞和收藏是我持续更新下去的最大动力 我们下期见