立创·天空星开发板-GD32F407VE-GPIO

本文以 立创·天空星开发板-GD32F407VET6-青春版 作为学习的板子,记录学习笔记。

立创·天空星开发板-GD32F407VE-GPIO

    • 基础概念
      • 三极管
      • MOS管
    • GPIO输出模式
    • 输出线与
    • GPIO输入模式
    • GPIO点灯

基础概念

  • GPIO,全称为“通用输入/输出”(General Purpose Input/Output),是计算机系统中用于与外部世界进行数字通信的一种接口标准。
  • 它允许硬件和软件通过电信号来交换数据,控制外部设备或接收外部事件。
  • GPIO通常用于连接各种外设,如按钮、LED灯、传感器、马达、继电器等,以便与计算机系统进行交互。GD32 支持的 GPIO 模式有如下八种:
模式性质
浮空输入数字输入
上拉输入数字输入
下拉输入数字输入
模拟输入模拟输入
开漏输出数字输出
推挽输出数字输出
复用开漏输出数字输出
复用推挽输出数字输出

三极管

总是记混 NPN 和 PNP 这两种型号的三极管,如下图所示:

三极管原理图对比
特性描述:

  1. 电流关系: I E = I B + I C I_E = I_B + I_C IE=IB+IC
  2. 导通条件: NPN型的基极比发射极电压高0.7v,PNP型的基极比发射极电压低0.7v
  3. 设计原理图: 无论是 NPN 还是 NPN 型的三极管,耗电元器件都需要接在集电极

助记小技巧:

  1. 电路图中,箭头永远指向的 N 极,根据箭头可快速确认是 NPN 还是 PNP
  2. 电路图中,箭头对应的极比箭尾对应的极的电压要低

思维导图:

三极管思维导图

MOS管

MOS管有 NMOS 和 PMOS 两种类型。MOS管包含了三个极:

  • 栅极(G),对应英文单词:Gate
  • 漏极(D),对应英文单词:Drain
  • 源极(S),对应英文单词:Source

MOS管的作用就是开关,通过栅极控制漏极和源极的导通。主要关注两个点:

  1. 控制:负责MOS管导通和截止,高电平导通还是低电平导通。
  2. 流向:是从漏极流向源极,还是从源极流向漏极。

MOS管和三级管主要区别:三极管导通有电流,而MOS管导通没有电流(有点像继电器)

一张图搞懂 MOS 管,如下所示:
一张图搞懂 MOS 管

如果 Input 为电平,PMOS 断开,NMOS 导通,如果 GPIO_PIN_X 有上拉电阻,则电流可以顺利从 NMOS 的漏极(D)流向源极(S)。
如果 Input 为电平,PMOS 导通,NMOS 断开,如果 GPIO_PIN_X 有下拉电阻,则电流可以顺利从 PMOS 的源极(S)流向漏极(D)。

特点描述:

  • PMOS 的栅极(G)低通高断,导通时,电流方向是源极(S)流向漏极(D)
  • PMOS 可以类比 PNP 类型的三极管
  • NMOS 的栅极(G)高通低断,导通时,电流方向是漏极(D)流向源极(S)
  • NMOS 可以类比 NPN 类型的三极管

思维导图:

MOS管思维导图

GPIO输出模式

  1. 推挽输出
  • 【推】寄存器控制输出高电平时,过非门后变低电平,PMOS导通,外部引脚为高,电流流出

输出高电平

  • 【挽】寄存器控制输出低电平时,过非门后变高电平,NMOS导通,外部引脚为低,电流流入
    输出低电平
  1. 开漏输出
  • 寄存器控制输出低电平时,过非门后变高电平,NMOS导通,外部引脚为低,电流流入

输出低电平

  • 寄存器控制输出高电平时,因为PMOS未接入,所以外部引脚断开。

无法输出高电平

  1. 高阻态
  • 因为 PMOS和 NMOS 均未接入,无论寄存器输出高或者低,外部引脚始终断开。

高阻态

  1. 复用开漏输出 和 复用推挽输出
  • 不经过寄存器来输出高低电平,也就是下图中的 Alternate function output 部分

