找回密码
 注册
关于网站域名变更的通知
查看: 612|回复: 1
打印 上一主题 下一主题

硬件和软件兼容i2c协议的24Cxx系列EEPROM存储器

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2019-1-15 13:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
硬件和软件兼容i2c协议的24Cxx系列EEPROM存储器+ L& c1 R  f# y9 U6 t2 m
/ O& v' l. `0 k) N8 H, Y
$ ]( B( x6 C5 S; N

- k5 B+ I. _9 o6 H* G# c& T" W' f  a! o7 S/ a" K2 L0 V3 [0 c7 m7 i: i
硬件上由于24c01的A0A1A2管脚不允许悬空,故暂时的想法是兼容24c02 ---24c16
# k/ q: _2 Q  ~' a5 w# O* M使用一个dip8封装的芯片插座,A0 A1 A2管脚都悬空即可,换芯片方便; s3 K4 i  E/ p& H
软件上24c02地址只有8位,而其他型号是大于8位的,故地址参数使用16位
  X1 \2 ]2 b' a$ H: _256个字节作为一个大页,即largePage,测试芯片24c04空间有512字节
2 ?- o  r3 }7 }( ?9 _7 W, K9 g* q$ N0 L" ~. w% _" V
上代码,求测试和讨论

1 `2 C( |& j5 a# G# E! L- i/ \7 e" T  I  e& F1 [

7 F6 l5 e5 }0 K5 H! K4 [#include "MY51.H"
# i$ d8 A% `* @4 z, I  n//转载请注明:  求测试讨论4 C$ b8 J3 J) d5 _. d, n7 o
//stc89c52rc,11.0592MHz晶振/ ~0 ]3 K' m/ `9 ^1 n
sbit sda=P2^0;                //总线连接口定义
& l+ e( H. D& Q: v( j( k1 C* S; ~sbit scl=P2^1;                //总线连接口定义
- q& M/ R! z! f
void delayus()                 //需要4个机器周期,大概4.34us
. M' x, q. K4 r: _: l8 v8 q{
5 \& v5 g. m% K( \7 H5 p5 a        ;                                //晶振频率11.0592M,机器周期为1.085微秒* v, u3 p( U! `/ y% |8 i! d" \4 O
}

6 G( b7 A; J+ t; S9 `) yvoid iic_start()          //启动信号
( k* Q! x0 [$ P% \! ]4 Q/ p7 O# m{; X$ l. \2 f. q$ H: T: w) V4 Z
        sda=1;2 e' x  V; x" Z- y5 s& Q
        scl=1;/ V# I; H" T. m2 V
        delayus();                //sda和scl同为高电平保持4.7us以上
; _) a0 J+ ]- s        _nop_();                //1.085us,共5.78us/ M0 p, F1 u5 T4 ^
        sda=0;                         //下降沿
: |; ?6 s4 f7 M! H( u        delayus();                //sda低电平保持4us以上        ,这里是4.34us满足要求7 ~6 u, h7 [% ], J* b
}
) m/ F. Q5 @8 c) B  {8 S1 F
void iic_stop()                //停止信号
% D0 e% N' v% X% B& \2 p{
  P: G: ?- ?( K9 V- x- `        sda=0;_nop_();        //准备状态
+ n" Q! C- `$ m& j! ^        scl=1;( N  G6 p7 o1 F
        delayus();                //该状态稳定时间要求保持4us以上
+ E8 R! E. H/ U7 c% m        sda=1;                        //scl高电平期间,sda来一个上升沿. x1 K& j# j: \0 C) K4 {
        delayus();                //sda保持4.7us以上,4.34加上函数返回时间大于4.7us
! R7 U" h3 P/ o$ @- i                                        //注:此时scl和sda都为1        
" O* [) ]$ H! e. K% Y0 v5 G}
2 o6 j3 E& V* I7 H( I
void iic_sendByte(u8 byteData) //mcu发送一个字节" v) ?% U5 c4 g4 b3 j! q
{( y, I; K! t( l- O1 l- L/ \1 |3 g
        u8 i;8 p' v, G! u7 r  [* y6 [7 v- m1 V
        u8 temp=byteData;
' v" }! s' q: p4 t1 S2 G% R- r        for(i=0;i<8;i++)' w: \, ]$ {; v# b
        {2 [+ C- P0 g: H/ T- V
                temp=temp<<1;    //移动后最高位到了PSW寄存器的CY位中
. D8 H- ^  `6 ~  E0 p1 x! z4 O  T7 q                scl=0;                         //准备9 |( m  f0 x% O% v2 [2 b. X) H
                _nop_();                 //稳定一下
$ ?! h: D* U8 y9 J* p0 A5 {                sda=CY;                         //将待发送的数据一位位的放到sda上
8 g; j/ A/ W4 Q0 j7 @$ w5 |2 }, t$ D                _nop_();
% z+ @9 K) q  w$ f) z                scl=1;                     //每一个高电平期间,ic器件都会将数据取走
* @, B" l3 e+ R2 z                _nop_();                8 y3 e: t1 s: ~( i
        }
) ^, A) j* B/ P! P9 d
        scl=0;                                 //如果写成scl=1;sda=1就是停止信号,不能这么写
4 _- |3 X" I$ _. T! x+ u        _nop_();                                
9 D) C( t3 V% o) a! M        sda=1;                                 //释放总线,数据总线不用时要释放( R  V% O4 j1 l% ^  V7 ~8 Z
        _nop_();: O' v9 f7 F# V+ ]! B
}
2 h' |' y, ^4 ?! @
u8 iic_readByte()                         //读一个字节
; n) \- m1 [+ d0 W2 W' q& }{
- H7 o7 B- E+ B2 A2 u; H, m8 {        u8 i,temp;' Z: k% ]$ j, @$ q. q0 n# b: ^' }5 l
        scl=0;                                        //准备读数据  s' X& ~/ j  v1 h3 L
        _nop_();
- s$ L2 S0 p- R/ f        sda=1;                                        //释放总线. g+ |) @7 H$ Z3 b+ r
        _nop_();

# A4 g- ?( N" z; U2 I- e        for(i=0;i<8;i++)
, p6 o2 [  X" D% k  Q6 N        {0 h# e6 _+ O3 f/ O
                scl=1;                                //mcu开始取数据; G: I4 z: G8 w. t
                delayus();                        //scl为高电平后,ic器件就会将1位数据送到sda上
0 F! S' r" F( F( P0 l( A) @                                                        //总共用时不会大于4.34us,然后就可以让mcu读sda了3 e) [. f0 z" v# G; F7 x6 F9 Z
                temp=(temp<<1)|sda; //读一位保存到temp中
% l: A1 h# L: d- T  ~                scl=0;
9 T. o- W1 T& E                delayus();               
5 N* F9 y) d) j6 f        }2 a# S# s2 D2 s5 v' ]' m8 D
        return temp;' L* _" m, m4 R  e
}
& C# B( Q0 L0 @' ]/ C$ X
bool iic_checkACK()                  //处理应答信号! S; @; i3 |8 \( [
{
3 ~9 t: t  Q% l7 W' |        u8 errCounts=255;           //定义超时量为255次
  Z  W+ ~% I9 ~9 m! I        scl=1;
' ~( p4 t% G% d7 U' `" T1 l        _nop_();1 p; }6 O5 q8 C1 a1 r* O. Q
        
$ Y/ t9 I+ X5 v' g' N5 h5 h        while(sda)                          //在一段时间内检测到sda=0的话认为是应答信号* o5 M! D9 Q6 O. p
        {        ( ?/ o, z1 Y2 A7 C9 Q" u  K, N
                if(0==errCounts)
* s& [$ ^& e  f+ j                {6 C5 e/ o0 ?3 [' a! V5 c2 ^
                        scl=0;                  //钳住总线
4 X7 V; H; l) I6 j& Z) M+ |6 F  S                        _nop_();9 E3 v  E. m' F* t( |! ]
                        return FALSE; //没有应答信号) Q* f. Y0 ?4 h9 a( ~8 U/ }8 {6 n: B
                }; b  @: C1 `1 B  B; A) F; N0 r! m# Z
                errCounts--;4 ~1 ?2 H; j7 \9 J) v) i  L7 m
        }

, c; E7 j4 Z2 c  J- G  ^( K        scl=0;                             //钳住总线,为下1次通信做准备
+ X" J9 P7 c( l! }' r' [" j+ R        _nop_();& X' u  X0 l* l) R  R. h" M
        return TRUE;             //成功处理应答信号
" s* B! z0 G5 V9 w# `& r+ Q3 t}

8 T9 a5 f* v5 j' P$ b/ cvoid iic_init()                     //总线初始化
4 c- [# P3 @0 L" o4 P( G" \; C{% v( x/ u) g+ x7 t. E
        scl=1;
: D# N& }) `  v0 L) F/ x2 v& s        sda=1;& J9 t/ t  P% o: e
        delayus();/ u# v) N& C. c. F
}
; _" {% q. D9 P3 a3 H7 y
void iic_sendACK(bool b_ACK)  //发送应答或非应答信号9 n; [; V+ _5 X
{; D# k8 @- b) i! |: i) s
        scl=0;                        //准备
7 Z% A6 P' E! R4 P        _nop_();

% \: f: ~) W, D3 @" C$ l, P8 T        if(b_ACK)                //ACK        发送应该信号
$ F0 J8 B/ j6 \6 U. G        {6 R+ H5 ^* t2 d5 D& N5 t8 A
                sda=0;9 c0 ]$ R* e3 K  x5 g. M5 q
        }( G% }$ {6 p: V2 B0 _8 }9 r
        else                        //unACK        发送非应答信号  C1 x2 p' c. q7 Y
        {: I0 {9 t! P* l* M" G8 y8 L4 z8 k
                sda=1;
+ `& M+ ~  Y: j; D        }

) @( w% ^- s2 n6 s$ l# b        _nop_();6 ?. x/ ?" b9 N5 {, C; T
        scl=1;
# r  L4 i( E# `9 L7 }* M& b1 q1 k        delayus();                 //大于4us的延时
7 L( W  Z8 `3 r  B$ Q' q9 V" p/ A% v        scl=0;                    //钳住scl,以便继续接收数据        ) X7 n  e6 }9 V
        _nop_();2 l6 O& C% |1 I2 m. m9 I: B
}

  n! s& G7 D  a! q* c/ z5 L  bvoid AT24Cxx_writeByte(u16 address,u8 dataByte)//向24cxx写一字节数据4 t7 h' G+ P6 \' s9 l4 `
{. f# V+ z+ [% I% s
        u8 largePage     = address/256;          //24c04是512字节(寻址范围0~511),largePage最大值是14 P/ j2 Z6 s6 M( v
        u8 addressOffset = address%256;   //largePage=0的话地址范围是(0~255)8 u, B6 {( g. p+ [$ N( j* \7 @
        iic_start();3 i6 a  x2 I' o7 x, B9 K* E* _
        iic_sendByte(0xa0|(largePage<<1));//控制字,前4位固定1010,后三位是器件地址,末位0是写% k* W2 B5 v) s
        iic_checkACK();                                      //mcu处理应答信号5 T  K2 ^7 W  t7 D% P! ~6 P3 y$ H
        iic_sendByte(addressOffset);            //指定要写入的器件内地址在        largePage块中的偏移
% `* d5 C; t8 m5 o) s! \        iic_checkACK();- I" ?, U4 M' P. p# O
        iic_sendByte(dataByte);                   //写数据
* Z  @9 C" K8 \" K# U$ v8 t7 e        iic_checkACK();- c# j1 m: h7 y4 n
        iic_stop();
+ @8 G: U9 A' x3 X        delayms(2);        3 j$ C) W& {" @  V0 A/ F) n
        //按字节写入时,24cxx在接收到停止信号后将数据擦写到内部,这需要时间! Z+ [7 B: d5 j* o2 L% r
        //并且在这段时间内不会响应总线上的任何请求,故让mcu有2毫秒以上的等待        ! u" a+ O( m  e; L1 j  A( ]2 `
}
6 s- Q, _+ Q7 q9 B
void AT24Cxx_writeData(u16 address,u8 numBytes,u8* buf)//写入任意长度数据(最大256字节)
0 h% ~0 |1 k7 q* o{# P( F; S7 W3 d
        while(numBytes--)
% h  S' \' a9 H. [3 @( b% e. x$ e        {5 P9 F  H% H! I1 i! G3 u8 x4 q4 O$ p
                AT24Cxx_writeByte(address++,*buf++);
" c1 D! t3 k9 p' K( v9 {        }) H' M& O# {4 i. ?' m1 i- w: J( m& h
}
4 @; n9 J5 D3 k% v7 ^
void AT24Cxx_readData(u16 beginAddr,u8 dataSize,u8* buf)//读取任意长度字节到缓冲区buf中
; q7 ^4 Z+ `$ K; A0 P{, ~+ _" R" l0 K# _" @* c5 @4 p
        u8 largePage     = beginAddr/256;        //计算largePage,256字节为一大页  s6 _$ d7 F/ A
        u8 addressOffset = beginAddr%256;        //计算相对于largePage的偏移
5 Z- N1 Y7 U. M$ }; I. T, i; K        iic_start();                                                  //起始信号
$ A# [: g4 r! n5 L* s        iic_sendByte(0xa0|(largePage<<1));        //控制字,写/ M! v  Z4 s& [6 n
        iic_checkACK();                                                //处理应答信号
$ P1 a# W- z$ S3 W- j- f1 Y0 g( q        iic_sendByte(addressOffset);                //要读取的目标地址偏移! Y0 B( F, K6 |7 @: o2 W/ \
        iic_checkACK();                                                //处理应答信号        0 e  `$ |. p5 P8 p7 a+ f+ C, C
        iic_start();                                                   //发送起始信号
% \$ y$ G4 O) f5 o# R) O        iic_sendByte(0xa1|(largePage<<1));        //控制字,读, ?  l0 v4 L. L0 r* Z4 D7 [
        iic_checkACK();                                                //处理应答信号9 K. U+ O3 E. T5 m" a& I/ G
        while(dataSize--)                                        //读取dataSize个字节,最大256个字节
+ i+ H% f+ I9 D! F        {                                                                        //dataSize用u16类型会暴掉ram的! `6 ]! }. \" }% S* r9 |8 [
                *buf++=iic_readByte();                        //读取一个个字节并保存到缓冲区buf中# S( c& I) j) X" f; f
                iic_sendACK(dataSize);                  //发送应答,当dataSize为0时mcu发送非应答
9 j/ N( c* N- P9 p        }) V1 \# Y- _  }( c' c; Y; F
        iic_stop();                                                        //发送停止信号/ U3 c% S: v. g/ W1 @
}
5 P; L  Z0 K1 m: Y
5 b5 N6 S- [# `" Y
6 b% M# [  v0 n) l: f) ?
void main()//测试  I- ?' y2 Q& d6 E1 U+ @
{  u) N  ~' d: t# l2 c/ I
        u8 buf[3];                                                                                //接受数据的缓冲区
3 A/ E+ q- Q3 \        u8 arr[7]={0x06,1,2,3,4,0x55,0x33};                                //待写入的数据
8 ^; _) l1 e6 u+ e: X                                                
% L5 C0 S7 s, x7 J: V        iic_init();                                                                                //总线初始化
/ n$ w/ d3 w8 ~: m! @7 u$ \        AT24Cxx_writeData(0x00+256,sizeof(arr),arr);        //向指定地址处开始写入7字节的数据
3 T8 |+ l1 w( G# b/ y
        P1=0xff;                                                                                 //调试代码,用P1口的led显示
. u+ [+ Y6 A& P2 u        delayms(1000);                                                                         //调试代码

& Q. T% y  [) P' [/ ~0 n# o        AT24Cxx_readData(0x00+256,sizeof(buf),buf);           //从指定地址开始读3个字节0 c. G2 ]2 G: [) A* t
        P1=buf[2];        //也就是2                                                                        //led灯显示数值; x$ S+ l$ \5 t$ s! J( B5 j6 w
                                                                                       
. W7 k! n; D( A) Z        while(1)6 [  p; R8 g+ S# b- D- b6 y
        {
9 r1 D& o5 i9 h, T+ J5 z6 k                P1=~P1;! [8 t! _+ x  c, Z/ J
                delayms(500);               
6 [  p, K, P' t        }
7 T  V1 B4 `1 [# [9 u2 G+ Z}
" X9 M2 t" F+ V
3 J1 Z$ d0 b" T

; w1 z4 D  p7 H( C6 B& `9 [6 s, H! j! j

5 _* c% ?7 Y2 u3 J4 U- Q
0 u8 }" `& X( V# u
3 Y2 z+ E) s" h$ y; g# ?  E
2 Q9 s. l' u" L$ u0 q$ U$ y2 Q/ [1 I
//my51.h中主要用到
9 i% ?0 h9 }9 p& D+ L. ?( a#include<reg52.h>

& T$ G4 I: w' B4 @) j" a#include"mytype.h"
6 [9 Q) L  n: u5 C6 R* Ovoid delayms(u16 ms)     //软延时函数% s; A3 s& \5 Z
{
1 A  E, u. A# g& F5 ]1 f- ^" h2 A        u16 i,j;
  p$ w9 {1 \1 g% a7 Y7 ~& T+ y8 s0 C        for(i=ms;i>0;i--)6 R+ E( g- r, g5 ^5 i# f
        {& k5 z, H8 h0 r+ O) u
        for(j=113;j>0;j--)8 t- h6 i+ e1 P
        {}
0 E( U- F. |" ^& l        }
5 F8 i3 E/ y+ ~# L, B" [$ |}
* o7 [+ ?$ a; r% p8 T# H# x6 [, i8 ?
, d! o( l0 O5 h8 ]
; D" M- n5 j7 M! G
$ }6 |9 D$ Y  Q0 s( A; {

* r; x1 Q5 ~) U6 R) N" R
) U: z2 U& c, T5 H
* _5 h6 G: ^/ }& g对代码进行了改进 3 @9 w; `/ M9 _" D" I, k2 W
去掉了在写数据时的
. M; k% B* c* x/ F- o2 h: bdelayms(2);0 S* j% E2 y" @
这句软延时代码低效 ,而且没有保障

& ]2 n# z* Q% v# \改成加一个检测函数
2 u. ]' c; G1 R1 Zbool check_icWriteComplete()   //检测eeprom是否对内部擦写完成
9 y/ N; t9 }; h; R5 |/ x{
3 o; p9 M/ B- f9 X, b& L8 | iic_start();
; T4 ?# `% l& G9 z& t% }# Z. z iic_sendByte(0xa0); 1 x6 ^3 G2 T, |3 q0 V5 d- P
return iic_checkACK(); # i3 K- k9 ?7 J$ o+ N4 \
}
3 a# j' s3 \2 s3 c+ F( B+ b( F  f

9 B' W6 D& ]1 b+ s% E9 l

该用户从未签到

2#
发表于 2019-1-15 23:29 | 只看该作者
这个不错,谢谢楼主分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-6-18 21:58 , Processed in 0.093750 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表