寄存器点灯
当我们学习完51单片机之后,我们知道如果要使用51点亮LED,我们只需将相应的端口写0或1即可:如P1口接了八个led,如果我们想让前7个被点亮,我们只需要将P1赋值0x7F即可(假设这八个共地),但单片机是如何识别P1到底是哪个端口的呢?这些全都在程序首句引用的头文件中包含了。 同理对于32来说也是相同的操作。
首先我们应当找到开发板LED所对应的引脚号,如图所示:
虽然这是个RGB_LED,但如果我们直接通其中某一个引脚,也能当作一个普通的LED使用,若想让他只显示红色,从原理图可见我们只需要将PH10置零即输出低电平即可。此处的H就代表GPIOH,他所代表的基地址为:
由于我们想让他作为输出,所以需要用到数据输出寄存器:GPIOx_ODR,他的偏移量为:
个人理解为其实他就是I\O口,只是将他划分为了输入与输出寄存器:ODR与IDR,且需要与MODER寄存器相互配合使用,否则他不会输出,就相当于是在MODER中选择好了模式后才会使能ODR寄存器使其工作。(由于我也刚学,如果有理解的差,请及时指正)
此外,MODER寄存器每两位控制一个输入输出,共能表示四种输入输出模式,如图所示,由于我们想让PH10输出低电平,那么相应的我们选择输出模式即01并赋值到相应位置20,21位。
接着是端口的输出类型,因为其复位值为0x0000 0000所以,已经是推挽输出,感觉定不定义似乎都不太要紧,而且对于普通的LED来说仅需几个毫安就能点亮,并且后续实验不对其定义也能正常输出。
最后就是与51最不相同的地方就是时钟,对于51来说,他都使用同一个时钟,因此不需要额外设置,但对于32,当他复位后默认外部时钟是关闭的,如果没有这相应的时钟我们就不能控制相应的引脚输入输出。所以我们需要找到RCC使能寄存器给相应的端口时钟信号。RCC的基地址与时钟外设分别为:
至此,点灯所需要用到的各种寄存器都已罗列出来下面就开始编写程序,同51一样新建工程,但不同的是,32需要我们加入官方固件库:.s文件。在做完这些后回想51单片机,程序首句为#include reg51.h
,所以我们也要相应的引入头文件。头文件就是用来存放各种宏定义的文件,因为单片机不知道什么是RCC,他只知道各个地址,所以,我们需要在头文件中完成上述寄存器的映射即可(基地址+偏移量=寄存器地址)。
具体代码如下
#define GPIOH_ODR *(unsigned int *)(0x40021C00+0x14) /*数据输出寄存器*/
#define GPIOH_MODER *(unsigned int *)(0x40021C00) /*模式选择寄存器*/
#define RCC *(unsigned int *)(0x40023800+0x30)
//外部RCC复位后初始状态是关闭的,为了节能,所以我们要打开
至此我们完成了寄存器的映射,就能开始写程序了,在这里,为了防止应为移位而导致的不期望的位数发生数值的变换,我们将会用到如下方法:
#include "stm32f4xx.h"
int main(void)
{
RCC |= (1<<7); /*外设时钟使能*/
GPIOH_MODER |= (1<<(2*10)); /*PH10为输出*/
GPIOH_ODR &=~(1<<10); /*低电平输出*/
while(1);
}
void SystemInit(void) /*要写,但还没理解为什么*/
{
}
这段程序引用他可能会报错,但似乎并不影响程序的正常运行。
当然如果想让他一闪一闪,我们还可以加上一个延时函数让他一亮一灭。
到这里程序似乎很完美的得到我们与想得到的结果,但如果我们分步运行,就会发现其中一点小问题:程序还未执行到输出低电平就亮灯了,那这是为什么呢。这得益于他的复位电路,上电后立即复位,端口输出为0,所以当程序执行到模式选择为输出后,其管脚为低电平,所以会点亮。