GD32F4xx系列入门——01_GPIO_Running_LED
前言
本文章将给大家解析官方库函数所给的第一章节——点亮LED灯,本质上就是GPIO的控制。
一、什么是GPIO
- GD32F4xx芯片最多可支持 140 个通用 I/O 引脚(GPIO),分别为 PA0 ~ PA15,PB0 ~ PB15,PC0 ~ PC15,
PD0 ~ PD15,PE0 ~ PE15,PF0 ~ PF15,PG0 ~ PG15,PH0 ~ PH15 和 PI0 ~ PI11,各片
上设备用其来实现逻辑输入/输出功能。每个 GPIO 端口有相关的控制和配置寄存器以满足特
定应用的需求。GPIO 引脚上的外部中断在中断/事件控制器(EXTI)中有相关的控制和配置寄
存器。 - GPIO 端口和其他的备用功能(AFs)共用引脚,在特定的封装下获得最大的灵活性。GPIO 引
脚通过配置相关的寄存器可以用作备用功能引脚,备用功能输入/输出都可以。
每个 GPIO 引脚可以由软件配置为输出(推挽或开漏)、输入、外设备用功能或者模拟模式。
每个 GPIO 引脚都可以配置为上拉、下拉或无上拉/下拉。除模拟模式外,所有的 GPIO 引脚都
具备大电流驱动能力。
二、GPIO模式
- GPIO 引脚可以配置为输入模式、输出模式和复用模式(AF)。
- 当 GPIO 引脚配置为输入引脚时:所有的 GPIO 引脚内部都有一个可选择的弱上拉和弱下拉电阻。外部引脚上的数据在每个 AHB 时钟周期时都会装载到数据输入寄存器(GPIOx_ISTAT)。
- 当 GPIO 引脚配置为输出引脚时:用户可以配置端口的输出速度和选择输出驱动模式:推挽或开漏模式。输出寄存器(GPIOx_OCTL)的值将会从相应 I/O 引脚上输出。
- 当端口配置为 AFIO(设置 GPIOx_CTL 寄存器中的 CTLy 值为“0b10”)时,该端口用作外设备用功能。通过配置 GPIO 备用功能选择寄存器(GPIOx_AFSELz(z=0,1)),每个端口可以配置 16 个备用功能。端口备用功能分配的详细介绍见芯片数据手册(后续使用时为你们介绍)。
三、此项目环境
- 软件:keil5;
- 版本:5.39;
- 电路板:官方GD32470I_EVAL_Demo_Suites
- 芯片:GD32F470xx(xx:依据不同的芯片去不同的芯片型号即可,我由于目前没有布置环境,见谅),见下图;
- 使用的库:官方库(可在官方库下载),你们依据官方库看此文章好哟;
- 目的:首先点亮一个LED灯,让你们体验一下单片机的魅力。
四、需要了解的库知识点
代码如下(示例):
//以下是需要了解的引脚工作模式
/* output mode definitions */
#define CTL_CLTR(regval) (BITS(0,1) & ((uint32_t)(regval) << 0))
#define GPIO_MODE_INPUT CTL_CLTR(0) /*输入模式*/
#define GPIO_MODE_OUTPUT CTL_CLTR(1) /*输出模式*/
#define GPIO_MODE_AF CTL_CLTR(2) /*复用模式*/
#define GPIO_MODE_ANALOG CTL_CLTR(3) /*模拟模式*/
//以下是引脚状态
/* pull-up/ pull-down definitions */
#define PUD_PUPD(regval) (BITS(0,1) & ((uint32_t)(regval) << 0))
#define GPIO_PUPD_NONE PUD_PUPD(0) /*浮空模式*/
#define GPIO_PUPD_PULLUP PUD_PUPD(1) /*上拉模式*/
#define GPIO_PUPD_PULLDOWN PUD_PUPD(2) /*下拉模式*/
//引脚输出类型
/* GPIO output type */
#define GPIO_OTYPE_PP ((uint8_t)(0x00U)) /*推挽模式*/
#define GPIO_OTYPE_OD ((uint8_t)(0x01U)) /*开漏模式*/
//引脚的驱动能力
/* GPIO output max speed value */
#define GPIO_OSPEED_2MHZ GPIO_OSPEED_LEVEL0 /*!< output max speed 2MHz */
#define GPIO_OSPEED_25MHZ GPIO_OSPEED_LEVEL1 /*!< output max speed 25MHz */
#define GPIO_OSPEED_50MHZ GPIO_OSPEED_LEVEL2 /*!< output max speed 50MHz */
#define GPIO_OSPEED_MAX GPIO_OSPEED_LEVEL3 /*!< GPIO very high output speed, max speed more than 50MHz */
/*!
\brief set GPIO mode
\param[in] gpio_periph: GPIO port
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,I)
\param[in] mode: GPIO pin mode
\arg GPIO_MODE_INPUT: input mode
\arg GPIO_MODE_OUTPUT: output mode
\arg GPIO_MODE_AF: alternate function mode
\arg GPIO_MODE_ANALOG: analog mode
\param[in] pull_up_down: GPIO pin with pull-up or pull-down resistor
\arg GPIO_PUPD_NONE: floating mode, no pull-up and pull-down resistors
\arg GPIO_PUPD_PULLUP: with pull-up resistor
\arg GPIO_PUPD_PULLDOWN:with pull-down resistor
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_mode_set(uint32_t gpio_periph, uint32_t mode, uint32_t pull_up_down, uint32_t pin)
{
uint16_t i;
uint32_t ctl, pupd;
ctl = GPIO_CTL(gpio_periph);
pupd = GPIO_PUD(gpio_periph);
for(i = 0U; i < 16U; i++) {
if((1U << i) & pin) {
/* clear the specified pin mode bits */
ctl &= ~GPIO_MODE_MASK(i);
/* set the specified pin mode bits */
ctl |= GPIO_MODE_SET(i, mode);
/* clear the specified pin pupd bits */
pupd &= ~GPIO_PUPD_MASK(i);
/* set the specified pin pupd bits */
pupd |= GPIO_PUPD_SET(i, pull_up_down);
}
}
GPIO_CTL(gpio_periph) = ctl;
GPIO_PUD(gpio_periph) = pupd;
}
/*!
\brief set GPIO output type and speed
\param[in] gpio_periph: GPIO port
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,I)
\param[in] otype: GPIO pin output mode
\arg GPIO_OTYPE_PP: push pull mode
\arg GPIO_OTYPE_OD: open drain mode
\param[in] speed: GPIO pin output max speed
\arg GPIO_OSPEED_2MHZ: output max speed 2MHz
\arg GPIO_OSPEED_25MHZ: output max speed 25MHz
\arg GPIO_OSPEED_50MHZ: output max speed 50MHz
\arg GPIO_OSPEED_MAX: output max speed more than 50MHz
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_output_options_set(uint32_t gpio_periph, uint8_t otype, uint32_t speed, uint32_t pin)
{
uint16_t i;
uint32_t ospeedr;
if(GPIO_OTYPE_OD == otype) {
GPIO_OMODE(gpio_periph) |= (uint32_t)pin;
} else {
GPIO_OMODE(gpio_periph) &= (uint32_t)(~pin);
}
/* get the specified pin output speed bits value */
ospeedr = GPIO_OSPD(gpio_periph);
for(i = 0U; i < 16U; i++) {
if((1U << i) & pin) {
/* clear the specified pin output speed bits */
ospeedr &= ~GPIO_OSPEED_MASK(i);
/* set the specified pin output speed bits */
ospeedr |= GPIO_OSPEED_SET(i, speed);
}
}
GPIO_OSPD(gpio_periph) = ospeedr;
}
/*!
\brief reset GPIO pin bit
\param[in] gpio_periph: GPIO port
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,I)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_bit_reset(uint32_t gpio_periph, uint32_t pin)
{
GPIO_BC(gpio_periph) = (uint32_t)pin;
}
/*!
\brief set GPIO pin bit
\param[in] gpio_periph: GPIO port
only one parameter can be selected which is shown as below:
\arg GPIOx(x = A,B,C,D,E,F,G,H,I)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_bit_set(uint32_t gpio_periph, uint32_t pin)
{
GPIO_BOP(gpio_periph) = (uint32_t)pin;
}
五、上正文(main函数)
代码如下(示例):
//一句话概括:使用代码控制GPIO引脚来拉高和拉低电频来实现灯的亮和暗
int main(void)
{
//首先使能时钟,所用的外设能使用,是依据芯片内部有一个时钟来工作,后续会详解
systick_config();
//使能引脚时钟,你查看的电路图,使用的LED接通到哪一个引脚上,你就使能哪一个时钟,
//此官方板上有三个LED灯,分别在PE2、PE3和PF10上所以使能这两个引脚时钟即可。
//只用使能一次即可。
rcu_periph_clock_enable(RCU_GPIOE);
rcu_periph_clock_enable(RCU_GPIOF);
//初始化引脚,使用输出模式,初始化时将引脚配置为浮空模式即可,依据引脚输入正确的PIN脚即可
gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_2);
//设置输出模式为推挽输出,驱动能力就默认即可,这个参数不重要
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_2);
//将引脚复位(此时LED灯不会亮)
gpio_bit_reset(GPIOE, GPIO_PIN_2);
/* enable the LED2 GPIO clock */
/* configure LED2 GPIO port */
gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_3);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_3);
/* reset LED2 GPIO pin */
gpio_bit_reset(GPIOE, GPIO_PIN_3);
/* enable the LED3 GPIO clock */
/* configure LED3 GPIO port */
gpio_mode_set(GPIOF, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_10);
gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
/* reset LED3 GPIO pin */
gpio_bit_reset(GPIOF, GPIO_PIN_10);
while(1) {
gpio_bit_set(GPIOF, GPIO_PIN_10); //上拉PF10引脚电频,LED3会点亮
gpio_bit_set(GPIOE, GPIO_PIN_2); //上拉PE2引脚电频,LED1会点亮
gpio_bit_reset(GPIOF, GPIO_PIN_10); //下拉PE3引脚点评,LED2会点暗
delay_1ms(1000); //延时函数,单位是毫秒,后续会讲解其工作原理,此处参数写1000,就是延时1S
gpio_bit_set(GPIOE, GPIO_PIN_3); //上拉PE3引脚电频,LED2会点亮
gpio_bit_reset(GPIOE, GPIO_PIN_2); //下拉PE2引脚电频,LED1会点暗
delay_1ms(1000);
gpio_bit_set(GPIOF, GPIO_PIN_10); //上拉PF10引脚电频,LED3会点亮
gpio_bit_reset(GPIOE, GPIO_PIN_3); //下拉PE3引脚电频,LED2会点暗
delay_1ms(1000);
}
}
六、说点题外话
- 可以学会了,制作好看的灯带,原理就是我上面写的内容,很简单。
- 可能会有人会问,外面使用的灯会慢慢的变量和变暗,那就是呼吸灯罢了,其实原理是一样的,只不过使用了更多的外设(TIMER外设),控制了变量和变暗的时间,来迷惑了我们的眼睛。后续我会讲解。
- 有什么问题可以私信,不玻璃心。
总结
以上就是今天要讲的内容,本文仅仅简单介绍了LED的使用。但是可以控制千变万化的不同颜色和不同数量的灯。