PCF8591的基本使用方法

本文介绍了PCF8591AD/DA转换芯片的工作原理、I2C通信方法,以及软件和硬件I2C驱动的实现。作者试图通过AD采样和DA输出功能测试,但发现AD读取时无法同时模拟输出,寻求解决方案。
摘要由CSDN通过智能技术生成

PCF8591简单介绍

芯片的作用是ADDA转换,有16脚,其中AIN0~AIN3为模拟信号输入,A0~A3为芯片地址,SDA、SCL为I2C引脚,AOUT为DA输出端。

PCF8951的器件地址为1010A3A2A1A0(二进制),我买的芯片A0~A3都接GND,所以地址为0x90。

PCF8951使用方法

通过I2C通信读取数据和写入数据。

读取AD数据:发送第一个字节为器件地址,第二个字节为寄存器地址。然后再发送期间地址,此时读取数据即可读取出AD值。

写入DA数据:发送器件地址,发送寄存器地址,发送8位DA值。 

寄存器
D7D6D5D4D3D2D1D0

D7:0

D6:模拟输出启动标志位(为1有效)。

D5&D4:模拟输入方式:00四路单端输入,01三鹿差分输入,10单端差分缓和输入,11两个差分输入。

D3:0

D2:自动增量标志位(为1有效)(开启时通道在AD转换完成自动递增)。

D1&D0:AD通道选择:00通道0,01通道1,10通道2,11通道3。

软件I2C代码部分

这里我使用STM32F103C8T6驱动该芯片,分别使用软件I2C和硬件I2C驱动该芯片,顺便了解两者区别。

MyI2C.h(软件I2C的代码)

void MyI2C_W_SCL(uint8_t BitValue)//封装函数,方便操作
{
	GPIO_WriteBit(GPIOA, I2C_SCL, (BitAction)BitValue);//进行位操作
}

void MyI2C_W_SDA(uint8_t BitValue)//封装函数,方便操作
{
	GPIO_WriteBit(GPIOA, I2C_SDA, (BitAction)BitValue);
}

uint8_t MyI2C_R_SDA(void)//封装函数,方便操作
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIOA, I2C_SDA);//位读取
	return BitValue;
}

void MyI2C_Init(void)//软件I2C的GPIO端口初始化
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;//开漏输出,弱上拉模式
	GPIO_InitStructure.GPIO_Pin = GPIO_I2C_Pin;//引脚为自己宏定义
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_WriteBit(GPIOA, I2C_SCL, Bit_SET);
	GPIO_WriteBit(GPIOA, I2C_SDA, Bit_SET);
}

