点了个灯开心不?开心个锤子。。。至于吗?Ctrl+F都摁坏了,而且这位运算,不好玩。。。
我们接下来升级
我觉得性能敏感可以寄存器,如果不敏感就库函数,你全用寄存器操作,我也不会说你一个牛逼。
F4,F7的片子怎么办?哭吧,卫生纸也挺缺的,我用完了。
在操作寄存器的时候,操作的是都寄存器的绝对地址,如果每个外设寄存器都这样操作,那将非常麻烦。我们考虑到外设寄存器的地址都是基于外设基地址的偏移地址,都是在外设基地址上逐个连续递增的,每个寄存器占32 个字节,这种方式跟结构体里面的成员类似。所以我们可以定义一种外设结构体,结构体的地址等于外设的基地址,结构体的成员等于寄存器,成员的排列顺序跟寄存器的顺序一样。这样我们操作寄存器的时候就不用每次都找到绝对地址,只要知道外设的基地址就可以操作外设的全部寄存器,即操作结构体的成员即可。
寄存器的值常常是芯片外设自动更改的,即使CPU 没有执行程序,也有可能发生变化,编译器有可能会对没有执行程序的变量进行优化。
这就是我们的库函数的样子。
这段代码在每个结构体成员前增加了一个“__IO”前缀,它的原型在这段代码的第一行,代表了C 语言中的关键字“volatile”,在C 语言中该关键字用于表示变量是易变的,要求编译器不要优化。这些结构体内的成员,都代表着寄存器,而寄存器很多时候是由外设或STM32 芯片状态修改的,也就是说即使CPU 不执行代码修改这些变量,变量的值也有可能被外设修改、更新,所以每次使用这些变量的时候,我们都要求CPU 去该变量的地址重新访问。若没有这个关键字修饰,在某些情况下,编译器认为没有代码修改该变量,就直接从CPU 的某个缓存获取该变量值,这时可以加快执行速度,但该缓存中的是陈旧数据,与我们要求的寄存器最新状态可能会有出入。
还有个事情,就是我们还没有和我们的地址产生联系,外设寄存器结构体定义仅仅是一个定义,要想实现给这个结构体赋值就达到操作寄存器的效果,我们还需要找到该寄存器的地址,就把寄存器地址跟结构体的地址对应起来。所以我们要再找到外设的地址,我们可以把这些外设的地址定义成一个个宏,实现外设存储器的映射。
不装逼了,就是这样的一点东西。
定义好外设寄存器结构体,实现完外设存储器映射后,我们再把外设的基址强制类型转换成相应的外设寄存器结构体指针,然后再把该指针声明成外设名,这样一来,外设名就跟外设的地址对应起来了,而且该外设名还是一个该外设类型的寄存器结构体指针,通过该指针可以直接操作该外设的全部寄存器。
哎,真理就是这样的朴实无华。
首先通过强制类型转换把外设的基地址转换成GPIO_TypeDef 类型的结构体指针,然后通过宏定义把GPIOA、GPIOB 等定义成外设的结构体指针,通过外设的结构体指针我们就可以达到访问外设的寄存器的目的。