IIC读写EEPROM
- 格式:docx
- 大小:18.07 KB
- 文档页数:11
通过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低电平时才可以任意变换。
IIC_EEPROM说明书
一:原理图
IIC_EEPROM电路图
二:工作原理
使用IIC控制器读写IIC_EEPROM中的数据。
开启IIC控制器,IIC_SCL产生正确的时序,通过判断总线的状态,通过IIC_SDA传输数据。
请参考《STM32中文参考资料》的IIC相关内容。
三:实验现象及操作
本实验使用使用串口通信显示数据。
在上位机上打开串口助手,波特率设置为115200,无校验。
串口助手中使用文本接受模式。
按RESET键后,可发现串口助手接受区中显示,“这是一个IIC_EEPROM测试例程”字符串;
在按下一次K3键,程序网IIC_EEPROM中写入0x00,0x01,0x02,0x03等等共20个数据,在串口助手中有显示,然后会自动读取IIC_EEPROM中的数据并发送给PC机;
若再次按下K3键,数据会乘2再写入;
再按下K3键,数据则会乘3再写入;
依次类推。
用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.采用循环地址的方式进行存储,避免只在一个固定地址上读写数据;。
基于STM32的IIC_EEPROM案例说明STM32是一系列由STMicroelectronics开发的32位ARM Cortex-M处理器的微控制器。
它具有高性能、低功耗和丰富的外设。
其中一个外设是I2C接口,可以用于连接外部器件,如EEPROM。
EEPROM(Electrically Erasable Programmable Read-Only Memory)是一种非易失性存储器,可以通过电量抹除并重新编程。
本文将说明如何在STM32微控制器上使用I2C接口来读取和写入EEPROM的数据。
以下是一个I2CEEPROM案例的步骤:1.硬件连接:找到适当的引脚连接STM32和EEPROM。
根据STM32型号和EEPROM的规格书,将SCL引脚连接到STM32的相应引脚,将SDA引脚连接到STM32的相应引脚。
确保EEPROM上的地址引脚正确连接到STM32的引脚,以选择EEPROM的地址。
另外,确保STM32的引脚配置正确。
2.初始化I2C外设:在STM32的代码中,首先需要初始化I2C外设。
这可以通过配置I2C控制器的寄存器来完成。
这些寄存器包含有关时钟速度、地址模式和使能I2C控制器的设置选项。
3.选择EEPROM地址:通过向I2C总线发送一个特定的命令字节,可以选择EEPROM的地址。
这个命令字节包含I2C总线上的设备地址和寻址模式。
4.读取EEPROM数据:为了从EEPROM读取数据,STM32将发送一个读取命令字节,将该命令字节传送到EEPROM,然后从EEPROM读取数据。
在读取数据之前,需要设置读取数据的长度和目标缓冲区。
5.写入EEPROM数据:为了向EEPROM写入数据,STM32将发送一个写入命令字节,将该命令字节传送到EEPROM,然后将数据写入EEPROM。
在写入数据之前,需要设置写入数据的长度和源缓冲区。
6.处理错误和超时:在进行I2CEEPROM读取和写入操作时,可能会出现错误和超时。
电气工程学院《嵌入式单片机原理及应用》课程改革三级项目任务书设计题目:应用IIC总线方式读取EEPROM一、项目设计目的通过该项目的学习和锻炼使学生熟悉、了解并掌握和STM32学习、开发相关的软、硬件环境;了解IIC总线协议,熟悉其主要特点及功能;练习使用库函数以IIC总线方式读取EEPROM芯片AT24C02中的数据。
二、项目设计要求(1)掌握Keil MDK软件的模板设计及工程配置。
(2)了解IIC总线协议,熟悉和掌握其主要特性、功能及基本原理。
(3)熟悉《STM32F103XXX参考手册》、《STM32固件库》,在此基础上能够根据特定要求进行相关内容的查找;(4)掌握STM32的库函数开发方法,实现以IIC总线协议对EEPROM芯片AT24C02的数据读写。
(5)设计的工程要能进行现场展示。
三、项目设计内容1)应用Keil Uvision4设计工程模板,并根据编译和仿真要求进行相关工程配置。
Version3.5版本的ST库源码可从ST的官方网站下载或者从讲课的资料中获取;工程设计模板要根据授课教师建立的方式进行设计;建立一个空的main()测试函数;仿真采用的STM32芯片为STM32F103VET6,数据通信可采用串口或Jlink两种形式。
2)设计IIC总线读取EEPROM芯片内数据的软件流程图。
了解IIC总线协议,熟悉STM32的I2C特性及架构,并在掌握AT24C02数据组织形式的基础上,根据库函数的开发方法设计IIC总线方式读取EEPROM芯片内数据的软件流程图。
3)使用库函数进行IIC总线读取EEPROM芯片内数据工程的开发。
建议使用stm32的库函数进行该项目的开发,如果有的同学想使用直接配置寄存器形式进行相关内容的设计,必须是在完成库开发的基础上实现;该项目设计的工程要求能在现场进行演示。
4.项目考核要求该项目考核采用现场答辩形式;准备的材料包含:电子版的相关原理性描述、和项目内容相关的PPT、纸质版项目设计报告一份;设计的项目工程要求能在指定的硬件上现场进行演示。
单片机模拟I2C总线读写EEPROM(24CXX)程序一下面是一个最简单的读写程序,可以用来检测线路状况。
先附上程序和电路,后面附有说明。
电路:说明:P2 口的LED 都是我用来检测电路执行到哪一步的,个人觉得一目了然。
程序:#include #define unit unsigned int#define uchar unsigned charint ok;sbit scl=P0;sbit sda=P0;sb it led0=P2;sbit led1=P2;sb it led2=P2 ;sbit led3=P2;sb it led4=P2;sb it led5=P2 ;sbit led6=P2;sb it led7=P2;delay(void) //delay{ int i; led1=1; for(i=0;istart(void) //start{ sda=1; scl=1; delay(); sda=0; delay(); scl=0; led0=0;}stop(void) //stop{ sda=0; scl=1; delay(); sda=1; delay(); scl=0;}checkanswer(void) //check answer{ sda=1; scl=1; if(sda==1) { F0=1; led7=0; } scl=0; led3=0;}sendabyte(int temps) //send a byte{ uchar n=8; while(n--) { led2=1; if((temps&0x80)==0x80){ sda=1; scl=1; delay(); scl=0;}else{ sda=0; scl=1; delay(); scl=0;}temps=tempsreciveabyte() //recive a byte{ uchar n=8,tempr; while(n--) {//uchar idata *abyte scl=1;tempr=temprmain(void) //MAIN{start();sendabyte(0xa0);checkanswer();if(F0==1) return;sendabyte(0x00);checkanswer();if(F0==1) return;sendabyte(0x11);checkanswer();if(F0==1) return;/*-----------------------*/start(); sendabyte(0xa0);checkanswer();if(F0==1) return;。
/*----------------------------------------------------------------------------------------------------------IIC总线读写EEPROM(串行扩展eeprom,24c02)(STC12C系列单片机自带eeprom,且有另外的eeprom操作方式)作者:Allen.H(帮同学修改的一个程序)时间:2010.11.5----------------------------------------------------------------------------------------------------------*/#include <reg52.h>#include <intrins.h>//是用括号还是双引号看情况,本地头文件用双引号,系统头文件用括号//这里使用了_nop_()函数,所以调用此头文件#define TRUE 1/*define宏定义一般用大写,宏定义并不会减少最终代码空间define多行语句时,每一行末尾写上\,最后一行可以不写,有时比较短的语句写成一个子函数会牺牲更多的时间,因为函数调用耗时比较多,这个时候用一个define语句更好*/#define FALSE 0typedef unsigned char uchar;//良好的程序风格,不应该用#define//#define uchar unsigned charsbit sda=P2^0; //---------你把sda和scl引脚可能定反了,我换过来了-------------------------------sbit scl=P2^1;//等号对其,变量名长短不一时,注意,且测试等于号"=="或者其他双目关系运算符两边都空一格//-----------------------------------------------------------------void delay(uchar z)//带参数很好{//大括号所在行不要写代码uchar i,j;//局部变量中用来自加自减可以用i,j之类的定义,计数建议不要用i,j//局部变量不占内存,函数调用时生成堆栈,不应该定义局部变量时作初始化//----局部变量命名后空一格,写正式代码for(i=z;i>0;i--)for(j=100;j>0;j--);//注明多少时间,在调试模式下,看窗口左边的SEC值}//函数与函数之间空一格void delay_7nop()//子程序命名最好顾名思义,比如delay_1ms(),这里考虑都是使用7nop,不带参数{/*程序代码每进一层逻辑就缩进一格TAB键,TAB设置为3,4格,在keil的view->options里面设置,不要使用几个空格来缩进,统一使用TAB键*/_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();//这里0-1000多个_nop_都可以}//delay函数都放在一起,函数顺序不要乱放,相关的放一起,//--------------------------------------------------------------------void init(){sda=1;delay_7nop();scl=1;delay_7nop();}//---SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;//SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。
EEPROMI2C操作说明EEPROM (Electrically Erasable Programmable Read-Only Memory)是一种非易失性存储器,可以通过电子方式擦除和编程,同时可以通过I2C总线进行操作。
本文将详细介绍EEPROM的I2C操作说明。
I2C(Inter-Integrated Circuit)是一种串行通信接口协议,可以在多个设备之间进行通信。
在EEPROM的I2C操作中,需要了解以下几个重要的概念和步骤。
1.设备地址:每个通过I2C连接的设备都有一个唯一的设备地址。
在EEPROM的I2C操作中,需要使用设备地址来与EEPROM进行通信。
2.起始条件和停止条件:I2C通信中,起始条件表示通信的开始,停止条件表示通信的结束。
起始条件由一个高电平到低电平的SCL上升沿和一个低电平的SDA下降沿组成,停止条件由一个低电平到高电平的SCL上升沿和一个高电平的SDA上升沿组成。
3. 数据传输:I2C通信中,数据可以以字节的形式进行传输。
每个字节由8个bit组成,包括7个数据位和1个校验位。
在进行EEPROM的I2C操作时,通常需要经过以下几个步骤:1.发送起始条件:将SCL和SDA引脚拉高,然后将SDA引脚拉低,形成起始条件。
2.发送设备地址和写命令:根据EEPROM的设备地址,将设备地址和写命令(0)发送到SDA引脚。
3.发送要写入的地址:将要写入数据的地址发送到SDA引脚。
4.发送数据:将要写入的数据发送到SDA引脚。
5.发送停止条件:将SCL引脚拉高,然后将SDA引脚拉高,形成停止条件。
实际的EEPROM的I2C操作可能还包括以下一些操作:1.读操作:通过发送读命令(1)和读取数据的地址,可以从EEPROM 中读取数据。
读操作与写操作类似,只是需要在发送设备地址时,将写命令(0)改为读命令(1)。
2.擦除操作:EEPROM的主要特点之一是可以擦除数据。
通过发送擦除命令和要擦除的数据的地址,可以将指定数据段擦除为初始值。
基于IIC协议的EEPROM 读写功能的实现(一)设计要求能用IIC协议实现对EEPROM的数据储存与读出。
(二)设计目的1. 通过本项课程设计,可以培养独立思考、综合运用所学有关相应知识的能力,能更好的巩固《单片机原理与应用》课程学习的内容,掌握工程软件设计的基本方法,强化上机动手编程能力,闯过理论与实践相结合的难关!更加了解了单片机的好处和其可用性!同时增加了同学之间的团队合作精神!更加也体会到以后在工作中团队合作的重要性和必要性!2. 通过课程设计,使学生了解高级程序设计语言的结构,掌握基本的程序设计过程和技巧,掌握基本的分析问题和利用计算机求解问题的能力,具备初步的高级语言程序设计能力。
为后续各门课程的学习和毕业设计打下坚实基础。
3、知道IIC串行总线协议原理与运用,明白EEPROM的存储结构,知道用keil51软件和proteus仿真进行连调,实习单片机开发。
(三) 所用仪器设备电脑、keil51和proteus软件(四) 方案选择由于用IIC串行总线读写EEPROM我们不能直观的观察他们的读写现象,所以我们选择的是用液晶1602进行读写显示,用4*4矩阵键盘进行读写控制和数字的输入,选用AT89C51为主控制器,选用AT24C02进行存储。
所以这个课程设计主要分为三个模块:1、IIC串行总线读写EEPROM模块;2、液晶显示模块;3、矩阵键盘控制模块;(五) 具体的设计过程现将IIC协议与AT24C02的工作原理讲解如下,关于液晶与AT89C51的工作原理这里不再讲解。
一、IIC串行总线的组成与通信原理I2C总线是PHLIPS公司推出的一种串行总线,是具备多主机系统所需的包括总线裁决和高低速器件同步功能的高性能串行总线。
I2C总线只有两根双向信号线。
一根是数据线SDA,另一根是时钟线SCL。
I2C总线通过上拉电阻接正电源。
当总线空闲时,两根线均为高电平。
连到总线上的任一器件输出的低电平,都将使总线的信号变低,即各器件的SDA及SCL都是线“与”关系。
浠g爜.v锛?`timescale 1ns/1nsmodule EEPROM_W_R(SDA,SCL,ACK,RESET,CLK,WR,RD,ADDR,DATA);output SCL; //涓茶鏃堕挓绾?output ACK; //璇诲啓涓€涓懆鏈熺殑搴旂瓟淇″彿input RESET; //澶嶄綅淇″彿input CLK; //鏃堕挓杈撳叆input WR,RD; //璇诲啓淇″彿input [10:0] ADDR; //鍦板潃绾?inout SDA; //涓茶鏁版嵁绾?inout [7:0] DATA; //骞惰鏁版嵁绾?reg ACK;reg SCL;reg WF,RF;reg FF;reg [1:0] head_buf;reg [1:0] stop_buf;reg [7:0] sh8out_buf;reg [8:0] sh8out_state;reg [9:0] sh8in_state;reg [2:0] head_state;reg [2:0] stop_state;reg [10:0] main_state;reg [7:0] data_from_rm;reg link_sda;reg link_read;reg link_head;reg link_write;reg link_stop;wire sda1,sda2,sda3,sda4;//-----------------------涓茶鏁版嵁鍦ㄥ紑鍏虫帶鍒朵笅鏈夊簭鐨勮緭鍏ユ垨杈撳嚭---------------------assign sda1 = (link_head) ? head_buf[1] : 1'b0;assign sda2 = (link_write) ? sh8out_buf[7] : 1'b0;assign sda3 = (link_stop) ? stop_buf[1] : 1'b0;assign sda4 = (sda1 | sda2 | sda3);assign SDA = (link_sda) ? sda4 :1'bz;assign DATA = (link_read) ? data_from_rm : 8'bzz;//-------------涓荤姸鎬佹満鐘舵€佸畾涔?--------------------------------parameterIdle = 11'b000_0000_0001,Ready = 11'b000_0000_0010,Write_start= 11'b000_0000_0100,Ctrl_write = 11'b000_0000_1000,Addr_write = 11'b000_0001_0000,Data_write = 11'b000_0010_0000,Read_start = 11'b000_0100_0000,Ctrl_read = 11'b000_1000_0000,Data_read = 11'b001_0000_0000,Stop = 11'b010_0000_0000,Ackn = 11'b100_0000_0000,//---------骞惰鏁版嵁涓茶杈撳嚭鐘舵€?------------------------------sh8out_bit7 = 9'b0_0000_0001,sh8out_bit6 = 9'b0_0000_0010,sh8out_bit5 = 9'b0_0000_0100,sh8out_bit4 = 9'b0_0000_1000,sh8out_bit3 = 9'b0_0001_0000,sh8out_bit2 = 9'b0_0010_0000,sh8out_bit1 = 9'b0_0100_0000,sh8out_bit0 = 9'b0_1000_0000,sh8out_end = 9'b1_0000_0000;//---------涓茶鏁版嵁骞惰杈撳嚭鐘舵€?-------------------------------parametersh8in_begin = 10'b00_0000_0001,sh8in_bit7 = 10'b00_0000_0010,sh8in_bit6 = 10'b00_0000_0100,sh8in_bit5 = 10'b00_0000_1000,sh8in_bit4 = 10'b00_0001_0000,sh8in_bit3 = 10'b00_0010_0000,sh8in_bit2 = 10'b00_0100_0000,sh8in_bit1 = 10'b00_1000_0000,sh8in_bit0 = 10'b01_0000_0000,sh8in_end = 10'b10_0000_0000,//----------鍚姩鐘舵€?--------------------------------------------head_begin = 3'b001,head_bit = 3'b010,head_end = 3'b100,//---------------------------------------------------------------------stop_begin = 3'b001,stop_bit = 3'b010,stop_end = 3'b100;//------------------------------------------------------------------------ parameterYES = 1,NO = 0;//-------------浜х敓涓茶鏃堕挓SCL,涓鸿緭鍏ユ椂閽熺殑2鍒嗛---------------------------always@(negedge CLK)if(RESET)SCL <= 0;elseSCL <= ~SCL;//---------------涓荤姸鎬佹満绋嬪簭-------------------------------------always@(posedge CLK)if(RESET)beginlink_read <= NO;link_write<= NO;link_head <= NO;link_stop <= NO;link_sda <= NO;ACK <= 0;RF <= 0;WF <= 0;FF <= 0;main_state <= Idle;endelsebegincasex(main_state)Idle:beginlink_read <= NO;link_write <= NO;link_head <= NO;link_stop <= NO;link_sda <= NO;if(WR)beginWF <= 1;main_state <= Ready;endelse if(RD)beginRF <= 1;main_state <= Ready;endelsebeginWF <= 0;RF <= 0;main_state <= Idle;endendReady:beginlink_read <= NO;link_write <= NO;link_stop <= NO;link_head <= YES;link_sda <= YES;head_buf[1:0] <= 2'b10;stop_buf[1:0] <= 2'b01;head_state <= head_begin;FF <= 0;ACK <= 0;main_state <= Write_start;endWrite_start:if(FF == 0)shift_head;elsebeginsh8out_buf[7:0] <= {1'b1,1'b0,1'b1,1'b0,ADDR[10:8],1'B0}; link_head <= NO;link_write <= YES;FF <= 0;sh8in_state <= sh8out_bit6;main_state <= Ctrl_write;endCtrl_write:if(FF == 0)shift8_out;elsebeginsh8out_state <= sh8out_bit7;sh8out_buf[7:0] <= ADDR[7:0];FF <= 0;main_state <= Addr_write;endAddr_write:if(FF == 0)shift8_out;elsebeginFF <= 0;if(WF)beginsh8out_state <= sh8out_bit7;sh8out_buf[7:0] <= DATA;main_state <= Data_write;endif(RF)beginhead_buf <= 2'b10;head_state <= head_begin;main_state <= Read_start;end endData_write:if(FF == 0)shift8_out;elsebeginstop_state <= stop_begin;main_state <= Stop;link_write <= NO;FF <= 0;endRead_start:if(FF == 0)shift_head;elsebeginsh8out_buf <= {1'b1,1'b0,1'b1,1'b0,ADDR[10:8],1'b1}; link_head <= NO;link_sda <= YES;link_write<= YES;FF <= 0;sh8out_state <= sh8out_bit6;main_state <= Ctrl_read;endCtrl_read:if(FF == 0)shift8_out;elsebeginlink_sda <=NO;link_write <= NO;FF <= 0;sh8in_state <= sh8in_begin;main_state <= Data_read;endData_read:if(FF == 0)shift8in;elsebeginlink_stop <= YES;link_sda <= YES;stop_state <= stop_bit;FF <= 0;main_state <= Stop;endStop:if(FF == 0)shift_stop;elsebeginACK <= 0;FF <= 0;main_state <= Ackn;endAckn:beginACK <= 0;WF <= 0;RF <= 0;main_state <= Idle;enddefault: main_state <= Idle;endcaseend//--------------------------------涓茶鏁版嵁杞寲涓哄苟琛屾暟鎹换鍔?---------------------------------task shift8in;begincasex(sh8in_state)sh8in_begin:sh8in_state <= sh8in_bit7;sh8in_bit7:if(SCL)begindata_from_rm[7] <= SDA;sh8in_state <= sh8in_bit6;endelsesh8in_state <= sh8in_bit7; sh8in_bit6:if(SCL)begindata_from_rm[6] <= SDA;sh8in_state <= sh8in_bit5;endelsesh8in_state <= sh8in_bit6; sh8in_bit5:if(SCL)begindata_from_rm[5] <= SDA;sh8in_state <= sh8in_bit4;endelsesh8in_state <= sh8in_bit5;sh8in_bit4:if(SCL)begindata_from_rm[4] <= SDA;sh8in_state <= sh8in_bit3;endelsesh8in_state <= sh8in_bit4;sh8in_bit3:if(SCL)begindata_from_rm[3] <= SDA;sh8in_state <= sh8in_bit2; endelsesh8in_state <= sh8in_bit3; sh8in_bit2:if(SCL)begindata_from_rm[2] <= SDA;sh8in_state <= sh8in_bit1; endelsesh8in_state <= sh8in_bit2; sh8in_bit1:if(SCL)begindata_from_rm[1] <= SDA;sh8in_state <= sh8in_bit0; endelsesh8in_state <= sh8in_bit1; sh8in_bit0:if(SCL)begindata_from_rm[0] <= SDA;sh8in_state <= sh8in_end; endelsesh8in_state <= sh8in_bit0; sh8in_end:if(SCL)beginlink_read <= YES;FF <= 1;sh8in_state <= sh8in_bit7; endelsesh8in_state <= sh8in_end; default:beginlink_read <= NO;sh8in_state <= sh8in_bit7;endendcaseendendtask//---------------------------骞惰鏁版嵁杞崲涓轰覆琛屾暟鎹换鍔?----------------------------task shift8_out;begincasex(sh8out_state)sh8out_bit7:if(!SCL)beginlink_sda <= YES;link_write <= YES;sh8out_state <= sh8out_bit6;endelsesh8out_state <= sh8out_bit7;sh8out_bit6:if(!SCL)beginlink_sda <= YES;link_write <= YES;sh8out_state <= sh8out_bit5;sh8out_buf <= sh8out_buf << 1;endelsesh8out_state <= sh8out_bit6;sh8out_bit5:if(!SCL)beginsh8out_state <= sh8out_bit4;sh8out_buf <= sh8out_buf << 1;endelsesh8out_state <= sh8out_bit5;sh8out_bit4:if(!SCL)beginsh8out_state <= sh8out_bit3;sh8out_buf <= sh8out_buf << 1;endsh8out_state <= sh8out_bit4; sh8out_bit3:if(!SCL)beginsh8out_state <= sh8out_bit2; sh8out_buf <= sh8out_buf << 1; endelsesh8out_state <= sh8out_bit3;sh8out_bit2:if(!SCL)beginsh8out_state <= sh8out_bit1; sh8out_buf <= sh8out_buf << 1; endelsesh8out_state <= sh8out_bit2;sh8out_bit1:if(!SCL)beginsh8out_state <= sh8out_bit0; sh8out_buf <= sh8out_buf << 1; endelsesh8out_state <= sh8out_bit1;sh8out_bit0:if(!SCL)beginsh8out_state <= sh8out_end;sh8out_buf <= sh8out_buf << 1; endelsesh8out_state <= sh8out_bit0;sh8out_end:if(!SCL)beginlink_sda <= NO;link_write <= NO;FF <= 1;elsesh8out_state <= sh8out_end;endcaseendendtask//-------------------------------杈撳嚭鍚姩淇″彿浠诲姟-------------------------------task shift_head;begincasex(head_state)head_begin:if(!SCL)beginlink_write <= NO;link_sda <= YES;link_head <= YES;head_state <= head_bit;endelsehead_state <= head_begin;head_bit:if(!SCL)beginFF <= 1;head_buf <= head_buf << 1;head_state <= head_end;endelsehead_state <= head_bit;head_end:if(!SCL)beginlink_head <= NO;link_write <= YES;endelsehead_state <= head_end;endcaseendendtask//--------------------------------杈撳嚭鍋滄淇″彿浠诲姟-----------------------------------task shift_stop;begincasex(stop_state)stop_begin:if(!SCL)beginlink_sda <= YES;link_write <= NO;link_stop <= YES;stop_state <= stop_bit;endelsestop_state <= stop_bit;stop_bit:if(!SCL)beginstop_buf <= stop_buf << 1;stop_state <= stop_end;endelsestop_state <= stop_bit;stop_end:if(!SCL)beginlink_head <= NO;link_stop <= NO;link_sda <= NO;FF <= 1;endelsestop_state <= stop_end;endcaseendendtaskendmodule。
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才启动内部写过程,这个过程才是保存数据的过程。
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的型号、设备地址或控制引
脚不一样,需根据实际工程修改。
STM32作为主机I2C,读写24C02EEPROM1、时钟和数据的传输:开始和停止条件,数据在SCL的高电平期间有效,在SCL的低电平期间改变。
2、开始条件:在SCL高电平期间,SDA产生一个下降沿3、停止条件:在SCL高电平期间,SDA产生一个上升沿4、应答:成功接收到数据(地址和数据),产生一个应答位(在第9个时钟周期,将SDA拉低)下面是源程序:原理上说,下面程序再移植时,只要将数据类型变化,可以应用到任何处理器AT24c02.h#ifndef __24CXX_H#define __24CXX_H#include "i2c.h"/************************************************************** *- 说明:以下参数是AT24Cxx的寻址空间,C0x ,X 表示XK 如C01表示1K- 127表示2^7 1Kbit/8=128Byte 128字节- 255表示2^8 2Kbit/8=256Byte 256字节- 512表示2^9 4Kbit/8=512Byte 512字节-*************************************************************** /#define AT24C01 127#define AT24C02 255#define AT24C04 511#define AT24C08 1023#define AT24C16 2047#define AT24C32 4095#define AT24C64 8191#define AT24C128 16383#define AT24C256 32767/************************************************************** --板子使用的是24c02,所以定义EE_TYPE为AT24C02**************************************************************/ #define EE_TYPE AT24C02/************************************************************** --EEPROM的操作函数--24CXX驱动函数**************************************************************/u8 AT24CXX_ReadOneByte(u16 ReadAddr); //指定地址读取一个字节void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite); //指定地址写入一个字节void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);//指定地址开始写入指定长度的数据u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len); //指定地址开始读取指定长度数据void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite); //从指定地址开始写入指定长度的数据void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead); //从指定地址开始读出指定长度的数据u8 AT24CXX_Check(void); //检查器件void AT24CXX_Init(void); //初始化IIC#endif----------------------------------------------------------------------------------------------------------------------------------------- AT24c02.c#include "at24cxx.h"#include "delay.h"/************************************************************** *************- 功能描述:STM32f103 EEPORM初始化函数- 隶属模块:STM32 EEPROM操作- 函数属性:外部,使用户使用- 参数说明:无- 返回说明:无- 函数功能:实现I2C的初始化。
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芯片访问将被忽略。
STM32 系统学习——I2C (读写EEPROM)
I2C 通讯协议(Inter-Integrated Circuit)引脚少,硬件实现简单,可扩展性强,不需要USART、CAN 等通讯协议的外部收发设备,现在被广泛地使用在系统内多个集成电路(IC)间的通讯。
在计算机科学里,大部分复杂的问题都可以通过分层来简化。
如芯片被分为
内核层和片上外设;STM32 标准库则是在寄存器与用户代码之间的软件层。
对于通讯协议,我们也以分层的方式来理解,最基本的是把它分为物理层和协
议层。
物理层规定通讯系统中具有机械、电子功能部分的特性,确保原始数据在物
理媒体的传输。
协议层主要规定通讯逻辑,统一收发双方的数据打包、解包标准。
简单来说物理层规定我们用嘴巴还是用肢体来交流,
协议层则规定我们用中文还是英文来交流。
一、I2C 物理层
它的物理层有如下特点:
(1) 它是一个支持设备的总线。
“总线”指多个设备共用的信号线。
在一个I2C 通讯总线中,可连接多个I2C 通讯设备,支持多个通讯主机及多个通讯从机。
(2) 一个I2C 总线只使用两条总线线路,一条双向串行数据线(SDA) ,一条串行时钟线(SCL)。
数据线即用来表示数据,时钟线用于数据收发同步。
(3) 每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备之间的访问。
(4) 总线通过上拉电阻接到电源。
当I2C 设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。