【CanMV K210】通信扩展 PCF8591 ADC 模数转换与模拟量读取

在智能硬件项目中,很多真实世界的数据并不是一开始就以数字形式存在。光照强弱、电位器旋转角度、模拟传感器电压、声音强度变化,这些信号通常表现为连续变化的模拟电压。开发板想要读取这些信息,就需要借助模数转换器把模拟量转换成程序可以处理的数字值。

本实验围绕 PCF8591 模数转换模块展开,通过 CanMV K210 的软件 I2C 接口与 PCF8591 通信,读取 AIN0 通道的模拟输入值,并在串口终端持续打印采集结果。程序运行后,如果 AIN0 接入电位器、光敏电阻模块或其他模拟信号源,终端中的数值会随着输入电压变化而变化。这个过程可以直观看到"外部电压变化如何变成 Python 程序中的数字"。

学习目标 说明
理解模拟量采集 认识模拟电压、ADC 转换和数字采样值之间的关系
掌握 PCF8591 基础用法 使用 PCF8591 读取 AIN0 模拟输入通道数据
理解 I2C 通信链路 明确 SCL、SDA、设备地址和控制字在采集过程中的作用
建立驱动封装思路 将 PCF8591 的底层读写封装成类,让主程序只关注采样结果
扩展传感器采集能力 为电位器、光敏传感器、声音传感器和多路模拟输入实验打基础

当前代码包含 PCF8591 驱动文件和主程序两部分。驱动文件负责封装控制字、I2C 写入、I2C 读取、通道选择和模拟输出配置;主程序负责创建 I2C 对象、实例化 PCF8591 对象,并在循环中每隔 1 秒读取一次 AIN0 数据。这个实验的重点不只是读取一个数字,而是理解 I2C 总线、ADC 通道、控制字和循环采样之间的关系。

文章目录

理论基础

PCF8591 可以理解成连接模拟世界和程序世界的转换模块。外部传感器或电位器输出的是连续变化的电压,程序无法直接把这种连续电压当成变量使用,需要 ADC 把电压变化转换成数字值。PCF8591 就承担这个转换任务,它把 AIN0、AIN1、AIN2、AIN3 等模拟输入通道的电压转换成数字数据,再通过 I2C 总线交给 CanMV K210。

普通 GPIO 更适合读取开关量,例如按键是否按下、LED 是否点亮、模块输出是否为高低电平。PCF8591 面向的是模拟量,例如电位器旋转到某个角度、光照逐渐增强、声音强度发生变化、模拟传感器输出电压波动。这类信号不是简单的 0 或 1,而是会在一定范围内连续变化,因此采集结果通常表现为一组不断变化的数字。

