使用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;
}
希望以上三种解决方法对你有所帮助。