51单片机系列——I2C通信方式——24C02(E2PROM)的应用

发布者:ikfnpo最新更新时间:2021-12-24 来源: eefocus关键字:51单片机系列  24C02  E2PROM 手机看文章 扫描二维码
随时随地手机看文章

仿真电路如下:
图1

代码如下:

i2c.h


#ifndef _I2C_H    //写头文件的固定格式

#define _I2C_H   //写头文件的固定格式


#include


sbit SCL=P1^2;   //E2PROM24C02的引脚定义

sbit SDA=P1^3;   //E2PROM24C02的引脚定义

sbit WP=P1^4; //读写保护


unsigned char I2CSendByte(unsigned char dat);

unsigned char I2CReadByte();

void I2CStop();

void I2CStart();

void At24c02Write(unsigned char addr,unsigned char dat);  //在头文件中申明,在主函数中便可调用

unsigned char At24c02Read(unsigned char addr);


#endif      //写头文件的固定格式


i2c.c


#include "i2c.h"


void delay5us(void)   //误差 0us

{

    unsigned char a;

    for(a=1;a>0;a--);


void I2CStart(){ //I2C开始信号,严格按照时序图

 SDA=1;

 SCL=1;

 delay5us(); 

 SDA=0;

 delay5us();

 SCL=0;

 delay5us(); 

}


void I2CStop(){ //停止信号

 SDA=0;

 SCL=1;

 delay5us();

 SDA=1;

 delay5us();   //后面的可以不管了,因为已经能起到stop的作用 

}


unsigned char I2CSendByte(unsigned char dat){ //写一个字节函数

  unsigned char a=8,b;

  for(a=8;a>0;a--){

   SDA=dat>>7;

  dat=dat<<1;

  delay5us();

  SCL=1;     //时钟线为低时数据才能传送,时钟线为高电平的时候数据是要求保持不变的

  delay5us();  //检测SDA是否为0,及是否应答

  SCL=0;

  delay5us();

  }

   SDA=1;   //释放时钟线和数据线,等待应答

  delay5us();

   SCL=1;

   while(SDA){   //检测是否应答,若应答SDA=0跳出循环,若SDA=1则非应答

     b++;   //SDA=1,设定一个时间跳出循环,返回0

   if(b>20){

    SCL=0;

    delay5us(); 

    return 0;

   }

   }

   SCL=0;

   delay5us(); 

   return 1;   //发送成功返回1   

}


unsigned char I2CReadByte(){ //读一个字节数据

 unsigned char a=8,dat=0;

 SDA=1; //拉高准备读

 delay5us();

 for(a=8;a>0;a--){

  SCL=1;   //SCL时数据稳定,读取时要求数据稳定

  delay5us();  

  dat<<=1;  //在这里读和写的顺序不一样,读:移位———>读数;写:写数-->移位

  dat|=SDA;  //为什么这里读数据可以直接移位然后相与呢?移位时钟线与数据线不是同一根线

  delay5us();  

  SCL=0;   //SCL为零时,SDA上的数据可以改变

  delay5us(); 

 }

 return dat;     

}


/* I2CSendByte、I2CReadByte这两个函数是用来确定8位字节数据是在什么条件下能读写出来的*/

/*可以吧I2CSendByte、I2CReadByte这两个函数理解为小环境*/

/*有了满足了小环境的读写(一个字节8位数的连续传输),就要创造大环境(即这个整体器件是在什么条件下怎么传送数据的*/

/*或者可以理解为先根据时序图写出满足I2C的读写数据方式,在写出满足器件读写的数据方式*/


void At24c02Write(unsigned char addr,unsigned char dat){ //先写地址,确定数据存放的位置;再写数据  (根据器件的写数据的流程来编写这个函数)

 I2CStart();

 I2CSendByte(0xa0);  //确定器件地址,及哪个器件

 I2CSendByte(addr);  //写器件内首地址,确定存放数据的首地址位置

 I2CSendByte(dat);   //确定玩地址后,就发送数据

 //关于应答部分已经写在发送函数中,相当于一个整体

 I2CStop();   //发送玩了,一个停止信号

}


unsigned char At24c02Read(unsigned char addr){  //读数据需要设一个返回值,靠这个返回值得到数据更容易编写

 unsigned char num;

 I2CStart();

 I2CSendByte(0xa0);  //读的时候先伪写入

 I2CSendByte(addr);  //伪写入包括两部分:确定器件地址和确定器件内首地址 

 I2CStart();     //在传送过程中,需要改变传送数据的方向时,起始信号和从机地址都会被重复产生一个,但两次读写方向正好相反

 I2CSendByte(0xa1);   //这两部很重要

 num=I2CReadByte();  //获取读的数据

 I2CStop();

 return num;

}


main.c


#include

#include "i2c.h"


typedef unsigned int u16;

 typedef unsigned char u8;

/*控制读写过程*/

 sbit K1=P3^1; //保存显示数据,即写入数据至E2Prom保存

 sbit K2=P3^0; //读取保存的数据

 sbit K3=P3^2; //累加

 sbit K4=P3^3; //清零


sbit LSA=P2^2;   //三八译码器的引脚设置

sbit LSB=P2^3;

sbit LSC=P2^4;


u8 code segment[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

u8 num=0,disp[4];  //disp也可以写成一个缓冲池 :disp[4]={1,1,2,3};


void delay(u16 i){

 while(i--);

}


void Keypros(){  //按键处理函数

 if(K1==0){

  delay(100);  //消抖

  if(K1==0){

   WP=0;  /*关闭保护*/

   At24c02Write(2,num);  //写入存放的首地址和要存放的数据(AT24C02有256个地址,2是其中的一个,num可以是自己设的一个数值)

    delay(100)  ;/*等待读完成*/

    WP=1;   /*打开保护*/

  }

  while(!K1);   //这个很重要,判断开关是否断开

 }

  if(K2==0){

  delay(100);  //消抖

  if(K2==0){

   num=At24c02Read(2);  //之前写入的地址为2,因此读2 ,num最后等于读取的返回值

  }

  while(!K2);

 }

 if(K3==0){

  delay(100);  //消抖

  if(K3==0){

   num++;  // num累计

   if(num>255){

    num=0;

   }

  }

  while(!K3);

 }

 if(K4==0){

  delay(100);  //消抖

  if(K4==0){

   num=0;  

  }

  while(!K4);

 }

}


void datapros(){ //数据处理函数,将存储器里的数转换为数码管理的数

   disp[0]=segment[num/1000];  //最高位

   disp[1]=segment[num%1000/100];

   disp[2]=segment[num%1000%100/10];

   disp[3]=segment[num%1000%100%10];

}


void Dispiay(){  //显示函数

 u8 i;

 for(i=0;i<4;i++){

  switch(i){

   case 0:LSA=0;LSB=0;LSC=0;break; //显示第0位

   case 1:LSA=1;LSB=0;LSC=0;break; //显示第1位

   case 2:LSA=0;LSB=1;LSC=0;break; //显示第2位

   case 3:LSA=1;LSB=1;LSC=0;break; //显示第3位

  }

  //上面选通了是哪一位,下面就传断选数据

  P0=disp[3-i];  //根据数据处理函数得到要显示的数,在循环的条件下,将一个数利用4个数码管显示了出来

  delay(100);

  P0=0x00;  //消隐

 }

}


void main(){ //  进入主函数调用

  while(1){

  Keypros(); //先判断按键是否有操作

  datapros();  //判断玩后对获取的数据要进行处理

   Dispiay();    //数据处理完了就可以显示  

 }

 }

仿真结果图:
1、按下K3,数码管显示数字自动加1,按3下显示:
图2

2、按下K1,数码管上的显示数自动保存至24C02中(本程序中地址是2),接着按几次K3改变数码管的显示数值,然后按下K1,数码管】显示保存的数“3”.按下K4,数码管清零。


**注意:**这个项目中将I2C的主从应答部分直接编程在unsigned char I2CSendByte(unsigned char dat)函数中,没有单独的验证主从应答的子函数。

关键字:51单片机系列  24C02  E2PROM 引用地址:51单片机系列——I2C通信方式——24C02(E2PROM)的应用

上一篇:51单片机实验2——I2C通信——24C01扩展实验
下一篇:51单片机系列——单总线通信方式——DS18B20温度检测的设计

推荐阅读最新更新时间:2024-11-09 12:22

8051/2单片机常用的本地通讯方式 UART,RS485,I2C,SPI 之 I2C E2PROM 3
一、说明 单片机IO模拟,使用E2PROM 24C02C 1. 起始信号保持时间 Thd:sta 4us 2. 起始信号的建立时间 Tsu:sta 4.7us 3. SCL低电平持续时间 Tlow 4.7us 4. SCL高电平持续时间 Thigh 4us 5. 停止信号的建立时间 Tsu:sta 4us 二、演示 3.代码 /** * 8051/2 DEMO 3 * 常用的本地通讯方式 * 1. 串口UART, 波特率:9600 * 接设备的时候,一般只接GND RX TX,不会接Vcc,避免与目标设备上的供电冲突。 * 1.1 RS485标准( +2V ~ +6V:1 / -6V ~ -
[单片机]
8051/2单片机常用的本地通讯<font color='red'>方式</font> UART,RS485,<font color='red'>I2C</font>,SPI 之 <font color='red'>I2C</font> <font color='red'>E2PROM</font> 3
51单片机-STC89C52系列学习第一篇之IO口学习
STC89C52系列单片机IO口有三种工作模式: 1、准双向口/弱上拉(标准8051输出模式) 2、开漏输出模式 3、输入模式 其中P1/P2/P3/P4上电复位后为传统的8051的IO口模式,而P0口上电后是开漏输出。 P0口作为IO口使用时需要加4.7K-10K的上拉电阻。 新增特殊功能寄存器的声明示例: sfr P4 = 0xe8; sbit P40 = 0xe8; sbit P41 = 0xe9; sbit P42 = 0xea; sbit P43 = 0xeb; sbit P44 = 0xec; sbit P45 = 0xed; sbit P46 = 0xee; 将寄存器P4的位全部置为1: P4 = 0xff; 单
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved