当前位置: 首页 > news >正文

Arduino与Visuino图形化编程:电位器模拟仪表OLED显示项目实践

1. 项目概述:从电位器到屏幕指针的旅程

在嵌入式开发里,给一个抽象的模拟量(比如温度、压力、音量或者速度)配上一个直观的、像传统机械表盘一样的可视化指示器,是个既经典又实用的需求。它比单纯的数字显示更能给人“量感”,一眼就能看出当前值是偏左(低)还是偏右(高)。这次,我们就用最常见的Arduino Uno、一个旋钮电位器、一块小巧的OLED屏,来亲手搭建一个这样的模拟仪表。整个过程,我们会借助一个叫Visuino的图形化工具来编程,它能让你像搭积木一样连接逻辑,特别适合快速原型开发或者对传统代码编写不那么熟悉的朋友。这个项目麻雀虽小,但五脏俱全,涵盖了模拟信号采集、数值处理、图形界面绘制这几个嵌入式系统的核心环节,做完它,你对如何让硬件“说话”会有更实在的理解。

2. 核心思路与方案选型解析

2.1 为什么选择“模拟仪表”这种形式?

数字显示(比如直接显示“75%”)当然精确,但在很多需要快速感知状态变化的场景下,一个摆动的指针或者一个填充的弧线,其传递信息的效率更高。想象一下汽车的速度表,如果只是一串数字跳动,远不如指针的扫动来得直观。我们这个项目要实现的,就是这种模拟仪表的电子版本。它的核心价值在于将连续的物理量(电位器旋钮的角度)映射为连续的视觉反馈(屏幕上的指针角度),构建起从物理世界到数字世界再到视觉世界的流畅桥梁。

2.2 硬件选型背后的考量

主控:Arduino Uno。选择它几乎不需要理由:生态庞大、资料极多、引脚兼容性好。它内置的10位精度ADC(模数转换器),足以应对我们这个项目对电位器电压的读取需求。当然,任何带有ADC功能的Arduino板(如Nano、Mega)都可以直接替换。

信号源:电位器。这里我们用它来模拟一个连续的模拟信号输入。电位器本质上是一个可调电阻,旋转旋钮改变电阻值,从而在中间引脚输出一个0V到5V之间可变的电压。这模拟了各种传感器(如光照、距离、压力传感器)的输出行为。选择它是因为它成本极低,且提供了最直接的、人手可交互的输入方式,方便调试和演示。

显示单元:OLED显示屏(I2C接口)。为什么是OLED而不是LCD?首先,OLED是自发光,对比度高,显示黑色时像素完全关闭,视觉上更“锐利”,尤其适合绘制精细的图形和指针。其次,我们选用的是I2C接口的版本,它只需要两根数据线(SDA, SCL)加上电源和地,总共四根线就能驱动,极大简化了布线。对于这种小型化、低功耗的指示器项目,OLED是更优解。

开发工具:Visuino。这是一个基于图形化数据流编程的Arduino开发环境。它的优势在于,你将编程逻辑可视化为一个个的“组件”和连接它们的“线”,这对于理解数据流向、快速搭建原型、以及避免繁琐的语法错误非常有帮助。特别适合教育、艺术创作和快速验证想法的场景。当然,它的灵活性可能不如直接写代码,但对于本项目而言,它能让焦点集中在“逻辑实现”而非“语法实现”上。

注意:Visuino有免费版本,但功能可能受限。对于个人学习和非商业项目,免费版通常足够。请从其官网下载并确认许可协议。

2.3 系统工作流程总览

整个系统的工作链条非常清晰:

  1. 信号采集:Arduino通过模拟输入引脚A0,持续读取电位器中间引脚输出的电压值(0-5V),并将其转换为一个0到1023之间的整数(因为ADC是10位精度,2^10=1024)。
  2. 数值处理:这个0-1023的原始值需要经过两步处理。第一步是缩放,将其乘以一个系数,转换成我们想显示的物理量范围(例如0-100代表百分比)。第二步是映射,将缩放后的物理量数值,映射到屏幕指针需要旋转的角度范围(例如-90度到+90度)。
  3. 图形渲染:处理后的角度值被送入OLED显示组件。Visuino中的显示组件会依据这个角度值,在每一帧刷新时,重新绘制表盘背景(椭圆)、指针(旋转直线)以及当前数值文本。
  4. 实时更新:上述过程在Arduino的loop函数中高速循环执行,因此当我们旋转电位器时,屏幕上的指针和数值会近乎实时地跟随变化。

