一.软件模拟IIC
1.IIC延时函数
#define DELAY_TIME 5
void IIC_Delay(unsigned char i)
{
do{_nop_();}
while(i--);
}
2.数据发送的条件
每个时钟脉冲传输一位数据。
3.开始和停止
//总线引脚定义
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
//总线启动条件
//当SCLK时钟信号一直处于高电平状态时,
//SDA线由高电平跳变到低电平这个动作,表示起始信号
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 0;
}
//总线停止条件
//当SCLK时钟信号一直处于高电平状态时,
//SDA线由低电平跳变到高电平这个动作,表示结束信号
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 1;
IIC_Delay(DELAY_TIME);
}
4.等待从机(外设)应答/主机发送应答
协议规定,当SDA和SCLK同时为高时,表示空闲状态。
应答:数据接收方发送信号(低电平),表示成功接收到数据,且可以继续接收。
非应答:数据接收方发送信号(高电平),表示由于某些原因不再接收数据。
//等待从机是否应答,0-应答,1-非应答
//主机每传完一个字节的数据即外设每收到一个字节的数据,
//从机就要在第9个时钟脉冲到来的时候,将SDA数据线拉低进行应答(ACK),
//且必须是稳定的低电平,表示已经收到了一个字节的数据,高电平表示不进行应答
bit IIC_WaitAck(void)
{
bit ackbit;
SCL = 1;
IIC_Delay(DELAY_TIME);
ackbit = SDA; //在时钟脉冲到来后,读取从机是否应答(此时已稳定)
SCL = 0;
IIC_Delay(DELAY_TIME);
return ackbit;
}
//主机发送是否应答
void IIC_SendAck(bit ackbit)
{
SCL = 0;
SDA = ackbit; // 0:应答,1:非应答,在时钟脉冲到来前给出是否应答信号
IIC_Delay(DELAY_TIME);
SCL = 1;
IIC_Delay(DELAY_TIME);
SCL = 0;
SDA = 1;
IIC_Delay(DELAY_TIME);
}
5.发送/接收一个字节
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++)
{
SCL = 0;
IIC_Delay(DELAY_TIME);
if(byt & 0x80) SDA = 1; //按位发送一个字节数据,先发高位
else SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 1; //产生时钟脉冲
byt <<= 1; //准备发送下一位
IIC_Delay(DELAY_TIME);
}
SCL = 0;
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char i, da;
for(i=0; i<8; i++)
{
SCL = 1; //产生时钟脉冲
IIC_Delay(DELAY_TIME);
da <<= 1; //准备接收下一位
if(SDA) da |= 1; //按位接收一个字节数据,先接收高位
SCL = 0;
IIC_Delay(DELAY_TIME);
}
return da;
}
二.原理图
三.PCF8591(A/D转换芯片)
PCF8591器件地址:
高四位固定,为1001。A2、A1、A0由芯片对应引脚确定,此开发板全部接低电平,即全为0。最低位表示读/写,1—读,0—写。所以读芯片数据时,器件地址为0x91,写数据时,器件地址为0x90。
控制字节:
第7位:固定值0;
第6位:0—A/D转换,1—D/A转换;
第5、4位:00—四路单端输入,01—三路差分输入,10—两路单端,一路差分,11—两路差分输入;
第3位:固定值0;
第2位:0—禁止自动增量,1—允许自动增量;
第1、0位:00—选择AIN0,01—选择AIN1,10—选择AIN2,11—选择AIN3.
1.A/D转换输出过程:
代码:
unsigned char READ_IIC_PCF8591(unsigned char con)
{
unsigned char temp;
EA=0; //关闭中断,防止干扰读取
IIC_Start();
IIC_SendByte(0x90); //发送器件地址,写
IIC_WaitAck();
IIC_SendByte(con); //发送控制字节
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91); //发送器件地址,读
IIC_WaitAck();
temp=IIC_RecByte(); //读一个字节数据
IIC_SendAck(1); //主机发送非应答,不再接收数据
IIC_Stop();
EA=1;
return temp;
}
void mian()
{
unsigned char vol;
while(1)
{
vol=READ_IIC_PCF8591(0x03);
//A/D转换模式,读取通道3的数据,即电位器电压数字量
//若为0x01,则读取通道1的数据,即光敏电阻的数值,得到光强
vol=vol/255.0*5; //把数字量回归成模拟量,8位AD
}
}
2.D/A转换输出过程:
代码
void IIC_PCF8591_DA(unsigned char dat)
{
IIC_Start();
IIC_SendByte(0x90); //发送器件地址,写
IIC_WaitAck();
IIC_SendByte(0x40); //发送控制字节,设置D/A转换模式
IIC_WaitAck();
IIC_SendByte(dat); //发送数字量
IIC_WaitAck();
IIC_Stop();
}
void mian()
{
unsigned char vol;
while(1)
{
vol=3.0/5*255; //把3V电压转换成8位数字量
IIC_PCF8591_DA(vol); //输出3V电压
}
}
四.AT24C02(EEPROM,256*8bit=2Kb容量,分成32页)
器件地址:
该系列芯片地址表,此芯片是2K容量,所以看第一个地址。与PCF8591类似。
1.向芯片写一个字节数据:
代码
void WRITE_AT24C02(unsigned char add,unsigned char dat)
{
IIC_Start();
IIC_SendByte(0xa0); //发送器件地址,写
IIC_WaitAck();
IIC_SendByte(add); //发送数据存储地址(0x00~0xFF,共256个地址,每个地址一个字节)
IIC_WaitAck();
IIC_SendByte(dat); //发送需存入的数据
IIC_WaitAck();
IIC_Stop();
}
2.从芯片任意地址读一个字节数据
代码
unsigned char READ_AT24C02(unsigned char add)
{
unsigned char temp;
EA=0;
IIC_Start();
IIC_SendByte(0xa0); //发送器件地址,写
IIC_WaitAck();
IIC_SendByte(add); //发送需要读取的数据地址
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1); //发送器件地址,读
IIC_WaitAck();
temp=IIC_RecByte(); //读取一个字节数据
IIC_SendAck(1); //主机发送非应答,停止读取数据
IIC_Stop();
EA=1;
return temp;
}
//每次复位或加电,自加1,并存入AT24C02
void main()
{
unsigned char number;
number=READ_AT24C02(0x00); //读取0x00地址的数据
WRITE_AT24C02(0x00,++number); //自加1后重新存入
while(1);
}
评论(0)
您还未登录,请登录后发表或查看评论