在这里插入图片描述

输出线与

  1. 推挽线与

推挽过程中,如果一方输出高,一方输出低,则会烧芯片。因此,推挽是不可以线与的。

推挽线与
2. 开漏线与

开漏过程中,无论双方输出高低电平,芯片都不会收到影响。I2C就是线与的一个实例。
开漏线与

GPIO输入模式

  1. 浮空输入
  • 就是将模拟信号、上拉、下拉全部断开,只接收外部电路的输入信号。如下图红色线条所示:
    浮空输入
  1. 上拉输入
  • 过上拉电阻后,经由斯密特触发器,写入寄存器。如下图红色线条所示:
  • 过斯密特后,也可做复用输入,不写入寄存器
    上拉输入
  1. 下拉输入
  • 过下拉电阻后,经由斯密特触发器,写入寄存器。如下图红色线条所示:
  • 过斯密特后,可做复用输入,不写入寄存器
    下拉输入
  1. 模拟输入
  • 不经过斯密特触发器,直接读入。如下图红色线条所示:

模拟输入

GPIO点灯

我用 GPIO 封装了一个可以动态点亮多个 LED 的拓展驱动,针对 PD 端口, 可以动态增加 LED 灯的引脚。只需要修改 LED_PINS 数组的元素即可。

  • ExtendedLED.h
#ifndef __EXTENDED_LED_H__
#define __EXTENDED_LED_H__

#include "gd32f4xx.h"
#include "systick.h"


#define LED_RCU  RCU_GPIOD
#define LED_PORT GPIOD
#ifndef BIT
#define BIT(x) ((uint16_t)((uint16_t)0x01U<<(x)))
#endif

// 声明需要针对的引脚, PDx(x=8...15)
static uint32_t LED_PINS[] = {
	BIT(8),  BIT(9),  BIT(10), BIT(11),
	BIT(12), BIT(13), BIT(14), BIT(15)
};


/*!
    \brief    初始化 LED
    \param[in]  none
    \param[out] none
    \retval     none
*/
void extended_led_init();

/*!
    \brief    熄灭所有 LED 灯
    \param[in]  none
    \param[out] none
    \retval     none
*/
void extended_led_turn_off_all();

/*!
    \brief    点亮所有 LED 灯
    \param[in]  none
    \param[out] none
    \retval     none
*/
void extended_led_turn_on_all();

/*!
    \brief    熄灭 LED 灯
    \param[in]  index[int]: LED 灯在 LED_PINS 数组中的索引, -1 针对所有引脚
    \param[out] none
    \retval     none
*/
void extended_led_turn_off(int index);

/*!
    \brief    点亮 LED 灯
    \param[in]  index[int]: LED 灯在 LED_PINS 数组中的索引, -1 针对所有引脚
    \param[out] none
    \retval     none
*/
void extended_led_turn_on(int index);

/*!
    \brief    运行多个共阳 LED 灯
	示例: extended_led_run(0,  1, 1); 效果为:从第一个灯开始依次亮起, 切灯过程不熄灭其他灯[流水灯]
	示例: extended_led_run(0,  1, 0); 效果为:从第一个灯开始依次亮起, 切灯过程会熄灭其他灯[跑马灯]
	示例: extended_led_run(0,  2, 1); 效果为:按 0.2.4.6 顺序依次亮起, 切灯过程不熄灭其他灯[流水灯]
	示例: extended_led_run(1,  2, 0); 效果为:按 1.3.5.7 顺序依次亮起, 切灯过程会熄灭其他灯[跑马灯]
	示例: extended_led_run(6, -2, 1); 效果为:按 6.4.2.0 顺序依次亮起, 切灯过程不熄灭其他灯[流水灯]
	示例: extended_led_run(7, -2, 0); 效果为:按 7.5.3.1 顺序依次亮起, 切灯过程会熄灭其他灯[跑马灯]
    \param[in]  status  [uint16_t]:     表示灯的状态, 可选值有 (亮:0) 或 (灭:1)
    \param[in]  start   [uint32_t]:     表示从哪个灯开始亮, 可选值有 0...
    \param[in]  step    [int16_t] :     表示切灯的时候跨越步长, 可选值有 0...
    \param[in]  flowing [uint16_t]:     表示切灯的时候是否采用流水灯
    \param[out] none
    \retval     none
*/
void extended_led_run(uint16_t status, uint32_t start, int16_t step, uint16_t flowing);