本实验中,外部模拟信号接入 PCF8591 的 AIN0 通道,CanMV K210 通过物理引脚 6 和物理引脚 7 连接 PCF8591 的 SCL 与 SDA。程序通过 I2C 地址 0x48 访问 PCF8591,发送控制字选择采样通道,再读取转换后的数字值。串口中打印出来的 adc0 就是 AIN0 当前采样结果。
#mermaid-svg-Wsapt4oXIpZSIu41{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Wsapt4oXIpZSIu41 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Wsapt4oXIpZSIu41 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Wsapt4oXIpZSIu41 .error-icon{fill:#552222;}#mermaid-svg-Wsapt4oXIpZSIu41 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Wsapt4oXIpZSIu41 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Wsapt4oXIpZSIu41 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Wsapt4oXIpZSIu41 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Wsapt4oXIpZSIu41 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Wsapt4oXIpZSIu41 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Wsapt4oXIpZSIu41 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Wsapt4oXIpZSIu41 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Wsapt4oXIpZSIu41 .marker.cross{stroke:#333333;}#mermaid-svg-Wsapt4oXIpZSIu41 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Wsapt4oXIpZSIu41 p{margin:0;}#mermaid-svg-Wsapt4oXIpZSIu41 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Wsapt4oXIpZSIu41 .cluster-label text{fill:#333;}#mermaid-svg-Wsapt4oXIpZSIu41 .cluster-label span{color:#333;}#mermaid-svg-Wsapt4oXIpZSIu41 .cluster-label span p{background-color:transparent;}#mermaid-svg-Wsapt4oXIpZSIu41 .label text,#mermaid-svg-Wsapt4oXIpZSIu41 span{fill:#333;color:#333;}#mermaid-svg-Wsapt4oXIpZSIu41 .node rect,#mermaid-svg-Wsapt4oXIpZSIu41 .node circle,#mermaid-svg-Wsapt4oXIpZSIu41 .node ellipse,#mermaid-svg-Wsapt4oXIpZSIu41 .node polygon,#mermaid-svg-Wsapt4oXIpZSIu41 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Wsapt4oXIpZSIu41 .rough-node .label text,#mermaid-svg-Wsapt4oXIpZSIu41 .node .label text,#mermaid-svg-Wsapt4oXIpZSIu41 .image-shape .label,#mermaid-svg-Wsapt4oXIpZSIu41 .icon-shape .label{text-anchor:middle;}#mermaid-svg-Wsapt4oXIpZSIu41 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Wsapt4oXIpZSIu41 .rough-node .label,#mermaid-svg-Wsapt4oXIpZSIu41 .node .label,#mermaid-svg-Wsapt4oXIpZSIu41 .image-shape .label,#mermaid-svg-Wsapt4oXIpZSIu41 .icon-shape .label{text-align:center;}#mermaid-svg-Wsapt4oXIpZSIu41 .node.clickable{cursor:pointer;}#mermaid-svg-Wsapt4oXIpZSIu41 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Wsapt4oXIpZSIu41 .arrowheadPath{fill:#333333;}#mermaid-svg-Wsapt4oXIpZSIu41 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Wsapt4oXIpZSIu41 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Wsapt4oXIpZSIu41 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Wsapt4oXIpZSIu41 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Wsapt4oXIpZSIu41 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Wsapt4oXIpZSIu41 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Wsapt4oXIpZSIu41 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Wsapt4oXIpZSIu41 .cluster text{fill:#333;}#mermaid-svg-Wsapt4oXIpZSIu41 .cluster span{color:#333;}#mermaid-svg-Wsapt4oXIpZSIu41 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Wsapt4oXIpZSIu41 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Wsapt4oXIpZSIu41 rect.text{fill:none;stroke-width:0;}#mermaid-svg-Wsapt4oXIpZSIu41 .icon-shape,#mermaid-svg-Wsapt4oXIpZSIu41 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Wsapt4oXIpZSIu41 .icon-shape p,#mermaid-svg-Wsapt4oXIpZSIu41 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Wsapt4oXIpZSIu41 .icon-shape .label rect,#mermaid-svg-Wsapt4oXIpZSIu41 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Wsapt4oXIpZSIu41 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Wsapt4oXIpZSIu41 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Wsapt4oXIpZSIu41 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-Wsapt4oXIpZSIu41 .analog>*{fill:#E8F3FF!important;stroke:#5B9BFF!important;stroke-width:2px!important;color:#1F3B6D!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .analog span{fill:#E8F3FF!important;stroke:#5B9BFF!important;stroke-width:2px!important;color:#1F3B6D!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .analog tspan{fill:#1F3B6D!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .adc>*{fill:#EAFBF1!important;stroke:#42B983!important;stroke-width:2px!important;color:#1F5C3A!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .adc span{fill:#EAFBF1!important;stroke:#42B983!important;stroke-width:2px!important;color:#1F5C3A!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .adc tspan{fill:#1F5C3A!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .bus>*{fill:#FFF4E8!important;stroke:#F4A261!important;stroke-width:2px!important;color:#7A4A00!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .bus span{fill:#FFF4E8!important;stroke:#F4A261!important;stroke-width:2px!important;color:#7A4A00!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .bus tspan{fill:#7A4A00!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .code>*{fill:#F4EEFF!important;stroke:#8E6AD8!important;stroke-width:2px!important;color:#3D2B68!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .code span{fill:#F4EEFF!important;stroke:#8E6AD8!important;stroke-width:2px!important;color:#3D2B68!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .code tspan{fill:#3D2B68!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .power>*{fill:#FCEEF4!important;stroke:#E76F51!important;stroke-width:2px!important;color:#7A2740!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .power span{fill:#FCEEF4!important;stroke:#E76F51!important;stroke-width:2px!important;color:#7A2740!important;}#mermaid-svg-Wsapt4oXIpZSIu41 .power tspan{fill:#7A2740!important;} 外部模拟信号

