【单片机/嵌入式】【梁山派】学习日志04:寄存器点灯

一、寄存器点亮LED

1.1配置流程

一般我们使用GPIO的端口,都需要有以下几个步骤。

1)开启GPIO端口时钟

2)配置GPIO模式

3)配置GPIO输出

LED介绍那一章节我们了解到LED1接的是单片机的PE3LED2接的是单片机的PD7LED3接的是单片机的PG3LED4接的是单片机的PA5。我们要使能LED就需要配置GPIOA端口,GPIOD端口,GPIOE端口和GPIOG端口。下面我们就以LED2接的PD7进行介绍,其它也是类似的。

1.1.1开启GPIO的端口时钟

GD32的所有外设资源时钟默认都是关闭的,在配置外设之前需要先开启对应的时钟。

要使能LED2,就要先开启GPIOD的时钟,从用户手册的第38页我们了解到GPIOD挂载在AHB1总线上,那操作GPIOD的时钟肯定要配置AHB1使能寄存器。

GPIOD 基地址:0x4002 0C00

AHB1-GPIOD地址范围:0x4002 0C00 - 0x4002 0FFF

地址偏移量为0x30,那这个基地址是多少呢?因为AHB1使能寄存器是在RCU外设的地址范围内,所以RCU的外设基地址就是AHB1使能寄存器的基地址,在用户手册的第96页有明确说明,RCU基地址:0x4002 3800

那我们RCU_AHB1EN寄存器的地址就是基地址加上偏移量,0x4002 3800 + 0x30 = 0x4002 3830

找到要操作的地址了,那我们怎么去配置这个值呢?我们继续看这个寄存器的说明,在用户手册的第116页有寄存器说明,如下

RCU_AHB1EN寄存器的3就是GPIOD端口时钟使能,我们要开启GPIOD端口时钟使能,就需要RCU_AHB1EN的第3位写1,然后为了保持其他位不变,我们可以使用一个或运算,也就是 RCU_AHB1EN |= 0x00000008 也就是相当于拉高RCU_AHB1EN寄存器的第3位,其他位保持不变。其实也可以写为 RCU_AHB1EN |=(1 << 3); 是一样的效果,这里的3就是寄存器的第3位,如果是4就是寄存器的第4位,依次类推。

1.1.2配置GPIO模式

GPIO的模式配置可分为两步,第一步就是通过控制寄存器(GPIOx_CTL)配置功能,输入功能、输出功能、复用功能还是模拟功能。第二步就是通过GPIO /下拉寄存器(GPIOx_PUD)配置GPIO的上下拉模式或者浮空

配置为输出功能

我们要使能LED,自然是配置GPIO为输出模式,找到控制寄存器(GPIOx_CTL),如下图所示。

可以看到GPIOX_CTL的地址偏移是0x00,我们要使能的是GPIOD的引脚,所以要加上GPIOD的基地址0x4002 0C00,即GPIOD_CTL寄存器的地址为0x4002 0C00 + 0x00。我们接着看这个寄存器的介绍说明,如下图所示。

可以看到每一个引脚都由2位控制,我们要操作的是PD7引脚,也就是pin7,也就是GPIOD_CTL寄存器的15位和第14。我们要配置为输出模式,也就是把这两位配置为01,我们用二进制来表示一下,0000 0000 0000 0000 0100 0000 0000 0000 ,转换成十六进制就是0x00004000。所以我们GPIOD_CTL寄存器里面写入0x00004000,就是把PD7这个引脚配置为了输出模式为了保持其它位的数据不发生变化,我们先清空这两位,然后再往这两位里面写值。操作为:

 GPIOD_CTL &= 0xffff3fff; 这句代码是清空第15位和第14

 GPIOD_CTL |= 0x00004000; 这句代码就是把第15位和第14位配置为01。

这样操作保证了其它位不发生变化

其实也可以这样配置

 GPIOD_CTL &= ~(0x03 << (2*7)); 

这句代码就是把GPIOD_CTL寄存器的第15位和第14清零

 GPIOD_CTL |= (0x01 << (2*7)); //因为一个引脚需要2位,故要修改pin7则用2*7作为左移值的书写方式,更便于直观理解 

这句代码就是把第15位和第14配置01。这里的7就是pin7,如果是pin6的话就配置为6即可。

配置为浮空模式,无上拉下拉

一般输出模式我们都配置为浮空模式输入模式我们才需要考虑上拉还是下拉,根据默认电平状态进行判断

