从硬件到代码:Pico 模拟电位器 ADC 采集实战(含 LED 控制与 SerialPlot 串口波形采集)

模拟电位器是电子设备中常见的组件,用于调整电压或电流。它通过物理旋转来改变电阻值,从而改变输出信号的强度。简单来说,电位器是一个可调电阻器,通常有三个引脚:两个外侧引脚连接到电阻器的两端,中间引脚(滑动触点)可以移动,从而改变与电阻器两端的接触点位置;当旋转电位器时,中间引脚与两端引脚之间的电阻会发生变化。这可以用来调整电压分布,从而实现对输出信号的控制。

1.PNG
常用的 RK09L1240A12 型电位器

这里,我们定时采集模拟电位器上的电压值,并根据其电压值调节板载 LED 灯亮度,同时将电压值通过串口发送给 SerialPlot 串口绘图仪查看电压波形。

这里,我们需要将风雅一号板-通用兼容扩展板插入到风雅一号板-LCD屏幕人机交互板上,同时打开风雅一号板-LCD屏幕人机交互板SWITCH2 拨码开关的 POT 选项,实物连接图如下所示:

2.JPEG

3.PNG

4.JPEG

除此之外,我们还需要将 MiniUSB 数据线连接到风雅一号板-通用兼容扩展板上的串口,这里,GP0GP1 是树莓派 Pico 的硬件串口 UART0 的默认引脚:

5.JPEG

器件接线情况如下表所示:

6.png

以下代码可以在我们提供的资料包中 elegance-devkit v1\Demo\58 ADC_Potentiometer 文件夹找到。

示例代码如下所示:

# Python env   : MicroPython v1.23.0
# -*- coding: utf-8 -*-        
# @Time    : 2024/8/27 上午11:33   
# @Author  : 李清水            
# @File    : main.py       
# @Description : ADC类实验,读取电位器两端电压

# ======================================== 导入相关模块 ========================================

# 导入硬件模块
from machine import ADC, Timer, Pin, PWM, UART
# 导入时间相关模块
import time
# 导入访问和控制 MicroPython 内部结构的模块
import micropython

# ======================================== 全局变量 ============================================

# ======================================== 功能函数 ============================================

# 用户自定义回调函数
def user_callback(value: float) -> None:
    """
​    用户自定义的回调函数,用于打印采集到的模拟电位器电压值。

​    Args:
​        value (float): 采集到的模拟电位器电压值。

​    Returns:
​        None
​    """

​    ​# 声明全局变量
    global LED, uart

    # 打印采集到的模拟电位器电压值
    print("Analog potentiometer value is %f" % value)
    # 调整LED的占空比,占空比为 ( value / SimulatedPotentiometer.conversion_factor )/ 65535
    LED.duty_u16(int(value/SimulatedPotentiometer.conversion_factor))
    # 串口发送value值,格式化浮点数为保留小数点后两位的字符串
    formatted_value = "{:.2f}".format(value)
    uart.write(str(formatted_value)+'\r\n')

# ======================================== 自定义类 ============================================

# 自定义模拟电位器类
class SimulatedPotentiometer:
    """
​    模拟电位器类,用于通过ADC引脚采集模拟电位器的电压值,并通过定时器定期更新数据。

​    该类封装了ADC引脚和定时器的初始化,提供了启动、停止采集以及获取当前电压值的功能。
​    支持通过用户自定义回调函数处理采集到的电压值。

​    Attributes:
​        conversion_factor (float): 电压转换系数,用于将ADC的原始值转换为实际电压值。
​        adc (ADC): ADC实例,用于读取模拟电位器的原始数据。
​        timer (Timer): 定时器实例,用于定期采集数据。
​        freq (int): 定时器频率,单位为Hz。
​        value (float): 当前采集到的电压值。
​        callback (Optional[Callable[[float], None]]): 用户自定义的回调函数,用于处理采集到的电压值。

​    Methods:
​        __init__(self, adc_id: int, freq: int = 100, callback=None):
​            初始化模拟电位器类实例。
​        start(self):
​            启动模拟电位器采集。
​        _timer_callback(self, timer: Timer):
​            定时器回调函数,用于采集模拟电位器的电压值并进行转换。
​        stop(self):
​            停止模拟电位器采集。
​        get_value(self) -> float:
​            返回当前电位器的电压值。
​    """

​    ​# 电压转换系数
    conversion_factor = 3.3 / (65535)

    def __init__(self, adc_id: int, freq: int = 100, callback=None) -> None:
        """
​        初始化模拟电位器类。

​        Args:
​            adc_id (int): 使用的ADC引脚编号,只能使用0~2之间的数字。
​            freq (int): 定时器频率,默认为100Hz。
​            callback (Optional[Callable[[float], None]]): 采集完成后调用的用户自定义回调函数。

​        Raises:
​            ValueError: 如果adc_id不在0~2范围内。
​        """

