打印
[其他ST产品]

关于STM32的寄存器操作学习

[复制链接]
103|11
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lxs0026|  楼主 | 2023-11-20 22:36 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
前言
本人使用的开发板的芯片是STM32H743XIH6,所以也是根据此芯片来进行操作。

一、寄存器
在STM32的学习过程里面,大部分人最开始应该都是学习标准库版本的,对于寄存器操作应该都不太了解。百度百科对于寄存器的介绍,寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。

简单的理解为,一个存放了东西的东西。只不过,里面存放的是某些数据或者指令。就像你身份*号,代表了你的省份、城市、县区等等。如果想要找到你,对你做某件事或者获取一些东西,就会根据你的身份*号,找到你的所在地。这些操作,对于寄存器来说,称为读和写。

对于寄存器的读操作来说,就是你想要获取寄存器的数据,那么就需要找到这个寄存器,然后直接读数据多少即可,这也叫访问寄存器。

对于寄存器的写操作来说,就是你想要修改寄存器的数据,那么就需要找到这个寄存器,然后直接将数据写在寄存器里,这也叫写寄存器。

现在我们已经知道了读写操作,但是寄存器这么多,怎么找到我们想要的寄存器呢?怎么去区分它们呢?这就要引用C语言的一个操作,指针和&的使用,想在窗口控制台输入一个变量,是不是要用到scanf这个语句?那这个&符号的作用,就是取这个变量的地址!不同的寄存器,地址也就不一样,所以想要找到对应的寄存器,我们就找到对应的地址就行了!就像前面讲的身份*号,你可能四处旅游,想通过身份*号找到你可能有点困难,但是在STM32芯片里就不同,每一个寄存器的地址都在芯片出厂的时候就已经分配了!


使用特权

评论回复
沙发
lxs0026|  楼主 | 2023-11-20 22:36 | 只看该作者
怎么找到寄存器的地址?
我们打开参考手册,看到存储器和总线架构这一章,往下滑就可以看到寄存器的边界地址。


使用特权

评论回复
板凳
lxs0026|  楼主 | 2023-11-20 22:37 | 只看该作者
例如,我们想要打开GPIOB的时钟,我们就要找到RCC的这一栏。由下图可看出,只要是和RCC相关的,都在0x58024400-0x580247FF这一区间。


使用特权

评论回复
地板
lxs0026|  楼主 | 2023-11-20 22:38 | 只看该作者
然后,我们就要打开芯片的数据手册,找到我们的GPIOB的时钟挂在哪一条总线上。由下图可看出,GPIOA~GPIOK都挂在AHB4总线上。

使用特权

评论回复
5
lxs0026|  楼主 | 2023-11-20 22:38 | 只看该作者
我们再回到参考手册的RCC寄存器说明,可以看到好几个和AHB4相关的寄存器。我们只需要看到RCC_AHB4ENR,实际上这里应该叫做时钟使能寄存器。

使用特权

评论回复
6
lxs0026|  楼主 | 2023-11-20 22:38 | 只看该作者
看到寄存器开头的介绍,里面是有两个偏移地址的,我两个都使用过,同样可行。我们找到了这个偏移地址后,RCC_AHB4ENR的地址就是0x58024400+0xE0;

使用特权

评论回复
7
lxs0026|  楼主 | 2023-11-20 22:39 | 只看该作者
怎么对寄存器的位进行操作?
这里我们需要掌握位操作,C语言有以下6个位操作符。

使用特权

评论回复
8
lxs0026|  楼主 | 2023-11-20 22:39 | 只看该作者
按位与(&):同一位上,同样为1,&的结果就为1,只要有一个0或者两个都是0,结果就为0;

按位或(|):同一位上,只要有一个为1,|的结果就为1,两个都是0,则结果就为0;

按位异或(^):同一位上,两个不相同则为1,相同则为0;

按位取反(~):将结果取反,1为0,0为1;

按位左移(<<):运算符左边的运算量全部向左边移动运算符右边的运算量,高位舍弃,低位补0;

按位右移(>>):运算符左边的运算量全部向右边移动运算符右边的运算量,高位补0,低位舍弃;

使用特权

评论回复
9
lxs0026|  楼主 | 2023-11-20 22:39 | 只看该作者
我们已经了解位操作,也会查找寄存器的地址后,看到寄存器的位说明,在这一位置位,即可使能GPIOB的时钟。

使用特权

评论回复
10
lxs0026|  楼主 | 2023-11-20 22:40 | 只看该作者
寄存器的直接操作
代码里我使用了宏定义来操作,但是,这些宏在我们看来是寄存器的地址,但是在编译器看来,这只是一个普通的变量,所以我们要让编译器也要让它认为是一个指针也就是地址,我们就得进行强制类型转换,把它转换成uint32_t类型的指针,然后对这个指针进行解引用操作也就是*操作。这样下来,我们就完成了GPIOB的时钟使能啦!
————————————————

uint32_t *pAHB4_Addr = (uint32_t *)(RCC_START_ADDR + RCC_AHB4_OFFEST);    //RCC->AHB4ENR
*pAHB4_Addr |= (0x01 << 1);    //开启GPIOB时钟

使用特权

评论回复
11
lxs0026|  楼主 | 2023-11-20 22:40 | 只看该作者
寄存器地址映射
直接访问的操作非常的麻烦,每操作一个寄存器就必须去查看数据手册,然后找找这个寄存器的地址。 ST官方专门在一个.h文件里面,做好了寄存器的地址映射,我的是stm32h743xx.h。下面就是使用映射的地址进行的GPIOB的时钟开启操作。

RCC->AHB4ENR |= (0x01 << 1);

使用特权

评论回复
12
lxs0026|  楼主 | 2023-11-20 22:40 | 只看该作者
总结
寄存器的操作,相对于标准库或者HAL库来说,会麻烦很多,但是操作是直接式的。在使用库的操作,需要知道函数的作用,然后知道要往里面填入什么变量即可,剩下的内容函数里已经帮你写好了。所以相对寄存器来说是非常省事的,而且填入不同的参数,也会去执行不同的操作,兼容性也很强。使用寄存器的话,可能当前的函数只能够符合当前的功能,如果要换其他的,可能又要重新写,重新去看寄存器的说明等等,要做成兼容其他功能的,又要重新写一个函数,相对库函数来说就非常费事了!

但是,如果在学习阶段,我还是非常建议学习寄存器操作的,这样对于芯片的外设会理解的比较深。库函数的话,也是可能会存在一些bug的,在学习过寄存器后再去学习库函数,就可以发现那些bug,并做出修复!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

61

主题

905

帖子

1

粉丝