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

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 3
  controlMessage = 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 digitals
  for (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.mfbz.cn/a/886739.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java将word转pdf

总结 建议使用aspose-words转pdf,poi的容易出问题还丑… poi的(多行的下边框就不对了) aspose-words的(基本和word一样) poi工具转换 <!-- 处理PDF --><dependency><groupId>fr.opensagres.xdocreport</groupId><artifactId>fr.opensagres…

Redis: 集群测试和集群原理

集群测试 1 ) SET/GET 命令 测试 set 和 get 因为其他命令也基本相似&#xff0c;我们在 101 节点上尝试连接 103 $ /usr/local/redis/bin/redis-cli -c -a 123456 -h 192.168.10.103 -p 6376我们在插入或读取一个 key的时候&#xff0c;会对这个key做一个hash运算&#xff0c…

【算法】---快速排序

参考 左神和神书算法导论. 学习前置 了解并实现过快速排序。 笔者曾经在数据结构篇写过快速排序&#xff0c;现在面向算法篇快排。 快速排序 输入数据所有排列是等概率的&#xff0c; 这种情况对于实际工程上不会总是成立。朴素快速排序对于特定的输入很糟糕&#xff0c; …

Redis入门第一步:认识Redis与快速安装配置

认识Redis与快速安装配置&#x1f343; Redis是什么&#x1f432; 1.Redis的背景&#x1f38d; Redis&#xff08;Remote Dictionary Server&#xff09;译为"远程字典服务"&#xff0c;它是一款基于内存实现的键值型 NoSQL 数据库&#xff0c; 通常也被称为数据结…

Python 从入门到实战33(使用MySQL)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;通过熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们讨论了数据库编程接口操作的相关知识。今天我们将学习…

音视频入门

一个视频&#xff0c;一秒内普遍大于等于25帧。 入门知识&#xff1a; 1.帧&#xff0c;一张画面就是一帧。一个视频就是由许许多多帧组成的。 帧率&#xff0c;单位时间内帧的数量。单位&#xff1a;帧/秒 或 fps。 分类&#xff1a;I帧&#xff0c;P帧&#xff0c;B帧 I…

IP协议报文

一.IP协议报头结构 二.IP协议报头拆解 1.4位版本 实际上只有两个取值&#xff0c;分别是4和6&#xff0c;4代表的是IPv4&#xff0c;6代表的是IPv6。 2.4位首部长度 IP协议报头的长度也是边长的&#xff0c;单位是*4&#xff0c;这里表示的大小为0~15&#xff0c;当数值为1…

【PyTorch】生成对抗网络

生成对抗网络是什么 概念 Generative Adversarial Nets&#xff0c;简称GAN GAN&#xff1a;生成对抗网络 —— 一种可以生成特定分布数据的模型 《Generative Adversarial Nets》 Ian J Goodfellow-2014 GAN网络结构 Recent Progress on Generative Adversarial Networks …

爬虫——同步与异步加载

一、同步加载 同步模式--阻塞模式&#xff08;就是会阻止你浏览器的一个后续加载&#xff09;停止了后续的解析 因此停止了后续的文件加载&#xff08;图像&#xff09; 比如hifini音乐网站 二、异步加载 异步加载--xhr(重点) 比如腾讯新闻&#xff0c;腾讯招聘等 三、同…

系统规划与管理——1信息系统综合知识(3)

文章目录 1.3 信息系统1.3.1 信息系统定义1.3.2 信息系统的生命周期1.3.3 信息系统常用的开发方法 1.3 信息系统 1.3.1 信息系统定义 信息系统是一种以处理信息为目的的专门的系统类型。信息系统可以是手工的&#xff0c;也可以是计算机化的。计算机化的信息系统的组成部件包…

【D3.js in Action 3 精译_025】3.4 让 D3 数据适应屏幕(中)—— 线性比例尺的用法

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可…

HTML:相关概念以及标签

目录 什么是网页? 什么是HTML语言? 语法规范 HTML基本结构标签 DOCTYPE,lang以及字符集 HTML常用标签 5>图像标签(重要) 除此之外还有几个调整图片属性的标签 图像标签总结 什么是网页? 我们平时使用电脑和手机都是离不开网站和网页的,那么什么是网页呢?什么又是网…

cocotb报错收集

1、原因是定义测试类的时候&#xff0c;idle_inserter的名字不一样 函数修正后 函数修正前

电脑显示mfc140u.dll丢失怎么办,分享4个有效的解决方法

1. mfc140u.dll 简介 1.1 定义与作用 mfc140u.dll 是 Microsoft Foundation Class (MFC) 库中的一个动态链接库文件&#xff0c;它是 MFC 库在 Unicode 版本中的一个特定实现。MFC 是微软为 Windows 平台开发的一套 C 类库&#xff0c;封装了众多 Windows API 函数&#xff0…

定时器定时中断定时器外部中断

基础背景&#xff1a;TIM定时中断-CSDN博客 TIM的函数 // 恢复缺省设置 void TIM_DeInit(TIM_TypeDef* TIMx); // 时基单元初始化&#xff0c;第一个参数TIMx选择某个定时器&#xff0c;第二个参数是结构体&#xff0c;包含了配置时基单元的一些参数。 void TIM_TimeBaseInit…

了解华为计算产品线,昇腾的业务都有哪些?

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 随着 ChatGPT 的现象级爆红&#xff0c;它引领了 AI 大模型时代的深刻变革&#xff0c;进而造成 AI 算力资源日益紧缺。与此同时&#xff0c;中美贸易战的持续也使得 AI 算力国产化适配成为必然趋势。 …

golang grpc初体验

grpc 是一个高性能、开源和通用的 RPC 框架&#xff0c;面向服务端和移动端&#xff0c;基于 HTTP/2 设计。目前支持c、java和go&#xff0c;分别是grpc、grpc-java、grpc-go&#xff0c;目前c版本支持c、c、node.js、ruby、python、objective-c、php和c#。grpc官网 grpc-go P…

Visual Studio 字体与主题推荐

个人推荐&#xff0c;仅供参考&#xff1a; 主题&#xff1a;One Monokai VS Theme 链接&#xff1a;One Monokai VS Theme - Visual Studio Marketplacehttps://marketplace.visualstudio.com/items?itemNameazemoh.onemonokai 效果&#xff1a; 字体&#xff1a;JetBrain…

[RabbitMQ] Spring Boot整合RabbitMQ

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

Scrapy 爬虫的大模型支持

使用 Scrapy 时&#xff0c;你可以轻松使用大型语言模型 (LLM) 来自动化或增强你的 Web 解析。 有多种使用 LLM 来帮助进行 Web 抓取的方法。在本指南中&#xff0c;我们将在每个页面上调用一个 LLM&#xff0c;从中抽取我们定义的一组属性&#xff0c;而无需编写任何选择器或…