一、查看原理图:
由图可知,该开发板的
LED0
和LED1
分别接PA8
和PD2
,且欲点亮LED0
和LED1
,需要让PA8
和PD2
输出低电平
二、查看参考手册:
1、外设时钟使能:
由以上信息可知:
RCC
寄存器的起始地址为0x40021000
,APB2 外设时钟使能寄存器RCC_APB2ENR
的偏移地址为0x18
,即绝对地址为 0x40021000+0x18=0x40021018
,把RCC_APB2ENR
寄存器的bit5
和bit2
置1
即可使能GPIOA
和GPIOD
的时钟
2、端口配置:
由以上信息可知:
GPIOA
寄存器和GPIOD
寄存器的起始地址分别为0x40010800
和0x40011400
,端口配置高寄存器GPIOx_CRH
的偏移地址为0x04
,端口配置低寄存器GPIOx_CRL
的偏移地址为0x00
,所以PA8
口:应配置地址0x40010804
的bit3~0
为0001
,PD2
口:应配置地址0x40011400
的bit11~8
为0001
(此处我们配置通用推挽输出模式
和输出模式,最大速度10MHZ
)
3、端口输出:
GPIOA
寄存器和GPIOD
寄存器的起始地址分别为0x40010800
和0x40011400
,端口输出数据寄存器GPIOx_ODR
的地址偏移为0x0C
,所以PA8
口:应配置地址0x4001080C
的bit8
置0
,PD2
口:应配置地址0x4001140C
的bit2
置0
三、参考程序:
!!逐步优化代码,不断接近库函数,从而实现 “寄存器版本” 向 “库函数版本” 的转变
1、直接操作寄存器:
void LED0_Init(void);
void LED1_Init(void);
int main(void)
{
LED0_Init();
LED1_Init();
*(unsigned int *)0x4001080C &= ~(1<<8); // PA8输出低电平
*(unsigned int *)0x4001140C &= ~(1<<2); // PD2输出低电平
}
void LED0_Init(void)
{
*(unsigned int *)0x40021018 |= (1<<2); // 开启GPIOA时钟
*(unsigned int *)0x40010804 &= ~((0x0f)<<(4*0)); // 配置 PA8
*(unsigned int *)0x40010804 |= ((1)<<(4*0));
}
void LED1_Init(void)
{
*(unsigned int *)0x40021018 |= (1<<5); // 开启GPIOD时钟
*(unsigned int *)0x40011400 &= ~((0x0f)<<(4*2)); // 配置PD2
*(unsigned int *)0x40011400 |= ((1)<<(4*2));
}
2、寄存器映射:
#define PERIPH_BASE ((unsigned int)0x40000000)
#define APB1PERIPH_BASE (PERIPH_BASE)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
#define GPIOA_BASE (APB2PERIPH_BASE + 0x800)
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
#define RCC_APB2ENR *(unsigned int *)(RCC_BASE + 0x18)
#define GPIOA_CRH *(unsigned int