相关链接

理论知识

中断系统

中断: 在主程序运行过程中,出现了特定的中断触发条件(中断源), 使得CPU暂停当前正在运行的程序,转而处
理中断程序,处理完成后又返回原来被暂停的位置继续运行.

中断优先级: 当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先相应更加紧急的中断源.

中断嵌套: 当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而处理新的中断程序,处理完成后依次进行返回.

中断执行流程

中断执行流程图如下图所示:

中断执行流程图

NVIC的基本结构

NVIC基本结构图

NVIC优先级分组

NVIC优先级分组

EXTI简介

外部中断(External Interrupt)是指来自外部设备或信号的中断请求。

EXTI可以监测GPIO口的电平信号,当其指定的GPIO口电平发生变化时,EXTI将立即向NVIC发出中断申请,
经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序.

支持的触发方式有:上升沿/下降沿/双边沿/软件触发。

支持的GPIO口: 所有GPIO口均可触发外部中断但是相同的Pin不能同时触发中断(如PA0和PB0不能同时触发中断).

通道数: 16个GPIO_Pin,外加PVD输出,RTC闹钟,USB唤醒,以太网唤醒.

触发响应方式: 中断响应/事件响应(用来触发其他外设的事件).

EXTI的基本结构

EXTI的基本结构图

  • 经过AFIO选择后仅有16路GPIO口可以触发EXTI中断,所以PA0和PB0不可以同时触发中断.
  • EXTI9_5和EXTI15_10需要通过标志位来区分是哪个GPIO口触发的中断.
  • EXTI给其他外设的中断为事件响应

AFIO结构图如下:

AFIO结构图

通过数据选择器来将PA0~PG0选择其中一条线到EXTI0.

EXTI框图如下:

EXTI框图

  1. 输入线进入边沿监测电路,选择上升沿/下降沿/双边沿触发.
  2. 边沿监测电路信号和软件中断事件寄存器一起进入逻辑或门
  3. 触发信号通过逻辑或门后分两路,上面一路触发中断,下面一路触发事件.
  4. 触发中断会置请求挂起寄存器, 请求挂起寄存器和中断屏蔽器一起进入逻辑与门,进入NVIC中断控制器.
  5. 触发事件和事件屏蔽寄存器一起进入逻辑与门,再通过脉冲发生器用来触发其他外设.

实验测试

实验目标: 使用火焰传感器监测火焰并通过OLED屏显示火焰警报

硬件连接

OLED连接

  • SCK 接 PG12
  • SDA 接 PD5
  • RES 接 PD4
  • DC 接 PD15
  • CS 接 PD1

火焰传感器连接

  • DO 接 PB13

火焰传感器

实物如图所示

火焰传感器3针蓝版

资料链接 : 火焰传感器链接

传感器型号: 3针版

当火焰强度超过阈值时,输出低电平,否则输出高电平,所以需要配置为下降沿触发

程序设计

fire.c文件中编写如下代码

1
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
#include "stm32f10x.h"                  // Device header
#include "stm32f10x_exti.h"

uint16_t FireState = 0; // 火焰传感器状态变量 0:无火焰,1:有火焰

/*
* 火焰传感器初始化函数
* 1. 打开GPIOB时钟和AFIO时钟
* 2. 配置PB14为上拉输入模式,速度50MHz
* 3. 配置中断线为PB14
* 4. 配置中断线为EXTI_Line14,使能中断线,模式选为中断模式,触发模式选为下降沿触发
* 4. NVIC分组设置为2组即2个抢占优先级,2个响应优先级
* 5. NVIC通道设置为EXTI15_10,使能NVIC通道,抢占优先级设置为1,响应优先级设置为1
*/
void Fire_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 打开GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 打开AFIO时钟

// GPIO PB14初始化
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 配置上拉输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; // 配置端口为14
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 配置输出速度50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); // 完成PB14初始化

// AFIO初始化(中断线配置)
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14); // 配置中断线为PB14


