PCF8591一次读取多条通道导致测量值不准确的原因及解决方法

devtools/2025/2/25 5:23:26/

使用PCF8591测量通道电压的时候,只测量一个通道电压是正常的,但是要测量两个通道的电压时,会异常显示。

产生原因

时序精度不够

PCF8591通过选择不同的通道进行模拟信号采样。每次转换前,通道的选择需要一定的时间,采样时,可能会出现通道选择和采样过程中的错误或者时序问题,尤其是当连续读取多个通道时,可能需要更高的时序精度和稳定性。

通道切换顺序问题

PCF8591在选择新通道时,它的输出可能在采样完当前通道的信号之前还会保持上一个通道的数据。所以,在采集多个通道时,可能会遇到通道数据还未完全更新就被读取的情况。

解决方法

pcf8591模块的代码已经详细地讲过了,以下是传送门:
(点我传送)
以下代码为例:

unsigned char AD_Read(unsigned char add) 
{unsigned char temp;I2CStart();I2CSendByte(0x90);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CStart();I2CSendByte(0x91);I2CWaitAck();temp = I2CReceiveByte(); I2CSendAck(1);I2CStop();return temp;
}
idata unsigned int RD1_100x;
idata unsigned int RB2_100x ;
void ADCProc()
{RD1_100x = AD_Read(0x01) * 100 / 51;//光敏电阻放大100倍RB2_100x = AD_Read(0x03) * 100 / 51;//变压器放大100倍 
}

1.交换变量的值

最简单的方法就是在调用PCF8591的时候交换变量的值了。这种方法不用修改底层代码,在调用函数中直接修改即可。

idata unsigned int RD1_100x;
idata unsigned int RB2_100x ;
void ADCProc()
{//将RD1_100x和RB2_100x读取的通道值对调RD1_100x = AD_Read(0x03) * 100 / 51;//光敏电阻放大100倍RB2_100x = AD_Read(0x01) * 100 / 51;//变压器放大100倍 
}

2. A/D转换时进行延迟

在每次切换通道后加入适当的延时,确保转换器的输出信号稳定。这个延迟函数由于不同的板子可能会有不同的延迟时间,读者可根据自己板子的需求修改延迟函数,一般来说延迟函数在90us~200us以内。

受影响的因素:

  • A/D 转换时间:PCF8591 的 A/D 转换时间在典型条件下约为 90μs 。在发送读取指令后,需要等待 A/D 转换完成才能读取到有效的数据,因此延迟时间至少要大于 A/D 转换时间。
  • I²C 总线速度:I²C 总线的时钟频率决定了数据传输的速度。PCF8591 支持的 I²C 总线时钟频率最高为 100kHz,对应的时钟周期为 10μs 。在进行 I²C 通信时,每个数据位的传输、应答信号等都需要一定时间,因此延迟时间要考虑 I²C 总线的传输特性。
  • 硬件特性:实际应用中的硬件电路特性,如 PCB 布线、上拉电阻值、电源稳定性等,都会影响信号的传输和芯片的响应时间。

调用函数无需修改,直接修改底层,以延迟150us为例。

void Delay150us(void)	//@12.000MHz
{unsigned char data i, j;i = 2;j = 189;do{while (--j);} while (--i);
}unsigned char AD_Read(unsigned char add) 
{unsigned char temp;I2CStart();I2CSendByte(0x90);I2CWaitAck();I2CSendByte(add);I2CWaitAck();Delay150us();//等待A/D转换,读者根据自身板子进行微调I2CStart();I2CSendByte(0x91);I2CWaitAck();temp = I2CReceiveByte(); I2CSendAck(1);I2CStop();return temp;
}

3.读取通道时连续读取两次,舍弃第一次读取的值

既然A/D转换需要时间,如果增加延迟还是无法解决问题,可能是板子上的PCF8591模块第一次读取数值不准,将其舍弃即可。

unsigned char AD_Read(unsigned char add) 
{//第一次读取,数值不保留unsigned char temp;I2CStart();I2CSendByte(0x90);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CStart();I2CSendByte(0x91);I2CWaitAck();temp = I2CReceiveByte(); I2CSendAck(1);I2CStop();//再次读取,保留数值I2CStart();I2CSendByte(0x90);I2CWaitAck();I2CSendByte(add);I2CWaitAck();I2CStart();I2CSendByte(0x91);I2CWaitAck();temp = I2CReceiveByte();I2CSendAck(1);I2CStop();return temp;
}

希望以上三种解决方法对你有所帮助。


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

相关文章

便携式动平衡仪Qt应用层详细设计说明书

便携式动平衡仪Qt应用层详细设计说明书 (DDD) 版本:1.1 日期:2023年10月 一、文档目录 系统概述应用层架构设计模块详细设计接口定义与数据流关键数据结构代码框架与实现测试计划附录 二、系统概述 2.1 功能需求 开机流程:长按电源键启动…

DeepSeek写俄罗斯方块手机小游戏

DeepSeek写俄罗斯方块手机小游戏 提问 根据提的要求,让DeepSeek整理的需求,进行提问,内容如下: 请生成一个包含以下功能的可运行移动端俄罗斯方块H5文件: 核心功能要求 原生JavaScript实现,适配手机屏幕 …

第六次作业

一.对比 LVS 负载均衡群集的 NAT 模式和 DR 模式,比较其各自的优势 。 LVS-NAT模式的优势 配置简单:NAT模式的配置相对容易,无需复杂的网络设置,适合初学者和小型网络环境。 网络架构灵活:由于使用了NAT技术&#xf…

Deepseek快速做PPT

背景: DeepSeek大纲生成 → Kimi结构化排版 → 数据审查,细节调整 DeepSeek 拥有深度思考能力,擅长逻辑构建与内容生成,它会根据我们的问题进行思考,其深度思考能力当前测试下来,不愧为国内No.1&#xff0…

【JavaEE进阶】数据库连接池

目录 🌴数据库连接池 🎋数据库连接池的使用 🌲MySQL企业开发规范 🌴数据库连接池 数据库连接池负责分配、管理和释放数据库连接,它允许应⽤程序重复使⽤⼀个现有的数据库连接,⽽不是再重新建⽴⼀个. 没…

1.1 go环境搭建及基本使用

golang下载地址: Download and install - The Go Programming Language (google.cn) 验证安装是否成功: go version 查看go环境 go env 注意:Go1.11版本之后无需手动配置环境变量,使用go mod 管理项目,也不需要把项目放到GO…

Baklib智能平台:数据驱动下的企业知识安全与协作

内容概要 在数字化转型加速渗透的今天,企业知识资产的智能化管理与安全防护已成为核心竞争力构建的关键环节。Baklib作为新一代知识中台(Knowledge Hub)的典型代表,以数据驱动技术为核心引擎,重构了企业知识管理的底层…

三元运算符(Ternary Operator):简洁而强大的条件表达式

在编程中,条件判断是不可或缺的一部分。我们经常需要根据某些条件来决定程序的执行路径。虽然 if-else 语句是最常见的条件判断方式,但在某些情况下,使用三元运算符(Ternary Operator)可以让代码更加简洁和易读。本文将…