IO口模拟I2C总线读写EEPROM

合集下载

I2C读写EEPROM文档说明

I2C读写EEPROM文档说明

通过I2C通讯协议对EEPROM进行读写操作发送串口进行通讯一.描述I2CI2C协议有启动,终止,应答,非应答四种信号,有按位发送数据,按位接收数据,有读操作和写操作。

1.启动I2C程序如下,保持SCL为高电平,SDA为高电平,当检测到SDA下降沿时,启动传送,如果2个信号没有被高则返回0。

程序启动成功返回1。

uint8 I2C_Start(void){CyDelayUs(10);SDA_Write(1);CyDelayUs(10);SCL_Write(1);CyDelayUs(10);if ( SDA_Read() == 0) return 0;if ( SCL_Read() == 0) return 0;SDA_Write(0);CyDelayUs(10);SCL_Write(0);CyDelayUs(10);return 1;}上面是模仿I2C启动时序2.终止传送程序如下SDA保持低电平SCL保持高电平而后拉高SDA,系统检测到SDA上升沿则终止传送。

void I2C_Stop(void){CyDelayUs(10);SDA_Write(0);CyDelayUs(10);SCL_Write(1);CyDelayUs(10);SDA_Write(1);CyDelayUs(10);}3.模拟应答信号,让SDA的低电平时间大于SCL的高电平时间,即可应答;也就是SDAvoid I2C_Ack(void){CyDelayUs(10);SDA_Write(0);CyDelayUs(10);SCL_Write(1);CyDelayUs(10);SCL_Write(0);CyDelayUs(10);}4.模拟非应答信号,让SDA的高电平时间大于SCL高电平时间,就是非应答void I2C_Nack(void){CyDelayUs(10);SDA_Write(1);CyDelayUs(10);SCL_Write(1);CyDelayUs(10);SCL_Write(0);CyDelayUs(10);}5.按位发送数据,按位发送数据的要求是数据位高电平的时间大于SCL,SCL高电平时不允许数据位电平变化,只有SCL低电平时才可以任意变换。

基于I^2C接口EEPROM读写控制器设计

