一、IIC协议介绍
总线启动:
SCL为高电平时,SDA由高电平向低电平变化
总线停止:
SCL为高电平时,SDA由低电平向高电平变化
应答信号:
在SCL为高电平时,接受设备将SDA拉为低电平表示传输正确,产生应答,否则为非应答。
IIC总线数据位的有效性规定:
IIC总线进行数据传送时,时钟信号SCL为高电平期间,数据线上的信号SDA必须保持稳定。只有SCL为低电平期间SDA上的电平才允许变化。因此在显示数据时,要在SCL为低的时候改变SDA。读数据时要在SCL为高的时候读SDA。
二、PCF8591
PCF8591地址定义
高四位固定不变
R/W:读1写0
器件地址:读0x91 写0x90
PCF8591读时序 A/D转换输出:
PCF8591写时序 D/A转换输出:
三、AT24C02
数据手册
Byte Write
Current Address Read
Device Address
四、代码实现
AT24C02 将开机次数显示在数码管上
#include <STC15F2K60S2.h>
#include <iic.h>
void display();
void Timer0Init(void);
void write_eeprom(unsigned char add,unsigned char val);
unsigned char read_eeprom(unsigned char add);
code unsigned char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};//共阳数码管段码
unsigned char dspbuf[]={11,11,11,11,11,11,11,11};//数据缓冲区
unsigned char dspcom=0;
//主函数
void main()
{
unsigned char reset_cnt=0;//开机次数存储,最大存储值为255
Timer0Init();
EA=1;//打开总中断
ET0=1;//打开定时器中断
// write_eeprom(0x00,0x30);//EEPROM中存储的数据需要进行初始化
reset_cnt=read_eeprom(0x10);//从AT24C02地址0x10中读取数据
reset_cnt++;
write_eeprom(0x10,reset_cnt);//向AT24C02地址0x10中写入数据
// write_eeprom(0x10,0x00);
//更新显示数据
dspbuf[5]=reset_cnt/100;
dspbuf[6]=reset_cnt%100/10;
dspbuf[7]=reset_cnt%10;
while(1);
}
void write_eeprom(unsigned char add,unsigned char val)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_SendByte(val);
IIC_WaitAck();
IIC_Stop();
}
unsigned char read_eeprom(unsigned char add)
{
unsigned char da;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
da=IIC_RecByte();
IIC_SendAck(0);
IIC_Stop();
return da;
}
//定时器0初始化
void Timer0Init(void) //2毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x9A; //设置定时初值
TH0 = 0xA9; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
//定时器0中断服务函数
void isr_timer_0(void)interrupt 1
{
display();
}
//显示函数
void display()
{
//消隐
P2=((P2&0x1f)|0xe0);
P0=0xff;
P2&=0x1f;
//位控制
P2=((P2&0x1f)|0xc0);
P0=(1<<dspcom);
P2&=0x1f;
//段选
P2=((P2&0x1f)|0xe0);
P0=tab[dspbuf[dspcom]];
P2&=0x1f;
if (++dspcom==8)
dspcom=0;
}
PCF8591
#include <STC15F2K60S2.h>
#include <intrins.h>
#include <iic.h>
void display();
void Timer0Init(void);
void Delay10us();
void init_pcf8591(unsigned char channel);
unsigned char read_pcf8591(void);
code unsigned char tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff,0x7f};//共阳数码管段码
unsigned char dspbuf[]={11,11,11,11,11,11,11,11};//数据缓冲区
unsigned char dspcom=0;
unsigned char intr,ad_value;
unsigned int v_value;
bit flag_100;
//主函数
void main()
{
Timer0Init();
EA=1;//打开总中断
ET0=1;//打开定时器中断
while(1)
{
if (flag_100)
{
flag_100=0;
init_pcf8591(0x03);
ad_value=read_pcf8591();
v_value=ad_value*100/51;
//更新显示数据
dspbuf[4]=v_value/100;
dspbuf[5]=12;
dspbuf[6]=v_value%100/10;
dspbuf[7]=v_value%10;
}
}
}
void init_pcf8591(unsigned char channel)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(channel);
IIC_WaitAck();
IIC_Stop();
Delay10us();
}
unsigned char read_pcf8591(void)
{
unsigned char temp;
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
temp=IIC_RecByte();
IIC_SendAck(0);
IIC_Stop();
return temp;
}
void Delay10us() //@11.0592MHz
{
unsigned char i;
_nop_();
i = 25;
while (--i);
}
//定时器0初始化
void Timer0Init(void) //2毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x9A; //设置定时初值
TH0 = 0xA9; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
}
//定时器0中断服务函数
void isr_timer_0(void)interrupt 1
{
if (++intr==50)
{
intr=0;
flag_100=1;
}
display();
}
//显示函数
void display()
{
//消隐
P2=((P2&0x1f)|0xe0);
P0=0xff;
P2&=0x1f;
//位控制
P2=((P2&0x1f)|0xc0);
P0=(1<<dspcom);
P2&=0x1f;
//段选
P2=((P2&0x1f)|0xe0);
P0=tab[dspbuf[dspcom]];
P2&=0x1f;
if (++dspcom==8)
dspcom=0;
}