历史上的今天
返回首页

历史上的今天

今天是:2024年12月24日(星期二)

正在发生

2021年12月24日 | 51单片机系列——I2C通信方式——24C02(E2PROM)的应用

2021-12-24 来源:eefocus

仿真电路如下:
图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)函数中,没有单独的验证主从应答的子函数。

推荐阅读

史海拾趣

ET Enterprises Ltd公司的发展小趣事

ET Enterprises Ltd公司的历史可以追溯到1930年代,当时它作为EMI公司的一部分,开始涉足光检测技术领域。在这个早期阶段,公司致力于研究光信号的特性及其检测方法,为后续的光电倍增管技术奠定基础。

固驰(GUERTE)公司的发展小趣事

浙江固驰电子有限公司,即固驰(GUERTE)品牌的发源地,于1995年在浙江省丽水市创立。公司由范*先生创立,初期专注于半导体器件的生产。经过数年的不懈努力,固驰电子逐渐在行业内崭露头角,通过持续的技术创新和产品优化,成功开发出ZQ系列整流管芯、CELL芯片、5-200A单三相整流桥及电力半导体模块等核心产品。这些产品广泛应用于变频器、逆变焊机、UPS电源等领域,为公司的快速发展奠定了坚实基础。

Compensated Devices Inc公司的发展小趣事

Compensated Devices Inc(简称CDI)最初是一家小型电子元件制造商,专注于生产高精度电阻器。随着科技的飞速发展,传统电阻器已无法满足新兴市场的需求。CDI的创始人李先生敏锐地洞察到这一点,决定投入大量资源进行研发,推出了具有温度补偿和自动校准功能的新型电阻器。这一创新产品迅速获得了市场的认可,CDI也因此逐渐在电子行业中崭露头角。

风华邦科(FH-BK)公司的发展小趣事

近年来,随着国家对电子信息和无人机行业的政策支持力度不断加大,FlyWin集团迎来了快速发展的机遇。公司充分利用政策红利,加大在技术创新、市场拓展和人才培养等方面的投入。同时,公司还积极参与地方政府组织的各类科技创新活动和产业论坛,与同行企业、科研机构及政府部门建立了良好的合作关系。在多方努力下,FlyWin集团的业务规模不断扩大,品牌影响力显著提升,成为了电子行业中一颗璀璨的新星。

Ambersil公司的发展小趣事

在国内市场取得一定成绩后,Ambersil公司开始将目光投向国际市场。公司积极参加国际电子展会,与国际同行进行交流合作,不断推广自己的产品和技术。同时,公司还设立了海外分支机构,拓展海外市场。这些举措使得Ambersil公司的品牌在国际上逐渐树立起来,公司的销售额也实现了快速增长。

Akahane Electronics Ind Corp公司的发展小趣事

为了应对市场的多变性和不确定性,Akahane实施了多元化战略。除了继续深耕半导体领域外,公司还积极拓展智能家居、物联网等新兴领域。通过不断推出创新产品和完善服务体系,Akahane成功打开了新市场的大门,实现了业务的多元化发展。这一战略不仅为公司带来了新的增长点,还增强了公司的抗风险能力。


这些故事虽然基于虚构,但它们反映了电子行业中企业可能经历的一些典型发展路径和挑战。希望这些故事能够满足你的需求。

问答坊 | AI 解惑

军用电解电容器的应用可靠性选择

引言   电容器一般由两个接近并相互绝缘的导体构成,是军用电子整机不可缺少的基础元件。在军用电子产品中,电解电容器占有相当大的比重,其可靠性在整机中起着至关重要的作用。   根据国内有关部门的统计,在整机故障原因中,由电容器选择和 ...…

查看全部问答>

怎么评价一个载波恢复系统

一般工程上会用哪些指标去衡量一个载波恢复系统呢 主要包括一个pll 和 dco…

查看全部问答>

SmartRF® Studio 怎么用啊

SmartRF® Studio要怎么连接 才能用? 有用过的吗,指点下~~…

查看全部问答>

请问EVC如何实现GetBitmapBits函数的方法?

各位大侠,最近在编写EVC时,发现EVC有一个函数没有GetBitmapBits,请问大家有什么替代的方法没有?…

查看全部问答>

[NMD原码问题]“回车”的消息响应,不才望赐教

在nmd中回车的功能是进入下一级页面。但并不是靠VK_RETURN消息实现的,代码中有句注释如下 // NOTE: VK_RETURN is actualy handled by LBN_DBLCLK in the WMCommand handler 但我搜遍整个nmd目录未发现那里有将回车消息转换了,难道是在nmd目录外 ...…

查看全部问答>

请问,在BSP中应如何修改SDHC驱动,让它支持多个SD设备,请给一些思路.

现有的BSP中只支持一个SD卡.(问题1:一般来说 CPU物理上应可支持多个SD卡,它应有相关寄存器表示支持的SDIO设备数, 是不是这样?)   问题2: 请问,在BSP中应如何修改SDHC驱动,让它支持多个SD设备,请给一些思路.谢谢…

查看全部问答>

i/o接口问题

I/O接口与I/O控制器的区别? 通常说的串口编程,与串口设备的驱动有什么不同。 为什么通常都说对串口编程,而不是对具体的串口设备编程?(因为串口通用的原因吗?)…

查看全部问答>

地址总线编程问题

我现在要编写arm9(YC2440)的地址总线的程序,目的是实现给另一块板子传输数据的功能,不知道有没有人做过??或者有没有这方面的资料推荐一下,要是有人做过能不能把程序给我看一下,嘿嘿,多谢了,麻烦路过的高手都帮我看一看,这个比较急…

查看全部问答>

请问,如果我打算用STM32系列的单片机,都要准备什么工具?

                                 请问斑竹和各位老师,如果我打算用STM32系列的单片机,都要准备什么工具?软件呢,我看有人用REALVIEW MDK,但是我 ...…

查看全部问答>