其实不管用库函数法还是位操作,其本质都是操作STM32单片机的寄存器。那什么是寄存器呢?先来给寄存器下个定义
寄存器就是给特定的内存单元取一个别名,这个别名就是我们常说的寄存器。这里的重点是"内存单元",如下栗子
上图来自于STM32官方数据手册,左边是地址,右边是相对应的外设。而寄存器就是,给这些地址取的一个别名。那为什么要这么做?如果我要给GPIOB的端口全部输出1,不用寄存器,即直接对地址进行操作:
每次这么操作很麻烦有木有。如果使用寄存器就会方便很多。
说白了,就是将端口的地址用宏定义定义好了。我们直接使用宏定义后的名称就好。当然,对于地址的宏定义是不需要我们操作的,我们直接操作相关的寄存器就好了。在每个引脚里面,很多的寄存器,可以看到这些寄存器相对于基地址的偏移。以GPIOB为例。
明白了什么是寄存器,再来看看怎么通过寄存器点亮跑马灯。
1. 时钟使能
2. GPIO配置
3. 点亮
步骤和库函数法一样,不过操作内容有区别。
还是以PA8和PD2为例,时钟使能操作如下
RCC->APB2ENR|=1<<2; //使能GPIO.A时钟
RCC->APB2ENR|=1<<5; //使能GPIO.D时钟
怎么实现的?通过查阅芯片数据手册,我们可以看到GPIO的端口,都是挂载在APB2总线上的
APB2是由RCC时钟进行控制的,因此,我们要进行时钟使能,就是要配置其寄存器。还是查阅数据手册,可以看到RCC_APB2RSTR寄存器,这是16位寄存器
可以看到,我们需要配置的PA和PD分别位该寄存器的第2位和第5位
直接给其写入1即可。所以有了这一步。
RCC->APB2ENR|=1<<2; //使能GPIO.A时钟
RCC->APB2ENR|=1<<5; //使能GPIO.D时钟
接下来,配置GPIO相关的寄存器。GPIO的寄存器在上面有展示,
端口配置低寄存器(GPIOx_CRL) (x=A…E)
端口配置高寄存器(GPIOx_CRH) (x=A…E)
端口输入数据寄存器(GPIOx_IDR) (x=A…E)
端口输出数据寄存器(GPIOx_ODR) (x=A…E)
端口位设置/清除寄存器(GPIOx_BSRR) (x=A…E)
端口位清除寄存器(GPIOx_BRR) (x=A…E)
端口配置锁定寄存器(GPIOx_LCKR) (x=A…E)
我们需要使用的端口配置寄存器和端口输出寄存器。端口配置寄存器分为高8位CRH和低8位CRL,根据输出引脚而定。例如输出引脚是PA15,则用高八位寄存器CRH配置,同样,若输出引脚为PA2,则用低八位寄存器CRL配置。我们这里引脚为PA8和PD2,因此用高八位配置和低八位配置。以低八位PD2配置为例
1. 找准引脚口
2. 配置正确的输出模式、速度
上图的四位为一个引脚,该寄存器32位一共对应8个引脚。PD2为第三个引脚,因此为8、9、10、11位。配置PA8也参考此方法,不过是在CRH寄存器中。
CNFy[1:0]:用于配置输出模式。MODEy[1:0]:用于配置输出速度。
00:通用推挽输出模式
01:通用开漏输出模式
10:复用功能推挽输出模式
11:复用功能开漏输出模式
00:输入模式(复位后的状态)
01:输出模式,最大速度10MHz
10:输出模式,最大速度2MHz
11:输出模式,最大速度50MHz
选择输出模式为推挽输出模式,速度为50Mhz。因此配置为0011,16进制表示为03
GPIOD->CRL&= 0xFFFFF0FF; //PD2 第二位清零
GPIOD->CRL|= 0x00000300; //设置输出模式、输出速度。这两步就配置好了CRL
配置时需要先对寄存器数据与运算进行清零,然后进行或运算写入
端口配置好以后,再配置数据输出寄存器:
这是低16位寄存器,根据引脚直接写入1即可,简单粗暴
GPIOD->ODR|=1<<2; //ODR寄存器给PTD.2第二个口高位.
这样就配置好了关于PD2的寄存器,PA8同样是使用该寄存器写入数据。
GPIOA->ODR|=1<<8; //ODR是数据输出寄存器
GPIOD->ODR=~(1<<2); //取非运算
delay_ms(300);
GPIOD->ODR|=1<<2;
GPIOA->ODR=~(1<<8);
delay_ms(300);
通过取非运算,操作ODR寄存器,来控制灯的熄灭。