#endif
  • ExtendedLED.c
#include "ExtendedLED.h"

// 获取 LED 灯的总数
static uint16_t pins_length(void) {
	return sizeof(LED_PINS) / sizeof(LED_PINS[0]);
}

// 获取所有引脚
static uint16_t pins_all(void) {
	int length = 0, i = 0;
	length = pins_length();
	uint16_t pin = (uint16_t)0x00U;
	
	for(i = 0; i < length; i++) {
		pin |= LED_PINS[i];
	}
	return pin;
}

/*!
    \brief    初始化 LED
    \param[in]  none
    \param[out] none
    \retval     none
*/
void extended_led_init() {
    rcu_periph_clock_enable(LED_RCU);
    gpio_mode_set(LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, pins_all());
    gpio_output_options_set(LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, pins_all());
	gpio_bit_set(GPIOD, pins_all());
}

/*!
    \brief    熄灭所有 LED 灯
    \param[in]  none
    \param[out] none
    \retval     none
*/
void extended_led_turn_off_all() { extended_led_turn_off(-1); }

/*!
    \brief    点亮所有 LED 灯
    \param[in]  none
    \param[out] none
    \retval     none
*/
void extended_led_turn_on_all() { extended_led_turn_on(-1); }

/*!
    \brief    熄灭 LED 灯
    \param[in]  index[int]: LED 灯在 LED_PINS 数组中的索引, -1 针对所有引脚
    \param[out] none
    \retval     none
*/
void extended_led_turn_off(int index) {
	int length = pins_length();
	if (index >= length) {
		return;
	}
	if (index < 0) {
		gpio_bit_set(GPIOD, pins_all());   // 负数针对所有
		return;
	}
	gpio_bit_set(GPIOD, LED_PINS[index]);
}

/*!
    \brief    点亮 LED 灯
    \param[in]  index[int]: LED 灯在 LED_PINS 数组中的索引, -1 针对所有引脚
    \param[out] none
    \retval     none
*/
void extended_led_turn_on(int index) {
	int length = pins_length();
	if (index >= length) {
		return;
	}
	if (index < 0) {
		gpio_bit_reset(GPIOD, pins_all());   // 负数针对所有
		return;
	}
	gpio_bit_reset(GPIOD, LED_PINS[index]);

}

/*!
    \brief    运行多个共阳 LED 灯
	示例: extended_led_run(0,  1, 1); 效果为:从第一个灯开始依次亮起, 切灯过程不熄灭其他灯[流水灯]
	示例: extended_led_run(0,  1, 0); 效果为:从第一个灯开始依次亮起, 切灯过程会熄灭其他灯[跑马灯]
	示例: extended_led_run(0,  2, 1); 效果为:按 0.2.4.6 顺序依次亮起, 切灯过程不熄灭其他灯[流水灯]
	示例: extended_led_run(1,  2, 0); 效果为:按 1.3.5.7 顺序依次亮起, 切灯过程会熄灭其他灯[跑马灯]
	示例: extended_led_run(6, -2, 1); 效果为:按 6.4.2.0 顺序依次亮起, 切灯过程不熄灭其他灯[流水灯]
	示例: extended_led_run(7, -2, 0); 效果为:按 7.5.3.1 顺序依次亮起, 切灯过程会熄灭其他灯[跑马灯]
    \param[in]  status  [uint16_t]:     表示灯的状态, 可选值有 (亮:0) 或 (灭:1)
    \param[in]  start   [uint32_t]:     表示从哪个灯开始亮, 可选值有 0...
    \param[in]  step    [int16_t] :     表示切灯的时候跨越步长, 可选值有 0...
    \param[in]  flowing [uint16_t]:     表示切灯的时候是否采用流水灯
    \param[out] none
    \retval     none
*/
void extended_led_run(uint16_t status, uint32_t start, int16_t step, uint16_t flowing) {
	int length = pins_length();
	int i = 0;
	if(start < 0 || start >= length) {
		start = 0;
	}
	if(start + step  >= length) {
		start = length - 1 - (step - 1);
	}
	
	for(i = start; i < length && i > -1; i += step) {
		if(status) {
			// 熄灭指定索引的灯
			extended_led_turn_off(i);
		} else {
			// 点亮指定索引的灯
			if(!flowing) {
				// 如果不是流水灯, 每次切灯之前都需要关掉所有灯
				extended_led_turn_off(-1);
				delay_1ms(200);
			}
			extended_led_turn_on(i);
		}
		delay_1ms(200);
	}
}

  • main.c
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>