​        ​# 入口参数检查
        if adc_id > 2 or adc_id < 0:
            raise ValueError("adc_id must be 0~2")

        # 初始化ADC引脚和定时器
        self.adc = ADC(adc_id)
        self.timer = Timer(-1)
        self.freq = freq
        # 采集到的电压值
        self.value = 0
        # 引用用户自定义的回调函数
        self.callback = callback

    def start(self) -> None:
        """
​        启动模拟电位器采集。
​        Args:
​            None

​        Returns:
​            None
​        """
​        ​# 启动定时器,并设置定时器回调函数
        self.timer.init(period=int(1000/self.freq), mode=Timer.PERIODIC, callback=self._timer_callback)

    def _timer_callback(self, timer: Timer) -> None:
        """
​        定时器回调函数,用于采集模拟电位器的电压值并进行转换。

​        Args:
​            timer (Timer): 定时器对象。

​        Returns:
​            None
​        """
​        ​# 读取ADC值并存储到self.value
        self.value = self.adc.read_u16() * SimulatedPotentiometer.conversion_factor
        # 调用用户自定义的回调函数,传递采集到的电位器电压值
        micropython.schedule(self.callback, self.value)

    def stop(self) -> None:
        """
​        停止模拟电位器采集。

​        Args:
​            None

​        Returns:
​            None
​        """
​        ​# 停止定时器
        self.timer.deinit()

    def get_value(self) -> float:
        """
​        返回当前电位器的值。

​        Args:
​            None

​        Returns:
​            float: 当前电位器的电压值。
​        """
​        ​# 返回当前电位器的值
        return self.value

# ======================================== 初始化配置 ==========================================

# 上电延时
time.sleep(3)
# 打印调试信息
print("FreakStudio : Analog potentiometer experiment")

# 配置呼吸LED引脚
LED = PWM(Pin(25), freq=100, duty_u16=0)

# 创建模拟电位器实例,使用ADC2-GP28, 定时器频率为100Hz, 回调函数为user_callback
potentiometer = SimulatedPotentiometer(2, 100, user_callback)

# 创建串口对象,设置波特率为115200
uart = UART(0, 115200)
# 初始化uart对象,波特率为115200,数据位为8,无校验位,停止位为1
# 设置串口超时时间为100ms
uart.init(baudrate  = 115200,
          bits      = 8,
          parity    = None,
          stop      = 1,
          tx        = 0,
          rx        = 1,
          timeout   = 100)

# ========================================  主程序  ===========================================

# 启动模拟电位器
potentiometer.start()
# 运行一段时间,观察电位器的值
time.sleep(20)
# 停止模拟电位器
potentiometer.stop()
# 获取最后一次读取的电位器值
print("Final Potentiometer value:", potentiometer.get_value())

这里,我们首先定义了一个 SimulatedPotentiometer 类,用于模拟电位器的采集操作:该类通过指定的 ADC 引脚读取模拟电位器的电压,并在定时器的帮助下定期执行采集操作。

在主程序中,通过调用 potentiometer.start() 启动模拟电位器的采集操作,定时器以 10Hz 的频率触发。

在每次定时器触发时,调用 _timer_callback 函数,该函数读取当前电位器的电压值,并将其存储在 self.value 中,调用用户自定义的回调函数 user_callback,传递电压值。user_callback 完成以下工作:

  • 调整 LED 的亮度,亮度与电位器的电压值成比例
  • 将电压值格式化为保留两位小数的字符串,并通过串口发送

在模拟电位器运行 20 秒后,停止定时器并获取最后一次读取的电位器值,打印输出。

在烧录代码之前,我们需要完成 SerialPlot 串口绘图仪的配置:

mmexport1782390886972.gif

  1. 配置串口参数​:在 Port 选项卡中,选择正确的串口(如 COM4),并设置波特率为 115200,数据位设置为 8,停止位设置为 1,无校验位
  2. 点击“Open”​:确认配置无误后,点击右上角的“​Open​”按钮,打开串口

8.png

  1. 选择数据格式​:切换到 Data Format 选项卡,选择“ASCII”格式。在单通道数据传输情况下,默认选择逗号作为数据分隔符

9.png

烧录代码,连接中断,输出如下:

10.png

mmexport1782391253398.gif

可以看到,随着我们移动电位器,终端显示的电压数据不断改变同时板载 LED 灯的亮度也不断变化。

12.png

串口绘图仪的波形如上图所示,我们可以右键框选我们想要仔细看的波形:

13.png

即可放大显示:

14.png

我们也可以在其运行过程中,保存接收到的数据到 csv 文件中:

15.png

操作步骤如下:

  1. 在接收数据之前,点击 Record 选项卡和 Record 按键,选择一个文件夹并创建一个新的 CSV 文件,或直接输入你想要保存的文件名,文件扩展名为 .csv
  2. 确保选中了 Write header line 选项,这样文件的第一行会包含数据的标题,方便后续分析,你还可以选择其他选项,如:
    1. Auto increment file name:如果选中,系统会在文件名后自动添加数字来防止覆盖已有文件
    2. Record while paused:即使接收暂停,仍然可以记录数据
    3. Stop recording when port closed:当关闭串口时自动停止记录
  3. 当你完成数据接收时,点击 Record 按钮停止记录

刚刚保存的电位器两端电压值数据如下:

16.png

00.gif

posted @ 2026-09-03 11:14  FreakStudio  阅读(15)  评论(0)    收藏  举报