编程语言
首页 > 编程语言> > RaspberryPi 4B 使用 PCF8591 8位AD和DA转换器

RaspberryPi 4B 使用 PCF8591 8位AD和DA转换器

作者:互联网

模数/数模转换在实际应用中非常有用。如何使用树莓派操作挂载到 PCF8591 I²C 线路上的设备?实际上和其他 I²C 设备操作并无差异。首先来学习 PCF8591 的使用方法,然后通过树莓派控制 PCF8591 芯片。

一、 PCF8591 预备知识

PCF8591 是一个单片集成、单独供电、低功耗、8-bit CMOS 数据获取器件。PCF8591 具有 4 个模拟输入、1 个模拟输出和 1 个串行 I²C 总线接口。PCF8591 的 3 个地址引脚 A0, A1 和 A2 可用于硬件地址编程,允许在同个 I²C 总线上接入 8 个器件,而无需额外的硬件。在 PCF8591 器件上输入输出的地址、控制和数据信号都是通过两线双向 I²C 总线以串行的方式进行传输。

特征

  1. 单独供电

  2. 工作电压范围 2.5V~6V

  3. 低待机电流

  4. 通过 I²C 总线串行输入/输出

  5. 通过 3 个硬件地址引脚编址

  6. 采样率由 I²C 总线速率决定

  7. 4 个模拟输入可编程为单端型或差分输入

  8. 自动增量通道选择

  9. 模拟电压范围:VSS~VDD

  10. 片上跟踪保持电路

  11. 8-bit 逐次逼近 A/D 转换器

  12. 带一个模拟输出的乘法 DAC

以下为 PCF8591 的引脚信息

在这里插入图片描述

引脚名称含义
AIN0~AIN3模拟信号输入端。
A0~A2引脚地址端。
VDD、Vss电源端。(2.5~6V)
SDA、SCLI²C 总线的数据线、时钟线。
OSC外部时钟输入端,内部时钟输出端。
EXT内部、外部时钟选择线,使用内部时钟时 EXT 接地。
AGND模拟信号地。
AOUTD/A 转换输出端。
VREF基准电源端。

PCF8591 芯片所能接收的地址包含固定部分和可编程部分。可编程部分必须根据地址引脚 A0,A1 和 A2 来设置,在 I²C 总线协议中地址必须是起始条件后作为第一个字节发送,地址字节的最后一位用来设置对目标地址的读或写。地址字节格式如下所示:

在这里插入图片描述

发送到 PCF8591 的第二个字节将被存储在控制寄存器,用于控制器件功能。控制寄存器的高半字节用于允许模拟输出,和将模拟输入编程为单端或差分输入。低半字节选择一个由高半字节定义的模拟输入通道。如果自动增量(auto-increment)标志置 1,每次 A/D 转换后通道号将自动增加。

如果自动增量(auto-increment)模式是使用内部振荡器的应用中所需要的,那么控制字中模拟输出允许标志应置 1。这要求内部振荡器持续运行,因此要防止振荡器启动延时的转换错误结果。模拟输出允许标志可以在其他时候复位以减少静态功耗。

选择一个不存在的输入通道将导致分配最高可用的通道号。所以,如果自动增量(auto-increment)被置 1,下一个被选择的通道将总是通道 0。两个半字节的最高有效位(即 bit 7 和 bit 3)是留给未来的功能,必须设置为逻辑 0。控制寄存器的所有位在上电复位后被复位为逻辑 0。D/A 转换器和振荡器在节能时被禁止。模拟输出被切换到高阻态。

在这里插入图片描述

二、PCF8591 模块

原理图如下
在这里插入图片描述

从原理图不难看出模块集成了电位计(INPUT0)、光敏电阻(INPUT1)和热敏电阻(INPUT2)作为输入端,同时将 A0、A1 和 A2 都接地,也就是置位 0。另外 INPUT 和 AIN 是通过跳线帽连接的,可以根据需要设置。D3 LED 在上电以后就会发光,作为电源指示灯。D4 LED 是由 AOUT 控制,也就是通过 D4 LED 的明暗程度来反映模拟输出。SCL 和 SDA 用来挂载 I²C。电阻 R7 和 R8 是典型的 I²C 设备上拉电阻。芯片参考电路设计建议在电源和参考电压输入端加上去耦电容(10μF),这反映在了原理图上的 C1 和 C2。这是为了防止额外的地线和电源噪声,以及减小数字信号对模拟信号路径的串扰。

