31.一节课讲明白STM32寄存器(下)
Hello,小伙伴们,大家好,这里是左左右,在上期视频中我们通过修改ODR这个寄存器中的值也同样实现了小灯闪烁的功能,这样的写法在这个案例中是没什么问题的,但他其实是存在一定的隐患的,我们在给寄存器中PA15这一位置1和置0时,也同时把PA0到PA15的位也置零了。
我们在做一个完整的项目时,前面的代码可能已经对PA0到PA15中的某些引脚置1了,我们在这时将他们全部置0,程序不就乱套了?那么有没有什么办法将PA15这一位单独置零或者置1呢?答案肯定是有的,首先我们来尝试一下将PA15这一位单独置1,其实也很简单,我们都知道1与任意值做或运算都等于1,而0与任意值做或运算都等于这个值本身。
基于这一原理,我们将GPIOA ODR这个指针指向的值与这个数做或运算,这样我们就实现了将PA15这一位单独置1,而不影响其他位的值。
在代码中我们要将它转换为16进制的数,那么每次都要将2进制的数转换为16进制的数
是不是很容易出错?
那么有什么更简单的方法呢
其实我们只要将16进制的0x1向左移动15位就可以了
接下来我们要将PA15这一位单独置0
我们都知道0与任意值做与运算都等于0
而1与任意值做与运算都等于这个值本身
这时将GPIO A ODR这个指针指向的值与这个数做与运算
我们就实现了将PA15这一位单独置0
而不影响其他位的值
我们要将这个2进制的数转换为16进制数是不是更容易出错啊?
其实我们只要将另外一个2进制数取反就等价与这个2进制的数
这么看是不是就很眼熟了?
我们只要将16进制的0x1向左移动15位就可以了
在STM 3 2 GPIO寄存器中除了ODR寄存器还有一个非常重要的寄存器
那就是BSRR寄存器
这是它的偏移量
一会会用到
STM 3 2将32比特的BSRR寄存器分为高16位和低16位
高16位是用来清除ODR中0到15位的值
命名为BR位 这里的R就是RESET
设置为1会将ODR对应的位的值置为0,设置为0不影响
而低16位是用来设置ODR中0到15位的值
命名为BS位 这里的S就是SET
设置为1会将ODR对应的位的值置为1,设置为0不影响
也就是说我们只需通过在BSSR这个寄存器中置1的操作
就可以实现ODR对应位置1或置0的操作
同样我们通过改变BSRR这个寄存器中的值也可以间接实现对小灯亮灭的控制
那么当高16位和低16位都同时置1该怎么办?
在文档中也有说明
当高16位和低16位都同时置1时
BS位起作用
接下来我们打开STM 32 cube IDE来试一下
点击运行,小灯同样实现了亮灭的功能
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这个寄存器中值来实现小灯的亮灭 点击运行,是不是也没有问题?
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这个结构体的指针
指针的两个功能分别是指向功能和存放地址的功能
指向的功能在传参时已经赋予了
接着来找一下GPIOA中存放的地址
顺藤摸瓜我们可以找到GPIOA中存放的就是手册中GPIOA的基地址0x40010800
接着我们找到定义GPIO_TypeDef这个结构体的地方
由于GPIOA的地址是0x40010800
由此就可推出ODR和BSRR的地址
是不是很眼熟
这不就是手册中ODR和BSRR寄存器的地址嘛
接着找到GPIO_PIN_15对应的值
此时的1处于BSRR寄存器低16位的最高位
将它左移16位
对应BSRR寄存器高16位的最高位置1
此时ODR PA15的值置0
所以hal库源码做的事和我们前面操作寄存器是一模一样的
那么 ODR和 BSSR到底是什么呢
他们对应的就是前面讲过的位设置清除寄存器
和输出数据寄存器
这里有两条路可以控制IO口输出高低电平
一条是通过改变BSRR中值来改变ODR
另一条就是直接改变ODR中的值
和输出数据寄存器
这就将前面视频的知识串在一起了
通过这两期视频我们完成了ODR和 BSSR两个寄存器的讲解
同时也完成了HAL_GPIO_WritePin这个函数的源码讲解
其他内容我也会在后面的HAL库源码解析的课程中陆续讲解到的
好的,今天的视频就到这里了
为了能让大家高效、易懂的学习
每期视频我都倾注了大量的时间和心血在里面
您的关注,点赞和收藏是我持续更新下去的最大动力
我们下期见