历史上的今天
返回首页

历史上的今天

今天是:2025年03月05日(星期三)

正在发生

2020年03月05日 | STC8A8K64单片机关于AT24C04基本读写操作

2020-03-05 来源:eefocus

实验:AT24C04基本读写操作


步骤及现象:在下载程序前,选择stc-isp的IRC频率:12MHz。

程序下载完成后,在串口助手界面,HEX模式下,选择波

特率9600,然后点击“打开串口”按钮。这时按独立按键1

在接收缓冲区打印出刚写入的16个数据。


*数据帧格式

I2C总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。

在起始信号后必须传送一个从机的地址(7位),第8位是数据的传送方向位(R/T),用“0”表示主机发送数据(T),“1”表示主机接收数据(R)。每次数据传送总是由主机产生的终止信号结束。但是,若主机希望继续占用总线进行新的数据传送,则可以不产生终止信号,马上再次发出起始信号对另一从机进行寻址。

在总线的一次数据传送过程中,可以有以下几种组合方式:

a、主机向从机发送数据,数据传送方向在整个传送过程中不变:

a

注:有阴影部分表示数据由主机向从机传送,无阴影部分则表示数据由从机向主机传送。

A表示应答,A非表示非应答(高电平)。S表示起始信号,P表示终止信号。

b、主机在第一个字节后,立即从从机读数据:

b

c、在传送过程中,当需要改变传送方向时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好反相。

c

总线的寻址

I2C总线协议有明确的规定:采用7位的寻址字节(寻址字节是起始信号后的第一个字节)。

(1)寻址字节的位定义

寻址方式

D7~D1位组成从机的地址。D0位是数据传送方向位,为“0”时表示主机向从机写数据,为“1”时表示主机由从机读数据。

主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,如果相同,则认为自己正被主机寻址,根据R/T位将自己确定为发送器或接收器。

从机的地址由固定部分和可编程部分组成。在一个系统中可能希望接入多个相同的从机,从机地址中可编程部分决定了可接入总线该类器件的最大数目。如一个从机的7位寻址位有4位是固定位,3位是可编程位,这时仅能寻址8个同样的器件,即可以有8个同样的器件接入到该I2C总线系统中。

(2)写入过程

AT24C系列E2PROM芯片地址的固定部分为1010,A2、A1、A0引脚接高、低电平后得到确定的3位编码。形成的7位编码即为该器件的地址码。

单片机进行写操作时,首先发送该器件的7位地址码和写方向位“0”(共8位,即一个字节),发送完后释放SDA线并在SCL线上产生第9个时钟信号。被选中的存储器器件在确认是自己的地址后,在SDA线上产生一个应答信号作为相应,单片机收到应答后就可以传送数据了。

传送数据时,单片机首先发送一个字节的被写入器件的存储区的首地址,收到存储器器件的应答后,单片机就逐个发送各数据字节,但每发送一个字节后都要等待应答。

AT24C系列器件片内地址在接收到每一个数据字节地址后自动加1,在芯片的“一次装载字节数”(不同芯片字节数不同)限度内,只需输入首地址。装载字节数超过芯片的“一次装载字节数”时,数据地址将“上卷”,前面的数据将被覆盖。

当要写入的数据传送完后,单片机应发出终止信号以结束写入操作。写入n个字节的数据格式 :

写格式

(3)读出过程

单片机先发送该器件的7位地址码和写方向位“0”(“伪写”),发送完后释放SDA线并在SCL线上产生第9个时钟信号。被选中的存储器器件在确认是自己的地址后,在SDA线上产生一个应答信号作为回应。

然后,再发一个字节的要读出器件的存储区的首地址,收到应答后,单片机要重复一次起始信号并发出器件地址和读方向位(“1”),收到器件应答后就可以读出数据字节,每读出一个字节,单片机都要回复应答信号。当最后一个字节数据读完后,单片机应返回以“非应答”(高电平),并发出终止信号以结束读出操作。


读过程

at24c04_i2c.c文件:


#include "at24c0x_i2c.h"

#include

#include


#define AT24_Address  0xA0    // AT24C0X的设备地址


// i2c总线引脚定义

sbit SDA = P7^6;              // 数据线

sbit SCL = P7^7;              // 时钟线 


/********************************************************************

**********                硬件I2C操作部分              **************

*********************************************************************/