不看最后的读写位,不难得出 PCF8591 模块的 I²C 地址为 0x1001 000,也就是 0x48。

三、smbus2

先给树莓派安装 smbus2 模块,方便接下来通过 smbus2 来读写 I²C 设备(PCF8591 模块)。

pip install smbus2

根据 Putty 的终端输出不难看到 smbus2-0.4.1 已经安装,接下来就可以在 python 中导入该模块使用了。

pi@raspberrypi:~/test $ pip install smbus2
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting smbus2
  Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0xb54bc490>: Failed to establish a new connection: [Errno 101] \xe7\xbd\x91\xe7\xbb\x9c\xe4\xb8\x8d\xe5\x8f\xaf\xe8\xbe\xbe',)': /packages/c8/bf/62ef029fb7077fc87c3539f7365859bccc6cedb2bb20796b737b788c8d09/smbus2-0.4.1-py2.py3-none-any.whl
  Downloading https://files.pythonhosted.org/packages/c8/bf/62ef029fb7077fc87c3539f7365859bccc6cedb2bb20796b737b788c8d09/smbus2-0.4.1-py2.py3-none-any.whl
Installing collected packages: smbus2
Successfully installed smbus2-0.4.1

使用之前先来学习一番 smbus2 提供的 API,可以直接去网站查看英文资料:https://pypi.org/project/smbus2/

这个库是为了在纯 Python 中替换 smbus-cffi/smbus-python。smbus2 是(另一个)Python -smbus 包的纯 Python 实现。

设计一开始就有两个目标:

  1. smbus 的替代品,语法必须相同;
  2. 与 pysmbus 等其他纯 Python 实现相比,更广泛地使用固有的 I²C 结构体和联合。通过这样做,获得更完整的特性和更容易扩展。

目前支持的特性有:

获得 I²C 功能(I2C_FUNCS)

SMBus报文错误检查 (PEC)支持

read_byte

write_byte

read_byte_data

write_byte_data

read_word_data

write_word_data

read_i2c_block_data

write_i2c_block_data

write_quick

process_call

read_block_data

write_block_data

block_process_call

I2c_rdwr 组合写/读事务,重复启动

它是在 Python 2.7 上开发的,但在 Python 3 中无需任何修改即可工作 3.X。

例一 读一个字节

from smbus2 import SMBus

# 打开 i2c 总线 1,从地址 80 读取一个字节,偏移量为 0
bus = SMBus(1)
b = bus.read_byte_data(80, 0)
print(b)
bus.close()

例二 使用 with 读一个字节

from smbus2 import SMBus

with SMBus(1) as bus:
    b = bus.read_byte_data(80, 0)
    print(b)

例三 写一个字节

from smbus2 import SMBus

with SMBus(1) as bus:
    # 写一个字节到地址 80,偏移量为0
    data = 45
    bus.write_byte_data(80, 0, data)

四、操作 PCF8591 模块

使用下面的 demo 前先要将树莓派 4B 的 I²C 支持打开。

将 PCF8591 模块接入树莓派 4B。

树莓派PCF8591 模块
SCLSCL
SDASDA
GNDGND
3.3VVCC
双色 LED 模块PCF8591 模块
SAOUT
GNDGND

程序首先读取通道 0、1 和 2 上的输入,然后将 0 通道的输入值作为输出写出。也就是将电位计的输入值写入到 AOUT,控制绿灯的明暗程度。

#!/usr/bin/env python3

import time
from smbus2 import SMBus

def do(addr):
    while True:
        vcc_in = read(addr, 0x40)
        print('AIN0 = ' + str(vcc_in)) 
        print('AIN1 = ' + str(read(addr, 0x41))) 
        print('AIN2 = ' + str(read(addr, 0x42))) 
        with SMBus(1) as bus:
            bus.write_byte_data(addr, 0, vcc_in)
        time.sleep(0.01)

def read(addr, ctl_byte): 
    with SMBus(1) as bus:
        bus.write_byte(addr, ctl_byte)
        return bus.read_byte_data(addr, 0)

if __name__ == "__main__":
    try:
        do(0x48)
    except KeyboardInterrupt:
        print("KeyboardInterrupt") 

标签:AD,read,bus,smbus2,DA,RaspberryPi,PCF8591,byte,data
来源: https://blog.csdn.net/tyyj90/article/details/118070818