电位器 / 光敏模块 / 模拟传感器
PCF8591 AIN0

模拟输入通道
ADC 转换

模拟电压转数字值
I2C 通信

SCL / SDA
CanMV K210

引脚 6 / 引脚 7
Python 程序

pcf.read(0)
串口输出

adc0 数值变化
模块供电

VCC
公共地线

GND

这张流程图展示的是电路和数据之间的关系。外部模拟信号进入 AIN0,PCF8591 完成模数转换,I2C 总线负责传输数据,CanMV K210 运行 Python 程序并读取采样值。这个链路打通后,后续读取电位器、光敏传感器、声音传感器和其他模拟模块时,只需要更换输入源或切换通道,整体采集思路保持一致。

控制字是 PCF8591 实验中比较重要的概念。程序不是直接发送"读取 AIN0"这样的文字命令,而是通过二进制位组合告诉 PCF8591 当前输入模式、是否启用模拟输出、是否自动递增通道、当前读取哪个 ADC 通道。驱动类中的 AOUTFLGAINPRG0AUTOINCACHNNL0 等常量,就是为了让这些二进制配置更容易阅读和维护。

硬件设施

本实验真正使用到的核心硬件是 CanMV K210 开发板和 PCF8591 模数转换模块。程序没有使用 LCD、按键、蜂鸣器、摄像头或其他传感器模块,因此硬件重点集中在 I2C 通信线、模块供电、公共地线和 AIN0 模拟输入通道。

接线关系可以先通过下面这张图建立整体印象。CanMV K210 使用物理引脚 6 作为 SCL,物理引脚 7 作为 SDA,PCF8591 通过 I2C 与开发板通信,外部模拟信号接入 AIN0 通道后由程序读取。

硬件 / 软件 作用 说明
CanMV K210 开发板 实验运行平台 负责执行 MicroPython 程序,并通过 I2C 与 PCF8591 通信
PCF8591 模数转换模块 模拟量采集模块 将 AIN0 等模拟输入通道的电压变化转换成数字数据
AIN0 模拟输入通道 当前采样通道 主循环中通过 pcf.read(0) 读取该通道数据
I2C 软件总线 通信接口 代码使用 I2C.I2C_SOFT 创建软件 I2C
SCL 引脚 6 I2C 时钟线 连接 PCF8591 的 SCL
SDA 引脚 7 I2C 数据线 连接 PCF8591 的 SDA
machine.I2C I2C 通信模块 用于创建 I2C 对象并完成读写操作
fpioa_manager.fm 引脚功能映射模块 用于给软件 I2C 指定 GPIOHS 功能
time 延时模块 用于程序启动等待和循环采样间隔控制
pcf8591 PCF8591 驱动模块 封装 PCF8591 的控制字、通道读取和模拟输出

实验中用到的核心模块如下。PCF8591 模块负责完成模拟量采集,CanMV K210 负责运行程序和读取数据,连接线负责建立 SCL、SDA、VCC、GND 和 AIN0 通道之间的硬件关系。

接线关系可以根据代码中的 I2C() 参数确认。当前程序使用软件 I2C,SCL 指定为物理引脚 6,SDA 指定为物理引脚 7,并分别绑定到 GPIOHS1GPIOHS2。PCF8591 的默认 I2C 地址设置为 0x48,主程序通过这个地址访问模块。

接口 / 通道 代码参数 对应硬件 说明
物理引脚 6 scl=6 PCF8591 SCL 作为 I2C 时钟线使用
物理引脚 7 sda=7 PCF8591 SDA 作为 I2C 数据线使用
GPIOHS1 gscl=fm.fpioa.GPIOHS1 软件 I2C 时钟功能 用于支持软件 I2C 时钟输出
GPIOHS2 gsda=fm.fpioa.GPIOHS2 软件 I2C 数据功能 用于支持软件 I2C 数据传输
AIN0 pcf.read(0) 外部模拟信号输入 当前循环读取的模拟采样通道
0x48 addr=0x48 PCF8591 模块地址 当前程序使用的 I2C 通信地址
VCC 模块供电 PCF8591 VCC 根据模块标识连接对应供电端
GND 公共地线 CanMV 与 PCF8591 GND 保证通信和采样具有统一参考电平