第一步配置好为输出模式之后,我们还需要进行第二步配置,配置PD7为浮空模式无上拉和下拉。关于端口上下拉寄存器如下图所示。

可以看到端口上下拉寄存器的地址偏移是0x0C,GPIOD_PUD的地址就是0x4002 0C00 + 0x0C我们接着往下看这个寄存器的介绍,如图1-2-4所示。

可以看到,每一个引脚都由2位进行控制,和GPIOD_CTL寄存器的配置一样,也是先清空这两位,然后再配置这两位为00。转化为下面这两句代码。

GPIOD_PUD &= ~(0x03 << (2*7));

GPIOD_PUD |= (0x00 << (2*7)); 

其实我们发现,第二句代码其实不用写,因为第一句就把这两位清零了。

1.1.3配置GPIO的输出

配置GPIO的输出也分为两步:

第一步配置端口输出模式寄存器GPIOx_OMODE

第二步配置端口速度寄存器GPIOx_OSPD

配置为推挽输出

当我们配置为输出模式的时候,可以有两种输出模式选择,一种是推挽输出模式,一种是开漏输出模式。

推挽输出 可以输出高低电平,推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止

开漏输出 输出端相当于三极管的集电极要得到高电平状态需要上拉电阻才行,适合做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。开漏输出可以很方便的调节输出的电平,因为输出电平完全是由上拉电阻连接的电源电平决定。开漏输出可以实现“线与”功能,就是可以把多个信号线连接在一起,只有当所有信号全部为高电平时,合在一起的总线为高电平,否则就为低电平

由于开漏需要外接上拉电阻才可以输出高电平,这里并不适合,所以需要设置为推挽输出。

端口输出模式寄存器如下图所示。

可以看到端口输出模式寄存器的地址偏移为0x04,那GPIOD_OMODE寄存器的地址就是0x4002 0C00 + 0x04。我们接着往下看这个寄存器的介绍,如图1-3-2所示。

 

可以看到每一个引脚由1位进行控制,要配置为推挽输出,只需要往对应的寄存器写0即可。转化为代码为GPIOD_OMODE &= ~(0x01 << 7); 

配置速度

我们配置引脚输出模式之后,我们还要选择这个引脚对应的速度,端口输出速度寄存器如下图所示。

可以看到端口输出速度寄存器的地址偏移是0x08,那么GPIOD_OSPD寄存器的地址就是0x4002 0C00 + 0x08。我们接着往下看这个寄存器的介绍,如下图所示。

可以看出每一个引脚由2位进行控制,要配置为多少等级,只需要往对应的位写入对应的值即可。从官方提供的代码中查找到了速度等级对应的频率关系,如下所示。

/* 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 */

我们这里选择配置为50MHZ,所以需要配置为等级2,需要往对应的位写入10。转化为代码就是

GPIOD_OSPD &= ~(0x03 << (2 * 7));

GPIOD_OSPD |= (0x02 << (2 * 7)); 

通过这两句我们就可以把PD7引脚的速度配置为50MHZ

到此,我们关于GPIO的配置就完成了。

1.2配置GPIO输出高电平

配置好GPIO之后,我们就可以进行点灯了。其实也就是GPIO引脚输出高低电平,到我们的开发板上就是PD7输出高电平

如何让PD7输出高电平呢?通过查阅用户手册7.4章节的GPIO寄存器,这里为大家总结了几种操作的方式。

1.2.1端口输出控制寄存器

可以看到端口输出控制寄存器的地址偏移为0x14,那么对应的GPIOD_OCTL寄存器的地址为0x4002 0C00 + 0x14

GPIOD_OCTL寄存器的16位有效,每一个引脚对应一位,往对应的位写0就是输出低电平,写1就输出高电平。

输出低电平转换为代码为GPIOD_OCTL &= ~ (0x01 << 7);

输出高电平转换为代码为GPIOD_OCTL |=  (0x01 << 7);

1.2.2端口位操作寄存器

端口输出控制寄存器的地址偏移为0x18,那么对应的GPIOD_BOP寄存器的地址为0x4002 0C00 + 0x18

GPIOD_BOP寄存器的16位是置116位是清0。对于16位每一个引脚对应一位,往对应的位写1就是输出高电平,写0电平状态不改变对于高16位每一个引脚对应一位,往对应的位写1就是输出低电平,写0电平状态不改变

输出低电平转换为代码为GPIOD_BOP |= (0x01 << (7 + 16));//由于共有16pin,所以7+16=23

输出高电平转换为代码为GPIOD_BOP |= (0x01 << 7);

