PCF8951+I2C+STC89C52 ADC采集与输出
I2C
IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。主要包括启始、停止、读、写、应答信号。这种方式简化了信号传输总线接口。
IIC总线上可以挂多个器件,而每个器件都有唯一的地址,这样可以标识通信目标。数据的通信的方式采用主从方式,主机负责主动联系从机,而从机则被动回应数据。
1.I2C总线信号
(1)开始和停止信号
- 开始信号:SCL=1,SDA下降沿;
void start()
{
SDA = 1; //初始时,SDA=1
SCL = 1; //初始时,SCL=1
delay(); //保持时间大于4.7us
SDA = 0; //SDA下降沿
delay(); //SDA下降沿保持时间大于4.0us
}
- 停止信号:SCL=1,SDA为上升沿。
void stop()
{
SDA = 0; //初始时,SDA=0;
SCL = 1; //初始时,SCL=1;
delay(); //保持时间大于4.0us
SDA = 1; //SDA上升沿
delay(); //保持时间大于4.7us
}
(2)应答信号
void ack()
{
uchar i = 0; //定义缓冲变量
SCL = 1;
delay();
while(SDA == 1 && i < 250)i++; //稳定时间大于4us
SCL = 0; //SCL=0时,SDA数据才可以改变
delay();
}
2.I2C总线数据传输条件
- SCL=1时,SDA必须保持稳定;
- SCL=0时,SDA才允许改变。
3.I2C总线读写操作
(1) 数据传送规则:
- 每传送一个字节时必须保证是8位长度;
- 数据传送时,先传送最高位(MSB);
- 每个被传送的字节后面,跟随一位应答信号,即一帧实际共有9位。
(2)数据传送流程:
- 主机向总线发送一个字节的数据后,释放总线,从机拉低总线(即应答信号),表示这一字节发送成功;
- 主机从总线读取完一个字节的数据后,主机把总线拉低,表示这一字节发送成功。
a.写入数据
void write_byte(uchar dat)
{
uchar i;
for(i = 0; i < 8; i++)
{
dat = dat << 1; //先写最高位,通过左移运算符,将一个字节的数据一位一位的传送到总线上
SCL = 0; //SCL=0,从机准备接收数据
delay();
SDA = CY; //CY存储的是左移后的进位
delay();
SCL = 1;
delay();
}
SCL = 0; //8位数据传输完后,释放SDA,准备接收应答位
SDA = 1; // 释放SDA
delay();
}
b.读取数据
uchar read_byte()
{
uchar dat = 0, tmp, i;
SCL = 0; //SCL=0,准备接收数据
delay();
for(i = 0; i < 8; i++)
{
SCL = 1; //SCL = 1,SDA稳定,准备读取数据
delay();
tmp = SDA; //读取此时SDA的状态
dat = dat << 1; //先写最高位,通过左移运算符,将一个字节的数据一位一位的传送到总线上
dat = dat | tmp; //读数据位,接收的数据位放在dat中
delay();
SCL = 0; //释放SDA总线,为下一次读取做准备
delay();
}
return dat; // 返回读取的dat值
}
4.I2C总线初始化
void I2C_init()
{
SDA = 1;
delay();
SCL = 1;
delay();
}
PCF8951
PCF8591是单片、单电源低功耗8位CMOS数据采集器件,具有4个模拟输入、一个输出和一个串行I2C总线接口。3个地址引脚A0、A1 和A2 用于编程硬件地址,允许将最多8个器件连接至I2C总线而不需要额外硬件。器件的地址、控制和数据通过两线双向I2C总线传输。器件功能包括多路复用模拟输入、片上跟踪和保持功能、8位模数转换和8位数模拟转换。最大转换速率取决于I2C总线的最高速率。
1.器件地址
总线启动后,发送的第一个字节。
由电路原理图可知,A0 A1 A2均为0,所以:
- lsb=0时,即器件地址为0x90时,表示主机向从机写数据,下一个字节向总线写入数据;
- lsb=1时,即器件地址为0x91时,表示主机从从机读数据,下一个字节从总线读取数据。
2.控制字
总线启动后,发送的第二个字节。
- msb,默认为0;
- 第6位,选择是否允许模拟电压输出,DA转换时设置为1,AD转换时设置为0或1均可;
- 第5/4位,选择模拟电压输出方式;
- 第3位,默认为0;
- 第2位,是自动增量使能位,设置1后,每次A/D 转换后通道号将自动增加;
- 第1/0位,是在AD转换时选择输入的电压转换为数字量的通道。
3.ADC
将AIN端口输入的模拟电压转换为数字量并发送到总线上。
uchar Read_D(uchar Channel)
{
uchar dat; //定义缓存变量
start(); //启动I2C总线
write_byte(0x90); //向总线写入从机地址09x0,表示下一个字节向总线写入数据 ,+0,主机发送数据
ack(); //应答信号
write_byte(Channel); //向总线写入控制字Channel表示通道1
ack(); //应答信号
start(); //重复启动I2C总线,读写方向和上一次相反
write_byte(0x91); //向总线写入从机地址09x1,表示下一个字节从总线读取数据 ,+1,主机接收数据
ack(); //应答信号
dat=read_byte(); //读取数据并赋给变量dat
ack(); //应答信号
stop(); //停止I2C总线
return dat; //返回读取的数据值
}
4.DAC
将从总线上接收到的数字量通过AOUT输出。
void Out_A(uchar Digital)
{
start(); //启动I2C总线
write_byte(0x90); //向总线写入主机地址09x0,表示下一个字节向总线写入数据,+0,主机发送数据
ack(); //应答信号
write_byte(0x40); //向总线写入控制字0x40,允许模拟输出,不自增单端,通道0
ack(); //应答信号
write_byte(Digital); //向总线写入要转换的数字量Digital
ack(); //应答信号
stop(); //停止I2C总线
}
主函数
void main()
{
I2C_init() ; //I2C总线初始化
dat1 = Read_D(0x01); //将通道1的模拟量转化为数字量,并读取
delay();
Out_A(dat1); //将数字量转化为模拟量输出
delay();
}
END!