基于I^2C接口EEPROM读写控制器设计
了 一 种 性 能 优 越 的
2 E E P R 0M 读 写 控 制 器 模 块 的 设 计 与 实现
在进 行数 据传 输 时 , 读 写 控 制 器 首 先 产 生 一 个 启 动
信号( 当 S C L为 高 电 平 时 , S D A 由高 变 为低 ) , 接 着 发 送 控 制字 ( 即 I 2 C总线器 件 的特 征编 码 和 3 b i t E E P R OM 的
Ab s t r a c t :T h e I n t e r - I n t e g r a t e d Ci r c u i t ( I C)b u s p r o t o c o l i s i n t r o d u c e d b r i e l f y .Us i n g F i e l d — P r o g r a mma b l e Ga t e Ar r a y( F P GA)
线器 件特 征码 为 1 0 1 0. 而 3 b i t E E P R OM 的 芯 片 地 址 为 0 0 0。 接着 主控 制器 释放 总线 , 等待 E E P R O M 发 出 的 应 答 信号, 由于采 用 的 E E P R O M 型号 是 2 4 L C 6 4, 因 此 在 控 制 器 收到应答 后 , 将 首先发送 E E P R O M 高 字 节 的 存 储 单 元 地址 。 当控制 器再 次收到 应答后 继续 发送 E E P R O M 低 字
双 向两 线 串行 总线 I 2 C( I n t e r — I n t e g r a t e d C i r c u i t ) 总 线 。 进
行 F P G A设 计 时经 常需 要与 外 围提 供 I 2 C接 口 的 芯 片 进

用IO模拟IIC方式读写EEPROM容易出现的问题

用IO模拟IIC方式读写EEPROM容易出现的问题

用IO模拟IIC方式读写EEPROM容易出现的问题 在嵌入式软件开发过程中,经常会用模拟IO的方式读写EEPROM 的操作。

有时会因程序编码的问题,出现读写数据不正确的情况。

根据笔者多年的开发经验与大家分享希望对大家有所帮助。

对EEPROM的操作常见的有两种方式:I2C,SPI;在应用中经常会用到模拟IO方式读写EEPROM。

在编写此类代码时必须要掌握I2C 与SPI协议。

I2C总线上的数据稳定规则,SCL为高电平时SDA上的数据保持稳定,SCL为低电平时允许SDA变化。

如果SCL处于高电平时,SDA上产生下降沿,则认为是起始位,SDA上的上升沿认为是停止位。

通信速率分为常规模式(时钟频率100kHz)和快速模式(时钟频率400kHz)。

同一总线上可以连接多个带有I2C接口的器件,每个器件都有一个唯一的地址,既可以是单接收的器件,也可以是能够接收发送的器件。

SPI,串行外围设备接口。

是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便。

在操作中出现读取数据不正确,或者不能读取数据可能有以下原因:1.没有遵照通信协议:这两种通信方式都有各自独立的协议,如果在编写程序时不按通信协议,自然就不能正常通信了;2.时序不对:两处通讯方式都有严格的时序,编写程序时要严格按对应的时序;3.IO口方式方向设置不正确:在通信中数据有输入与输出的时候,特别是在I2C的方式下,有数据输入时相应的IO口要设置为输入,反之亦然,初学都容易犯这样的错误;4.看页的大小,超过一个页连续写就回滚,前面的就被覆盖。

其实里面有一个页地址计数器,如果页是8个byte,那么这个计数器就3bit,增加的地址(连续写的地址范围)就相当于溢出或者相当于按页取模。

在应用中的建议:1. SCL与SDA引脚用2.2K--4.7K电阻上拉;2. IO口与EEPROM的相应引脚不能直接相连,串一个几百欧电阻;3.为保证数据的正确性,在写入数据时最好对数据进行检验;4.采用循环地址的方式进行存储,避免只在一个固定地址上读写数据;。

Eeprom的读写

Eeprom的读写

所看过的对24系列I2C读写时序描述最准确最容易理解的资料,尤其是关于主从器件的应答描述和页写描述,看完后明白了很多。

关于页写的描述,网络上绝大部分范程都没提到页写时的数据地址必须是每页的首地址才能准确写入,而且如果写入超过一页的数据会循环覆盖当前页的数据。

关于IIC总线I2C总线:i2c总线是Philips 公司首先推出的一种两线制串行传输总线。

它由一根数据线(SDA)和一根时钟线(SDL)组成。

i2c总线的数据传输过程如图3所示,基本过程为:1、主机发出开始信号。

2、主机接着送出1字节的从机地址信息,其中最低位为读写控制码(1为读、0为写),高7位为从机器件地址代码。

3、从机发出认可信号。

4、主机开始发送信息,每发完一字节后,从机发出认可信号给主机。

5、主机发出停止信号。

I2C总线上各信号的具体说明:开始信号:在时钟线(SCL)为高电平其间,数据线(SDA)由高变低,将产生一个开始信号。

停止信号:在时钟线(SCL)为高电平其间,数据线(SDA)由低变高,将产生一个停止信号。

应答信号:既认可信号,主机写从机时每写完一字节,如果正确从机将在下一个时钟周期将数据线(SDA)拉低,以告诉主机操作有效。

在主机读从机时正确读完一字节后,主机在下一个时钟周期同样也要将数据线(SDA)拉低,发出认可信号,告诉从机所发数据已经收妥。

(注:读从机时主机在最后1字节数据接收完以后不发应答,直接发停止信号)。

注意:在I2C通信过程中,所有的数据改变都必须在时钟线SCL为低电平时改变,在时钟线SCL为高电平时必须保持数据SDA信号的稳定,任何在时钟线为高电平时数据线上的电平改变都被认为是起始或停止信号。

作为一种非易失性存储器(NVM),24系列EEPROM使用的很普遍,一般作为数据量不太大的数据存储器。

下面总结一下其应用的一些要点。

从命名上看,24CXX中XX的单位是kbit,如24C08,其存储容量为8k bit,即1k Byte=1024 Byte。

I2C总线与EEPROM

I2C总线与EEPROM

I2C通信时序
• I2C总线规定了严格的数据通信格式,所有具有I2C总线 接口的器件都必须遵守。
• I2C总线上主机与从机之间一次传送的数据称为一帧, 由起始信号、数据传输部分和停止信号组成。数据传送 的基本单元为一位数据。对比UART的数据帧格式。
空闲状态:I2C总线的SDA和SCL两条信号线同时处于高 电平时,规定为总线的空闲状态。此时各个器件的输出级 场效应管均处在截止状态,即释放总线,由两条信号线各 自的上拉电阻把电平拉高。 起始信号:I2C 通信的起始信号的定义是 SCL 为高电平期 间, SDA 由高电平向低电平变化产生一个下降沿。
/* I2C 总线写操作, dat-待写入字节,返回值-从机应答位的值 *
bit I2CWrite(unsigned char dat) { bit ack; //用于暂存应答位的值 unsigned char mask; //用于探测字节内某一位值的掩码变量 for (mask=0x80; mask!=0; mask>>=1) //从高位到低位依次 { if ((mask&dat) == 0) //该位的值输出到 SDA 上 I2C_SDA = 0; else I2C_SDA = 1; I2CDelay.1 SCL/P1.0
>4.7μ s >4.0μ s
SDA/P1.1 SCL/P1.0
>4.0μ s
>4.7μ s
(a)启动
SDA/P1.1 SDA/P1.1 SCL/P1.0
>4.0μ s
(b)终止
SCL/P1.0
>4.0μ s
(c)发送0/发送应答位
(d)发送1/发送非应答位
I2C简介
• I2C总线支持多主(multi-mastering)和主从(master-slave)两 种工作方式。 • 多主方式下,I2C总线上可以有多个主机。I2C总线需通 过硬件和软件仲裁来确定主机对总线的控制权。 • 主从工作方式时,系统中只有一个主机,总线上的其它 器件均为从机(具有I2C总线接口),只有主机能对从机 进行读写访问,因此,不存在总线的竞争等问题。在主 从方式下,I2C总线的时序可以模拟 ,I2C总线的使用不 受主机是否具有I2C总线接口的制约。80C51 单片机本身 不具有I2C总线接口,可以用其I/O口线模拟I2C总线 。

单片机IO口介绍

单片机IO口介绍

单片机IO口介绍单片机(microcontroller)是一种集成电路芯片,具有运算、存储和控制功能。

它是嵌入式系统中最常用的处理器之一、在单片机中,IO (Input/Output)口是用来进行输入输出操作的接口。

IO口通常包括数字IO口和模拟IO口两种类型。

下面将详细介绍单片机IO口的功能和应用。

1.数字IO口:数字IO口是单片机与外部设备进行数字信号交换的接口。

数字IO口可以进行输入和输出操作,具有以下特点:-输入功能:可以通过读取外部设备的状态或信号,并将其转换为数字信号输入到单片机中进行处理。

例如,传感器的信号输入和按键的输入等。

-输出功能:可以通过将数字信号输出到外部设备,控制其工作状态。

例如,LED的控制、驱动电机或继电器等。

数字IO口通常以引脚(pin)的形式存在于单片机芯片上。

一个引脚包括输入端和输出端,可以根据需要进行配置。

数字IO口操作简单、速度快、精度高,常用于控制和通信等方面。

2.模拟IO口:模拟IO口是单片机与外部设备进行模拟信号交换的接口。

模拟IO口可以进行模拟输入和输出操作,常用于采集和控制模拟信号。

-模拟输入功能:可以从外部信号源中获取模拟信号,并将其转换为数字信号输入到单片机中进行处理。

例如,温度传感器、声音传感器等。

-模拟输出功能:可以将数字信号转换为模拟电压、电流等形式,输出到外部设备中。

例如,通过PWM(脉冲宽度调制)信号控制电机的转速。

模拟IO口通常通过ADC(模数转换器)和DAC(数模转换器)实现。

ADC将模拟信号转换为数字信号,DAC将数字信号转换为模拟信号。

模拟IO口的使用相对复杂,需要进行模数转换和数模转换,但在一些需要对模拟信号进行处理和控制的应用中起到关键作用。

3.应用场景:IO口在单片机系统中广泛应用于各种应用场景。

以下是一些常见的应用场景:-传感器接口:通过IO口连接传感器,读取传感器的输出信号,进行数据采集和处理。

例如温度、湿度、光照等传感器的接口。

用AVR单片机IO口模拟I2C总线操作AT24CXX的通用程序

用AVR单片机IO口模拟I2C总线操作AT24CXX的通用程序
twi_ack(ack);
*c=ret;
return(ret);
}
以下为AT24CXX的操作函数实现:
at24cxx.h:
//AT24CXX.H
#ifndef AT24CXX_H
#define AT24CXX-H
void At24cxxWaitBusy(void);
#include <util/delay.h>
#include <stdint.h>
/*注:
AVR单片机I/O口模拟I2C总线时建议在外部连接上拉电阻
这样可通过改变I/O口输入输出方向的方式来设置高低
输出口保持不变(0)
此时如DDRX寄存器为1则变成输出0
若DDRX为0,则I/O口程高阻,但因外部的上拉电阻,总线相当于设置高
#define TW_READ 1
#define TW_ACK 1
#define TW_NOACK 0
Hale Waihona Puke /*以下两个宏控制AT24CXX的WP引脚,如未连接可定义为空:
#define EEPROM_WRITE_ENABLE
#define EEPROM_WRITE_DISABLE
AT24CXX中WP引脚接地时写允许,接电源(高)时写保护,
如不接,器件内部有接地电阻,即写允许. */
//在CA-M8X板上该引脚通过S7(3)连接MEGA8的PC3
#define EEPROM_WRITE_ENABLE PORTC&=~_BV(PC3),DDRC|=_BV(PC3)
void At24cxxConfig(uint8_t device_addr,uint8_t page_size);

STM32F4利用I2C向EEPROM写入、读取数据步骤

STM32F4利用I2C向EEPROM写入、读取数据步骤

STM32F4利⽤I2C向EEPROM写⼊、读取数据步骤
写⼊⼀个字节:
第⼀步:使⽤库函数I2C_GenerateSTART()产⽣I2C起始信号,调⽤库函数I2C_CheckEvent()检测事件,若检测到下⼀事件,则进⼊通讯下⼀阶段
第⼆步:调⽤库函数I2C_Send7bitAddress()发送EEPROM的设备地址,并把数据传输⽅向设置为I2C_Direction_Transmitter(即发送⽅向),发送地址后以同样的⽅式检测相应的事件。

第三步:调⽤库函数I2C_SendData向EEPROM发送要写⼊的地址,发送完后等待EV8事件的产⽣。

第四步:继续调⽤库函数I2C_SendData向EEPROM发送要写⼊的数据,然后等待EV8事件的产⽣。

第五步:通讯结束,调⽤I2C_GenerateSTOP发送停⽌信号。

读取⼀字节的数据:
第⼀步:通过库函数I2C_GETFlagStatus()查询库函数是否处于忙碌状态,若不忙碌,则进⼊下⼀状态。

第⼆步:使⽤库函数I2C_GenerateSTART()产⽣起始信号,调⽤库函数I2C_CheckEvent()检测Event1,若检测成功则进⼊下⼀阶段。

第三步:发送EEPROM的设备地址,⽅向为I2C_Direction_Transmitter(即写⽅向),检测事件6
第四步:利⽤库函数I2C_Cmd重新使能I2C外设
第五步:利⽤库函数I2C_Senddata()发送要读取的EEPROM的内部地址,检测Event8事件的产⽣
第六步:产⽣第⼆次I2C起始信号,并检测相关事件
第七步:发送I2C设备地址
第⼋步:读取数据。

EEPROM I2C操作说明知识讲解

EEPROM   I2C操作说明知识讲解

E E P R O M I2C操作说明I2C协议2条双向串行线,一条数据线SDA,一条时钟线SCL。

SDA传输数据是大端传输,每次传输8bit,即一字节。

支持多主控(multimastering),任何时间点只能有一个主控。

总线上每个设备都有自己的一个addr,共7个bit,广播地址全0.系统中可能有多个同种芯片,为此addr分为固定部分和可编程部份,细节视芯片而定,看datasheet。

1.1 I2C位传输数据传输:SCL为高电平时,SDA线若保持稳定,那么SDA上是在传输数据bit;若SDA发生跳变,则用来表示一个会话的开始或结束(后面讲)数据改变:SCL为低电平时,SDA线才能改变传输的bit1.2 I2C开始和结束信号开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。

结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。

1.3 I2C应答信号Master每发送完8bit数据后等待Slave的ACK。

即在第9个clock,若从IC发ACK,SDA会被拉低。

若没有ACK,SDA会被置高,这会引起Master发生RESTART或STOP流程,如下所示:1.4 I2C写流程写寄存器的标准流程为:1. Master发起START2. Master发送I2C addr(7bit)和w操作0(1bit),等待ACK3. Slave发送ACK4. Master发送reg addr(8bit),等待ACK5. Slave发送ACK6. Master发送data(8bit),即要写入寄存器中的数据,等待ACK7. Slave发送ACK8. 第6步和第7步可以重复多次,即顺序写多个寄存器9. Master发起STOP写一个寄存器写多个寄存器1.5 I2C读流程读寄存器的标准流程为:1. Master发送I2C addr(7bit)和w操作1(1bit),等待ACK2. Slave发送ACK3. Master发送reg addr(8bit),等待ACK4. Slave发送ACK5. Master发起START6. Master发送I2C addr(7bit)和r操作1(1bit),等待ACK7. Slave发送ACK8. Slave发送data(8bit),即寄存器里的值9. Master发送ACK10. 第8步和第9步可以重复多次,即顺序读多个寄存器读一个寄存器读多个寄存器1.前言对于大多数工程师而言,I2C永远是一个头疼的问题。

基于STM32F103的I2C总线EEPROM的读写(带超时检测)

基于STM32F103的I2C总线EEPROM的读写(带超时检测)

基于STM32F103的I2C总线EEPROM的读写(带超时检测)————————————————————————————————作者:————————————————————————————————日期:【原创】基于STM32F103的I2C总线EEPROM的读写(带超时检测)本人最近参考了st 公司关于STM32的I2C的例程,觉得不是很适合我的应用,于是自己写了一个基于STM32F103的I2C总线EEPROM(24C256)的读写程序,总线的最高速度可达400K,现在将源代码原原本本的公布如下,希望得到高手的指点,也希望能够给和我有同样想法的同仁们一些参考价值。

注意:最好将固件库升级一下,st网站上面有V2。

03库的补丁。

u32 ulTimeOut_Time;/***********************************************************************************************************I2C_EE_WriteStr()** Description : 将一个数据块写入EEPROM 的指定的地址**Argument(s) : xChip - 从器件地址* xAddr — EEPROM存储空间地址*xpBuf —数据缓冲区指针* xLen - 数据长度**Return(s) : none.**Caller(s) : Application.** Note(s) :(1)*——--—-——----————--—-——---——--—--—---—-—----———--—-—-————-——-——---—-—--—————----——--—————-—-——--——-———--*Modified by :* Modified date :* Description :*—---———----———-—------——--—--—-——————-—-————-——-———-——---—--——-——————--—————----———-—---—-——-——-—-——--—**********************************************************************************************************/void I2C_EE_WriteStr(u8 xChip, u16 xAddr, u8 *xpBuf, u16 xLen){u8 *pbuf;u8 err;u8 retry;u16 addr;u16 len;个人收集整理,勿做商业用途本文为互联网收集,请勿用作商业用途//pbuf = xpBuf;addr = xAddr;len = xLen;I2C_EE_Drv_BusEn(); // 允许总线,写允许retry = 5; // 重试5次while(len){err = I2C_EE_Drv_WriteByte(xChip,addr, *pbuf);if(err){if(--retry == 0 ) // 已经试了5次,写下一个数据{retry = 5;pbuf++;addr++;len——;}}else // 顺利,写下一个数据{pbuf++;addr++;len--;}}I2C_EE_Drv_BusDis(); // 失能总线,写保护}/*********************************************************************************************************** I2C_EE_ReadStr()**Description :从EEPROM 的指定的地址读出一个数据块** Argument(s) : xChip —从器件地址* xAddr - EEPROM存储空间地址*xpBuf - 数据缓冲区指针*xLen - 数据长度**Return(s) : none.** Caller(s) : Application。

九齐MCUio口模拟I2C

九齐MCUio口模拟I2C

九齐MCUio⼝模拟I2C IO⼝模拟I2C的要点:1. 数据帧符合标准的I2C协议2. 分的清楚ACK与NACK的区别,是那个设备下拉。

3. 数据位时间符合要求项⽬合作开发,吹⽜扯蛋、交朋友,请联系:186********#include "iic_p.h"#include <ny8.h>#include "main.h"#include <ny8_constant.h>#include <stdint.h>#define sda_out() IOSTA=(IOSTA & ((uint8_t)(~ C_PA6_Input))) //输出#define sda_in() IOSTA=(IOSTA | C_PA6_Input) //输⼊#define sda PORTAbits.PA6 //sda输出⾼#define scl PORTAbits.PA4 //scl输出⾼,写程序注意默认让其保持⾼电平void delayus(uint8_t tim){while(tim--) //2.4us周期 clk_8M{NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();}}void i2c_stop(void){scl = 0;delayus(1);sda = 0;sda_out();delayus(2);scl = 1;delayus(1);sda = 1;}void i2c_start(void){sda = 1; //delayus(1);scl = 1; //发送停⽌位后将SCL及SDA置位delayus(1);sda = 0;delayus(1);}//测试okvoid trandata(uint8_t data){//IOSTB=(IOSTB & ((uint8_t)(~ C_PB2_Input))); //输出uint8_t i;//scl = 0;for( i = 0;i<8;i++ ){scl = 0;delayus(1);if((data & 0x80) == 0x80){sda = 1;}else{sda = 0;data <<=1;delayus(2);scl = 1;delayus(3);}//scl = 0;//delayus(3);//sda = 0; //因该把IO输出禁⽌,不然slaver⽆法下拉}//测试okvoid revdata(uint8_t *data){uint8_t i;//sda_in();for(i=0;i<8;i++){scl = 0;delayus(3);scl = 1;delayus(1);*data <<= 1;if(sda==1){*data |= 0x01; //⾸位置为⼀}else{*data &= 0xfe;}delayus(2);}}//测试okvoid i2c_nack(void){scl = 0;delayus(1);sda = 1;sda_out();delayus(2);scl = 1;delayus(3);}//测试okuint8_t i2c_dectack(void){uint8_t ackflg;scl = 0;delayus(1);sda_in();delayus(2);scl = 1;delayus(1);if(sda ==1){ackflg = 0; //为接收到应答}else{ackflg = 1; //接收到应答}delayus(2);return ackflg;}//测试ok 3msuint8_t i2c_wtdata(uint8_t address,uint8_t data){uint8_t temp,errflg=0;i2c_start();temp = 0xa0; //地址位赋值1010add(R/W)trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据scl = 0;delayus(1);sda = 1;sda_out();temp = address;trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}scl = 0;delayus(1);sda = 1;sda_out();trandata(data);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}// scl = 0;// delayus(3);// sda = 0;// sda_out();i2c_stop();return errflg;}//测试ok //测试不稳定uint8_t curddata(uint8_t *data){uint8_t temp,errflg=0;i2c_start();temp = 0xa1; //地址位赋值1010add(R/W)trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}//sda_out();revdata(data);i2c_nack();i2c_stop();return errflg;}//测试ok 4msuint8_t i2c_rddata(uint8_t address,uint8_t *pdata) {uint8_t temp,errflg=0;i2c_start();temp = 0xa0; //地址位赋值1010000(R/W)trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}scl = 0;delayus(1);sda = 1; //默认为上拉sda_out();temp = address;trandata(temp);if(i2c_dectack() == 0){errflg = 1; //未接收到应答数据}scl = 0;delayus(1);sda = 1;sda_out();if(curddata(pdata) == 1){errflg = 1;return errflg;}/*//写数据遵守写⼊读出void i2cbus_wt(uint8_t address,uint8_t data){uint8_t temp;do{while(i2c_wtdata(address,data) == 1); //写⼊数据 while(curddata(&temp) == 1); //读出数据} while(data != temp); //⽐较通过视为写⼊成功}*/。

i2c标准读写流程

i2c标准读写流程

i2c标准读写流程
I2C(Inter-Integrated Circuit)是一种串行通信协议,用于连接微控制器和外围设备。

以下是I2C标准的读写流程:
1. 主设备发送起始信号:主设备将SCL线拉低,然后将SDA线拉低,表示起始信号的开始。

2. 主设备发送设备地址和读写位:主设备将设备地址和读写位发送到SDA 线上,然后保持SCL线保持低电平。

3. 从设备响应:从设备检测到起始信号后,根据地址进行响应。

如果从设备地址匹配,从设备将拉低SDA线,表示响应;否则,从设备将保持SDA线为高电平,表示无响应。

4. 主设备发送数据:主设备继续发送需要写入的数据到SDA线上,并在每个数据字节后等待从设备的ACK(应答)。

5. 从设备应答:从设备接收到每个字节后,将拉低SDA线表示ACK;如果出现错误或数据无法接受,从设备将保持SDA线高电平,表示NACK(非应答)。

6. 主设备继续发送数据:如果从设备成功应答,主设备将继续发送数据。

7. 主设备发送停止信号:主设备发送停止信号,即将SCL线保持高电平,然后将SDA线拉高,表示通信结束。

注意事项:
- 在发送和接收数据之间,主设备和从设备都需要在每个字节后进行ACK/NACK。

- 从设备的地址包括7位设备地址和1位读写位(最低位)。

- 主设备可以连续发送多个数据字节,直到发送停止信号。

- 从设备可以在主设备发送数据之前发送请求,以指示其需要哪些数据。

- 在整个通信过程中,主设备控制时钟线(SCL),从设备控制数据线(SDA)。

以上是I2C标准的读写流程,具体实现可能会根据设备的要求和通信需求有所不同。

I2C读写EEPROM 问题总结

I2C读写EEPROM 问题总结

2017年6月30日星期五目的:利用TMS320F2801芯片上外设I2C(2线串口)读写EEPROM数据(24LC128)关键点1:24LC时钟频率400KHz,寄存器设置如下:I2caRegs.I2CPSC.all = 9; // Prescaler - need 7-12 Mhz on module clk I2caRegs.I2CCLKL = 10; // NOTE: must be non zeroI2caRegs.I2CCLKH = 5; // NOTE: must be non zero时钟频率也可设为200KHz,三个参数分别为9、20、20(CPU时钟频率为100MHz)(未测试)关键点2:波形分析问题:I2C模块是不是只有I2CCNT 减到0才会发出停止信号??I2C模块是硬件的,当检测到发送完了就会发结束自动发信号,不需要人为干预问题1:字节写操作正常,但是字节读函数出错原因:写EEPROM是在七位器件地址后添加写标志,而读EEPROM需要在七位器件地址后添加写标志。

关键点:读EEPROM数据需要发送两次命令。

第一次为写地址(此地址会被赋值给EEPROM 内的地址指针),因此需要添加写标志;第二次为读数据,将写标志改为读标志。

问题2:主机接收时,SDA数据线上有数据传输,且I2CDRR接收数据寄存器有数据更新,但寄存器显示不可读,即CPU认为一直没接收到数据,一直停在下面语句while关键点:初始化设置时采用的是FIFO接收方式,因此无效,应查询FIFO接收中断位while 方式查询位。

此位只有在非FIFO中断接收方式时才有效。

问题3:断续单字节读写正常,但是采用连续的单字节读写出错。

原因:EEPROM写过程的结束并不是I2C总线写结束就结束,实际上I2C总线的写入数据先被保存到了EEPROM内部的缓冲区,当遇到I2C结束条件后,EEPROM才启动内部写过程,这个过程才是保存数据的过程。

stm8s使用IO口模拟I2C

stm8s使用IO口模拟I2C

stm8s使⽤IO⼝模拟I2C刚⼊职不久,下⾯是使⽤stm8s005k6写的eeprom驱动程序。

EEPROM型号为ST公司的M24C256.#include "bsp_i2c.h"/* 在stm8平台下移植,只需要改下⾯的宏定义即可 */#define PORT_I2C_SCL GPIOC#define PIN_I2C_SCL GPIO_PIN_1#define PORT_I2C_SDA GPIOC#define PIN_I2C_SDA GPIO_PIN_2static void i2c_Delay(void);static void i2c_PinModeOutput(void);static void i2c_PinModeInput(void);static void i2c_SCL(uint8_t stat);static void i2c_SDA(uint8_t stat);static uint8_t i2c_ReadSDA(void);/** 函数名: i2c_InitGpio* 功能说明: 初始化IIC接⼝* 形参: ⽆* 返回值: ⽆*/void i2c_InitGpio(void){GPIO_Init(PORT_I2C_SCL, PIN_I2C_SCL, GPIO_MODE_OUT_PP_LOW_FAST);GPIO_Init(PORT_I2C_SDA, PIN_I2C_SDA, GPIO_MODE_OUT_PP_LOW_FAST);i2c_Stop();}/** 函数名: i2c_Delay* 功能说明: 延时函数* 形参: ⽆* 返回值: ⽆*/static void i2c_Delay(void){uint8_t time = 10;while (time--);}/** 函数名: i2c_PinModeOutput* 功能说明: 将SDA线的端⼝设置为输出* 形参: ⽆* 返回值: ⽆*/static void i2c_PinModeOutput(void){GPIO_Init(PORT_I2C_SDA, PIN_I2C_SDA, GPIO_MODE_OUT_PP_LOW_FAST);}/** 函数名: i2c_PinModeOutput* 功能说明: 将SDA线的端⼝设置为输⼊* 形参: ⽆* 返回值: ⽆*/static void i2c_PinModeInput(void){GPIO_Init(PORT_I2C_SDA, PIN_I2C_SDA, GPIO_MODE_IN_FL_NO_IT);}/** 函数名: i2c_SCL* 功能说明: 控制SCL线电平状态* 形参: stat:0 输出低电平,1 输出⾼电平* 返回值: ⽆*/static void i2c_SCL(uint8_t stat){if (stat){GPIO_WriteHigh(PORT_I2C_SCL, PIN_I2C_SCL);}else{GPIO_WriteLow(PORT_I2C_SCL, PIN_I2C_SCL);}}/** 函数名: i2c_SDA* 功能说明: 控制SDA线电平状态* 形参: stat:0 输出低电平,1 输出⾼电平* 返回值: ⽆*/static void i2c_SDA(uint8_t stat){if (stat){GPIO_WriteHigh(PORT_I2C_SDA, PIN_I2C_SDA);}else{GPIO_WriteLow(PORT_I2C_SDA, PIN_I2C_SDA);}}/** 函数名: i2c_ReadSDA* 功能说明: 读取SDA线电平状态* 形参: ⽆* 返回值: 0 或 1*/static uint8_t i2c_ReadSDA(void){if (GPIO_ReadInputPin(PORT_I2C_SDA, PIN_I2C_SDA)) {return1;}else{return0;}}/** 函数名: i2c_Start* 功能说明: IIC总线起始信号* 形参: ⽆* 返回值: ⽆*/void i2c_Start(void){i2c_PinModeOutput();i2c_SDA(1);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_SDA(0);i2c_Delay();i2c_SCL(0);i2c_Delay();}/** 函数名: i2c_Stop* 功能说明: IIC总线停⽌信号* 形参: ⽆* 返回值: ⽆*/void i2c_Stop(void){i2c_PinModeOutput();i2c_SCL(0);i2c_SDA(0);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_SDA(1);i2c_Delay();}/** 函数名: i2c_WriteByte* 功能说明: IIC总线写数据* 形参: _ucByte:写⼊的⼀个字节数据* 返回值: ⽆*/void i2c_WriteByte(uint8_t _ucByte){uint8_t i;i2c_PinModeOutput();i2c_SCL(0);i2c_Delay();for (i = 0; i < 8; i++){if (_ucByte & 0x80){i2c_SDA(1);}else{i2c_SDA(0);}_ucByte = _ucByte << 1;i2c_SCL(1);i2c_Delay();i2c_SCL(0);i2c_Delay();}i2c_SDA(1);}/** 函数名: i2c_ReadByte* 功能说明: IIC总线读数据* 形参: ⽆* 返回值: recv:读取的⼀个字节数据*/uint8_t i2c_ReadByte(void){uint8_t i;uint8_t recv = 0;i2c_PinModeOutput();i2c_SDA(1);i2c_Delay();i2c_PinModeInput();for (i = 0; i < 8; i++){recv = recv << 1;i2c_SCL(1);i2c_Delay();if (i2c_ReadSDA()){recv |= 0x01;}else{recv |= 0x00;}i2c_SCL(0);i2c_Delay();}return recv;}/** 函数名: i2c_Ack* 功能说明: IIC总线主机主动应答* 形参: ⽆* 返回值: ⽆*/void i2c_Ack(void){i2c_PinModeOutput();i2c_SCL(0);i2c_SDA(0);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_SCL(0);}/** 函数名: i2c_NAck* 功能说明: IIC总线主机主动⾮应答* 形参: ⽆* 返回值: ⽆*/void i2c_NAck(void){i2c_PinModeOutput();i2c_SCL(0);i2c_SDA(1);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_SCL(0);}/** 函数名: i2c_CheckAck* 功能说明: IIC总线检测应答信号* 形参: ⽆* 返回值: 0 应答信号,1 ⾮应答信号*/uint8_t i2c_CheckAck(void){uint8_t time = 0;i2c_PinModeOutput();i2c_SDA(1);i2c_Delay();i2c_SCL(1);i2c_Delay();i2c_PinModeInput();while (i2c_ReadSDA()){time++;if (time >= 100){return1;}}i2c_SCL(0);return0;}bsp_i2c.c#ifndef __BSP_I2C_H__#define __BSP_I2C_H__#include "stm8s.h"#define I2C_WR ((uint8_t) 0) /* 写控制bit */ #define I2C_RD ((uint8_t) 1) /* 读控制bit */ #define ACK ((uint8_t) 0)#define NOACK ((uint8_t) 1)void i2c_InitGpio(void);void i2c_Start(void);void i2c_Stop(void);void i2c_WriteByte(uint8_t _ucByte);uint8_t i2c_ReadByte(void);void i2c_Ack(void);void i2c_NAck(void);uint8_t i2c_CheckAck(void);#endif /* __BSP_I2C_H__ */bsp_i2c.h#include "m24256_driver.h"#include "bsp_i2c.h"#include "modbus_driver.h"//uint8_t g_ucIsEEPROMBusy;/** 函数名: M24256_Init* 功能说明: 初始化* 形参: ⽆* 返回值: ⽆*/void M24256_Init(void){i2c_InitGpio();}/** 函数名: M24256_WriteByte* 功能说明: 写⼀个字节* 形参: _usAddress:地址* _ucByte:数据* 返回值: ⽆*/uint8_t M24256_WriteByte(uint16_t _usAddress, uint8_t _ucByte) {uint16_t i;for (i = 0; i < 3000; i++){i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_WR); /* 选中器件 + 写 */ if (i2c_CheckAck() == ACK){break;}}if (i >= 3000){i2c_Stop();return0;}/* 发送地址 */i2c_WriteByte((_usAddress & 0xFF00) >> 8);if (i2c_CheckAck() == NOACK){i2c_Stop();return2;}i2c_WriteByte(_usAddress & 0x00FF);if (i2c_CheckAck() == NOACK){i2c_Stop();return3;}/* 读数据 */i2c_WriteByte(_ucByte);if (i2c_CheckAck() == NOACK){i2c_Stop();return4;}i2c_Stop();/** 函数名: M24256_ReadByte* 功能说明: 读⼀个字节* 形参: _usAddress:地址* 返回值: recv:读取到的⼀个字节数据*/uint8_t M24256_ReadByte(uint16_t _usAddress){uint8_t recv = 0;uint16_t i;for (i = 0; i < 3000; i++){i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_WR); /* 选中器件 + 写 */if (i2c_CheckAck() == ACK){break;}}if (i >= 3000){i2c_Stop();return0;}/* 发送地址 */i2c_WriteByte((_usAddress & 0xFF00) >> 8);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_WriteByte(_usAddress & 0x00FF);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_RD); /* 选中器件 + 读 */if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}recv = i2c_ReadByte();i2c_NAck();i2c_Stop();return recv;}/** 函数名: M24256_ReadBlock* 功能说明: 从串⾏EEPROM指定地址处开始读取若⼲数据* 形参: _usAddress : 起始地址* _usSize : 数据长度,单位为字节* _pReadBuf : 存放读到的数据的缓冲区指针* 返回值: 0 表⽰失败,1表⽰成功*/unsigned char M24256_ReadBlock(unsigned char *_pReadBuf, unsigned short _usSize, unsigned short _usAddress) {uint16_t i;for (i = 0; i < 3000; i++){i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_WR); /* 选中器件 + 写 */if (i2c_CheckAck() == ACK){break;}}if (i >= 3000){i2c_Stop();/* 发送地址 */i2c_WriteByte((_usAddress & 0xFF00) >> 8);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_WriteByte(_usAddress &0x00FF);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_RD); /* 选中器件 + 读 */if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}/* 循环读取数据 */for (i = 0; i < _usSize; i++){_pReadBuf[i] = i2c_ReadByte();if (i != _usSize - 1){i2c_Ack();}else{i2c_NAck(); /* 读完最后⼀个字节,主机发送⾮应答 */}}i2c_Stop();return1;}/** 函数名: M24256_WriteBlock* 功能说明: 向串⾏EEPROM指定地址写⼊若⼲数据,采⽤页写操作提⾼写⼊效率* 形参: _usAddress : 起始地址* _usSize : 数据长度,单位为字节* _pWriteBuf : 存放读到的数据的缓冲区指针* 返回值: 0 表⽰失败,1表⽰成功*/unsigned char M24256_WriteBlock(unsigned char *_pWriteBuf, unsigned short _usSize, unsigned short _usAddress) {uint16_t i, m;uint16_t usAddr;usAddr = _usAddress;for (i = 0; i < _usSize; i++){if ((i == 0) || (usAddr & (EE_PAGE_SIZE - 1)) == 0){i2c_Stop();/* 重复发送起始信号,eeprom要重新开始写要等待10ms左右 */for (m = 0; m < 3000; m++){i2c_Start();i2c_WriteByte(EE_DEV_ADDR | I2C_WR);if (i2c_CheckAck() == ACK){break;}}if (m >= 3000){i2c_Stop(); /* 写eeprom超时 */return0;}/* 发送地址 */i2c_WriteByte((usAddr & 0xFF00) >> 8);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}i2c_WriteByte(usAddr & 0x00FF);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}}/* 写⼊数据 */i2c_WriteByte(_pWriteBuf[i]);if (i2c_CheckAck() == NOACK){i2c_Stop();return0;}usAddr++;}i2c_Stop();return1;}bsp_eeprom.c#ifndef __M24256_DRIVER_H__#define __M24256_DRIVER_H__#include "stm8s.h"#define EE_MODEL_NAME "M24256"#define EE_DEV_ADDR 0xA0 /* 设备地址 */#define EE_PAGE_SIZE 64 /* 页⾯⼤⼩(字节) */#define EE_SIZE (32*1024) /* 总容量(字节) */#define EE_ADDR_BYTES 1 /* 地址字节个数 */extern unsigned char g_ucIsEEPROMBusy;void M24256_Init(void);uint8_t M24256_WriteByte(uint16_t _usAddress, uint8_t _ucByte);uint8_t M24256_ReadByte(uint16_t _usAddress);unsigned char M24256_ReadBlock(unsigned char *_pReadBuf, unsigned short _usSize, unsigned short _usAddress); unsigned char M24256_WriteBlock(unsigned char *_pWriteBuf, unsigned short _usSize, unsigned short _usAddress); void ee_Test(void);#endif /* __M24256_DRIVER_H__ */bsp_eeprom.h。

IIC接口EEPROM的控制

IIC接口EEPROM的控制

I 2C 接口EEPROM 的控制AT24Cxx 是Atmel 公司生产的串行电可擦的可编程存储器EEPROM ,它采用8引脚双排直插式封装,具有结构紧凑、存储容量大等特点,可以在I 2C 总线上并接4片该芯片,特别适用于具有大容量数据存储要求的数据采集系统。

本设计以AT24C512为例,介绍该芯片的工作原理和与单片机的软硬件接口。

一.AT24C512简要介绍AT24C512是Atmel 公司生产的64KByte 串行电可擦的可编程存储器,内部有512页,每一页为128Byte ,任一单元的地址为16位,地址范围为0000~0FFFFH 。

它采用8引脚封装,具有结构紧凑、存储容量大等特点,可以在I 2C 总线上并接4片芯片,特别适用于具有大容量数据存储要求的数据采集系统。

因此在测控系统中被大量采用。

1、AT24C512的主要特性具有如下3种工作电压:5.0 (VCC = 4.5V to 5.5V)。

2.7 (VCC = 2.7V to 5.5V)。

1.8 (VCC = 1.8V to 3.6V)。

存储容量为65,536Byte 即512Kbit( 64Kx 8bit)。

与100kHz 、400kHz 、1MHz I 2C 总线兼容。

ESD 保护电压>4kV 。

数据可保存40年。

CMOS 低功耗技术,最大写入电流为3mA 。

采用施密特触发,可抑制输入噪声。

符合双向数据传送协议。

具有硬件写保护和软件数据保护功能。

具有128Byte 页写入缓存器。

自动定时的写周期。

具有8引脚DIP 及20引脚SOIC 封装等多种。

2、管脚说明AT24C512的管脚如图 所示各引脚的功能如下:A0、A1:地址选择输入端。

在串行总线结构中,如需连接4个AT24C512芯片,则可用A0、A1来区分各芯片。

A0、A1悬空时为0。

SDA :双向串行数据输入输出口。

用于存储器与单片机之间的数据交换。

SCL :串行时钟输入。

i2c读写程序的详细讲解

i2c读写程序的详细讲解

i2c读写程序的详细讲解I2C即Inter-IntegratedCircuit(内部集成电路),是一种同步串行总线技术,它可以用来连接多个芯片,并使用它们之间的2条双向数据总线进行通信。

I2C总线可以通过5根线实现,其中2条用于数据传输,另外3条用于控制传输过程:SCL(时间同步线)、SDA(数据线)、VCC(电源线)。

I2C在光学芯片、DSP和ARM芯片等领域都得到了广泛应用,能够实现在一个系统或介质中共享数据,有助于节省系统开发成本和实现系统节能。

第二部分:I2C读写程序I2C读写程序是通过I2C总线实现数据读写的特定程序,主要由以下步骤构成:1、设置I2C总线:通过一系列硬件设置完成I2C总线的初始化,以满足对应数据读写的要求;2、发送I2C开始信号:在进行数据读写前,需要发送一个开始信号,以通知主从端可以进行通信;3、发送I2C地址:根据读写操作,发送I2C地址;4、发送I2C数据:根据读写操作,发送相关数据;5、接收I2C数据:根据读写操作,接收相关数据;6、发送I2C停止信号:发送I2C停止信号,结束数据读写过程。

第三部分:I2C读写程序实例下面以C语言为例,介绍在I2C通讯操作中读写程序的编写流程: 1、I2C总线的初始化:可以使用如下函数来设置I2C总线的参数,完成I2C总线的初始化:#include <linux/i2c.h>#include <linux/i2c-dev.h>int i2c_init (int busno);其中busno表示I2C总线号;2、发送I2C开始信号:可以使用如下函数来发送I2C开始信号:int i2c_smbus_write_start(int busno, int addr);其中busno表示I2C总线号,addr表示要发送的I2C地址;3、发送I2C地址:可以使用如下函数来发送I2C地址:int i2c_smbus_write_byte(int busno, int addr);其中busno表示I2C总线号,addr表示要发送的I2C地址;4、发送I2C数据:可以使用如下函数发送I2C数据:int i2c_smbus_write_byte_data(int busno, int addr, int data);其中busno表示I2C总线号,addr表示要发送的I2C地址,data 表示要发送的数据;5、接收I2C数据:可以使用如下函数接收I2C数据:int i2c_smbus_read_byte_data(int busno, int addr);其中busno表示I2C总线号,addr表示要读取的I2C地址;6、发送I2C停止信号:可以使用如下函数发送I2C停止信号:int i2c_smbus_write_stop(int busno);其中busno表示I2C总线号;第四部分:结论以上就是I2C读写程序的详细讲解,可以看出,I2C读写程序的实现步骤非常简单,只需要对每个步骤做出正确的设置,就可以实现I2C数据读写操作。

i2c读写eeprom手册

i2c读写eeprom手册

i2c读写eeprom手册
I2C读写EEPROM的手册主要包括以下步骤:
1. 确定EEPROM的设备地址:I2C通讯时,地址跟读写方向连在一起构成一个8位数。

当R/W位为0时,表示写方向,加上7位地址,其值为
“0xA0”,常称该值为I2C设备的“写地址”;当R/W位为1时,表示读方向,加上7位地址,其值为“0xA1”,常称该值为“读地址”。

2. 准备读写操作:主机产生并发送起始信号到从机,将控制命令写入从机设备,读写控制位设置为低电平,表示对从机进行数据写操作,控制命令的写入高位在前低位在后。

3. 发送存储地址:从机接收到控制指令后,回传应答信号,主机接收到应答信号后开始存储地址的写入。

4. 进行读写操作:根据一次读操作读取数据量的多少,读操作可分为随机读操作和顺序读操作。

随机读操作可以理解为单字节数据的读取。

5. 结束操作:读写操作完成后,主机发送停止信号结束操作。

请注意,所有I2C设备均支持单字节数据写入操作,但只有部分I2C设备支持页写操作;且支持页写操作的设备,一次页写操作写入的字节数不能超过设备单页包含的存储单元数。

此外,EEPROM芯片中还有一个WP引脚,
具有写保护功能,当该引脚电平为高时,禁止写入数据,当引脚为低电平时,可写入数据。

以上步骤仅供参考,如果使用实验板EEPROM的型号、设备地址或控制引
脚不一样,需根据实际工程修改。

单片机模拟I2C总线及24C02(I2C EEPROM)读写实例

单片机模拟I2C总线及24C02(I2C EEPROM)读写实例
{
/*发送1,在SCL为高电平时使SDA信号为高*/
SDA=1;
SCL=1;
DELAY(DELAY_TIME);
SCL=0;
DELAY(DELAY_TIME);
}
bit Check_Acknowledge(void)
/* Language: C51单片机编程语言 */
/* Platform: Win98,Intel Celeron 433 Processor,伟福仿真器,仿真8751 */
/* Author: StephenZhu javasdk@ */
for(i=0;i<7;i++)
{
WriteI2CByte(buffer[i]);
if(!Check_Acknowledge())
{
I2C_Stop();
WriteI2CByte(addr);/*address*/
acktemp=Check_Acknowledge();
WriteI2CByte(thedata);/*thedata*/
acktemp=Check_Acknowledge();
I2C_Start();
WriteI2CByte(0xa0);
acktemp=Check_Acknowledge();
WriteI2CByte(addr);/*address*/
acktemp=Check_Acknowledge();
I2C_Start();
WriteI2CByte(0xa1);
acktemp=Check_Acknowledge();
for(i=0;i<n;i++)

I2C读写EEPROM问题总结

I2C读写EEPROM问题总结

2017 年6 月3 0 日星期五目的:利用TMS320F2801芯片上外设I2C (2线串口)读写EEPROM数据(24LC128)关键点1 : 24LC时钟频率400KHZ,寄存器设置如下://Prescaler- need7-12Mhzo nm oduleclk=10; 〃NOTE:mustbe non zero=5; 〃NOTE:mustbe non zero时钟频率也可设为200KHz,三个参数分别为9、20、20(CPU时钟频率为100MHz)(未测试)关键点2 :波形分析问题:I2C模块是不是只有I2CCNT减到0才会发出停止信号I2C模块是硬件的,当检测到发送完了就会发结束自动发信号,不需要人为干预问题1:字节写操作正常,但是字节读函数出错原因:写EEPROM是在七位器件地址后添加写标志,而读EEPROM需要在七位器件地址后添加写标志。

关键点:读EEPROM数据需要发送两次命令。

第一次为写地址(此地址会被赋值给EEPROM 内的地址指针),因此需要添加写标志;第二次为读数据,将写标志改为读标志。

问题2:主机接收时,SDA数据线上有数据传输,且I2CDRR接收数据寄存器有数据更新,但寄存器显示不可读,即CPU认为一直没接收到数据,一直停在下面语句while!=1);关键点:初始化设置时采用的是FIF O接收方式,因此无效,应查询FIF O接收中断位while!=1);//FIFORX 方式查询位。

此位只有在非FIFO中断接收方式时才有效。

问题3:断续单字节读写正常,但是采用连续的单字节读写出错。

原因:EEPRO M写过程的结束并不是I2C总线写结束就结束,实际上I2C总线的写入数据先被保存到了EEPRO M内部的缓冲区,当遇到I2C结束条件后,EEPROM才启动内部写过程,这个过程才是保存数据的过程。

非常悲哀的是这个过程比较长,官方文档标注为5ms。

如果在这5ms以内对EEPROM芯片访问将被忽略。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
SCL = 0;
SDA = 1;
}
void I2cSendNack()
{
SDA_DIR = 0;
SDA = 1;
I2c_delay();
SCL = 0;
I2c_delay();
SCL = 1;
I2c_delay();
SCLபைடு நூலகம்= 0;
}
INT8U I2cCheckAck()
void WriteOneByte(INT8U cData);
INT8U ReadOneByte();
INT8U WriteI2cData(INT16U addr, INT8U cData);
INT8U ReadI2cData(INT16U addr);
void I2c_delay()
{
return 0;
}
cTemp = L_BYTE(addr);
WriteOneByte(cTemp);
if(I2cCheckAck() == 0)
{
return 0;
}
WriteOneByte(cData);
if(I2cCheckAck() == 0)
#define H_BYTE(wVal) *( (unsigned char*)&wVal+1)
#define L_BYTE(wVal) *( (unsigned char*)&wVal )
#define NOP() asm("nop")
#define INT8U unsigned char
if(I2cCheckAck() == 0)
{
return 0;
}
I2c_delay();
I2c_delay();
I2c_delay();
I2c_delay();
cTemp = H_BYTE(addr);
WriteOneByte(cTemp);
if(I2cCheckAck() == 0)
#define INT16U unsigned int
void I2cInit();
void I2c_delay();
void I2cStop();
void I2cStart();
void I2cSendAck();
void I2cSendNack();
INT8U I2cCheckAck();
}
else
{
cData &= 0xFE;
}
SCL = 0;
}
SDA_DIR = 0;
return cData;
}
INT8U WriteI2cData(INT16U addr, INT8U cData)
{
INT8U cTemp;
I2cStart();
I2c_delay();
SCL = 1;
I2c_delay();
SCL = 0;
I2c_delay();
cData <<= 1;
}
I2c_delay();
I2c_delay();
I2c_delay();
I2c_delay();
}
INT8U ReadOneByte()
WriteOneByte(0xa0); //Slave device address
if(I2cCheckAck() == 0)
{
return 0;
}
cTemp = H_BYTE(addr);
WriteOneByte(cTemp);
if(I2cCheckAck() == 0)
I2c_delay();
cTemp = ReadOneByte();
I2cSendNack();
I2cStop();
I2c_delay();
I2c_delay();
I2c_delay();
I2c_delay();
I2c_delay();
return(cTemp);
}
void WriteOneByte(INT8U cData)
{
INT8U i;
SDA_DIR = 0;
for(i=0; i<8; i++)
{
if(cData & 0x80)
{
SDA = 1;
}
else
{
SDA = 0;
}
I2c_delay();
I2c_delay();
if(I2cCheckAck() == 0) //程序执行到这里的时候没有应答信号,直接执行 return 0 返回,前面的时序都是对的
{
return 0;
}
I2c_delay();
I2c_delay();
I2c_delay();
}
return 0;
}
问题是:用示波器观测时序图,写EEPROM时序正常,也就是执行WriteI2cData(0x0036, 0xC8)指令时候时序是正常的,但是读I2C时(cTemp = ReadI2cData(0x0036);),写入控制字0xa1(即 WriteOneByte(0xa1); )后没有应答信号,直接执行return 0 指令返回。不知道是什么原因,SCL和SDA的上拉电阻是10k,换成4.7k、20k都试过,现象是一样的。望高手指点一二。。。
}
I2c_delay();
I2c_delay();
I2c_delay();
I2c_delay();
I2cStart();
I2c_delay();
I2c_delay();
I2c_delay();
I2c_delay();
WriteOneByte(0xa1);
SDA = 1;
I2c_delay();
SDA = 0;
I2c_delay();
SCL = 0;
I2c_delay();
}
void I2cStop()
{
SCL_DIR = 0;
SDA_DIR = 0;
I2c_delay();
SDA = 0;
I2c_delay();
{
return 0;
}
I2c_delay();
I2c_delay();
I2c_delay();
I2c_delay();
cTemp = L_BYTE(addr);
WriteOneByte(cTemp);
if(I2cCheckAck() == 0)
{
return 0;
{
INT8U AckStatus;
SDA_DIR = 1;
SCL = 1;
I2c_delay();
if(SDA == 1)
{
AckStatus = 0;
}
else
{
AckStatus = 1;
}
SCL = 0;
I2c_delay();
return AckStatus;
}
int main()
{
unsigned char cTemp;
I2cInit();
while(1)
{
// WriteI2cData(0x0036, 0xC8);
// WriteI2cData(0x00aa, 0x9A);
cTemp = ReadI2cData(0x0036);
{
return 0;
}
I2cStop(); //Stop condition
// delay_10us(80);
return 0;
}
INT8U ReadI2cData(INT16U addr)
{
INT8U cTemp;
I2cStart();
WriteOneByte(0xa0);
{
INT8U cData = 0, i;
SDA_DIR = 1;
SCL = 0;
I2c_delay();
for(i=0; i<8; i++)
{
SCL = 1;
I2c_delay();
cData <<= 1;
if(SDA == 1)
{
cData |= 0x01;
用IO口模拟I2C总线与24C256通信,代码如下:
#define SCL TG2
#define SDA TG3
#define SCL_DIR TRISGbits.TRISG2
#define SDA_DIR TRISGbits.TRISG3
{
NOP();
NOP();
NOP();
NOP();
}
void I2cInit()
{
I2cStop();
I2cStart();
I2cStop();
}
void I2cStart()
{
SCL_DIR = 0;
SDA_DIR = 0;
SCL = 1;
SCL = 1;
I2c_delay();
SDA = 1;
I2c_delay();
}
void I2cSendAck()
{
相关文档
最新文档