hello,小伙伴们,大家好。这里是左左右。大家有没有思考过这样一个问题?我们是如何通过几行简单的代码就实现了对单片机上LED小灯亮灭的控制呢?这些代码在我看来无异于是直接写了一句把灯打开。只不过这里的代码是英文的而已。
那么,代码与灯之间到底经历了什么?这里我们就不得不提到一个关键的概念了。那就是寄存器。那么,什么是寄存器呢?说白了寄存器就是单片机内存空间中一块特殊的区域。我们通过修改寄存器中特定位置中的值。当寄存器特定位置中的值发生改变时,led小灯就实现了亮灭的功能。
同时,我们也可以读取寄存器特定位置中的值。来判断小灯此时的状态是亮还是灭。这里所说的特定位置就是地址。说专业点就是通过改变寄存器中特定地址中的值来来输出高低电平,从而实现小灯的亮灭,也就是前面我们说的通过庙来找和尚或者换和尚。所以,在stm32中不管是标准库还是hal库的源代码,都大量使用了指针。
这也是我为什么在前面连续几期视频对指针的概念和使用方法做了详细讲解?当然,实际情况要比这里所说的复杂一些,但基本的实现原理就是这样。接着,我们打开stm32中文手册。手册对于芯片来说就是一份详细的使用说明书。所以,阅读手册是每一个嵌入式学习者的基本功。大家一定要仔细阅读手册。
接着,我们找到2.3存储器映像中GPIO端口A(28页)。这里的地址区间就是寄存器分配给GPIOA来使用的。接着,跳转到8.5。横的这一行这里的0-31代表它占用了32位比特的地址,也就是四个字节。和我们前面讲过的int型数据类型占用的地址是一样的。竖的这一列指的是偏移量。

那么,它是相对于哪个地址来偏移的呢?这里的偏移量是相对于GPIOA的基地址而言的。如果是GPIOB就是以这个基地址为偏移的。其他也是以此类推。接着,来看这里的偏移量。相邻偏移量的差值都是4。就是前面这里每一组寄存器地址是占用了4个字节的空间。接着,来看这里的ODR这个寄存器。
这里的值就是控制GPIO引脚输出高低电平的。假设我们要控制GPIOA,那么,这里的16位比特,分别控制PA0到PA15。如果我们要控制的是PA15这个引脚,就要改变这里的值。当这里的值是0时,PA15就向外输出低电平,小灯点亮。当这里的值是1时,PA15就向外输出高电平,小灯熄灭。
接着,我们打开stm32cubeIDE来验证一下。首先,定义一个指针将基地址加偏移量放入其中。之前我们说过指针不仅有存放地址的功能还有指向的功能,而这里我们只是传入一个地址,并无指向的功能。所以,所以我们要把这里的地址强转为指针的形式。接着,我们给这个指针指向的地址赋值,也就是给GPIOA中ODR这个寄存器赋值。
通过前面视频的学习我们很容易就把这里的值转化为16进制的数。接着,点击运行。也同样实现了小灯的闪烁功能。接着,我们点击Debug这个按钮,然后打开SFR视图。这里就能实时看到STM32所有外设寄存器的值。找到GPIOA中ODR寄存器。接着,点击F6让代码一步一步向下执行。


然后,我们就能看到ODR15中的值。找到GPIOA下的ODR寄存器。点击F6让代码单步执行。就能看到ODR15位的值随着代码执行在0和1之间变化。同时,小灯也在闪烁。我们甚至可以直接在调试界面点击ODR15位的值来手动修改它,小灯也会随之立刻亮灭。其实,寄存器的存在就像一个翻译官一样。

我们通过向寄存器写值的操作,来告诉单片机我们想让它做什么操作。比如:让某个引脚输出高电平,也可以通过读取寄存器中的值,来"听懂"单片机向我们"传达"的信息。比如:某个引脚当前的电压状态,有了它的存在,我们才能与单片机进行无障碍沟通。虽然在实际开发中,我们很少直接使用寄存器来编写程序。
但理解寄存器的工作原理,对我们深入理解STM32是至关重要的。也是我们读懂STM32 HAL库或标准库源码的关键。如果你把我前面讲指针的视频都弄明白了,学习这期内容应该有一种豁然开朗的感觉。其实,这里的写法还是有一些瑕疵的,下期视频我会完善这里的代码,并分析hal库源码。
如果大家对这些底层源码分析的内容反响比较好,我后续也会穿插做更多这样的深度解析。同时,我也把这期视频的要点整理成了文档。供大家查漏补缺。之前视频的文档我也会陆续补齐。
同时,我也把这期视频的内容做成了文档的形式供大家查漏补缺。前面视频的文档内容我也会陆陆续续补齐。好的,今天的视频就到这里了。为了能让大家高效、易懂的学习,每期视频我都倾注了大量的时间和心血在里面。您的关注,点赞和收藏是我持续更新下去的最大动力。我们下期见。
那么,我们该如何改变其中某一位中的值呢?stm32已经替我想好了。接着,我们来看BSRR这个寄存器。这个寄存器分为低16位和高16位。这里也是分别控制PA0到PA15。
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;
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE)
#define GPIO_PIN_15 ((uint16_t)0x8000)
#define GPIOA_BASE (APB2PERIPH_BASE + 0x00000800UL)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000UL)
#define PERIPH_BASE 0x40000000ULuint32_t *GPIOA_ODR = (uint32_t*)0x40010800 + 0x0000000C;
*GPIOA_ODR = 0x00008000;
HAL_Delay(500);
*GPIOA_ODR = 0x00000000;HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_RESET);
HAL_Delay(500);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, GPIO_PIN_SET);
HAL_Delay(500);这里我们打开实现LED小灯闪烁的那期视频的程序。来看看hal库具体是怎么操作寄存器的?打开HAL_GPIO_WritePin这个函数。这两行代码作用是判断我们输入的这两个参数是否合法?
下期视频 改代码 讲bssr寄存器 看输出数据寄存器图片 读源码。
uint32_t *GPIOA_ODR = (uint32_t*)(0x40010800 + 0x0000000C);
*GPIOA_ODR = 0x00008000;
HAL_Delay(500);
*GPIOA_ODR = 0x00000000;
HAL_Delay(500);也同样实现了小灯的闪烁功能。