#include "ExtendedLED.h"

int main(void) {
    systick_config();
    
	extended_led_init();
	extended_led_run(0, 0,  1, 1);
	extended_led_run(1, 7, -1, 1);
	extended_led_run(0, 0,  1, 0);
	extended_led_turn_off_all();
	
    while(1) { }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/690828.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Wireshark自定义Lua插件

背景&#xff1a; 常见的抓包工具有tcpdump和wireshark&#xff0c;二者可基于网卡进行抓包&#xff1a;tcpdump用于Linux环境抓包&#xff0c;而wireshark用于windows环境。抓包后需借助包分析工具对数据进行解析&#xff0c;将不可读的二进制数转换为可读的数据结构。 wires…

SpringBoot+Vue实现前后端分离基本的环境搭建

目录 一、Vue项目的搭建 &#xff08;1&#xff09;基于vite创建vue项目 &#xff08;2&#xff09;引入elementplus &#xff08;3&#xff09;启动后端服务&#xff0c;并测试 二、SpringBoot项目的搭建 &#xff08;1&#xff09;通过idea创建SpringBoot项目 &#x…

ipables防火墙

一、Linux防火墙基础 Linux 的防火墙体系主要工作在网络层&#xff0c;针对 TCP/IP 数据包实施过滤和限制&#xff0c;属于典 型的包过滤防火墙&#xff08;或称为网络层防火墙&#xff09;。Linux 系统的防火墙体系基于内核编码实现&#xff0c; 具有非常稳定的性能和高效率&…

AI高考大战,揭秘五大热门模型谁能问鼎数学之巅?

在高考前&#xff0c;我就有想法了&#xff0c;这一次让AI来做做高考题。就用国内的大模型&#xff0c;看哪家的大模型解题最厉害。 第一天考完&#xff0c;就拿到了2024高考数学2卷的电子版&#xff0c;这也是重庆市采用的高考试卷 这次选了5个AI工具&#xff0c;分别是天工&a…

FlexJavaFramwork

FlexJavaFramwork架构

【python】python商业客户流失数据模型训练分析可视化(源码+数据集+课程论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

skywalking学习

文章目录 前言一、skywalking单体安装部署1. 下载skywalking2. 部署oap和oap-ui服务3. 测试skywalking监控springboot应用 二、搭建swck(skywalking集群)1.安装k8s2.下载swck3.设置pod自动注入java agent 三、skywalking监控python四、skywalking监控cpp总结参考 前言 本文主要…

生气时,你的“心”会发生什么变化?孟德尔随机化分析猛如虎,结果都是套路...

“不生气不生气&#xff0c;气出病来无人替”&#xff0c;不少人遇事常这样宽慰自己。事实上&#xff0c;“气死”真不是危言耸听。越来越多的研究证明了情绪稳定对健康的重要性&#xff0c;那么&#xff0c;当情绪频繁波动时&#xff0c;我们的心血管究竟会发生什么变化&#…

SpringBoot 的多配置文件

文章目录 SpringBoot 的多配置文件spring.profiles.active 配置Profile 和 ActiveProfiles 注解 SpringBoot 的多配置文件 spring.profiles.active 配置 默认情况下&#xff0c;当你启动 SpringBoot 项目时&#xff0c;会在日志中看到如下一条 INFO 信息&#xff1a; No act…

产气荚膜梭菌定植与婴儿食物过敏之间的关联

谷禾健康 牛奶蛋白过敏&#xff08;CMPA&#xff09;是婴儿最常见的食物过敏类型之一。粪便病原菌培养显示产气荚膜梭菌阳性率超过30%&#xff0c;明显高于其他细菌。因此推测产气荚膜梭菌定植可能是婴儿牛奶蛋白过敏的发病因素之一。 一项真实世界的研究&#xff0c;杨敏团队从…

C++全栈聊天项目(21) 滚动聊天布局设计

滚动聊天布局设计 我们的聊天布局如下图 最外层的是一个chatview&#xff08;黑色&#xff09;&#xff0c; chatview内部在添加一个MainLayout&#xff08;蓝色&#xff09;&#xff0c;MainLayout内部添加一个scrollarea(红色)&#xff0c;scrollarea内部包含一个widget&…

【Redis】Redis经典问题:缓存穿透、缓存击穿、缓存雪崩

目录 缓存的处理流程缓存穿透解释产生原因解决方案1.针对不存在的数据也进行缓存2.设置合适的缓存过期时间3. 对缓存访问进行限流和降级4. 接口层增加校验5. 布隆过滤器原理优点缺点关于扩容其他使用场景SpringBoot 整合 布隆过滤器 缓存击穿产生原因解决方案1.设置热点数据永不…

Swift 序列(Sequence)排序面面俱到 - 从过去到现在(二)

概览 在上篇 Swift 序列(Sequence)排序面面俱到 - 从过去到现在(一)博文中,我们讨论了 Swift 语言中序列和集合元素排序的一些基本知识,我们还给出了以自定义类型中任意属性排序的“康庄大道”。 不过在实际的撸码场景中,我们往往需要的是“多属性”同时参与到排序的考…

STM32F103C8T6基于HAL库移植uC/OS-III

文章目录 一、建立STM32CubeMX工程二、移植1、 uC/OS-III源码2、移植过程 三、配置相关代码1、bsp.c和bsp.h2、main.c3、修改启动代码4、修改app_cfg.h文件5、修改includes.h文件6、修改lib_cfg.h文件 四、编译与烧录总结参考资料 学习嵌入式实时操作系统&#xff08;RTOS&…

Swift 序列(Sequence)排序面面俱到 - 从过去到现在(一)

概览 在任何语言中对序列(或集合)元素的排序无疑是一种司空见惯的常规操作,在 Swift 语言里自然也不例外。序列排序看似简单,实则“暗藏玄机”。 要想真正掌握 Swift 语言中对排序的“各种姿势”,我们还得从长计议。不如就先从最简单的排序基本功开始聊起吧。 在本篇博…

9行超强代码用Python工具快速获取放假日期

9行超强代码用Python工具快速获取放假日期 在很多场景下,我们需要获知国内具体的节假日安排情况,而国内每一年具体的放假安排以及调休情况,都依赖于国务院发布的具体公告,如果不想自己手动整理相关数据的话,我们可以用Python来快速获取最新的放假日期. 可以通过调用公开的 API…

spark-3.5.1+Hadoop 3.4.0+Hive4.0 分布式集群 安装配置

Hadoop安装参考: Hadoop 3.4.0HBase2.5.8ZooKeeper3.8.4Hive4.0Sqoop 分布式高可用集群部署安装 大数据系列二-CSDN博客 一 下载:Downloads | Apache Spark 1 下载Maven – Welcome to Apache Maven # maven安装及配置教程 wget https://dlcdn.apache.org/maven/maven-3/3.8…

App UI 风格创新无限

App UI 风格创新无限

如何理解与学习数学分析——第二部分——数学分析中的基本概念——第8章——可微性

第2 部分&#xff1a;数学分析中的基本概念 (Concepts in Analysis) 8. 可微性(Differentiability) 本章讨论梯度(gradients)/斜率(slopes)和切线(tangent)&#xff0c;指出常见的误解并解释如何避免这些误解。将可微性的定义与图形表示联系起来&#xff0c;展示如何将其应用…