3. 硬件连接与电路搭建详解

正确的硬件连接是项目成功的第一步。虽然原理简单,但接错线是新手最常遇到的问题。下面我们一步步来,并解释每一根线的作用。

3.1 元器件引脚识别

在动手之前,务必认清你手中元件的每个引脚:

  • 电位器:通常有三个引脚。两侧的引脚分别接电源(VCC, 如5V)和地(GND)。中间引脚是信号输出(OUT或Wiper),它的电压会随着旋钮转动在VCC和GND之间线性变化。
  • OLED显示屏(I2C):常见的四针模块,引脚标识通常为:
    • GND:电源地。
    • VCC:电源正极,接5V。
    • SCL:I2C时钟线。
    • SDA:I2C数据线。
    • 有些模块可能还有RESET引脚,如果存在,通常可以悬空或接高电平(通过一个电阻上拉到VCC),具体需参考模块手册。我们使用的通用模块通常内部已处理好。

3.2 分步连接指南

建议使用面包板进行连接,这样既安全又便于修改。请严格按照以下顺序和说明操作:

  1. 为面包板供电:将Arduino Uno的5V引脚连接到面包板的正极电源轨(通常标有红色“+”),将GND引脚连接到面包板的负极电源轨(通常标有蓝色“-”)。这样,整个面包板就有了统一的5V电源和地参考。

  2. 连接电位器

    • 将电位器左侧引脚(或任意一个外侧引脚)插入面包板,并用一根跳线将其连接到面包板的正极电源轨(5V)
    • 将电位器右侧引脚(与上一步相对的另一个外侧引脚)插入面包板,并用跳线连接到负极电源轨(GND)
    • 将电位器的中间引脚插入面包板,用一根跳线连接到Arduino的模拟输入引脚 A0
    • 原理:这样连接后,旋转电位器,中间引脚的电压就在0V到5V之间变化,并被A0引脚读取。
  3. 连接OLED显示屏

    • 将OLED模块的GND引脚用跳线连接到面包板的负极电源轨(GND)
    • 将OLED模块的VCC引脚用跳线连接到面包板的正极电源轨(5V)
    • 将OLED模块的SDA引脚用跳线连接到Arduino Uno上标有SDA的引脚。在Uno上,这通常是A4引脚(在靠近AREF引脚的地方也有“SDA”标识)。
    • 将OLED模块的SCL引脚用跳线连接到Arduino Uno上标有SCL的引脚。在Uno上,这通常是A5引脚(同样有“SCL”标识)。
    • 原理:I2C是一种两线制串行通信协议,SCL是时钟线,SDA是数据线。Arduino通过这两根线与OLED屏通信,发送绘图指令。

实操心得:连接I2C设备时,务必确保SDA和SCL没有接反。一个快速记忆方法是:SDA是数据(Data),它需要“流动”,所以接到A4;SCL是时钟(Clock),它提供节奏,接到A5。另外,虽然I2C总线上可以挂多个设备,但在这个简单项目中,我们只接了一个OLED,所以不需要考虑地址冲突和上拉电阻问题(大多数OLED模块已内置上拉电阻)。

3.3 连接完成检查清单

在通电前,花一分钟对照下表检查你的连接,可以避免烧坏元件:

元件引脚连接到 Arduino/面包板检查点
电位器左侧/引脚1面包板5V电源轨电压供给正确
右侧/引脚3面包板GND电源轨接地良好
中间/引脚2A0模拟输入引脚信号线连接牢固
OLED屏GND面包板GND电源轨共地,确保逻辑电平一致
VCC面包板5V电源轨供电电压匹配(勿接3.3V)
SDASDA (A4)引脚I2C数据线正确
SCLSCL (A5)引脚I2C时钟线正确

确认无误后,用USB线将Arduino Uno连接到电脑,准备进行软件部分的配置。

4. 使用Visuino进行图形化编程

Visuino的核心思想是“数据流”。我们将通过拖放组件并连接它们的“引脚”来构建程序逻辑。请跟随以下步骤,并理解每个操作的意义。