void MyI2C_Start(void)//I2C开始信号
{
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

void MyI2C_Stop(void)//I2C结束信号
{
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

void MyI2C_SendByte(uint8_t Byte)//I2C发送一个字节
{
	uint8_t i;
	for(i = 0; i < 8; i ++)
	{
		MyI2C_W_SDA(Byte & (0x80 >> i));
		MyI2C_W_SCL(1);
		MyI2C_W_SCL(0);
	}
}

uint8_t MyI2C_ReceiveByte(void)//I2C读取一个字节
{
	uint8_t Byte=0, i;
	MyI2C_W_SDA(1);//释放SDA,控制权给从机					
	for(i = 0; i < 8; i ++)
	{
		MyI2C_W_SCL(1);
		if(MyI2C_R_SDA())
			Byte |= (0x80 >> i);
		MyI2C_W_SCL(0);
	}
	return Byte;
}

void MyI2C_SendAck(uint8_t Ack)//I2C发送应答函数
{
	MyI2C_W_SDA(Ack);
	MyI2C_W_SCL(1);
	MyI2C_W_SCL(0);
}

uint8_t MyI2C_ReceiveAck(void)//I2C读取应答函数
{
	uint8_t Ack = 1;
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	Ack = MyI2C_R_SDA();
	MyI2C_W_SCL(0);
	return Ack;
}

通过软件I2C通信的PCF8591代码

uint8_t RegistCmd;

void PCF8591_SoftWareI2C_Init(void)//再次封装(声明其中一个即可)
{
	MyI2C_Init();
}

uint8_t PCF8591_SoftWareI2C_ADC_Ipt(uint8_t Command)//读取AD值函数
{
	uint8_t Data = 0;
	RegistCmd = (RegistCmd & 0x44) | Command;//进行或操作防止干扰其他
	MyI2C_Start();
	MyI2C_SendByte(0x90);
    MyI2C_ReceiveAck();
	MyI2C_SendByte(RegistCmd);
	MyI2C_Start();
	MyI2C_SendByte(0x91);
	MyI2C_ReceiveAck();
	Data = MyI2C_ReceiveByte();
	MyI2C_SendAck(1);
	MyI2C_Stop();
	return Data;
}

void PCF8591_SoftWareI2C_DAC_Opt(uint8_t Value)//写DA值函数
{
	MyI2C_Start();
	MyI2C_SendByte(0x90);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(0x40);
	MyI2C_ReceiveAck();
	MyI2C_SendByte(Value);
	MyI2C_Stop();
}

 主函数代码部分

#include "stm32f10x.h"
#include "OLED.h"
#include "PCF8951.h"

uint8_t AD_Value;

int main(void)
{
    OLED_Init();
    PCF8591_HardWareI2C_Init();
    while(1)
    {
        AD_Value = PCF8591_SoftWareI2C_ADC_Ipt(0x00);//读取滑动变阻器通道0的AD值
        OLED_ShowNum(1, 1, AD_Value, 3);
    }
}

/*
for(uint8_t i = 0; i < 255; i ++)//锯齿波的函数,需要注意AD读取和DA转换不能同时操作
{
    PCF8591_SoftWare_DAC_Opt(i);
}
*/

软件I2C通信PCF8591的实验现象

通过调节可变电阻器可以观察到数值在0~255之间产生变化

通过DA输出锯齿波,可以看出利用软件I2C输出的波形严重失真了,在5V每格的时候才能看出为锯齿波。

硬件I2C代码部分

void I2C_EventWait(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)//检查事件封装函数,防止死循环
{
	uint16_t LOOP = 10000;
	while(I2C_CheckEvent(I2Cx, I2C_EVENT) != SUCCESS)
	{
		LOOP --;
		if(LOOP == 0)
			break;
	}
}

void PCF8591_HardWareI2C_Init(void)//I2C初始化
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	I2C_InitTypeDef I2C_InitStructure;
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
	I2C_InitStructure.I2C_ClockSpeed = 40000;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_Init(I2C2, &I2C_InitStructure);
	
	I2C_Cmd(I2C2, ENABLE);
}

void PCF8591_HardWareI2C_ClearRegistCmd(void)//清除RegistCmd 的值
{
	RegistCmd = 0;
	I2C_GenerateSTART(I2C2, ENABLE);
	I2C_EventWait(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
	
	I2C_Send7bitAddress(I2C2, 0x90, I2C_Direction_Transmitter);
	I2C_EventWait(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	
	I2C_SendData(I2C2, RegistCmd);
	I2C_EventWait(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
	
	I2C_GenerateSTOP(I2C2, ENABLE);
}

uint8_t PCF8591_HardWareI2C_ADC_Ipt(uint8_t Command)
{
	uint8_t Data = 0;
	
	RegistCmd = (RegistCmd & 0x44) | Command;
	
	I2C_GenerateSTART(I2C2, ENABLE);
	I2C_EventWait(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
	
	I2C_Send7bitAddress(I2C2, 0x90, I2C_Direction_Transmitter);
	I2C_EventWait(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	
	I2C_SendData(I2C2, RegistCmd);
	I2C_EventWait(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
	
	I2C_GenerateSTART(I2C2, ENABLE);
	I2C_EventWait(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
	
	I2C_Send7bitAddress(I2C2, 0x90, I2C_Direction_Receiver);
	I2C_EventWait(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);
	
	I2C_EventWait(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED);
	Data = I2C_ReceiveData(I2C2);
	
	I2C_AcknowledgeConfig(I2C2, DISABLE);
	I2C_GenerateSTOP(I2C2, ENABLE);
	
	return Data;
}

void PCF8591_HardWareI2C_DAC_Opt(uint8_t Value)
{
	I2C_GenerateSTART(I2C2, ENABLE);
	I2C_EventWait(I2C2, I2C_EVENT_MASTER_MODE_SELECT);
	
	I2C_Send7bitAddress(I2C2, 0x90, I2C_Direction_Transmitter);
	I2C_EventWait(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
	
	I2C_SendData(I2C2, 0x40);
	I2C_EventWait(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTING);
	
	I2C_SendData(I2C2, Value);
	I2C_EventWait(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED);
	
	I2C_GenerateSTOP(I2C2, ENABLE);
}

主函数代码部分

硬件I2C通信PCF8591的实验现象

AD的实验现象与软件无异。

而通过硬件I2C通信的PCF8591输出的锯齿波波形可以看出比较干净。

本来购买该模块是用来做AD采样同时DA输出相同波形的实验,但是发现该芯片在AD读取的时候不能模拟输出,导致无法完成实验(也可能自己使用错误)。如果有大神可以实现希望能在评论区帮助一下,十分感谢。

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值