// EXTI初始化
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line14; // 中断线选为14
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 中断线使能
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 模式选为中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 触发模式选为下降沿触发
EXTI_Init(&EXTI_InitStructure);

// NVIC初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // NVIC分组设置为2组即2个抢占优先级,2个响应优先级
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; // NVIC通道设置为EXTI15_10
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能NVIC通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级设置为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 响应优先级设置为1
NVIC_Init(&NVIC_InitStructure);
}

/*
* 火焰传感器状态获取函数
* 返回值: 0:无火焰,1:有火焰
*/
uint16_t FireState_Get(void)
{
return FireState;
}

/*
* 火焰传感器状态清除函数
* 清除火焰传感器状态,将状态变量清零
*/
void FireState_Clear(void)
{
FireState = 0;
}

/*
* EXTI15_10中断处理函数
* 1. 判断中断线是否为EXTI_Line14,如果是,则将火焰状态变量置为1,表示有火焰
* 2. 清除中断标志位
*/
void EXTI15_10_IRQHandler(void)
{
if (SET == EXTI_GetITStatus(EXTI_Line14))
{
FireState = 1;
EXTI_ClearITPendingBit(EXTI_Line14);
}

}

fire.h文件中编写如下代码

1
2
3
4
5
6
7
8
9
#ifndef __FIRE_H
#define __FIRE_H

void Fire_Init(void); // 初始化火焰传感器
uint16_t FireState_Get(void); // 获取火焰传感器状态
void FireState_Clear(void); // 清除火焰传感器状态

#endif

main.c文件中编写如下代码

1
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
#include "stm32f10x.h"                  // Device header
#include "stm32f10x_exti.h"
#include "delay.h"
#include "sys.h"
#include "oled.h"
#include "bmp.h"
#include "fire.h"

int main(void)
{
// 初始化延迟函数
delay_init();
// 初始化OLED屏幕
OLED_Init();
// 初始化火焰传感器
Fire_Init();

while(1)
{
if (1 == FireState_Get()) // 如果火焰传感器检测到火焰
{
OLED_Clear(); // 清屏
OLED_ShowString(1, 1, "Fire Warning", 16); // 显示火焰警报
OLED_Refresh(); // 刷新屏幕
delay_ms(5000); // 延时5秒
FireState_Clear(); // 清除火焰传感器状态
OLED_Clear(); // 清屏
}
else if (0 == FireState_Get()) // 如果火焰传感器没有检测到火焰
{
OLED_Clear(); // 清屏
OLED_ShowString(1, 1, "Stand By", 16); // 显示待机状态
OLED_Refresh(); // 刷新屏幕
delay_ms(5000); // 延时5秒
OLED_Clear(); // 清屏
}
else // 如果火焰传感器状态异常
{
OLED_Clear(); // 清屏
OLED_ShowString(1, 1, "Sensor Error", 16); // 显示传感器错误
OLED_Refresh(); // 刷新屏幕
delay_ms(5000); // 延时5秒
OLED_Clear(); // 清屏
}
}
}

相关链接

实验测试

LED驱动

新建Hardware文件夹来存放驱动文件

其中LED.hLED.c为LED的驱动文件

LED硬件电路如下图所示

LED硬件电路

  • 红色LED在PB5
  • 绿色LED在PB0
  • 蓝色LED在PB1
  • 红绿蓝LED均为低电平点亮,共阳极接法

LED.c中定义红色LED的驱动函数

  • LED_R_Init():初始化红色LED
  • LED_R_ON():点亮红色LED
  • LED_R_OFF():熄灭红色LED
  • LED_R_Turn():翻转红色LED状态
1
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
#include "stm32f10x.h"                  // Device header

// 初始化红色LED(PB5)
void LED_R_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 打开GPIOB时钟

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 配置为推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // 配置端口为5
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 配置端口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); // 完成PB5初始化
}