4.1 软件初始化与项目设置

  1. 启动Visuino。首次运行可能会要求你选择语言和设置Arduino IDE路径。确保它已正确指向你的Arduino IDE安装目录,因为最终编译需要调用它。
  2. 创建一个新项目。在左侧的组件面板中,找到并拖拽一个Arduino组件到设计区域。这代表了你的物理Arduino板。
  3. 配置板卡类型:点击设计区域中的Arduino组件,在右下角的属性面板中,找到Board属性。点击下拉菜单,选择Arduino UNO(或者你实际使用的板卡型号)。这一步至关重要,它确保了后续的引脚定义和编译选项正确。

4.2 添加并配置处理组件

我们需要三个核心处理组件来搭建数据流管道。

  1. 添加“乘系数”组件

    • 在左侧组件面板的Filters分类下,找到Multiply Analog By Value组件,将其拖到设计区域。这个组件的作用是将输入的模拟值乘以一个固定的系数。
    • 点击该组件,在属性面板中找到Value属性,将其设置为100
    • 为什么是100?Arduino ADC读取的原始值是0-1023。如果我们想把它直观地显示为百分比(0%-100%),最直接的方法就是(原始值 / 1023) * 100。Visuino的Multiply By Value组件做的是乘法,而除法可以通过后续的映射范围来实现,但这里我们先乘以100,是为了让数值变大,方便后续映射到角度时精度更高。你也可以将其理解为“放大100倍后的原始值”,后续映射时会将其对应到0-100的范围。
  2. 添加“映射范围”组件

    • Math分类下,找到Map Range Analog组件,拖到设计区域。这个组件是核心,它负责将一个输入范围线性映射到另一个输出范围。
    • 点击该组件,在属性面板中设置:
      • Input Range Max:1023(这是ADC原始最大值)
      • Input Range Min:0(这是ADC原始最小值)
      • Output Range Max:0(注意,这里设置的是映射后的最大值)
      • Output Range Min:-180(这里设置的是映射后的最小值)
    • 角度映射逻辑解析:我们希望电位器拧到最左(ADC值0)时,指针指向最左边(比如-90度);拧到最右(ADC值1023)时,指针指向最右边(+90度)。但Visuino中Draw Angled Line组件的0度是水平向右(3点钟方向)。为了实现-90度(垂直向上)到+90度(垂直向下)的扫动,一个常见的技巧是将输出范围设置为-1800。这样,当输入为0时,输出-180度(相当于从0度逆时针转180度,即垂直向上?这里需要校准)。实际上,我们需要根据屏幕坐标和起始角度来调整。原教程设置Output Min-180Output Max0,结合指针起始角度设为-10度,是为了让映射后的角度变化能驱动指针在屏幕上大约从左上(-10-180?)摆动到右下。关键在于理解这是一个线性变换y = (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min。你可以根据想要的指针摆动范围,灵活调整这四个参数。
  3. 添加并配置OLED显示组件

    • Displays->OLED分类下,找到OLED I2C组件,拖到设计区域。
    • 双击设计区域中的DisplayOLED1组件,会弹出一个“元素”窗口。这里我们将添加构成表盘的各种图形元素。
    • 添加表盘背景(椭圆):在元素窗口左侧,找到Draw Ellipse(绘制椭圆)元素,将其拖拽到右侧的“元素”区域。点击它,在属性面板中设置:
      • Width(宽度):124
      • Height(高度):124
      • Y:20(这是椭圆左上角的Y坐标,用于在屏幕上垂直居中)
      • X通常会自动计算居中,可以不管或设为2
      • 作用:这个椭圆将作为我们模拟仪表的圆形外框。
    • 添加清屏指令:找到Fill Screen(填充屏幕)元素,拖到右侧。这个元素必须添加,且通常需要放在其他绘图元素之前(在元素列表中靠上)。它的作用是在每一帧绘制前,用黑色(默认)清除整个屏幕,避免上一帧的图像残留。保持其属性默认即可。
    • 添加指针(旋转直线):找到Draw Angled Line(绘制角度线)元素,拖到右侧。这是最关键的动态元素。点击它,在属性面板中设置:
      • X:64(屏幕水平中心,假设屏幕宽度128)
      • Y:63(屏幕垂直中心附近,假设屏幕高度64,这里作为指针旋转的圆心)
      • End:60(指针的长度,从圆心算起)
      • Angle:-10(指针的起始角度。0度为水平向右。设为-10度让指针初始位置略向上倾斜,看起来更自然)
      • 接下来,需要将角度绑定到动态输入。在Angle属性右侧,有一个小的“引脚”图标。点击这个图标,会弹出一个菜单,选择Float SinkPin。这会在该元素上创建一个名为“Angle”的输入引脚,用于接收外部传入的角度值。
    • 添加数值显示(文本):找到Text Field(文本域)元素,拖到右侧。点击它,在属性面板中设置:
      • X:50(文本显示的X坐标)
      • Y:50(文本显示的Y坐标,可以放在表盘下方)
      • 同样,需要绑定文本内容。找到Text属性或In引脚(可能默认已存在),确保它有一个输入引脚用于接收要显示的数值字符串。
    • 配置完成后,关闭“元素”窗口。

4.3 连接数据流:像接线一样编程

现在回到主设计区域,我们将用“线”把各个组件的“引脚”连接起来,定义数据流向。

  1. 连接信号源:点击Arduino组件,你会看到它周围出现很多引脚。找到代表模拟引脚0的Analog Pin 0的输出引脚(通常是一个小圆点)。点击并拖动,拉出一根线,分别连接到MapRange1组件的In引脚和MultiplyByValue1组件的In引脚。这意味着Arduino读取到的原始ADC值,同时发送给“映射”和“乘系数”两个处理通道。

  2. 连接映射输出到图形元素

    • MapRange1组件的Out引脚,连接到DisplayOLED1组件上。当你把线拖到DisplayOLED1附近时,会弹出其所有可用的输入引脚。
    • 你需要将这条线多次连接到以下引脚:
      • Fill Screen1Clock引脚:这告诉清屏元素,每当有新角度值时,就执行一次清屏。
      • Draw Ellipse1Clock引脚:同样,更新角度时重绘表盘边框。
      • Draw Angled Line1Angle引脚:这是最关键的一步!将计算出的角度值直接驱动指针旋转。
      • Draw Angled Line1Clock引脚:触发指针绘制。
    • 为什么都要接Clock?在Visuino中,很多图形元素的Clock引脚是一个“触发”引脚。当有信号(任何值)到达这个引脚时,元素就会执行一次绘制操作。我们把角度输出的变化同时触发所有元素的重绘,确保了屏幕刷新的同步性。
  3. 连接数值显示:将MultiplyByValue1组件的Out引脚,连接到DisplayOLED1组件中Text Field1In引脚。这样,放大后的ADC值(0-102300)就会作为文本显示出来。注意,此时显示的是原始ADC值乘以100后的数,范围是0-102300,看起来很大。一个更常见的做法是,在MultiplyByValue1之后,再添加一个Divide By Value组件除以1023,再乘以100,才能得到真正的百分比。原教程可能简化了这一步,或者依赖文本字段的格式设置。我们可以在Visuino中搜索“Format”相关组件来处理这个数值,将其格式化为整数百分比。

  4. 连接I2C通信:最后,将DisplayOLED1组件上的I2C输出引脚(或Out引脚),连接到Arduino组件上的I2C输入引脚。这建立了微控制器与显示屏之间的通信链路。

至此,你的Visuino设计图应该是一个清晰的流程图:Arduino[A0]->MapRange&Multiply->OLED的各种绘图元素。

5. 代码生成、编译与上传

图形化编程完成后,Visuino会将其转换为Arduino标准的C++代码(基于Wiring框架),并调用Arduino IDE进行编译和上传。

  1. 在Visuino界面底部,切换到Build选项卡。
  2. Port下拉菜单中,选择你的Arduino Uno所连接的串口(在Windows设备管理器中通常是COMx,在macOS/Linux上是/dev/tty.usbmodemxxx)。
  3. 确保Board已正确选择为“Arduino Uno”。
  4. 点击Compile/Build and Upload按钮。
  5. Visuino会开始后台工作:
    • 生成代码:将图形设计转换为.ino文件。
    • 编译:调用Arduino IDE的编译器,将代码和所有库编译成机器码。第一次编译可能会花费较长时间,因为需要下载和编译OLED显示库(如Adafruit_GFXAdafruit_SSD1306),Visuino通常会自动处理这些依赖。
    • 上传:通过串口将编译好的程序烧录到Arduino Uno的芯片中。
  6. 观察Arduino Uno板上的TX/RX指示灯会闪烁,表示正在上传。上传成功后,Visuino会提示“Done uploading”。

实操心得:编译过程中最常见的错误是库缺失或端口被占用。如果报错,首先检查Visuino的偏好设置中,Arduino IDE的路径是否正确。其次,确保Arduino IDE没有在后台打开并占用了同一个串口。最后,可以尝试在Visuino的“Tools”菜单下,手动安装可能缺失的库。

6. 功能测试与效果调优

上传成功后,Arduino会自动重启运行新程序。此时,你可以旋转电位器,观察OLED屏幕的变化。

预期效果:屏幕中央应该显示一个椭圆形的表盘,一根指针会随着电位器的旋转而摆动。同时,屏幕某处会显示一个变化的数字(可能是很大的数)。

如果屏幕没有显示或显示异常,请按以下步骤排查

  1. 检查电源:确认OLED屏的VCC和GND是否接反或接触不良。屏幕是否微微发热?有些OLED屏接反电源会瞬间损坏。
  2. 检查I2C连接:确认SDA和SCL是否接对(Arduino Uno上是A4和A5)。可以尝试交换这两根线。
  3. 检查电位器连接:确认电位器的中间引脚确实接到了A0,并且两侧引脚分别接5V和GND。
  4. 检查程序逻辑:回到Visuino,确认每一个连接线都准确无误,特别是MapRange1的输出是否连接到了Draw Angled Line1Angle引脚。
  5. 调整映射参数:如果指针摆动范围不是你想要的(例如,不能覆盖整个屏幕,或者方向反了),不要慌,这是正常的。你需要调整MapRange1组件的Output Range MinOutput Range Max这两个参数。这是一个试错和校准的过程。例如,如果你发现指针只在很小范围内移动,可以尝试将输出范围拉大,比如从(-180, 0)改为(-270, 90)。如果指针转动方向与电位器旋转方向相反,则交换Output Range MinOutput Range Max的值。

数值显示优化:如前所述,直接显示ADC值*100不直观。我们可以在Visuino中改进:

  1. MultiplyByValue1组件之后,添加一个Divide By Value组件(在Filters分类里)。
  2. 设置Divide By Value组件的Value10.23。因为(ADC * 100) / 10.23 ≈ ADC * 9.77 ≈ ADC / 102.3,这能将0-102300的数值近似映射到0-1000。要得到百分比,可以再除以10,或者直接修改除数。
  3. 更精确的做法是:MultiplyByValue1的系数设为100.0,然后Divide By Value的除数设为1023.0,这样输出就是精确的百分比了(浮点数)。再将这个结果连接到一个Format Value组件(在Data->Text分类里),设置格式为固定小数点后1位或直接取整,最后输出给Text Field1

7. 项目扩展与进阶思路

这个基础项目就像一个乐高底座,你可以在此基础上添加无数创意。

  1. 更换信号源:将电位器替换成真正的传感器。

    • 光照强度表:使用光敏电阻(LDR)配合一个固定电阻组成分压电路,接A0。映射范围调整为室内光照的合理lux值范围。
    • 温度表:使用LM35或DS18B20温度传感器。LM35输出模拟电压(10mV/°C),可直接接ADC。DS18B20是数字传感器,需要使用OneWire库读取,然后将温度值通过一个Analog Value组件(在Math里)转换成模拟信号流,接入现有的处理管道。
    • 音量表(VU表):使用麦克风模块(如MAX9814)。这类模块通常输出模拟电压,其幅值随声音大小变化。你可以取一段时间的电压峰值或平均值,经过映射后驱动指针,就能实现一个简单的音频电平指示器。
  2. 美化界面:Visuino的OLED组件支持更多绘图元素。

    • 添加刻度:使用多个Draw Angled Line元素,将它们的Angle属性固定为不同的值(如-90, -45, 0, 45, 90),长度稍短,作为表盘上的刻度线。
    • 添加刻度标签:使用多个Text Field元素,放置在刻度线末端,静态显示“0”, “50”, “100%”等文字。
    • 改变指针样式Draw Angled Line只能画直线。你可以尝试用Draw Polygon(多边形)画一个三角形指针,但这需要更复杂的坐标计算。
  3. 增加功能

    • 峰值保持:添加一个Max组件(在Math->Analog里),将处理后的信号输入,其输出可以驱动另一个指针或一个条形图,显示历史最大值,并在一定时间后缓慢回落。
    • 报警指示:添加一个Compare Analog组件(在Logic->Analog里)。设置一个阈值(比如80%),当输入值超过阈值时,其输出会变为高电平。你可以将这个输出连接到一个Draw Rectangle元素(设置为红色填充)的Clock引脚,并设置其Enabled引脚由比较器控制,从而实现超限报警(屏幕某处变红)。
  4. 脱离Visuino,用代码实现:当你理解了整个数据流和原理后,可以尝试用Arduino IDE直接编写代码。你需要掌握:

    • analogRead()函数读取ADC。
    • map()函数进行数值映射。
    • Adafruit_SSD1306Adafruit_GFX库来驱动OLED绘图。
    • loop()中不断读取、计算、绘制。这能给你带来更大的灵活性和对细节的完全控制。

这个项目成功的关键,不在于完全复现教程,而在于理解“模拟信号->数字量->映射处理->图形渲染”这条核心链路。Visuino帮你可视化地搭建了这条链路,而链路中的每一个环节,都对应着嵌入式系统中的一个基本概念。动手调一调参数,改一改连接,甚至故意接错线看看现象,你的收获会比单纯照做要大得多。

http://www.jsqmd.com/news/924880/

相关文章:

  • 2026暑假四川7天6晚家庭游导游推荐|舒适路线规划与真实体验 - 随峰国旅
  • 如何突破原神60帧限制:终极帧率解锁工具完整指南
  • 3大核心功能解锁:用GHelper释放华硕笔记本隐藏性能
  • Harness Engineering:Agent上下文动态扩展优化
  • 树莓派4B改装AtGames街机:单电源供电与GPIO状态指示实战
  • 【Redis】线上并发三大灾难
  • 基于APDS-9960与Arduino的智能篮球框:非接触式进球检测与声光反馈系统
  • 2026年实用降AI率工具:实测AI率从90%降至4%的靠谱方案 - 降AI小能手
  • 口碑好的永康软件开发企业 - 企业推荐官【官方】
  • 5步快速上手IguanaTex:免费LaTeX公式插入PowerPoint终极指南
  • 2026温州中央空调多联机维修|专业高效检修,首选满意家电维修 - 资讯纵览
  • 现在不升级Gemini邮件工作流,30天后将面临iOS 18邮件智能过滤降权(附紧急迁移路线图)
  • 茉莉花插件:3个核心功能彻底改变你的中文文献管理体验
  • 如何用res-downloader轻松保存微信视频号等平台内容:完整下载指南
  • 考试报名用的免费证件照制作入口有哪些?2026各类考试报名照片免费制作工具汇总 - 科技大爆炸
  • 如何高效实现Switch与Wii U跨平台存档转换:BotW-Save-Manager完全指南
  • 避坑指南:给GTX750/1050装CUDA,千万别踩‘DCH驱动’和‘PyTorch版本’这两个大坑
  • 苏州管道循环泵生产厂商排行榜 - 品牌推广大师
  • B站视频怎么下载2026全场景操作解析含合规方式与风险规避技巧
  • 2026 年 05 月博物馆通柜上门测量服务全流程技术细节与避坑指南 - 奔跑123
  • Arduino智能时钟:光敏传感器触发与舵机控制的交互装置制作
  • 保定家庭教育指导师报名入口在哪?授权机构中山优才教育说明 - 当下教育培训干货
  • 5步永久备份QQ空间:GetQzonehistory让青春回忆永不丢失
  • 基于Arduino与电感传感的智能减速带系统设计与实现
  • 资源编号298_疯狂动物城主题高德地图车机版9.1.0.600087正式版分支魔改
  • 2026劳力士售后升级公告:官方维修门店新址落地最新服务热线同步开通 - 资讯纵览
  • 视频号怎么保存到相册安卓苹果全机型通用高清保存操作详解
  • 终极指南:RevokeMsgPatcher如何实现Windows微信QQ消息防撤回与多开功能
  • 别再只关心快充瓦数了!手把手教你读懂USB PD协议里的Source、Sink和角色互换
  • 基于Arduino与状态机的智能抢答器系统:从硬件到软件的完整实现