寄存器结构体定义
头文件
当我们完成了第一个试验后,或许会发现在头文件的部分,如果我们只用到一个端口,定义的量还尚可,但如果当我们有多个端口需要定义时,那我们就需要重复上面的所有定义再改去端口名,这样会比较麻烦且程序看着过于冗余,因此,我们可以用到结构体。
结构体的一般表达式为:
struct
{
成员表名;
}变量表名;
结构体在我的理解当中就类似于一个数组,与数组不同的是,结构体中的元素可以是我们自定义的不同类型的变量,更确切地来说,结构体就像是个大集合,这个集合中能够包含我们想要的任何元素。
因此,按此思路,我们就能将I/O口所有的寄存器用结构体包含起来,如下所示:
typedef struct
{
unsigned int MODER;
unsigned int OTYPER;
unsigned int OSPEEDER;
unsigned int PUPDR;
unsigned int IDR;
unsigned int ODR;
unsigned short BSRRL;
unsigned short BSRRH;
unsigned int LCKR;
unsigned int AFRL;
unsigned int AFRH;
}GPIO_TypeDef;
这段代码包含了两步操作:
- 定义了一个结构体,其中包含了所有的寄存器名。
- 将本结构体去一个新的变量名为GPIO_TypeDef。(变量名可任取,不要与关键字重就行)
这样,结构体就定义完成了。但光有结构体还不够我们还需要将其对应到相应的地址。由之前可得GPIOH的首地址为0x40021C00,因此我们需要一条强制类型转换语句将这个结构体指向对应的地址
#define GPIOH ((GPIO_TypeDef*)0x40021C00)
这句语句就将GPIO_TypeDef这个结构体指向了GPIOH的基地址并将其定义给GPIOH端口,结构体中的各个元素就按照其顺序以及字长逐次排列。按此方法,如果我们以后用到其他的端口,我们只需要更改最后指针指向的基地址就行避免了重复定义。至此我们就完成了头文件的编写接下来就是主程序。
main.c
依旧是闪灯程序,但不同的是,一般我们读取一个结构体的内容时,我们只需要使用变量名.成员名即可,但当我们用一个指针变量去指向结构体成员时,我们就需要用到指向运算符,如下所示:
->
具体代码如下:
GPIOH->MODER &= ~(3<<(2*10));
GPIOH->MODER |= (1<<(2*10));
GPIOH->ODR |=(1<<10);
- 首先将我们需要操纵的位清零。(为了防止寄存器原有的数值的干扰,最好清空一下)
- 将其写入01为输出模式。
- 因为是共阳极链接,所以全部置一使其关闭(虽然调试的时候依旧会亮一下)
到此为止,输出口就已经配置好了,只需要将10号位置零就可以使小灯亮起。不过既然我们已经掌握了如何点亮小灯且这个小灯是个RGB小灯,相当于是红绿蓝三个小灯,那我们是否就能将其改写成三种颜色交替闪烁的效果呢。
由前一次实验可知,小灯的3个引脚分别为:
- PH10 红色
- PH11 绿色
- PH12 蓝色
因此我们只需要配置完引脚就能使其闪烁,但我们需要注意的是,当我们点亮后一定记得将其关闭,否则这几种颜色就会混杂在一起,达不到预期效果。具体代码如下所示:
void delay(unsigned int in)
{
for(;in!=0;in--);
}
int main(void)
{
RCC |= (1<<7);
GPIOH->MODER &= ~(3<<(2*10));
GPIOH->MODER |= (1<<(2*10));
GPIOH->ODR |=(1<<10);
GPIOH->MODER &= ~(3<<(2*11));
GPIOH->MODER |= (1<<(2*11));
GPIOH->ODR |=(1<<11);
GPIOH->MODER &= ~(3<<(2*12));
GPIOH->MODER |= (1<<(2*12));
GPIOH->ODR |=(1<<12);
GPIOH->ODR &=~(1<<10);
delay(0xefffff);
GPIOH->ODR |=(1<<10);
delay(0xefffff);
while(1)
{
GPIOH->ODR &=~(1<<10);
delay(0xeffff);
GPIOH->ODR |= (1<<10);
GPIOH->ODR &=~(1<<11);
delay(0xeffff);
GPIOH->ODR |= (1<<11);
GPIOH->ODR &=~(1<<12);
delay(0xeffff);
GPIOH->ODR |= (1<<12);
}
}
void SystemInit(void)
{
}