用Arduino单片机读取PCF8591模数转换器的模拟量并转化为数字输出

devtools/2024/10/10 23:33:33/

PCF8591是一款单芯片,单电源和低功耗8位CMOS数据采集设备。博文[1]对该产品已有介绍,此处不再赘述。但该博文是使用NVIDIA Jetson nano运行python读取输入PCF8591的模拟量的,读取的结果显示在屏幕上,或输出模拟量点亮灯。NVIDIA Jetson nano是一款类似树莓派的,安装操作系统的PC[2],虽然性能强,但毕竟需要启动操作系统,功耗大,成本高[3]。关于单片机和复杂电脑的区别见[3]。本文用Arduino单片机的C++语言实现同样的读取模拟量的功能,但读取完后不输出模拟量,也不显示在屏幕上,而是产生8个数字输出(该模数转换器是8位的,也就是说支持的模拟量和输出的数据是0~255之间的整数,可用8个二进制位表示)。这样的做法,对于不支持模拟输入,只支持数字输入的PLC来说是有用的。

一、基本知识的简介

(一)I2C通信方式

I2C是一种串口通信方式,使用SCL和SDA两根线进行通讯。使用该通信方式的两个设备有主站和从站之分。主站启动通讯,发送从站地址,以及一个读/写比特。如果发出的比特是0,即写,那么主站就继续向从站发送数据;如果主站发出的读/写比特是1,即读,那么就是由从站向主站发送数据,主站读取数据。具体的通讯过程,见[4]。在该实验中,Arduino单片机是主站,PCF8591是从站。

(二)PCF8591的地址

PCF8591的地址有7位,其中前4位是1001,后三位分别由数字输入A0,A1,A2决定[5]。在该试验中,使用的PCF8591板缺少A0,A1,A2的引脚,所以其地址固定为1001000。

(三)PCF8591的控制字节

PCF8591的控制字节是主站向其发送的第一个字节数据,用于设定PCF8591的模拟量输出参数。控制字节的详细说明见[1]。简单地说,从高位起第1位是0;第2位表明PCF8591的模拟量输出是否激活,该实验由于是通过串口向Arduino输出模拟量的值,所以无需使用模拟量输出,故为0;第3-4位表明模拟输入的形式,这里用单端输入,不用差分输入,故为00;第5位是0;第6位不使用自动递增所以也是0;第7-8位决定用哪个模拟量输入(PCF8591总共有4个模拟量输入)。

PCF8591上有3个可调电阻,其中Input0针脚对应的是蓝白电位器(可用一字型螺丝刀转动从而调节电阻);Input1针脚对应的是光敏电阻;Input2针脚对应的是热敏电阻。该模数转换器的内部电路大致如图所示:

该产品带一些短接帽,可以将Input?和AIN?连接起来。因此,可以通过调节电阻,控制PCF8591的模拟量输入。

二、Arduino程序

Arduino单片机通过I2C的通讯方式和PCF8591进行交互。这里需要使用Arduino里的Wire.h库。该库的详细说明见[6]。

(一)程序基本说明

由于本实验使用的Arduino板是UNO R3,SDA和SCL的针脚分别为A4和A5。

这里,PCF8591的地址在代码中是一个固定值PCF8591,值为0b1001000。

程序最终产生的8个数字输出,按从低位到高位排,分别对应Arduino板的针脚2,3,4,5,6,7,8,9。所以要将它们的模式均设为数字输出。Arduino的输出是推挽输出,即高电平输出。

Arduino和PCF8591的交互主要分为两部分:

第一部分,是写数据,即Arduino向PCF8591发送控制字节,设定模拟量输出参数。用Wire.beginTransmission(address)函数开始,这里发送的是地址,然后通过Wire.write(data)先令读/写比特为0,然后发送数据,即控制字节。这里,用蓝白电位器作为模拟输入,所以控制字节为00000000。

第二部分,是读数据,即Arduino先启动通讯,然后PCF8591向Arduino发送字节,即收到的模拟量值。用Wire.requestForm(address, byte number, stop bit)开始,发送地址,令读/写比特为1,然后接收指定长度的数据,并结束通讯。这里只需读一个字节即可,因为PCF8591发送的模拟量值只占1个字节。所以byte number=1,stop bit=1。然后用Wire.read()读取收到的数据。

为了方便调试,这里也把收到的数据发送到Serial串口中(UART串口),供电脑端查看。

最后,把数据转换为8个布尔变量。用二进制移位的方式[7],以及逻辑运算的方式提取字节中的每一个比特,然后用其激活Arduino板的数字输出。

(二)程序代码和接线方式

代码如下:

#include <Wire.h>
/*
Here try: PCF8591 gets value from analog input, then Arduino reads from the PCF8591, and export to discrete output of Arduino
*/int outputPins[] = {2,3,4,5,6,7,8,9};
bool ch1;
bool ch2;
byte controlMessage;
byte result;
#define PCF8591 0b1001000
void setup() {for (int i = 0; i<=7; i++){pinMode(outputPins[i], OUTPUT); //set pins to output}Wire.begin();Serial.begin(9600);
}void loop() {Wire.beginTransmission(PCF8591);ch1 = false;ch2 = false;//ch1 f ch2 f: channel 0: adjust pan//ch1 f ch2 t: channel 1: light resistor//ch1 t ch2 f: channel 2: thermal resistor//ch1 t ch2 t: channel 3controlMessage = 0x00 + (byte)ch1 * 0b00000010 + (byte)ch2 * 0b00000001;Wire.write(controlMessage); //write control message first, then relaunch and enter read mode//Wire.beginTransmission(PCF8591);Wire.requestFrom(PCF8591, 1, true);result = Wire.read();Serial.print(result);Serial.print(' ');Wire.endTransmission();//Now I would like to convert the variable into digitalsfor (int i=0; i<=7; i++) // For each digit, i need to extract from result{byte mask = 0x01 << i;byte maskedResult = result & mask;bool resultThisBit = (bool)(maskedResult >> i);if (resultThisBit){digitalWrite(outputPins[i], HIGH);}else{digitalWrite(outputPins[i], LOW);}}delay(100);
}

接线方式如下:

(三)运行结果

刚才的图中,8个发光二极管从左至右代表了Arduino从PCF8591中得到的值二进制从高到低排列。当前二进制数为10100001。通过串口调试器,可得数值为161。

161的二进制表示确实是10100001,正确。现在把用于模拟输入的蓝白电位器旋转,观察数值变化。

二进制数为00111100

数值为60。其二进制数确实为00111100。

当然,这些输出都可接入PLC,如果PLC不支持模拟输入,只支持数字输入。

三、总结

用Arduino,可以通过I2C串口和PCF8591模数转换器交互,读取模拟量。通过发送控制字节数据,可以设置PCF8591的串口输出参数。读取的模拟量,可以转化为数字输出,用于不支持模拟输入只支持数字输入的PLC。

四、链接

[1]jetson连接PCF8591读取模拟电压值_pcf8591读取模拟电压值大小-CSDN博客

[2]Jetson Nano 从入门到实战(案例:Opencv配置、人脸检测、二维码检测)_jetson nano 从入门到实战(案例:opencv配置、人脸检测、二维码检测)-CSDN博客​​​​​​​

[3]嵌入式开发中树莓派和单片机关键区别_树莓派和单片机的区别-CSDN博客

[4]i2c协议详解_i2c fast mode-CSDN博客

[5]PCF8591详解(蓝桥杯单片机模块(IIC总线))-CSDN博客

[6]Wire - Arduino Reference

[7]计算机中二进制的移位运算_二进制的乘法移位原理-CSDN博客


http://www.ppmy.cn/devtools/122036.html

相关文章

技术成神之路:设计模式(十八)适配器模式

介绍 适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许接口不兼容的类可以协同工作&#xff0c;通过将一个类的接口转换成客户端所期望的另一个接口&#xff0c;使得原本由于接口不兼容而不能一起工作的类可以一起工作。 1.定义 适配…

ThreadLocal底层原理及数据结构详解

ThreadLocal允许为每个线程创建独立的变量副本&#xff0c;使得同一个ThreadLocal对象在不同的线程中拥有不同的值。它的主要作用是在并发环境下提供线程隔离&#xff0c;避免多个线程共享同一个变量&#xff0c;从而减少线程间的相互干扰。 ThreadLocal的核心在于为每个线程维…

如何伪装服务器地址?

在现代网络环境中&#xff0c;出于隐私、安全或绕过限制的目的&#xff0c;伪装服务器地址成为一种重要的技术手段。伪装服务器地址的目的主要是隐藏服务器的真实IP&#xff0c;以防止恶意攻击、数据追踪或规避某些网络限制。在没有提到VPN的前提下&#xff0c;仍然有多种方法可…

flutter_鸿蒙next_Dart基础①字符串

目录 代码示例 代码逐段解析 1. 字符串的声明与打印 2. 数字的声明与打印 3. 多行字符串 4. 字符串拼接 5. 字符串分割 6. 字符串修剪 7. 检查字符串是否为空 8. 字符串替换 9. 正则表达式与电话号码验证 10. 字符串查找 11. 字符串定位 写在最后 在本篇博客中&a…

Webstorm 中对 Node.js 后端项目进行断点调试

首先&#xff0c;肯定需要有一个启动服务器的命令脚本。 然后&#xff0c;写一个 debug 的配置&#xff1a; 然后&#xff0c;debug 模式 启动项目和 启动调试服务&#xff1a; 最后&#xff0c;发送请求&#xff0c;即可调试&#xff1a; 这几个关键按钮含义&#xff1a; 重启…

【MySQL】Ubuntu环境下MySQL的安装与卸载

目录 1.MYSQL的安装 2.MySQL的登录 3.MYSQL的卸载 4.设置配置文件 1.MYSQL的安装 首先我们要看看我们环境里面有没有已经安装好的MySQL 我们发现是默认是没有的。 我们还可以通过下面这个命令来确认有没有mysql的安装包 首先我们得知道我们当前的系统版本是什么 lsb_…

iOS--RunLoop原理

前言 曾经在写项目的时候遇到过这么一个问题。&#xff1a; 项目中添加了一个tableview&#xff0c;然后还有一个计时器&#xff0c;当滑动tableview的时候会阻塞计时器&#xff0c;你得执行这么一段代码后&#xff0c;计时器才能正常运行。 RunLoop.current.add(timer, for…

核心理论框架对比:如何通过TOGAF实现企业数字化转型的全面战略

数字化转型中的理论与实践融合 随着全球市场竞争的加剧和技术的快速革新&#xff0c;企业必须不断适应数字化技术带来的变化。数字化转型不仅是技术的升级&#xff0c;更是企业业务模式、组织架构以及文化的深度变革。然而&#xff0c;在面对复杂的技术和业务环境时&#xff0…