// 点亮红色LED(低电平点亮)
void LED_R_ON(void)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_5);
}

// 熄灭红色LED(高电平熄灭)
void LED_R_OFF(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_5);
}

// 翻转LED状态
void LED_R_Turn(void)
{
if (0 == GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_5))
{
GPIO_SetBits(GPIOB, GPIO_Pin_5); // PB5低电平时设置为高电平
}
else
{
GPIO_ResetBits(GPIOB, GPIO_Pin_5); // PB5高电平时设置为低电平
}
}

````

在`LED.h`中提供函数接口

```c
#ifndef __LED_H
#define __LED_H

void LED_R_Init(void); // LED_R初始化
void LED_R_ON(void); // LED_R点亮函数
void LED_R_OFF(void); // LED_R熄灭函数
void LED_R_Turn(void); // LED_R翻转状态函数

#endif

按键驱动

按键接在PA0引脚, 按键按下PA0为高电平

按键的硬件连接图如下图所示

按键连接图

配置PA0引脚为下拉输入模式

KEY.c定义按键的驱动函数

1
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
#include "stm32f10x.h"                  // Device header
#include "Delay.h" // 延时模块

// 初始化按键PA0
void KEY_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 打开GPIOA时钟

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // 配置下拉输入模式,默认低电平
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 配置端口0
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 配置输出速度50MHz不影响输入模式
GPIO_Init(GPIOA, &GPIO_InitStructure); // 完成初始化
}

// 按键按下返回1
uint8_t KEY_GetNum(void)
{
uint8_t KEYNum = 0;
if (1 == GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) // 按键按下PA0为高电平
{
Delay_ms(20); // 按下按键延时消抖
while (1 == GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0))
{
;
}
Delay_ms(20); // 松开按键延时消抖
KEYNum = 1; // 按键按下KEYNum为1
}

return KEYNum;
}

KEY.h中提供函数接口

1
2
3
4
5
6
7
8
#ifndef __KEY_H
#define __KEY_H

void KEY_Init(void); // 按键初始化函数
uint8_t KEY_GetNum(void); // 读取按键函数

#endif

软件设计

执行流程

  1. main.c中定义全局变量KEYNum用来存储按键状态
  2. 进行LED和按键的初始化
  3. 在while循环中不断读取按键的状态并存储在KEYNum中
  4. 判断按键是否按下,按下则翻转LED状态,未按下则不执行翻转操作

main.c中实现主控制流程

1
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
/*
* 实验目标:实现按键控制LED点亮
* 硬件连接: 红色LED接在PB5, 按键接在PA0
*/

#include "stm32f10x.h"
#include "Delay.h"
#include "LED.h"
#include "KEY.h"

uint8_t KEYNum = 0; // 全局变量KEYNum

int main(void)
{
// 初始化红色LED
LED_R_Init();
// 初始化按键
KEY_Init();

while (1)
{
KEYNum = KEY_GetNum(); // 读取按键值
if (1 == KEYNum) // 按键按下
{
LED_R_Turn();
}

}
}

相关链接

理论知识

GPIO简介

共八种输入输出模式,引脚电平为0V~3.3V, 部分引脚可容忍5V电平。

  • 输出模式下可控制端口输出输出高低电平,用来驱动led,蜂鸣器,模拟通信协议输出时序等。
  • 输入模式下可读取端口的高低电平或电压值,用来读取案件输入,外接模块电平信号输入,ADC电压采集,模拟通信协议接收数据等。

GPIO基本结构

GPIO基本结构

GPIO位结构

GPIO位结构

IO引脚(0~3.3V)

  • 上保护二极管: 如果输入电压大于3.3V, 二极管导通,电流流入VDD引脚,保护内部电路。
  • 下保护二极管: 如果输入电压小于0V, 二极管导通,电流流出IO引脚,保护内部电路。

输入驱动器

  1. 上拉输入模式:上面导通,下面断开,连接到VDD, 当IO引脚悬空时,输入电平默认为高电平。
  2. 下拉输入模式:下面导通,上面断开,连接到VSS, 当IO引脚悬空时,输入电平默认为低电平。
  3. 浮空输入模式:上面和下面都断开,当IO引脚悬空时,输入电平不确定。
  4. 施密特触发器:肖特基触发器为翻译错误,实际应为施密特触发器,作用为当输入电压高于某一阈值时,输出高电平,当输入电压低于某一阈值时,输出低电平。
  5. 模拟输入: 在进入施密特触发器前引出来,输入电压范围为0V~3.3V, 适合ADC采集。
  6. 复用功能输入:经过施密特触发器后引出,为数字量。
  7. 读出:经过施密特触发器后进入输入数据寄存器,读出数据。

输出寄存器

  1. 位设置/清除寄存器:可单独设置或清除某一位的数据且不影响其他位。
  2. 输出数据寄存器:同时控制16个端口且只能整体读写。
  3. 推挽输出模式:PMOS和NMOS均有效,数据寄存器为1时上管导通,下管断开,输出为VDD即高电平;数据寄存器为0是下管导通,上管断开,输出为VSS即低电平,高低电平均有驱动能力。
  4. 开漏输出模式:PMOS无效,数据寄存器为1时下管断开,输出为高组态模式;数据寄存器为0时下管导通,输出为低电平,对高电平没有驱动能力,可作为I2C的通信引脚,在多级通讯下可避免设备干扰,还可以用于输出5V的电平信号。
  5. 关闭输出:当引脚配置为输入模式时,PMOSS和NMOS均无效,端口电平由外部电平控制。

GPIO模式

GPIO模式

GPIO模式

浮空/上拉/下拉输入

输入浮空/上拉/下拉配置

模拟输入

模拟输入

开漏/推挽输出

开漏/推挽输出

复用开漏/推挽输出

复用开漏/推挽输出

实验测试

实验目标

使用GPIO输出高低电平,控制LED灯的亮灭。

LED硬件电路图

LED硬件连线电路图

LED红绿蓝均为低电平点亮,红灯接PB5,绿灯接PB0,蓝灯接PB1。

软件设计

PB5(红灯)为GPIO输出模式,推挽输出模式。低电平点亮。

添加系统延时模块在System文件夹下

Delay.c中定义

1
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
#include "stm32f10x.h"

/**
* @brief 微秒级延时
* @param xus 延时时长,范围:0~233015
* @retval 无
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}

/**
* @brief 毫秒级延时
* @param xms 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}

/**
* @brief 秒级延时
* @param xs 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_s(uint32_t xs)
{
while(xs--)
{
Delay_ms(1000);
}
}


Delay.h中声明

1
2
3
4
5
6
7
8
9
#ifndef __DELAY_H
#define __DELAY_H

void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);

#endif

在主函数中控制LED闪烁

  1. 打开GPIOB时钟
  2. 初始化GPIOB,设置PB5为推挽输出模式,速度50MHz
  3. 进入死循环,先将PB5拉低,延时500ms,再将PB5拉高,延时500ms。

代码如下

1
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
/*
* 实验目标:实现LED红灯闪烁,接在PB5,低电平点亮
*/

#include "stm32f10x.h"
#include "Delay.h"


int main(void)
{
// 打开GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

// 初始化GPIOB
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // Pin5
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);

while (1)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_5); // 低电平点亮
Delay_ms(500); // 500ms延时
GPIO_SetBits(GPIOB, GPIO_Pin_5); // 高电平熄灭
Delay_ms(500); // 500ms延时
}
}

基础安装和使用

下载nodejs和npm

nodejs下载地址

安装hexo

1
nmp install -g hexo-cli

使用hexo

在你想要创建博客的目录下执行以下命令:

1
hexo init

这会在当前目录下创建一个新的hexo项目。

常用命令

1
2
3
4
5
hexo new "post title" # 创建一篇新的文章
hexo g # 生成静态文件
hexo s # 启动本地服务器
hexo d # 部署到远端服务器
hexo clear # 清除缓存

部署到github

github创建仓库

仓库名为username.github.io,其中username为你的github用户名。

安装部署到github的依赖

1
npm install --save hexo-deployer-git 

修改hexo配置文件

修改_config.yml文件,修改以下内容:

1
2
3
4
5
6
# Deployment
## Docs: https://hexo.io/docs/one-command-deployment
deploy:
type: git
repo: # 刚刚创建的仓库地址
branch: master

此时使用 hexo d 即可将博客部署到github上。

主题美化

安装主题

在hexo目录下执行以下命令来安装next主题:

1
npm install hexo-theme-next

升级主题

1
npm install hexo-theme-next@latest

配置文件

1
2
# Installed through npm
cp node_modules/hexo-theme-next/_config.yml _config.next.yml

修改hexo配置文件

打开_config.yml文件,修改以下内容:

1
theme: next

修改主题配置文件

打开_config.next.yml文件,修改以下内容:

1
2
3
4
5
6
7
8
# Allow to cache content generation.
cache:
enable: true

#scheme: Muse
scheme: Mist
#scheme: Pisces
#scheme: Gemini

配置标签功能

在根目录下输入

1
hexo new page tags

默认在source\tags\index.md中创建

修改index.md文件,添加以下内容:

即添加type: “tags”

1
2
3
4
5
---
title: tags
date: 2025-04-18 06:00:31
type: "tags"
---

修改_config-next.yml文件,修改以下内容:

1
2
3
# themes\scallop\_config.yml
menu:
tags: /tags/ || fa fa-tags

在文章中添加tags标签即可

1
2
3
4
5
6
7
---
title: EXTI外部中断
date: 2025-04-18 05:52:58
tags:
- STM32
- EXTI
---

安装搜索功能

安装搜索插件

1
npm install hexo-generator-searchdb

修改hexo配置文件

打开_config.yml文件,添加以下内容:

1
2
3
4
5
search:
path: search.xml
field: post
content: true
format: html

修改主题配置文件

打开_config.next.yml文件,添加以下内容:

1
2
3
4
5
6
7
8
9
10
# Local search
# Dependencies: https://github.com/next-theme/hexo-generator-searchdb
local_search:
enable: true
# Show top n results per article, show all results by setting to -1
top_n_per_article: 1
# Unescape html strings to the readable one.
unescape: false
# Preload the search data when the page loads.
preload: false

安装评论功能

使用LiveRe

登录LiveRe并安装

LiveRe链接

安装完成后找到data-uid

LiveRe data-uid链接

复制data-uid = 后的内容

修改主题配置文件

打开_config.next.yml文件,添加以下内容:

1
2
3
# Support for LiveRe comments system.
# You can get your uid from https://livere.com/insight/myCode (General web site)
livere_uid: "your_uid"

外部库功能

功能描述

fancybox和mediumzoom不要同时启用

1
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
# Easily enable fast Ajax navigation on your website.
# For more information: https://github.com/next-theme/pjax
pjax: true

fancybox: true

# Vanilla JavaScript plugin for lazyloading images.
lazyload: true

# Pangu Support
pangu: true

...
quicklink:
enable: true
home: true
archive: true
delay: true
timeout: 3000
priority: true
...

# Use Animate.css to animate everything.
# For more information: https://animate.style
motion:
enable: true
async: false
transition:
# All available Transition variants: https://theme-next.js.org/animate/
menu_item: fadeInDown
post_block: fadeIn
post_header: fadeInDown
post_body: fadeInDown
coll_header: fadeInLeft
# Only for Pisces | Gemini.
sidebar: fadeInUp

pace:
enable: true

canvas_ribbon:
enable: true
size: 300
alpha: 0.6
zIndex: -1

参考链接

Next主题使用说明
B站视频链接Codesheep

0%