本实验仅点亮LED1
一:分析芯片手册:
LED灯原理
1)首先确定LED1引脚
由此可知,LED1对应的引脚为PE10
2)分析引脚寄存器(GPIOE)所在总线
查手册可知,其为AHB4总线
3)分析RCC寄存器章节
找到RCC章节对应的AHB4总线使能部分
设置GPIOE时钟使能
易得,GPIOE使能即为把寄存器第四位置 1 :RCC_MP_AHB4ENSETR[4] = 1
4)分析GPIO章节
点亮LED灯,我们需要把PE10引脚设置为:输出模式、推挽输出模式、低速模式、引脚禁止上下拉
1.GPIO_MODER寄存器,设置为输出模式 ![](https://i-blog.csdnimg.cn/blog_migrate/1a7333a7b15de4fa2a07520f36fda185.png)
即,把GPIOE_MODER寄存器21、20位置为‘01’ :GPOIE_MODER[21:20] = 01
2.GPIOE_OTYPER寄存器,设置推挽输出模式 ![](https://i-blog.csdnimg.cn/blog_migrate/699a79a482b3f4ff4a9b6c0fd9d41057.png)
即:GPIOE_OTYPER[10] = 0
3.GPIOE_OSPEEDR寄存器,设置引脚为低速模式 ![](https://i-blog.csdnimg.cn/blog_migrate/bf2a1fea85cc90a744e7b637a95fd22b.png)
即:GPIOE_OSPEEDR[21:20] = 00
4.GPIOE_PUPDR寄存器,设置禁止上下拉 ![](https://i-blog.csdnimg.cn/blog_migrate/bd3d6f9ef2df58d740d9307c54cffdfb.png)
即:GPIOE_PUPDR[21:20] = 00
至此,引脚模式设置完毕
5.GPIOE_ODR寄存器,设置灯的亮灭,1为亮,0为灭
二:代码实现
头文件:gpio.h
因为是第一次实现(虽然对我来说不是第一次了),所以模拟没有对应头文件的情况,由我自己封装GPIO、RCC寄存器的宏定义以及结构体
首先要确定的是,这几个寄存器的地址:
查阅芯片手册
RCC:
RCC_AHB4_ENSETR地址为 0x50000A28 (根据芯片手册知,地址偏移为A28,起始地址为0x50000000)(这个具体参看前面的RCC章节分析,那个Address offset,就是地址的偏移量)
直接进行宏定义
//1.RCC寄存器封装,用宏定义进行封装
#define RCC_AHB4_ENSETR (*(volatile unsigned int*)0x50000A28)
GPIO:
由芯片手册可知,AHB4总线的GPIOE的起始地址为:0x50006000,每个功能寄存器(这个具体参看前面的GPIO章节分析,那个Address offset,就是地址的偏移量)的地址偏移量为4,所以,可以把功能寄存器封装为一个结构体,定义为unsigned int类型,要注意,虽然GPIOx_IDR我们并没有使用到,但是因为它在PUPDR和ODR之间,所以要在结构体内加上
//2.GPIO寄存器进行封装,用结构体
typedef struct
{
volatile unsigned int MODER; //00 ---->地址偏移量
volatile unsigned int OTYPER; //04
volatile unsigned int OSPEEDR; //08
volatile unsigned int PUPDR; //0c
volatile unsigned int IDR; //10
volatile unsigned int ODR; //14
}gpio_t;
再将GPIOE宏定义为 gpio_t * 类型的变量,起始地址设定为0x50006000,这样一来,就可以用结构体指针调用的方式来使用
#define GPIOE ((gpio_t*)0x50006000)
最后是三个函数:初始化、开灯、关灯
//3.LED1灯初始化
void LED1_init();
//4.LED1灯点亮
void LED_ON();
//5.LED1灯熄灭
void LED_OFF();
功能函数文件:gpio.c
把分析芯片手册的到的结果具象化
//1..LED1灯初始化PE10
void LED1_init()
{
//0.设置GPIOE时钟使能
RCC_AHB4_ENSETR |= (1 << 4);
//1.设置PE10引脚为输出模式,01
GPIOE->MODER &= ~(0x3 << 20); //把21、20位先全部置0,就可以用 |= 直接赋值
GPIOE->MODER |= (0x1 << 20);
//2.设置PE10引脚为推挽输出,0
GPIOE->OTYPER &= ~(0x1 << 10);
//3.设置PE10引脚为低速模式,00
GPIOE->OSPEEDR &= ~(0x3 << 20);
//4.设置PE10引脚禁止上下拉,00
GPIOE->PUPDR &= ~(0x3 << 20);
}
开灯关灯:
//2..LED1点亮
void LED_ON()
{
//1.设置PE10引脚输出高电平
GPIOE->ODR |= (1 << 10);
}
//3..LED1熄灭
void LED_OFF()
{
//1.设置PE10引脚输出低电平
GPIOE->ODR &= ~(1 << 10);
}
在主函数中编写延时函数,即可实现LED灯的闪烁
int main()
{
LED1_init();
while(1)
{
LED_ON();
delay_ms(500); //500毫秒延时,这个就由读者自己写了
LED_OFF();
delay_ms(500);
}
}
附上头文件与功能函数的完整代码
头文件:
#ifndef __GPIO_H__
#define __GPIO_H__
//1.RCC寄存器封装,用宏定义进行封装
#define RCC_AHB4_ENSETR (*(volatile unsigned int*)0x50000A28)
//2.GPIO寄存器进行封装,用结构体
typedef struct
{
volatile unsigned int MODER; //00
volatile unsigned int OTYPER; //04
volatile unsigned int OSPEEDR; //08
volatile unsigned int PUPDR; //0c
volatile unsigned int IDR; //10
volatile unsigned int ODR; //14
}gpio_t;
#define GPIOE ((gpio_t*)0x50006000)
//3.LED1灯初始化
void LED1_init();
//4.LED1灯点亮
void LED_ON();
//5.LED1灯熄灭
void LED_OFF();
#endif
功能函数:
#include "gpio.h"
//1..LED1灯初始化PE10
void LED1_init()
{
//0.设置GPIOE时钟使能
RCC_AHB4_ENSETR |= (1 << 4);
//1.设置PE10引脚为输出模式,01
GPIOE->MODER &= ~(0x3 << 20); //把21、20位先全部置0,就可以用 |= 直接赋值
GPIOE->MODER |= (0x1 << 20);
//2.设置PE10引脚为推挽输出,0
GPIOE->OTYPER &= ~(0x1 << 10);
//3.设置PE10引脚为低速模式,00
GPIOE->OSPEEDR &= ~(0x3 << 20);
//4.设置PE10引脚禁止上下拉,00
GPIOE->PUPDR &= ~(0x3 << 20);
}
//2..LED1点亮
void LED_ON()
{
//1.设置PE10引脚输出高电平
GPIOE->ODR |= (1 << 10);
}
//3..LED1熄灭
void LED_OFF()
{
//1.设置PE10引脚输出低电平
GPIOE->ODR &= ~(1 << 10);
}