写的不知道好不好,有什么不对的地方还请指出,谢了。
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;
}