2. GPIO 使用
本节介绍
📝本节您将了解 GPIO 的概念,并且了解开发板的 LED 和按键的硬件电路,学习如何使用图形化代码生成工具,通过开发板上的按键,让开发板上的LED灯进行变色。
🏆本章⽬标
1️⃣了解GPIO的概念。
2️⃣了解主控 F28P550 的 GPIO 硬件特性。
3️⃣了解开发板上的 LED 和按键的硬件电路。
4️⃣通过GPIO的输入输出,使用按键控制LED灯变色。
GPIO 的基本概念
什么是 GPIO
GPIO,全称为 「General-Purpose Input/Output」,即通用输入/输出端口
。
它是微控制器、微处理器和某些其他集成电路上的一个引脚
,可以由软件控制其输入或输出状态。
GPIO 为开发者提供了一种简单、灵活的方式来控制硬件设备或与外部设备进行通信。
GPIO 的输入\输出
GPIO 输入模式
当 GPIO 引脚被配置为输入模式
时,它可以读取外部信号的状态,通常是高电平或低电平。 这种模式常用于以下场景:
- 读取开关/按钮状态:例如,检测一个按钮是否被按下。
- 接收信号:从其他设备(如传感器、其他微控制器)接收数字信号。
- 中断触发:配置为输入的 GPIO 引脚可以用于触发中断,响应外部事件。
在输入模式下,GPIO 引脚通常具有
高阻态
,以防止对连接的设备造成影响。
GPIO 输出模式
当 GPIO引 脚被配置为输出模式时,它可以输出高电平或低电平,用于控制外部设备。 这种模式常用于以下场景:
- 驱动LED:通过输出高电平或低电平来控制LED的亮灭。
- 控制继电器:通过输出信号来控制继电器的开关。
- 通信:在诸如I2C、SPI等通信协议中,GPIO引脚用于输出时钟信号或数据。
在输出模式下,GPIO 引脚可以提供一定的驱动能力,以驱动外部负载。
高电平与低电平
高电平
与低电平
是数字电路中的基本概念,用于表示电路中的两种不同的电压状态,这两种状态通常用于表示二进制数据中的 1
和 0
。
高电平(High Level / 1)
- 定义:在数字电路中,高电平通常表示一种较高的电压状态。
- 电压范围:具体的电压范围取决于所使用的逻辑电路标准。在 F28P550 中,IO 电平 VDDIO 接入的是 3.3V,那么输出的高电平就是 3.3V。
- 表示:在数字逻辑中,高电平通常表示 “1” 或 “真(True)” 状态。
低电平(Low Level / 0)
- 定义:与高电平相对,低电平表示一种较低的电压状态。
- 电压范围:同样,具体的电压范围取决于逻辑电路标准。在 F28P550 中,低电平是接近 地 电位的值(如 0 V)。
- 表示:在数字逻辑中,低电平通常表示 “0” 或 “假(false)” 状态。
注意
- 不同的电子设备可能使用不同的电平标准,因此在连接不同设备时需要确保电平兼容。比如芯片的 IO 是 3.3V,当它需要接入到 5V 的传感器时,就需要考虑电平兼容问题。在 F28P550 中,除了GPIO2、GPIO3、GPIO9、GPIO32外,其他的 GPIO 都不兼容 5V 电平。
- 在实际电路中,由于噪声的存在,高电平和低电平之间需要有一定的电压差(称为噪声容限)来确保电路的稳定工作。
主控的 GPIO 硬件特性
省流总结(点击展开)
除 GPIO2\3\9\32 外,其他 GPIO 的最大输入电压为 4.6V(建议用户输入时尽量不要超过3.3V),GPIO2\3\9\32 最大输入电压为 6V(建议用户输入时尽量不要超过5V)。
GPIO 每一个引脚最大的输出电流为 20 mA; GPIO 最大的输入电流为 120 ~ 160 mA。
引出的全部 GPIO 在复位\上电后默认为 输入状态。
绝对最大额定值
![]() |
---|
建议运行条件
![]() |
---|
电气特性
电气特性(点击展开)
LED 与按键电路介绍
GPIO 章节我们将使用 LED 和 按键 作为案例,而作为案例那我们就需要了解其具体的应用电路,了解应如何通过 GPIO 操控 LED 和按键。
板载LED电路解析
LED 灯的基本介绍(点击展开)
LED 灯发光原理
LED(发光二极管)发光原理基于半导体特性。在半导体中,存在着两类载流子:电子(n型半导体)和空穴(p型半导体)。当n型与p型半导体材料接触时,会在交界处形成一个层结。当施加适当的电压时,层结中空穴和电子可重组并释放能量。这个能量以光子的形式释放出来,产生光。
LED 灯驱动原理
LED 驱动指的是通过稳定的电源为 LED 提供合适的电流和电压,使其正常工作点亮。LED 驱动方式主要有恒流和恒压两种。限定电流的恒流驱动是最常见的方式,因为 LED 灯对电流敏感,电流大于其额定值可能导致损坏。恒流驱动保证了稳定的电流,从而确保了 LED 安全。 LED 灯的驱动比较简单,只需要给将对应的正负极接到单片机的正负极即可驱动。LED的接法也分有两种,灌入电流和输出电流。
![]() |
---|
- 灌入电流指的是LED的供电电流是由外部提供电流,将电流灌入我们的MCU;风险是当外部电源出现变化时,会导致MCU的引脚烧坏。
- 输出电流指的是由MCU提供电压电流,将电流输出给LED;如果使用 MCU的GPIO 直接驱动 LED,则驱动能力较弱,可能无法提供足够的电流驱动 LED。
需要注意的 是 LED 灯的颜色不同,对应的电压压降也不同。电流不可过大,通常需要接入220欧姆到10K欧姆左右的限流电阻,限流电阻的阻值越大,LED的亮度越暗。
![]() |
---|
- 主要器件为 LED3,这是一个将三个颜色的灯融合到一起的彩灯器件,三个颜色分别为 R(红色red)、G(绿色green)、B(蓝色blue)。
图片说明(点击展开)
![]() | ![]() |
---|---|
- R127、R128、R129 为LED灯的限流电阻,通常跟LED搭配,防止LED灯电路上的电流过大,导致LED灯烧毁。放置的阻值通常在 220Ω ~ 10KΩ。在原理图中,三个不同颜色的LED灯限流电阻分别用了不同的阻值,是因为 LED 灯颜色材料的不同其消化的电流也不同,为了让三个颜色的LED灯亮度一致,经过实测发现使用 3KΩ、4.3KΩ、9.1KΩ 时,通过肉眼观察,发现亮度基本一致。
- R130、R131 是上拉电阻。主要的功能就是让LED灯在上电未驱动的情况下,默认是灭的。因为 LED 的正极是高电平,负级也因为接入了上拉电阻导致其也是高电平,高电平和高电平无法形成压差产生电流,而没有电流,灯就不会亮。只有当 RGB-B 或 RGB-G 为低电平时,LED 灯才会亮。
上拉电阻与下拉电阻介绍(点击展开)
上拉电阻和下拉电阻是数字电路设计中常用的两种电阻接法,它们在电路中起到稳定电平的作用。
上拉电阻(Pull-up Resistor)
上拉电阻是指将电路中的某一点通过一个电阻连接到电源正极(例如 VCC 或 VDD )的电阻。
主要作用:
- 确保稳定的高电平:当电路中的开关或晶体管断开时,上拉电阻可以保证线路维持在高电平状态。
- 防止信号线悬空:避免信号线因为浮空而受到噪声干扰,保证信号的稳定性。
下拉电阻(Pull-down Resistor)
下拉电阻是指将电路中的某一点通过一个电阻连接到电源负极(例如GND)的电阻。
作用:
- 确保稳定的低电平:当电路中的开关或晶体管断开时,下拉电阻可以保证线路维持在低电平状态。
- 防止信号线悬空:与上拉电阻类似,下拉电阻可以防止信号线因未连接而导致的噪声干扰。
原理图中,三个颜色的 LED 正极接入了 3V3,除红色灯的负级尽头是到 GND 外,其他颜色的负极分别接入限流电阻再到主控的 GPIO 口。通过 LED 灯的基本介绍 下的 LED 灯的驱动原理可以知道,红色的 LED 灯是电源灯,正极是 3V3,负级是 GND,无法控制,只要 3V3 有电,红色灯就亮。而其他颜色的灯,我们只要控制开发板的 GPIO21 和 GPIO20 引脚输出低电平,即可点亮 LED;
板载按键电路解析
按键的基本介绍(点击展开)
独立按键是一种简单的输入设备,广泛应用于各种电子设备中,用于实现基本的用户交互。它们的工作原理通常基于一个简单的机械开关,当按下按键时触发某些操作。独立按键可以有多种尺寸、形状和颜色,便于用户辨识和使用。
![]() |
---|
按键结构组成
独立按键的主要结构组成包括:按钮、外壳、弹簧、触点、导电片和引脚。当按下按键时,导电片触碰到触点,从而形成一个闭合电路。
![]() |
---|
独立按键原理
独立按键原理主要是基于机械触点和电气触点之间的关系。当按键未被按下时,通常触点是分开的,电路是断开的。当用户按下按键时,触点在弹簧和导电片的作用下形成闭合,这时电路连通,微控制器能够读取到该按键触发的信号。
独立按键驱动是为了让微控制器能识别按键的状态,而微控制器正好可以识别高电平和低电平,所以大多数的按键都是通过给按键的一端接入高电平,一端接入 GPIO;或者是给按键的一端接入低电平,一端接入 GPIO。通过检测连接按键的引脚有没有发生电平变化,就可以知道按键是否按下。
![]() |
---|
在开发板的原理图中,一共有三个按键,分别是RST、BOOT、KEY按键。
其中 RST 是芯片复位功能按键,不能通过软件的方式去控制该按键,当按键按下时,芯片的 XRSN 引脚将会接入 GND,导致芯片将会自动复位重新工作。其中 R58 和 C76 组成了上电复位电路。R58是一个上拉电阻,让 XRSN 引脚上电时为高电平。C76是一个 100nF 的小电容,根据电容的原理可知道,电容其实就是一个电池,电容在上电时会保持一个很短暂的导通现象,所以上电的瞬间,XRSN 通过电容变成了低电平进行复位;当电容充满电后,电容隔开了直流,XRSN 不再是低电平。这样就实现了上电复位功能。
BOOT 是特殊按键,它接到了 GPIO24 引脚,该引脚和 GPIO32 引脚是用于设置启动模式的特殊引脚。通过这两个引脚,可以设置四种模式,具体见下图:
![]() |
---|
开发板硬件上,默认将 GPIO24 和 GPIO32 引脚通过上拉电阻 R55 和 R56 接到了高电平,这样启动模式就是从 Flash 中启动,我们的代码就是烧录到 Flash 中。如果你要从 SCI 串口启动,则按住 BOOT 键,再上电即可。
KEY 按键就是用户的可以操控的按键,将 GPIO27 引脚接入了这个按键,通过按键接到 GND。采用的检测方式是通过给按键的一端接入低电平,一端接入 GPIO。在没有按下按键时,因为上拉电阻 R137 的存在,导致一直处在高电平;当按键按下时,上拉电阻失效,GPIO27 引脚将被变为低电平的 GND。这样高低电平的变化,就可以让开发板检测到按键的状态。
工程创建与代码编写
工程创建
打开CCS,创建一个新的基于 F28P55X 的工程。
![]() | ![]() |
---|---|
工程配置
配置工程选项,将我们后面写好的代码烧录到 FLASH 中,并且使用的烧录模式是 cJTAG(1149.7)2-pin 模式。
![]() | ![]() |
---|---|
GPIO外设初始化
打开工程下的 .syscfg 文件。该文件为该工程的图形化代码生成工具的索引文件。
如果有弹出 Select Device 提示框,则依次选择 TMS320F28P550SJ - 128PDT - TMS320F28P550SJ9 选项。
![]() |
---|
找到GPIO选项卡,新建两个GPIO配置。一个用于配置蓝灯引脚为输出模式,一个用于配置按键引脚为输入模式。
蓝灯引脚配置
![]() |
---|
按键引脚配置
![]() |
---|
选项说明
序号 | 名称 | 功能 |
---|---|---|
1 | Name | 为当前配置的引脚起一个名字 |
2 | Analog Mode | 引脚的模拟模式,不过GPIO只能用于数字信号的 digital 数字模式 |
3 | GPIO Direction | 引脚的方向,有输入 input 和输出模式 output |
4 | Pin Type | 引脚类型,有8种模式,具体说明见下一个引脚类型说明 |
5 | Qualification Mode | 限定模式,对输入信号进行噪声过滤和同步处理,有四个选项,分别是与系统时钟同步、采样3次确定是否稳定、采样6次确定是否稳定、不使用同步和滤波。 |
6 | External Interrupts | 引脚的中断配置,到中断章节时再介绍 |
7 | Core Select | 运行核心选择,选择是在CPU运行还是在CLA运行 |
8 | PinMux | 外设引脚的配置,选择对应的引脚 |
引脚类型说明
序号 | 名称 | 功能 |
---|---|---|
1 | Push-pull output/floating input | 推挽输出/浮空输入 |
2 | Push-pull output/pull-up enabled on input | 推挽输出/上拉输入 |
3 | Push-pull output/floating INVERTED polarity on an input | 推挽输出/浮动输入反相 |
4 | Push-pull output/pull-up enabled on INVERTED input | 推挽输出/带上拉的反相输入 |
5 | Open-drain output/floating input | 开漏输出/浮空输入 |
6 | Open-drain output with pull-up enabled output and input | 带上拉功能的开漏输入输出 |
7 | Open-drain output/floating inverted input | 开漏输出/浮空的反相输入 |
8 | Open-drain output with pull-up enabled output and INVERTED input | 带上拉功能的开漏输入输出,但输入反相 |
以上配置完成后,可以按快捷键 Ctrl + S 快速保存。
相关GPIO函数介绍
序号 | 函数名称 | 功能 |
---|---|---|
1 | void GPIO_setInterruptType(GPIO_ExternalIntNum extIntNum, GPIO_IntType intType) | 设置中断类型 |
2 | GPIO_IntType GPIO_getInterruptType(GPIO_ExternalIntNum extIntNum) | 获取中断类型 |
3 | void GPIO_enableInterrupt(GPIO_ExternalIntNum extIntNum) | 使能外部中断 |
4 | void GPIO_disableInterrupt(GPIO_ExternalIntNum extIntNum) | 失能外部中断 |
5 | uint16_t GPIO_getInterruptCounter(GPIO_ExternalIntNum extIntNum) | 获取外部中断计数器的值 |
6 | uint32_t GPIO_readPin(uint32_t pin) | 读取指定引脚上的值 |
7 | uint32_t GPIO_readPinDataRegister(uint32_t pin) | 读取指定引脚的数据寄存器值 |
8 | void GPIO_writePin(uint32_t pin, uint32_t outVal) | 将一个值写入指定引脚 |
9 | void GPIO_togglePin(uint32_t pin) | 指定引脚的值进行翻转 |
10 | uint32_t GPIO_readPortData(GPIO_Port port) | 读取指定端口上的数据 |
11 | uint32_t GPIO_readPortDataRegister(GPIO_Port port) | 读取存储在GPIO数据寄存器中的值 |
12 | void GPIO_writePortData(GPIO_Port port, uint32_t outVal) | 将一个值写入指定端口 |
13 | void GPIO_setPortPins(GPIO_Port port, uint32_t pinMask) | 将指定端口上的所有指定引脚配置为特定状态 |
14 | void GPIO_clearPortPins(GPIO_Port port, uint32_t pinMask) | 清除指定端口上的所有指定引脚 |
15 | void GPIO_togglePortPins(GPIO_Port port, uint32_t pinMask) | 翻转指定端口上的所有指定引脚 |
16 | void GPIO_lockPortConfig(GPIO_Port port, uint32_t pinMask) | 锁定指定端口上指定引脚的配置 |
17 | void GPIO_unlockPortConfig(GPIO_Port port, uint32_t pinMask) | 解锁指定端口上指定引脚的配置 |
18 | void GPIO_commitPortConfig(GPIO_Port port, uint32_t pinMask) | 对指定端口上的指定引脚的锁存配置进行设置 |
19 | void GPIO_setDirectionMode(uint32_t pin, GPIO_Direction pinIO) | 设置指定引脚的方向和模式 |
20 | GPIO_Direction GPIO_getDirectionMode(uint32_t pin) | 获取指定引脚上的方向和模式 |
21 | void GPIO_setInterruptPin(uint32_t pin, GPIO_ExternalIntNum extIntNum) | 为指定的外部中断配置引脚 |
22 | void GPIO_setPadConfig(uint32_t pin, uint32_t pinType) | 设置指定引脚的引脚类型 |
23 | uint32_t GPIO_getPadConfig(uint32_t pin) | 获取指定引脚的引脚类型 |
24 | void GPIO_setQualificationMode(uint32_t pin, GPIO_QualificationMode qualification) | 设置指定引脚的限定模式 |
25 | GPIO_QualificationMode GPIO_getQualificationMode(uint32_t pin) | 获取指定引脚的限定模式 |
26 | void GPIO_setQualificationPeriod(uint32_t pin, uint32_t divider) | 配置指定GPIO输入信号滤波采样周期 |
27 | void GPIO_setControllerCore(uint32_t pin, GPIO_CoreSelect core) | 设置指定引脚在指定核心上运行 |
28 | void GPIO_setAnalogMode(uint32_t pin, GPIO_AnalogMode mode) | 设置指定引脚的模拟模式 |
29 | void GPIO_setPinConfig(uint32_t pinConfig) | 设置指定引脚的复用功能通常是复用于GPIO外设 |
比较常用的功能函数已经加粗表示。具体的代码,请见库中的 gpio.h。在原版的文件中每一个功能函数都有进行英文注释,如果需要中文版注释,请看下方的机翻代码:
机器翻译的中文注释 gpio.h
//###########################################################################
//
// 文件: gpio.h
//
// 标题: C28x GPIO驱动
//
//###########################################################################
//
// C2000Ware版本 v5.04.00.00
//
// 版权所有 (C) 2024 德州仪器公司 - http://www.ti.com
//
// 允许以源代码和二进制形式重新分发和使用(无论是否修改),需满足以下条件:
//
// 源代码的再分发必须保留上述版权声明、本条件列表及以下免责声明。
//
// 二进制形式的再分发必须在文档和/或其他提供的材料中复制上述版权声明、
// 本条件列表及以下免责声明。
//
// 未经事先书面许可,不得使用德州仪器公司或其贡献者名称来推广衍生自本软件的产品。
//
// 本软件按"原样"提供,版权持有人和贡献者不承担任何明示或默示的担保,
// 包括但不限于对适销性和特定用途适用性的默示担保。在任何情况下,版权持有人或
// 贡献者均不对任何直接、间接、偶然、特殊、惩戒性或后果性损害(包括但不限于
// 替代商品或服务采购、使用损失、数据或利润损失或业务中断)承担责任。
// $
//###########################################################################
#ifndef GPIO_H
#define GPIO_H
//*****************************************************************************
//
// 若使用C++编译器,确保本头文件中的所有定义具有C语言绑定
//
//*****************************************************************************
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
//! \addtogroup gpio_api GPIO
//! @{
//
//*****************************************************************************
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_gpio.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_xint.h"
#include "cpu.h"
#include "xbar.h"
#include "debug.h"
//*****************************************************************************
//
// 驱动函数内部使用的寄存器访问宏定义(不适用于应用代码)
// 除以2是针对C28x的字访问特性
//
//*****************************************************************************
#define GPIO_CTRL_REGS_STEP ((GPIO_O_GPBCTRL - GPIO_O_GPACTRL) / 2U)
#define GPIO_DATA_REGS_STEP ((GPIO_O_GPBDAT - GPIO_O_GPADAT) / 2U)
#define GPIO_DATA_READ_REGS_STEP ((GPIO_O_GPBDAT_R - GPIO_O_GPADAT_R) / 2U)
#define GPIO_GPxCTRL_INDEX (GPIO_O_GPACTRL / 2U)
#define GPIO_GPxQSEL_INDEX (GPIO_O_GPAQSEL1 / 2U)
#define GPIO_GPxMUX_INDEX (GPIO_O_GPAMUX1 / 2U)
#define GPIO_GPxDIR_INDEX (GPIO_O_GPADIR / 2U)
#define GPIO_GPxAMSEL_INDEX (0x00000014U / 2U) // GPAAMSEL保留地址
#define GPIO_GPxPUD_INDEX (GPIO_O_GPAPUD / 2U)
#define GPIO_GPxINV_INDEX (GPIO_O_GPAINV / 2U)
#define GPIO_GPxODR_INDEX (GPIO_O_GPAODR / 2U)
#define GPIO_GPxGMUX_INDEX (GPIO_O_GPAGMUX1 / 2U)
#define GPIO_GPxCSEL_INDEX (GPIO_O_GPACSEL1 / 2U)
#define GPIO_GPxLOCK_INDEX (GPIO_O_GPALOCK / 2U)
#define GPIO_GPxCR_INDEX (GPIO_O_GPACR / 2U)
#define GPIO_GPxDAT_INDEX (GPIO_O_GPADAT / 2U)
#define GPIO_GPxSET_INDEX (GPIO_O_GPASET / 2U)
#define GPIO_GPxCLEAR_INDEX (GPIO_O_GPACLEAR / 2U)
#define GPIO_GPxTOGGLE_INDEX (GPIO_O_GPATOGGLE / 2U)
#define GPIO_GPxDAT_R_INDEX (GPIO_O_GPADAT_R / 2U)
#define GPIO_MUX_TO_GMUX (GPIO_O_GPAGMUX1 - GPIO_O_GPAMUX1)
#ifndef DOXYGEN_PDF_IGNORE
//*****************************************************************************
//
// 可传递给GPIO_setPadConfig()的引脚类型参数及GPIO_getPadConfig()返回值
//
//*****************************************************************************
#define GPIO_PIN_TYPE_STD 0x0000U //!< 推挽输出或浮空输入
#define GPIO_PIN_TYPE_PULLUP 0x0001U //!< 输入上拉使能
#define GPIO_PIN_TYPE_INVERT 0x0002U //!< 输入极性反转
#define GPIO_PIN_TYPE_OD 0x0004U //!< 开漏输出
#endif
//*****************************************************************************
//
//! 可传递给GPIO_setDirectionMode()的方向模式参数及GPIO_getDirectionMode()返回值
//
//*****************************************************************************
typedef enum
{
GPIO_DIR_MODE_IN, //!< 引脚配置为GPIO输入
GPIO_DIR_MODE_OUT //!< 引脚配置为GPIO输出
} GPIO_Direction;
//*****************************************************************************
//
//! 可传递给GPIO_setInterruptType()的中断类型参数及GPIO_getInterruptType()返回值
//
//*****************************************************************************
typedef enum
{
GPIO_INT_TYPE_FALLING_EDGE = 0x00, //!< 下降沿中断
GPIO_INT_TYPE_RISING_EDGE = 0x04, //!< 上升沿中断
GPIO_INT_TYPE_BOTH_EDGES = 0x0C //!< 双沿中断
} GPIO_IntType;
//*****************************************************************************
//
//! 可传递给GPIO_setQualificationMode()的滤波模式参数及返回值
//
//*****************************************************************************
typedef enum
{
GPIO_QUAL_SYNC, //!< 同步SYSCLK
GPIO_QUAL_3SAMPLE, //!< 3采样滤波
GPIO_QUAL_6SAMPLE, //!< 6采样滤波
GPIO_QUAL_ASYNC //!< 无同步
} GPIO_QualificationMode;
//*****************************************************************************
//
//! 可传递给GPIO_setAnalogMode()的模拟模式参数
//
//*****************************************************************************
typedef enum
{
GPIO_ANALOG_DISABLED, //!< 数字模式
GPIO_ANALOG_ENABLED //!< 模拟模式
} GPIO_AnalogMode;
//*****************************************************************************
//
//! 可传递给GPIO_setControllerCore()的核心选择参数
//
//*****************************************************************************
typedef enum
{
GPIO_CORE_CPU1, //!< 选择CPU1作为控制核心
GPIO_CORE_CPU1_CLA1 //!< 选择CPU1的CLA1作为控制核心
} GPIO_CoreSelect;
//*****************************************************************************
//
//! 可传递给端口操作函数的端口标识
//
//*****************************************************************************
typedef enum
{
GPIO_PORT_A = 0, //!< GPIO端口A
GPIO_PORT_B = 1, //!< GPIO端口B
GPIO_PORT_C = 2, //!< GPIO端口C
GPIO_PORT_G = 6, //!< GPIO端口G
GPIO_PORT_H = 7, //!< GPIO端口H
} GPIO_Port;
//*****************************************************************************
//
//! 外部中断编号(用于相关中断函数参数)
//
//*****************************************************************************
typedef enum
{
GPIO_INT_XINT1, //!< 外部中断1
GPIO_INT_XINT2, //!< 外部中断2
GPIO_INT_XINT3, //!< 外部中断3
GPIO_INT_XINT4, //!< 外部中断4
GPIO_INT_XINT5 //!< 外部中断5
} GPIO_ExternalIntNum;
//*****************************************************************************
//
// API函数原型
//
//*****************************************************************************
//*****************************************************************************
//
//! \internal
//! 检查引脚编号是否有效
//!
//! 注意:此函数反映设备最大封装下的最高GPIO编号。
//! 具体封装的有效引脚范围请参考数据手册。
//!
//! \return 布尔值表示引脚是否有效
//
//*****************************************************************************
#ifdef DEBUG
static inline bool
GPIO_isPinValid(uint32_t pin)
{
return((pin <= 81U) || ((pin >= 208U) && (pin <= 215U)) ||
((pin >= 224U) && (pin <= 253U) && (pin != 243U) &&
(pin != 246U) && (pin != 250U)));
}
#endif
//*****************************************************************************
//
//! 设置指定外部中断的触发类型
//!
//! \param extIntNum 外部中断编号
//! \param intType 中断触发类型
//!
//! 此函数为指定外部中断配置触发机制:
//! - GPIO_INT_TYPE_FALLING_EDGE 下降沿触发
//! - GPIO_INT_TYPE_RISING_EDGE 上升沿触发
//! - GPIO_INT_TYPE_BOTH_EDGES 双沿触发
//!
//! \return 无
//
//*****************************************************************************
static inline void
GPIO_setInterruptType(GPIO_ExternalIntNum extIntNum, GPIO_IntType intType)
{
HWREGH(XINT_BASE + (uint16_t)extIntNum) =
(HWREGH(XINT_BASE + (uint16_t)extIntNum) & ~XINT_1CR_POLARITY_M) |
(uint16_t)intType;
}
//*****************************************************************************
//
//! 获取外部中断的触发类型
//!
//! \param extIntNum 外部中断编号
//!
//! \return 返回GPIO_setInterruptType()描述的枚举值之一
//
//*****************************************************************************
static inline GPIO_IntType
GPIO_getInterruptType(GPIO_ExternalIntNum extIntNum)
{
return((GPIO_IntType)((uint16_t)(HWREGH(XINT_BASE + (uint16_t)extIntNum) &
XINT_1CR_POLARITY_M)));
}
//*****************************************************************************
//
//! 使能指定外部中断
//!
//! \param extIntNum 外部中断编号
//!
//! \return 无
//
//*****************************************************************************
static inline void
GPIO_enableInterrupt(GPIO_ExternalIntNum extIntNum)
{
HWREGH(XINT_BASE + (uint16_t)extIntNum) |= XINT_1CR_ENABLE;
}
//*****************************************************************************
//
//! 禁用指定外部中断
//!
//! \param extIntNum 外部中断编号
//!
//! \return 无
//
//*****************************************************************************
static inline void
GPIO_disableInterrupt(GPIO_ExternalIntNum extIntNum)
{
HWREGH(XINT_BASE + (uint16_t)extIntNum) &= ~XINT_1CR_ENABLE;
}
//*****************************************************************************
//
//! 获取外部中断计数器值
//!
//! \param extIntNum 外部中断编号
//!
//! 注意:计数器以SYSCLKOUT速率时钟
//!
//! \return 返回外部中断计数器值
//
//*****************************************************************************
static inline uint16_t
GPIO_getInterruptCounter(GPIO_ExternalIntNum extIntNum)
{
ASSERT(extIntNum <= GPIO_INT_XINT3);
return((HWREGH(XINT_BASE + XINT_O_1CTR + (uint16_t)extIntNum)));
}
//*****************************************************************************
//
//! 读取指定引脚的电平值
//!
//! \param pin 引脚编号(如GPIO34对应34)
//!
//! \return 返回指定引脚的数据寄存器值
//
//*****************************************************************************
static inline uint32_t
GPIO_readPin(uint32_t pin)
{
volatile uint32_t *gpioDataReg;
ASSERT(GPIO_isPinValid(pin));
gpioDataReg = (uint32_t *)((uintptr_t)GPIODATA_BASE) +
((pin / 32U) * GPIO_DATA_REGS_STEP);
return((gpioDataReg[GPIO_GPxDAT_INDEX] >> (pin % 32U)) & (uint32_t)0x1U);
}
//*****************************************************************************
//
//! 读取指定引脚的数据寄存器值
//!
//! \param pin 引脚编号(如GPIO34对应34)
//!
//! \return 返回指定引脚的数据寄存器值
//
//*****************************************************************************
static inline uint32_t
GPIO_readPinDataRegister(uint32_t pin)
{
volatile uint32_t *gpioDataReg;
ASSERT(GPIO_isPinValid(pin));
gpioDataReg = (uint32_t *)((uintptr_t)GPIODATAREAD_BASE) +
((pin / 32U) * GPIO_DATA_READ_REGS_STEP);
return((gpioDataReg[GPIO_GPxDAT_R_INDEX] >> (pin % 32U)) & (uint32_t)0x1U);
}
//*****************************************************************************
//
//! 设置指定引脚的输出值
//!
//! \param pin 引脚编号(如GPIO34对应34)
//! \param outVal 要写入的值(0或1)
//!
//! \return 无
//
//*****************************************************************************
static inline void
GPIO_writePin(uint32_t pin, uint32_t outVal)
{
volatile uint32_t *gpioDataReg;
uint32_t pinMask;
ASSERT(GPIO_isPinValid(pin));
gpioDataReg = (uint32_t *)((uintptr_t)GPIODATA_BASE) +
((pin / 32U) * GPIO_DATA_REGS_STEP);
pinMask = (uint32_t)1U << (pin % 32U);
if(outVal == 0U)
{
gpioDataReg[GPIO_GPxCLEAR_INDEX] = pinMask;
}
else
{
gpioDataReg[GPIO_GPxSET_INDEX] = pinMask;
}
}
//*****************************************************************************
//
//! 翻转指定引脚的电平
//!
//! \param pin 引脚编号(如GPIO34对应34)
//!
//! \return 无
//
//*****************************************************************************
static inline void
GPIO_togglePin(uint32_t pin)
{
volatile uint32_t *gpioDataReg;
ASSERT(GPIO_isPinValid(pin));
gpioDataReg = (uint32_t *)((uintptr_t)GPIODATA_BASE) +
((pin / 32U) * GPIO_DATA_REGS_STEP);
gpioDataReg[GPIO_GPxTOGGLE_INDEX] = (uint32_t)1U << (pin % 32U);
}
//*****************************************************************************
//
//! 读取指定端口的数据
//!
//! \param port 端口标识(如GPIO_PORT_A)
//!
//! \return 返回端口各引脚状态(位0对应引脚0,依此类推)
//
//*****************************************************************************
static inline uint32_t
GPIO_readPortData(GPIO_Port port)
{
volatile uint32_t *gpioDataReg;
gpioDataReg = (uint32_t *)((uintptr_t)GPIODATA_BASE) +
((uint32_t)port * GPIO_DATA_REGS_STEP);
return(gpioDataReg[GPIO_GPxDAT_INDEX]);
}
//*****************************************************************************
//
//! 读取指定端口的数据寄存器值
//!
//! \param port 端口标识(如GPIO_PORT_A)
//!
//! \return 返回端口数据寄存器值(位0对应引脚0,依此类推)
//
//*****************************************************************************
static inline uint32_t
GPIO_readPortDataRegister(GPIO_Port port)
{
volatile uint32_t *gpioDataReg;
gpioDataReg = (uint32_t *)((uintptr_t)GPIODATAREAD_BASE) +
((uint32_t)port * GPIO_DATA_READ_REGS_STEP);
return(gpioDataReg[GPIO_GPxDAT_R_INDEX]);
}
//*****************************************************************************
//
//! 设置指定端口的输出值
//!
//! \param port 端口标识(如GPIO_PORT_A)
//! \param outVal 要写入的值(位0对应引脚0,依此类推)
//!
//! \return 无
//
//*****************************************************************************
static inline void
GPIO_writePortData(GPIO_Port port, uint32_t outVal)
{
volatile uint32_t *gpioDataReg;
gpioDataReg = (uint32_t *)((uintptr_t)GPIODATA_BASE) +
((uint32_t)port * GPIO_DATA_REGS_STEP);
gpioDataReg[GPIO_GPxDAT_INDEX] = outVal;
}
//*****************************************************************************
//
//! 置位指定端口的引脚
//!
//! \param port 端口标识(如GPIO_PORT_A)
//! \param pinMask 引脚掩码(置位对应引脚)
//!
//! \return 无
//
//*****************************************************************************
static inline void
GPIO_setPortPins(GPIO_Port port, uint32_t pinMask)
{
volatile uint32_t *gpioDataReg;
gpioDataReg = (uint32_t *)((uintptr_t)GPIODATA_BASE) +
((uint32_t)port * GPIO_DATA_REGS_STEP);
gpioDataReg[GPIO_GPxSET_INDEX] = pinMask;
}
//*****************************************************************************
//
//! 清除指定端口的引脚
//!
//! \param port 端口标识(如GPIO_PORT_A)
//! \param pinMask 引脚掩码(清除对应引脚)
//!
//! \return 无
//
//*****************************************************************************
static inline void
GPIO_clearPortPins(GPIO_Port port, uint32_t pinMask)
{
volatile uint32_t *gpioDataReg;
gpioDataReg = (uint32_t *)((uintptr_t)GPIODATA_BASE) +
((uint32_t)port * GPIO_DATA_REGS_STEP);
gpioDataReg[GPIO_GPxCLEAR_INDEX] = pinMask;
}
//*****************************************************************************
//
//! 翻转指定端口的引脚
//!
//! \param port 端口标识(如GPIO_PORT_A)
//! \param pinMask 引脚掩码(翻转对应引脚)
//!
//! \return 无
//
//*****************************************************************************
static inline void
GPIO_togglePortPins(GPIO_Port port, uint32_t pinMask)
{
volatile uint32_t *gpioDataReg;
gpioDataReg = (uint32_t *)((uintptr_t)GPIODATA_BASE) +
((uint32_t)port * GPIO_DATA_REGS_STEP);
gpioDataReg[GPIO_GPxTOGGLE_INDEX] = pinMask;
}
//*****************************************************************************
//
//! 锁定指定端口的引脚配置
//!
//! \param port 端口标识(如GPIO_PORT_A)
//! \param pinMask 引脚掩码(锁定对应引脚)
//!
//! 注意:此函数锁定引脚复用、方向等配置寄存器,不影响引脚值修改
//!
//! \return 无
//
//*****************************************************************************
static inline void
GPIO_lockPortConfig(GPIO_Port port, uint32_t pinMask)
{
volatile uint32_t *gpioDataReg;
gpioDataReg = (uint32_t *)((uintptr_t)GPIOCTRL_BASE) +
((uint32_t)port * GPIO_CTRL_REGS_STEP);
EALLOW;
gpioDataReg[GPIO_GPxLOCK_INDEX] |= pinMask;
EDIS;
}
//*****************************************************************************
//
//! 解锁指定端口的引脚配置
//!
//! \param port 端口标识(如GPIO_PORT_A)
//! \param pinMask 引脚掩码(解锁对应引脚)
//!
//! \return 无
//
//*****************************************************************************
static inline void
GPIO_unlockPortConfig(GPIO_Port port, uint32_t pinMask)
{
volatile uint32_t *gpioDataReg;
gpioDataReg = (uint32_t *)((uintptr_t)GPIOCTRL_BASE) +
((uint32_t)port * GPIO_CTRL_REGS_STEP);
EALLOW;
gpioDataReg[GPIO_GPxLOCK_INDEX] &= ~pinMask;
EDIS;
}
//*****************************************************************************
//
//! 提交锁定配置(永久锁定)
//!
//! \param port 端口标识(如GPIO_PORT_A)
//! \param pinMask 引脚掩码(锁定对应引脚)
//!
//! 注意:调用后GPIO_lockPortConfig()和GPIO_unlockPortConfig()将不再有效
//!
//! \return 无
//
//*****************************************************************************
static inline void
GPIO_commitPortConfig(GPIO_Port port, uint32_t pinMask)
{
volatile uint32_t *gpioDataReg;
gpioDataReg = (uint32_t *)((uintptr_t)GPIOCTRL_BASE) +
((uint32_t)port * GPIO_CTRL_REGS_STEP);
EALLOW;
gpioDataReg[GPIO_GPxCR_INDEX] |= pinMask;
EDIS;
}
//*****************************************************************************
//
//! 设置引脚方向和模式
//!
//! \param pin 引脚编号(如GPIO34对应34)
//! \param pinIO 方向模式(输入/输出)
//!
//! \return 无
//
//*****************************************************************************
extern void
GPIO_setDirectionMode(uint32_t pin, GPIO_Direction pinIO);
//*****************************************************************************
//
//! 获取引脚方向模式
//!
//! \param pin 引脚编号(如GPIO34对应34)
//!
//! \return 返回GPIO_setDirectionMode()描述的枚举值之一
//
//*****************************************************************************
extern GPIO_Direction
GPIO_getDirectionMode(uint32_t pin);
//*****************************************************************************
//
//! 设置外部中断引脚
//!
//! \param pin 引脚编号(如GPIO34对应34)
//! \param extIntNum 外部中断编号
//!
//! \return 无
//
//*****************************************************************************
extern void
GPIO_setInterruptPin(uint32_t pin, GPIO_ExternalIntNum extIntNum);
//*****************************************************************************
//
//! 设置引脚电气特性
//!
//! \param pin 引脚编号(如GPIO34对应34)
//! \param pinType 引脚类型(标准/上拉/开漏/反相等)
//!
//! \return 无
//
//*****************************************************************************
extern void
GPIO_setPadConfig(uint32_t pin, uint32_t pinType);
//*****************************************************************************
//
//! 获取引脚电气特性配置
//!
//! \param pin 引脚编号(如GPIO34对应34)
//!
//! \return 返回GPIO_setPadConfig()描述的位域组合
//
//*****************************************************************************
extern uint32_t
GPIO_getPadConfig(uint32_t pin);
//*****************************************************************************
//
//! 设置引脚输入滤波模式
//!
//! \param pin 引脚编号(如GPIO34对应34)
//! \param qualification 滤波模式
//!
//! 要设置滤波采样周期,需使用GPIO_setQualificationPeriod()
//!
//! \return 无
//
//*****************************************************************************
extern void
GPIO_setQualificationMode(uint32_t pin, GPIO_QualificationMode qualification);
//*****************************************************************************
//
//! 获取引脚滤波模式
//!
//! \param pin 引脚编号(如GPIO34对应34)
//!
//! \return 返回滤波模式枚举值
//
//*****************************************************************************
extern GPIO_QualificationMode
GPIO_getQualificationMode(uint32_t pin);
//*****************************************************************************
//
//! 设置引脚滤波周期
//!
//! \param pin 引脚编号(如GPIO34对应34)
//! \param divider 分频系数(1或2-510之间的偶数)
//!
//! 注意:此函数配置8个引脚的共享滤波周期寄存器
//!
//! \return 无
//
//*****************************************************************************
extern void
GPIO_setQualificationPeriod(uint32_t pin, uint32_t divider);
//*****************************************************************************
//
//! 设置引脚控制核心
//!
//! \param pin 引脚编号(如GPIO34对应34)
//! \param core 控制核心选择
//!
//! \return 无
//
//*****************************************************************************
extern void
GPIO_setControllerCore(uint32_t pin, GPIO_CoreSelect core);
//*****************************************************************************
//
//! 设置引脚模拟模式
//!
//! \param pin 引脚编号(如GPIO34对应34)
//! \param mode 模拟模式使能/禁用
//!
//! 注意:此参数同时适用于AIO和GPIO
//!
//! \return 无
//
//*****************************************************************************
extern void
GPIO_setAnalogMode(uint32_t pin, GPIO_AnalogMode mode);
//*****************************************************************************
//
//! 配置GPIO引脚的复用功能
//!
//! \param pinConfig 引脚配置值(仅使用GPIO_#_????预定义值)
//!
//! 此函数配置选择外设功能的引脚复用器。每个GPIO引脚同一时间只能关联一个
//! 外设功能,且每个外设功能应只关联一个GPIO引脚(尽管许多外设功能可以
//! 映射到多个GPIO引脚)。
//!
//! 可用映射关系定义在<pin_map.h>中。
//!
//! \return 无
//
//*****************************************************************************
extern void
GPIO_setPinConfig(uint32_t pinConfig);
//*****************************************************************************
//
// 关闭Doxygen分组
//! @}
//
//*****************************************************************************
//*****************************************************************************
//
// 结束C++编译器的C语言绑定段
//
//*****************************************************************************
#ifdef __cplusplus
}
#endif
#endif // GPIO_H
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
代码编写
在我们新建的工程找到 empty_driverlib_main.c 文件,该文件中的 void main(void) 就是我们的代码执行入口。
因为我们的GPIO初始化已经由图像化代码生成工具生成了,所以我们只需要使用GPIO实现功能就可以。
直接在 while(1) 中添加以下代码:
if( GPIO_readPin(GPIO_KEY) == 0 )
{
GPIO_writePin(GPIO_BULE, 0);
}
else
{
GPIO_writePin(GPIO_BULE, 1);
}
2
3
4
5
6
7
8
案例验证
下载器连接
XDS110下载器 | 开发板 |
---|---|
SWD | SWD/TMS |
CLK | CLK/TCK |
GND | GND |
5V | 5V |
代码烧录
将工程编译:
编译没有问题后进行调试仿真下载:
GIF动图操作:
案例现象
按下开发板的 KEY 键,则开发板上的彩灯蓝色部分会亮。