#ifdef HardI2C                // 硬件I2C操作部分


// 毫秒延时

void DelayI2C(unsigned int xms)

{

    unsigned int i, j;


for(i=xms;i>0;i--)

{

for(j=921;j>0;j--);

}

}


// 初始化硬件I2C

void InitI2C()

{

// 访问逻辑地址位于XDATA区域的特殊功能寄存器前需要

// 将 P_SW2(BAH)寄存器的最高位(EAXFR)置 1

P_SW2 = 0x80; 

    I2CCFG = 0xe0;            // 使能I2C主机模式

    I2CMSST = 0x00;

P_SW2 |= 0x20;

}


// 清中断

void Wait()     

{

    while (!(I2CMSST & 0x40));

    I2CMSST &= ~0x40;

}


// 起始信号

void Start()

{

    I2CMSCR = 0x01;                             //发送START命令

    Wait();

}


// 发送数据

void SendData(char dat)

{

    I2CTXD = dat;                               //写数据到数据缓冲区

    I2CMSCR = 0x02;                             //发送SEND命令

    Wait();

}


// 接收应答信号

void RecvACK()

{

    I2CMSCR = 0x03;                             //发送读ACK命令

    Wait();

}


// 接收数据

char RecvData()

{

    I2CMSCR = 0x04;                             //发送RECV命令

    Wait();

    return I2CRXD;

}


// 发送应答信号

void SendACK()

{

    I2CMSST = 0x00;                             //设置ACK信号

    I2CMSCR = 0x05;                             //发送ACK命令

    Wait();

}


// 发送非应答信号

void SendNAK()

{

    I2CMSST = 0x01;                             //设置NAK信号

    I2CMSCR = 0x05;                             //发送ACK命令

    Wait();

}


// 停止信号

void Stop()

{

    I2CMSCR = 0x06;                             //发送STOP命令

    Wait();

}


// 往地址add中,写入数据dat

//void write_24c04(unsigned char add, unsigned char dat)

//{

// Start();                  // 发送起始命令

//    SendData(AT24_Address);   // 发送设备地址+写命令

//    RecvACK();

//    SendData(add);            // 发送存储地址

//    RecvACK();

//    SendData(dat);            // 写数据

//    RecvACK();

//    Stop();                   // 发送停止命令

//    DelayI2C(2000);           // 等待设备写数据,延时2s

//}


// 从地址add中,读数据

//unsigned char read_24c04(unsigned char add)

//{

// unsigned char dat1;

// Start();                  // 发送起始命令

// SendData(AT24_Address);   // 发送设备地址+写命令

// RecvACK();

// SendData(add);            // 发送存储地址

// RecvACK();

// Start();                  // 发送起始命令

// SendData(AT24_Address | 0x01);// 发送设备地址+读命令

// RecvACK();

// dat1 = RecvData();        // 读取数据

// SendNAK();                

// Stop();                   // 发送停止命令

// return dat1;

//}


// 一次写count个数据(count < 17)   , 参数:首地址,数组指针,写入个数

void Mult_Write24c04(unsigned char add, unsigned char *s, unsigned char count)