完成接线后的整体效果如下。检查时重点关注四类连接:SCL 是否接到物理引脚 6,SDA 是否接到物理引脚 7,PCF8591 是否正常供电并与 CanMV 共地,外部模拟信号是否接入 AIN0。只要 I2C 通信正常,串口就能持续打印采样结果。

实验现象 正常表现 异常提示
程序启动 串口每隔约 1 秒打印一次数字 没有输出时检查脚本运行状态和串口连接
AIN0 输入变化 打印值随输入电压变化而变化 数值不变化时检查 AIN0 是否接入有效模拟信号
AIN0 输入悬空 打印值可能不稳定波动 悬空输入没有明确参考电压,不适合判断模块是否正常
接入电位器 旋转电位器时数值连续变化 数值方向与预期不同属于正常现象,取决于接线端顺序
接入光敏模块 光照变化时数值发生变化 变化幅度小可检查模块供电和输出端连接
I2C 接线错误 程序可能报通信错误或无法读取 核对 SCL、SDA、VCC、GND 和地址配置

软件代码

本实验代码围绕 PCF8591 的 I2C 通信和模拟输入采集展开。为了避免驱动类和主程序混在一起,建议将代码拆成两个文件保存。pcf8591.py 用于保存 PCF8591 驱动类,主程序文件用于创建 I2C 对象并循环读取 AIN0 通道。两个文件放在同一运行目录下,主程序才能正常执行 import pcf8591

软件环境 作用 检查重点
CanMV IDE 编辑、运行和调试 K210 程序 能识别开发板串口,并能运行基础 print() 测试
CanMV 固件 提供 machine.I2Cfpioa_manager 等模块 固件环境需要支持当前 I2C 与 FPIOA 写法
USB 串口驱动 让电脑识别开发板串口 串口工具中能看到对应端口
pcf8591.py PCF8591 驱动文件 需要与主程序放在同一运行目录下
串口终端 查看采样结果 能持续看到 AIN0 采样值输出

驱动文件保存为 pcf8591.py

python 复制代码
#********************************************
# ----湖南创乐博智能科技有限公司----
#  文件名:pcf8591.py
#  版本:V2.0
#  author: zhulin
#  说明:PCF8591 模数转换传感器驱动文件
#********************************************

AOUTFLG = 0b01000000
AINPRG0 = 0b00000000
AINPRG1 = 0b00010000
AINPRG2 = 0b00100000
AINPRG3 = 0b00110000
AUTOINC = 0b00000100
ACHNNL0 = 0b00000000
ACHNNL1 = 0b00000001
ACHNNL2 = 0b00000010
ACHNNL3 = 0b00000011


class PCF8591:
    def __init__(self, i2c, addr=0x48, enable_out=True, in_program=AINPRG0):
        self.i2c = i2c
        self.addr = addr
        self._aout = self.set_out(enable_out)
        self._ainprg = self.set_program(in_program)
        self._last_ctl = None

    def _make_control(self, auto_increment=False, channel=ACHNNL0):
        return 0 | self._aout | self._ainprg | (AUTOINC if auto_increment else 0) | channel

    def _write_control(self, control):
        if control != self._last_ctl:
            self.i2c.writeto(self.addr, bytes([control]))
            self.i2c.readfrom(self.addr, 1)
            self._last_ctl = control

    def _read_raw(self):
        return self.i2c.readfrom(self.addr, 4)

    def set_out(self, enable_out):
        self._aout = AOUTFLG if enable_out else 0
        return self._aout

    def set_program(self, in_program):
        self._ainprg = in_program
        return self._ainprg

    def read(self, channel=-1):
        if channel == -1:
            self.set_out(True)
            self._write_control(self._make_control(auto_increment=True))
            return self._read_raw()
        else:
            self._write_control(self._make_control(channel=channel))
            return int(self._read_raw()[0])

    def write(self, value):
        self.set_out(True)
        control = self._make_control()
        self._last_ctl = control
        self.i2c.writeto(self.addr, bytes([control, value]))

主程序保存为 main.py 或直接在 CanMV IDE 中运行:

python 复制代码
#********************************************
# ----湖南创乐博智能科技有限公司----
#  文件名:main.py
#  版本:V2.0
#  说明:CanMV K210 通过 PCF8591 读取 AIN0 模拟量数据
#********************************************

from machine import I2C
from fpioa_manager import fm
import pcf8591
import time


# =========================
# I2C 初始化
# =========================

i2c = I2C(
    I2C.I2C_SOFT,
    freq=400000,
    scl=6,
    sda=7,
    gscl=fm.fpioa.GPIOHS1,
    gsda=fm.fpioa.GPIOHS2
)


# =========================
# 创建 PCF8591 对象
# =========================

pcf = pcf8591.PCF8591(i2c)

time.sleep(1)


# =========================
# 循环读取 AIN0
# =========================

while True:
    adc0 = pcf.read(0)
    time.sleep(1)
    print(adc0)

这段代码的核心并不复杂。驱动文件负责把 PCF8591 的底层通信细节封装好,主程序只需要创建 I2C 对象,再调用 pcf.read(0) 读取 AIN0。这样写的好处是主循环非常清晰,后续切换到 AIN1、AIN2、AIN3 时,只需要修改通道编号,不需要反复编写 I2C 控制字。

驱动类中的 _make_control() 用来生成控制字,_write_control() 用来把控制字写入 PCF8591,_read_raw() 用来读取原始采样数据。read(0) 表示读取 AIN0,read(1) 表示读取 AIN1,read(-1) 表示按自动递增方式读取多通道数据。write(value) 则用于 PCF8591 的模拟输出能力,当前实验主要关注 ADC 输入,因此主程序没有使用它。

函数 / 语句 功能 对应现象
PCF8591(i2c) 创建 PCF8591 对象 保存 I2C 总线和设备地址,准备后续采样
_make_control() 生成控制字 决定读取通道、输入模式和自动递增状态
_write_control() 写入控制字 通知 PCF8591 切换到指定采样配置
_read_raw() 读取原始数据 从 PCF8591 获取采样结果
read(0) 读取 AIN0 通道 返回当前模拟输入对应的数字值
read(-1) 自动递增读取多通道 可用于一次读取多个模拟输入
write(value) 写入模拟输出值 向 PCF8591 的 DAC 输出端写入数值
time.sleep(1) 控制采样间隔 每隔 1 秒打印一次采样数据
print(adc0) 输出采样结果 在终端显示 AIN0 的数字值

主循环结构适合入门理解模拟量采集。while True 让程序持续运行,adc0 = pcf.read(0) 负责读取当前模拟输入,time.sleep(1) 控制采样频率,print(adc0) 把采集结果输出到终端。如果 AIN0 接入电位器,旋转电位器时打印值会随电压变化而变化;如果接入光敏模拟模块,光照变化也会反映为不同的数字值。

扩展应用

PCF8591 实验常见问题集中在 I2C 接线、模块地址、驱动文件、模拟输入和采样结果理解几个方面。排查时应优先确认 SCL、SDA、供电和 GND,再检查程序中的模块导入方式和 I2C 地址是否正确。

问题现象 可能原因 处理思路
程序提示找不到 pcf8591 驱动文件没有保存为 pcf8591.py,或文件不在当前运行目录 将驱动类保存为 pcf8591.py,并与主程序放在同一运行目录
终端没有任何输出 程序没有正常运行、串口终端未打开、主循环未执行 确认脚本已经运行,检查串口工具是否连接到正确端口
I2C 通信报错 SCL / SDA 接线错误、模块未供电、GND 未共地 按代码检查引脚 6 和引脚 7 的连接,并确认 PCF8591 与开发板共地
读取值一直不变 AIN0 输入悬空、外部模拟源没有变化、通道接错 给 AIN0 接入明确的模拟信号,例如电位器中间端或模拟传感器输出端
读取值波动较大 模拟输入不稳定、连线较长、输入端悬空 缩短连接线,确认模拟源稳定,避免 AIN0 无输入状态下直接采样
读取值与预期不一致 PCF8591 切换通道后可能需要一次虚读 保留驱动中的切换后读取处理,必要时连续读取两次并使用后一次结果
地址通信失败 PCF8591 模块地址不是 0x48 检查模块地址跳线,或使用 I2C 扫描程序确认实际地址
数值范围理解错误 PCF8591 采样值通常按 8 位结果输出 采样结果通常在 0~255 范围内变化,数值越大代表输入电压越接近参考高电平