1.2.3端口位翻转寄存器

使用端口位翻转寄存器也有类似的功能,从名称就可以知道这个寄存器是把对应的位电平进行翻转,这是一个很不错的操作,使用起来也很方便。但前提是我们要知道当下的引脚电平是一个什么状态,然后我们翻转之后又是一个什么状态。

1.3实验

如果用上面的代码需要注意一下,像RCU_BASE这种宏定义其实在GD32的头文件中已经定义了,可以直接使用原来定义的,这样我们就不用再编写,也可以把我们编写的名称稍微修改一下,比如在它们前面加上一个LED或者BSP等等都可。

1.3.1编写工程

具体操作如下:

首先,需要将LED硬件库添加到我们的模板工程目录,即Template\Hardware\led

 

在工程中添加.c文件

 

添加头文件路径

 

编译一次,可看到bsp_led.c文件包含(找到)了很多头文件

 

1.3.2编写代码

主函数如下

#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "bsp_led.h" //添加小灯头文件
int i;
int main(void)
{
    systick_config();    // 滴答定时器初始化
    led_gpio_config();  // led初始化

    while(1) {
        BSP_GPIOD_OCTL|= (0x01 << 7);     // 端口输出控制寄存器        
        delay_1ms (1000);
        for(i=0;i<5;i++){
            delay_1ms(200);
            BSP_GPIOD_TG  |= (0x01 << 7);        // 端口位翻转寄存器         
        }
        delay_1ms(1000);
        BSP_GPIOD_BOP |= (0x01 << 7);        // 端口位操作寄存器
        delay_1ms(1000);
        BSP_GPIOD_BOP |= (0x01 << (7+16));        // 端口位操作寄存器
        delay_1ms(1000);
    }
}

bsp_led.h如下

#ifndef _BSP_LED_H
#define _BSP_LED_H

#include "gd32f4xx.h" #include "systick.h" #define BSP_RCU_BASE (unsigned int)0x40023800U // RCU寄存器的基地址 #define BSP_RCU_AHB1EN *(unsigned int*)(BSP_RCU_BASE + 0x30U) // AHB1使能寄存器地址 #define BSP_GPIOD_BASE (unsigned int)0x40020C00U // GPIOD的基地址 #define BSP_GPIOD_CTL *(unsigned int*)(BSP_GPIOD_BASE + 0x00U) // GPIOD控制寄存器的地址 #define BSP_GPIOD_PUD *(unsigned int*)(BSP_GPIOD_BASE + 0x0CU) // GPIOD的上下拉寄存器的地址 #define BSP_GPIOD_OMODE *(unsigned int*)(BSP_GPIOD_BASE + 0x04U) // GPIOD的输出模式寄存器的地址 #define BSP_GPIOD_OSPD *(unsigned int*)(BSP_GPIOD_BASE + 0x08U) // GPIOD的速度寄存器的地址 #define BSP_GPIOD_OCTL *(unsigned int*)(BSP_GPIOD_BASE + 0x14U) // GPIOD的输出控制寄存器的地址 #define BSP_GPIOD_BOP *(unsigned int*)(BSP_GPIOD_BASE + 0x18U) // GPIOD的位操作寄存器的地址 #define BSP_GPIOD_TG *(unsigned int*)(BSP_GPIOD_BASE + 0x2CU) // GPIOD的位翻转寄存器的地址 void led_gpio_config(void); // led gpio引脚配置 #endif /* BSP_LED_H */

1.3.3代码烧录

电脑与开发板的连接

 

由于我的Keil版本老旧,故无法识别CMSIS-DAP v2,可更新免费的社区版或者采用官方的串口下载助手,或者用立创EDA的网上烧录。这里采用官方烧录串口下载助手。

前往官网下载串口下载调试工具:GigaDevice MCU ISP Programmer

 

【官网下载】https://www.gd32mcu.com/cn/download?kw=ISP+Programmer&lan=cn

下载后解压,打开文件夹

此时点击Next,然后迅速持续按住BOOT0,同时再按一下RESET,烧录完成后再按一次RESET

 

如果没进入ISP模式会报错要求检查

见到如下界面即成功进入ISP模式

 

 

 

下载完成后,一定要再按一次RESET,开发板的程序才会开始运行。

1.3.4实验现象

LED灯按照主程序中的延迟亮灭。

 

 

 

 

 

// LED2输出高电平
posted @ 2022-11-04 12:13  U羊U  阅读(562)  评论(0编辑  收藏  举报