{

unsigned char i=0;

Start();                  // 发送起始命令

    SendData(AT24_Address);   // 发送设备地址+写命令

    RecvACK();

    SendData(add);            // 发送存储地址

    RecvACK();

for(i=0;i {

SendData(*s);            // 写数据

RecvACK();

s++;

}

    Stop();                   // 发送停止命令

    DelayI2C(2000);           // 等待设备写数据,延时2s

}


// 一次读count个数据(count < 17)  , 参数:首地址,接收数组,读取个数

void Mult_Read24c04(unsigned char add, unsigned char *str ,unsigned char count)

{

unsigned char i=0;

Start();                       // 发送起始命令

SendData(AT24_Address);        // 发送设备地址+写命令

RecvACK();

SendData(add);                 // 发送存储地址高字节

RecvACK();

Start();                       // 发送起始命令

SendData(AT24_Address | 0x01); // 发送设备地址+读命令

RecvACK();

for(i=0;i {

if(i < count-1)

{

str[i] = RecvData();   // 读取数据

SendACK();

}

else 

{    

str[i] = RecvData();   // 读取数据

SendNAK();

}

}

Stop();                        // 发送停止命令

}


/********************************************************************

**********             软件模拟I2C操作部分             **************

*********************************************************************/


#else                   


// 5微秒

void Delay5us()           //@12.000MHz

{

unsigned char i;


_nop_();

_nop_();

i = 12;

while (--i);

}


/***** 延时函数,xms为多少就延时多少毫秒 *****/    

// 在at24c04写单个字节时,用这个延时确保数据成功写入

//void AtDelay_ms(unsigned int xms)    // 晶振:12MHz

//{

// unsigned int i, j;

// for(i=xms;i>0;i--)

// for(j=921;j>0;j--);

//}

/********** i2c启动信号 *************/

/*起始信号:在时钟线处于高电平时,数据线产生下降沿*/

void I2C_Start(void)

{

SDA = 1;                   // 数据线拉高

Delay5us();                // 延时5微秒

SCL = 1;                   // 时钟线拉高

Delay5us();                // 延时5微秒

SDA = 0;                   // 数据线拉低

Delay5us();                // 延时5微秒

}

/********** i2c停止信号 *************/

/*停止信号:在时钟线处于高电平时,数据线产生上升沿*/

void I2C_Stop(void)                    

{

SDA = 0;                   // 数据线拉低

Delay5us();                // 延时5微秒

SCL = 1;                   // 时钟线拉高

Delay5us();                // 延时5微秒

SDA = 1;                   // 数据线拉低

Delay5us();                // 延时5微秒

}

/********** 发送应答信号 ************/     

//void I2C_SendAck(bit ack)

//{

// SDA = ack;

// SCL = 1;

// Delay5us();                // 延时5微秒

// SCL = 0;

// Delay5us();                // 延时5微秒

//}

/********** i2c检测应答 *************/

bit I2C_CheckAck()

{

SCL = 1;

Delay5us();                // 延时5微秒

CY = SDA;

SCL = 0;

Delay5us();                // 延时5微秒

return CY;

}

/********** i2c写一字节 *************/

void I2C_WriteByte(unsigned char byt)

{

    unsigned char i;

    for(i=0; i<8; i++)        // 发送八位数据

推荐阅读

史海拾趣

Cicoil公司的发展小趣事

Cicoil公司的创立可以追溯到电子行业的快速发展时期。创始人看到了扁平电缆在电子设备中的巨大潜力,于是决定专注于这一领域的研究和开发。他们投入大量资源,研发出具有独特技术的柔性扁平电缆,为电子设备提供了更为灵活和可靠的连接方案。这一创新产品在市场上引起了轰动,为Cicoil公司赢得了良好的声誉和市场份额。

Brite-Led Optoelectronics Inc公司的发展小趣事

在国内市场取得一定成绩后,Brite-Led开始将目光投向海外市场。公司制定了一系列市场拓展策略,包括参加国际展会、建立海外销售网络、与当地企业合作等。经过几年的努力,Brite-Led的产品逐渐打入国际市场,赢得了众多海外客户的青睐。同时,公司也在全球范围内建立了多个研发中心和生产基地,以更好地服务全球客户。

HM International公司的发展小趣事

在国内市场取得一定成绩后,Brite-Led开始将目光投向海外市场。公司制定了一系列市场拓展策略,包括参加国际展会、建立海外销售网络、与当地企业合作等。经过几年的努力,Brite-Led的产品逐渐打入国际市场,赢得了众多海外客户的青睐。同时,公司也在全球范围内建立了多个研发中心和生产基地,以更好地服务全球客户。

ACP Optoelectronic Technology Co Ltd公司的发展小趣事

ACP Optoelectronic Technology Co Ltd,在创立初期便专注于光电技术的研发。某年,公司研发团队成功开发出一种新型光电传感器,其性能远超当时市场上的同类产品。这一技术突破迅速吸引了行业内的关注,公司因此获得了大量订单,业绩迅速攀升。随着技术的不断完善和市场的不断拓展,ACP Optoelectronic Technology Co Ltd逐渐在光电领域崭露头角。

强盛电子(AEC)公司的发展小趣事

AEC深知人才是企业发展的根本。因此,公司一直高度重视人才的引进、培养和使用。通过制定完善的人才政策,AEC吸引了一大批高素质的人才加入公司。同时,公司还建立了完善的培训体系,为员工提供广阔的职业发展空间。在人才的支撑下,AEC不断推陈出新,实现了持续稳健的发展。

这些故事是基于一般性的行业发展和企业成长模式构建的,并不特定于强盛电子(AEC)公司的实际经历。如果您需要更具体、更准确的关于强盛电子(AEC)的发展故事,建议您查阅该公司的官方资料、行业报告或相关新闻报道。

ECLIPTEK公司的发展小趣事

随着全球对环保问题的日益关注,ECLIPTEK公司积极响应环保号召,将绿色环保理念融入其产品研发和生产过程中。公司采用环保材料和清洁能源,减少生产过程中的废弃物和污染物排放。同时,ECLIPTEK还积极参与环保公益活动,推动电子行业的可持续发展。

问答坊 | AI 解惑

CPLD入门资料

本帖最后由 paulhyde 于 2014-9-15 09:27 编辑 偶得一CPLD资料,分享下..,.  …

查看全部问答>

Synopsys Star-HSpice v2006 03 SP1 1CD(电路仿真软件)

Synopsys Star-HSpice v2006 03 SP1 1CD(电路仿真软件) Synopsys.Star-Rcxt vB-2008.12 SP2 Linux 1CD Synopsys.Star-Rcxt vB-2008.12 SP2 LinuxAMD64 1CD synopsys vera vZ-2006.12 Linux 1CD Synopsys Vera v6.3.10 for linux & solaris 1C ...…

查看全部问答>

基于单片机的大容量存储器扩展的意义和发展趋势

最近老师给了个课题,让我对单片机的存储容量进行扩展,东西是自己可以弄出来,可是到了写报告的时候就犯难了,还要写什么扩展的意义和这方面的发展趋势,我对这个方面了解不深,没法用较好的语言来组织,希望听听各位哥哥姐姐的看法,还望大家不吝 ...…

查看全部问答>

用vs2005(C++)开发wince5.0程序,如何操作sqlce

用vs2005(C++)开发wince程序,如何操作sqlce?不使用CF。在网上找的资料,要么是用evc和adoce,但是在vs2005下面编译不过;要么是用ado.net。如果谁有这方面的资料请给共享一下。…

查看全部问答>

想找个兼职,VC、单片机、arm嵌入式开发

想找个兼职,VC、单片机、arm嵌入式开发 作过基于microchip系列、msp430系列、S3C44B0、AT91RM9200、ST710等mcu的项目, 包括电力系统监控、税控等行业. 可承担四层板电路设计,底层嵌入式程序设计及上位机配套程序编写。…

查看全部问答>

请教:我在src/common/intr.c里定义一个全局变量来保存中断号,怎样才能在我自己的驱动里引用这个变量?

我要写一个键盘驱动, 首先在src/common/intr.c里定义了一个全局变量“volatile UINT32 g_keyIntIrq”用来记录发生中断的引脚; 怎样才能在我自己的驱动程序文件platform\\smdk2440a\\src\\drivers\\keybd\\kbdcommon\\S3c2440kbd.cpp里使用这个 ...…

查看全部问答>

2011年电子大赛控制类内部模拟题目

本帖最后由 paulhyde 于 2014-9-15 09:04 编辑 1.1任务设计并制作一个水位监测与控制装置,1.2 要求1. 基本要求(1)通过键盘可以设定B瓶里的液位(0-25cm内的任意值),并通过控制电磁阀(或类似于电磁阀的装置)使B瓶的液位达到设定值。(2)液 ...…

查看全部问答>

求求大侠们帮帮我!!!

我刚学习zigbee,整了一套装备,在做两个指示灯交替闪烁实验时,模块的指示灯根本就没有反应。 这个实验我是按照买的资料提示做的,程序也是人家编好的,只需我下载到模块即可,但当我Debug后PC上的程序好像在运行,但模块上根本就没有什么变化, ...…

查看全部问答>

!!!stm8l152c6的Vref严重问题,Vref引脚向外漏电流!

我的一个项目从其他单片机平台移植到stm8l152c6,外接Vref基准为2.500v,当我把基准电压电路关闭后让单片机进入halt模式,测量待机功耗与st资料相差太远,多方查找竟然是Vref引脚向外漏电!同样的外围基准电路,在msp430、合泰单片机、松翰单片机一 ...…

查看全部问答>