PCF8591 实验的价值在于把模拟世界接入程序世界。很多传感器输出的并不是固定的 0 或 1,而是连续变化的电压。通过 PCF8591,开发板可以把这些电压变化转成数字数据,再交给 Python 进行判断、计算、显示或控制。当前代码虽然只读取 AIN0 一个通道,但驱动类已经支持通道选择、自动递增读取和模拟输出写入,因此具备继续扩展的基础。

应用场景 实现思路 可扩展能力
电位器数值采集 将电位器输出端接入 AIN0,通过 pcf.read(0) 获取旋转位置 可扩展为亮度调节、音量控制或参数设置旋钮
光照强度检测 将模拟光敏模块输出接入 AIN0,根据采样值判断环境亮暗 后续可扩展 LED 或蜂鸣器,实现光照提醒
多路模拟传感器采集 使用 AIN0~AIN3 接入多个模拟信号源 可通过 read(-1) 或多次 read(channel) 采集多通道数据
模拟阈值判断 对采样值设置阈值,例如大于某个数值触发提示逻辑 可扩展为自动控制开关、状态告警或数据过滤
硬件调试工具 通过串口持续打印 ADC 值,观察外部模拟信号变化 可用于判断传感器是否接线正确、输出是否正常
数据记录实验 将采样值按时间间隔保存或上传 后续可扩展文件记录、网络上传或可视化曲线
DAC 模拟输出 使用 write(value) 向 PCF8591 写入模拟输出值 可扩展为简单波形输出、电压控制或模拟信号演示

从工程角度看,当前程序已经把 PCF8591 的底层控制封装成类,主程序只需要关心 pcf.read(0) 这样的高层调用。这样的结构便于后续扩展:新增通道采集时只需要改变通道编号,新增阈值判断时只需要围绕采样结果编写条件逻辑,新增显示或报警时也可以把采样值交给后续模块处理。驱动层负责通信,业务层负责应用判断,这种分层思路比把所有 I2C 读写代码堆在主循环中更适合长期维护。

总结

本实验通过 CanMV K210 和 PCF8591 模数转换模块完成了模拟量采集,核心能力包括软件 I2C 初始化、SCL / SDA 引脚配置、PCF8591 控制字生成、I2C 数据读写、模拟输入通道选择和循环采样输出。程序把外部模拟电压转换成 Python 中可以打印、判断和处理的数字值,展示了硬件采集类实验最基础的一条数据链路。

这类实验是传感器课程的重要入口。GPIO 更适合处理开关量,PCF8591 这类 ADC 模块则适合处理连续变化的模拟量。掌握这种采集方式后,后续可以继续扩展到光照检测、电位器控制、声音强度采集、模拟传感器监测、数据曲线显示、阈值报警和自动控制等方向。只要理解 I2C 通信和模拟量转换之间的关系,更多真实环境数据都可以被接入程序逻辑中,成为智能硬件项目的一部分。

相关推荐
DogDaoDao14 小时前
【GitHub】RealtimeSTT 深度解析:打造低延迟、生产级语音识别应用的全栈利器
人工智能·语言模型·大模型·github·语音识别·stt·realtimestt
菜鸡旭旭14 小时前
【AI培训中台-练习评分V0】
人工智能
chenying99817914 小时前
本地部署 TTS 方案横向对比:Fish Speech、CosyVoice 2、GPT-SoVITS 与 VoxFlash-TTS
人工智能·实时音视频·语音合成·tts
A153625515 小时前
流量暗战:2026年科技公司GEO应用成熟度调查
人工智能·科技·chatgpt
私人珍藏库15 小时前
[Android] 全能语音计算器v4.6
人工智能·windows·语音识别·工具·软件·多功能
梦想三三15 小时前
【OpenCV】图像的轮廓检测
人工智能·opencv·计算机视觉
久菜盒子工作室15 小时前
深科技最近的经营状况
大数据·人工智能·科技
yubo050915 小时前
计算机视觉第一课:环境搭建 + 第一个 CV 程序
人工智能·计算机视觉
weixin_3975740915 小时前
食品包装AI质检时代来了,标签审核效率提升千倍
人工智能