51单片机——PCF8591_ADC_DAC驱动-模拟IIC通讯1.0

写的不知道好不好,有什么不对的地方还请指出,谢了。

1、上节已经单独写好了IIC驱动代码,本次驱动PCF8591就直接拿来用了。

2、首先,运用了go to语句,不知道如何使用的可自行学习。

3、驱动PCF8591,接口代码3个:读取端口的数字信号、通过端口输出模拟量、PCF8591数字转模拟量算法函数。

4、本代码里加入了判断通讯是否异常,感觉好啰嗦,应该单独写一个测试代码(测试代码以后在写),把正常通讯的精简一下。

5、哪个数字量转换成模拟量,之前我也不懂就把别人的代码抄过来了,现在知道为啥那样算了。

#ifndef __PCF8591_H__
#define __PCF8591_H__

//PCF8591 iic通讯时序还没有AT24C02快呢,iic器件遵守iic通讯协议,故,在这里就使用AT24C02器件的iic通讯协议了
//PCF8591芯片地址为1001 xxxy最后4位看原理图,在本单片机里芯片地址位1001 000y  即0x9?其中y位表示是读取器件还是向器件写入
//PCF8591使用逐次逼近型A/D转换,转换时间us级。

//AD转换,读取com通道的8位数据,
//0x00/0x40表示打开通道AIN0光敏	0x01/0x41表示打开通道AIN1热敏
//0x02/0x42表示打开通道AIN2滑动变阻器	
//0x03/0x43表示打开通带AIN3额外预留接口
unsigned char read_AD_data(unsigned char com);//直接读取的就是芯片转换后的数字信号

//DA转换,输出模拟量通过芯片的AOUT端口输出
unsigned char write_DA_data(unsigned char dat);//芯片直接接收数字信号后自动转换为模式信号并输出

//数字量转换成模拟电压公式如下
unsigned char convert_data(unsigned char DA);

#endif // !__PCF8591_H__

//PCF8591 iic通讯时序还没有AT24C02快呢,iic器件遵守iic通讯协议,故,在这里就使用AT24C02器件的iic通讯协议了
//PCF8591芯片地址为1001 xxxy最后4位看原理图,在本单片机里芯片地址位1001 000y  即0x9?其中y位表示是读取器件还是向器件写入
//读器件使用0x91,向器件写入数据使用0x90
//PCF8591使用逐次逼近型A/D转换,转换时间us级。

// SCL = P2_1;//时钟连接P2.1口
// SDA = P2_0;//时钟连接P2.0口

/*高位							地位
	0	x	x	x	0	x	x	x
	bit7位默认为0
	bit6位是否允许模拟电压输出,在DA转换时设置1,AD转换设置0或1均可。
	bit5和bit4位是选择模拟电压输出方式,一般位00单端输入方式。
	bit3位默认为0
	bit2位第是自动增量使能位,如果自动增量(auto-increment)标志置1,每次A/D 转换后通道号将自动增加。
	bit1和bit0位是在AD转换时选择哪一个通道输入的电压转换位数字量 00表示打开通道AIN0	01表示打开通道AIN1	10表示打开通道AIN2	11表示打开通带AIN3
*/
//AIN0通道连接光敏电阻,AIN1通道连接热敏电阻,AIN2通道连接模拟信号输入(滑动电阻器),AIN3未连接其他器件
#include "iic.h"

//本代码加入了读取ACK问题,使用了goto语句

//AD转换,读取com通道的8位数据,0x00/0x40表示打开通道AIN0	0x01/0x41表示打开通道AIN1	0x02/0x42表示打开通道AIN2	0x03/0x43表示打开通带AIN3
unsigned char read_AD_data(unsigned char com)
{
	unsigned char dat = 0;
	unsigned char i = 0;
	read_ad_data:
	START_IIC();
	write_1_byte_IIC(0x90);//准备向pcf8591器件写入数据,此器件的地址为1001 A0 A1 A2 R/W
	if (!read_ACK_IIC())//若接收到ACK则与器件握手成功
	{
		write_1_byte_IIC(com);//向器件写入使用哪个AD通到开始采集数据,0x00/0x40表示通道AIN0	0x01/0x41表示通道AIN1	0x02/0x42表示通道AIN2	0x03/0x43表示通带AIN3
		if (!read_ACK_IIC())
		{
			START_IIC();//和at24c02 读取数据有点类似   马来币之前没有写 手册英文没有看到这个地方如何读取的,参考别人写的代码
			write_1_byte_IIC(0x91);//准备读取pcf8591发来的数据
			if (!read_ACK_IIC())
			{
				dat = read_1_byte_IIC();
				write_ACK_IIC(1);//主机接收到数据向从设备不发送应答信号
				STOP_IIC();	//结束本次通讯
				return dat;
			}
			else
			{
				STOP_IIC();
				goto read_ad_data;
			}
		}
		else
		{
			STOP_IIC();
			goto read_ad_data;
		}
	}
	else
	{
		i++;
		if (i == 255)
		{
			return i;//如果握手失败255次则直接结束本函数,并向函数返回运行结果255;
		}
		STOP_IIC();
		goto read_ad_data;
	}
		
}

//DA转换,输出模拟量通过芯片的AOUT端口输出
unsigned char write_DA_data(unsigned char dat)//0~255对应0V~5V
{
	unsigned char i = 0;
	write_da_data:
	START_IIC();
	write_1_byte_IIC(0x90);
	if (read_ACK_IIC() == 0)
	{
		write_1_byte_IIC(0x40);//允许器件模拟输出,并且不自动增加输出端口
		if (!read_ACK_IIC())
		{
			write_1_byte_IIC(dat);
			if (!read_ACK_IIC())
			{
				STOP_IIC();
				return i;//如果握手失败255次则直接结束本函数,并向函数返回运行结果255;
			}
			else
			{
				STOP_IIC();
				goto write_da_data;
				
			}
				
		}
	 else
	 {
			STOP_IIC();
			goto write_da_data;
	 }
	}
	else
	{
		i++;
		if (i == 255)
		{
			return i;//如果握手失败255次则直接结束本函数,并向函数返回运行结果255;
		}
		STOP_IIC();
		goto write_da_data;
	}
}
//数字量转换成模拟电压公式如下
unsigned char convert_data(unsigned char DA)
{
	unsigned char i = 0;
	i = (unsigned char)(DA * 5 / 256.0 + 0.0005);//pcf8591内部数字量转化为模拟量的计算公式
	return i;
}

你可能感兴趣的:(单片机,嵌入式,c语言)