一、原理部分
设备寻址
在开启eeprom后需要一个8位设备地址,以使芯片能够进行读或写操作,第八位为0的时候进行写的操作,为1的时候进行读的操作。
写操作
进行写操作的时候要先写入一个设备地址,然后还需要写入一个8位的数据地址,eeprom收到这个地址后会再次响应,这时eeprom会接受后面的8位的数据,接受完成后会储存数据到内部,直到全部写完后才会再次响应。
根据时序图编写以下代码
void write_eeprom(unsigned char add,unsigned char date)
{
IIC_Start();//启动总线
IIC_SendByte(0xa0);//发送设备地址,第八位为0所以为写
IIC_WaitAck();//等待应答
IIC_SendByte(add);//发送数据地址
IIC_WaitAck();//等待应答
IIC_SendByte(date);//发送数据
IIC_WaitAck();//等待应答
IIC_Stop();//停止总线
}
读操作
读操作的时候只需要在设备地址的第八位改成1就可以进行读取。
根据时序图编写以下代码
unsigned char read_eeprom(unsigned char add)
{
unsigned char temp;//定义变量temp用来获得eeprom中的数据
EA = 0;//关闭中断,中断可能会影响总线时序
IIC_Start();//开启总线
IIC_SendByte(0xa0);
//发送设备地址,第八位为0所以为写,因为读取的时候为读取现在的地址加一,所以要发送现在写的地址进去
IIC_WaitAck();//等待应答
IIC_SendByte(add);//发送数据地址
IIC_WaitAck();//等待应答
IIC_Start();//开启总线
IIC_SendByte(0xa1);//发送设备地址,第八位为1所以为读,读取的地址为刚刚我们写入的地址
IIC_WaitAck();//等待应答
temp = IIC_RecByte();//读取数据
IIC_WaitAck();//等待应答
IIC_Stop();//停止总线
EA = 1;//打开中断
return temp;//返回temp
}
二、代码部分
实验平台:CT107D
实验芯片:stc15f2k60s2
实验现象:记录开机次数,并且保存在eeprom中
代码如下
iic.c
#include "stc15f2k60s2.h"
#include "intrins.h"
#define DELAY_TIME 5
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//总线引脚定义
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
void IIC_Delay(unsigned char i)
{
do{_nop_();}
while(i--);
}
//总线启动条件
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 0;
IIC_Delay(DELAY_TIME);
SCL = 0;
}
//总线停止条件
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
IIC_Delay(DELAY_TIME);
SDA = 1;
IIC_Delay(DELAY_TIME);
}
//发送应答
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);
}
//等待应答
bit IIC_WaitAck(void)
{
bit ackbit;
SCL = 1;
IIC_Delay(DELAY_TIME);
ackbit = SDA;
SCL = 0;
IIC_Delay(DELAY_TIME);
return ackbit;
}
//通过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;
}
void write_eeprom(unsigned char add,unsigned char date)
{
IIC_Start();//启动总线
IIC_SendByte(0xa0);//发送设备地址,第八位为0所以为写
IIC_WaitAck();//等待应答
IIC_SendByte(add);//发送数据地址
IIC_WaitAck();//等待应答
IIC_SendByte(date);//发送数据
IIC_WaitAck();//等待应答
IIC_Stop();//停止总线
}
unsigned char read_eeprom(unsigned char add)
{
unsigned char temp;//定义变量temp用来获得eeprom中的数据
EA = 0;//关闭中断,中断可能会影响总线时序
IIC_Start();//开启总线
IIC_SendByte(0xa0);
//发送设备地址,第八位为0所以为写,因为读取的时候为读取现在的地址加一,所以要发送现在写的地址进去
IIC_WaitAck();//等待应答
IIC_SendByte(add);//发送数据地址
IIC_WaitAck();//等待应答
IIC_Start();//开启总线
IIC_SendByte(0xa1);//发送设备地址,第八位为1所以为读,读取的地址为刚刚我们写入的地址
IIC_WaitAck();//等待应答
temp = IIC_RecByte();//读取数据
IIC_WaitAck();//等待应答
IIC_Stop();//停止总线
EA = 1;//打开中断
return temp;//返回temp
}
iic.h
#ifndef _IIC_H
#define _IIC_H
void IIC_Start(void);
void IIC_Stop(void);
bit IIC_WaitAck(void);
void IIC_SendAck(bit ackbit);
void IIC_SendByte(unsigned char byt);
unsigned char IIC_RecByte(void);
void write_eeprom(unsigned char add,unsigned char date);
unsigned char read_eeprom(unsigned char add);
void init_adc(unsigned char add);
unsigned char read_adc();
#endif
main.c
#include<stc15f2k60s2.h>
#include<iic.h>
#define uchar unsigned char
#define uint unsigned int
sbit buzz = P0^6;
uchar code duan[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00};//定义段码数组
uchar disbuff[8];//定义显示数字数字
uchar boot_time = 0;
void closebuzz()
{
P2 = 0xa0;
buzz = 0;
P2 = 0x00;
}
void shownum()//显示数字函数
{
disbuff[0]=10;
disbuff[1]=10;
disbuff[2]=10;
disbuff[3]=10;
disbuff[4]=10;
disbuff[5]=10;
disbuff[6]=boot_time/10;
disbuff[7]=boot_time%10;
}
void display()//数码管扫描函数
{
static uchar index = 0;
P2 = 0xe0;
P0 = 0xff;
P2 = 0x00;
P2 = 0xc0;
P0 = 1<<index;
P2 = 0x00;
P2 = 0xe0;
P0 = ~duan[disbuff[index]];
P2 = 0x00;
index++;
index &= 0x07;
}
void Timer0Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x40; //设置定时初值
TH0 = 0xA2; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1 ;
}
void time0() interrupt 1
{
display();
}
void main()
{
closebuzz();
Timer0Init();
boot_time = read_eeprom(0x01);
write_eeprom(0x01,++boot_time);
while(1)
{
shownum();
}
}
来源:CSDN
作者:天地神仙
链接:https://blog.csdn.net/FuckerGod/article/details/104174115