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

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
硬件和软件兼容i2c协议的24Cxx系列EEPROM存储器7 S2 x6 d: W$ w( a
# n0 {0 h9 p2 V. d( u" Q
8 ]; ]/ c4 n3 H" n7 o
* y5 H( A# e6 a: z" c8 B# J: O. G

/ C# b. v0 t  _& v硬件上由于24c01的A0A1A2管脚不允许悬空,故暂时的想法是兼容24c02 ---24c16
( z! i, s' |9 ]7 X" b' R% y) [0 G使用一个dip8封装的芯片插座,A0 A1 A2管脚都悬空即可,换芯片方便
# b! g7 Y: Q6 P1 ]. o4 m; H( X3 }软件上24c02地址只有8位,而其他型号是大于8位的,故地址参数使用16位
" @# U4 ]4 t+ t8 M) O' D/ K$ z3 W256个字节作为一个大页,即largePage,测试芯片24c04空间有512字节+ |4 h& q$ C' O* r& X

0 D: ^% Q. a) _8 v& M上代码,求测试和讨论

7 K. z  T5 d3 F" t, w. ?( `7 |/ u/ ?  [: T' \8 f
: y  F- F+ \3 t: S2 I6 l
#include "MY51.H"
7 H4 K4 o" k' ?- F8 R/ `//转载请注明:  求测试讨论& t8 O& |8 k3 a3 ~
//stc89c52rc,11.0592MHz晶振/ |; @2 w' D. U, H
sbit sda=P2^0;                //总线连接口定义
, z1 w( W9 q( C3 L6 Wsbit scl=P2^1;                //总线连接口定义
2 P7 Z( q8 `6 o, x5 v0 J9 r) ~$ ?
void delayus()                 //需要4个机器周期,大概4.34us; P2 r+ u3 n& r
{" Y4 l* d* x+ @; V& l, V
        ;                                //晶振频率11.0592M,机器周期为1.085微秒
# J5 X& p6 |5 A: B}

- w# l  O% H/ k7 Y6 H8 _( z& ovoid iic_start()          //启动信号7 ^" [3 S4 C0 J. J' f
{( Q% O8 K+ H4 n# \' O# D. m% k
        sda=1;
% B/ i! x$ `4 T: Z        scl=1;7 W  k: _9 R. S+ |% B7 \( D
        delayus();                //sda和scl同为高电平保持4.7us以上/ l* `: ~/ k$ h- G9 N' P
        _nop_();                //1.085us,共5.78us! }( Z& ~: o/ O+ b* n. d# T
        sda=0;                         //下降沿
  q. s: q- |+ ~' T9 S; l% b) y        delayus();                //sda低电平保持4us以上        ,这里是4.34us满足要求
% s( {, h; ^4 u+ X; \}

* Z4 d' w! E; B" \; V/ H+ K& h0 M6 \void iic_stop()                //停止信号
% J2 `8 N$ O" d0 m{4 t7 L+ B9 y, U/ }9 N2 o
        sda=0;_nop_();        //准备状态& s7 t3 o2 o; i& d& O3 E+ j
        scl=1;9 H( }% o+ m/ a
        delayus();                //该状态稳定时间要求保持4us以上
, H$ Z2 U- u2 M/ @3 F; A/ k: S' g        sda=1;                        //scl高电平期间,sda来一个上升沿  B) ]3 ?" X$ Q( h7 Q0 N8 w
        delayus();                //sda保持4.7us以上,4.34加上函数返回时间大于4.7us
  R2 K- v, m  T$ S6 W                                        //注:此时scl和sda都为1        
& Q7 k+ C' d: ^! a' X}

& V2 o5 k; N" I0 W. s. x# L) Ovoid iic_sendByte(u8 byteData) //mcu发送一个字节
+ m) n- q& m2 `; P& _{
1 o5 p- O) D/ a  k9 n+ K4 r        u8 i;
/ j' e% t* S8 Y# t' I' P        u8 temp=byteData;
# o% {3 `$ d% f& J3 F        for(i=0;i<8;i++)
# S; R6 k: r1 t; p! f        {
6 Y* t6 S9 e; q4 e7 U* p8 h                temp=temp<<1;    //移动后最高位到了PSW寄存器的CY位中% P: v) b' g4 @
                scl=0;                         //准备
) M1 b2 J: D% A) f                _nop_();                 //稳定一下
, n9 l2 M9 H3 [( i' S) R4 @                sda=CY;                         //将待发送的数据一位位的放到sda上
- \4 L7 I2 d- x& F( w/ g4 T                _nop_();
. V) [- r- [; Z( y0 n2 O1 Z9 [                scl=1;                     //每一个高电平期间,ic器件都会将数据取走
& O  i0 m4 @1 {, {0 T: y                _nop_();                ( h' p7 g8 R; a
        }

0 H0 d2 D! N) Y4 ~( p        scl=0;                                 //如果写成scl=1;sda=1就是停止信号,不能这么写
8 S# `* ^. {& j' w        _nop_();                                
* W' G3 x5 w# `. f! ^& J: e0 e4 @        sda=1;                                 //释放总线,数据总线不用时要释放5 _& r& x& b( U
        _nop_();5 L. t0 s2 M* p) k! G) ^
}

# J% x; k- }1 V/ Cu8 iic_readByte()                         //读一个字节
  G: [$ f8 c) }# {( S8 B{
9 N  F  r" T1 i$ R, O: t        u8 i,temp;2 o  @7 y3 C( n' P4 K) ~% q( ]7 S
        scl=0;                                        //准备读数据* n8 b: y( d( G# c3 E
        _nop_();2 e) u8 j0 Q$ n3 m+ k8 D0 u2 [% t+ U
        sda=1;                                        //释放总线
; P- ~6 ~( V1 ~# }        _nop_();
. B0 Z% G; t; e% x3 H9 b1 G! g* F
        for(i=0;i<8;i++)
- U7 _4 E/ v+ _* }) P2 x        {
+ z- H! W( r5 |8 ^( C& A! k3 G8 \, k                scl=1;                                //mcu开始取数据
$ d# H2 P1 k3 B$ J                delayus();                        //scl为高电平后,ic器件就会将1位数据送到sda上
( `4 ?5 O/ a! f+ I4 M+ e3 I0 Z                                                        //总共用时不会大于4.34us,然后就可以让mcu读sda了" r# {/ n+ h$ T- g) y7 ^4 B
                temp=(temp<<1)|sda; //读一位保存到temp中
; I3 k" j8 D6 V5 D+ G, I# }                scl=0;6 b4 M1 l$ a' R( a9 v+ I  j
                delayus();                ' g7 ?) [( Z' m( _) n( C. }
        }
3 [) T4 h9 f7 d! z$ w+ i8 r" c        return temp;2 ]: w$ q, p( K& Z
}
# _5 t( J, W: P% V1 H: Y3 w: X
bool iic_checkACK()                  //处理应答信号
5 ^' B4 t1 ~7 ^; q3 b+ m9 L6 M& o{
# _: |! }6 b; A        u8 errCounts=255;           //定义超时量为255次
, f0 d' d7 `4 y        scl=1;
. I0 ^) O, g: U        _nop_();. J/ l5 v& J/ |. h- c+ V- I; n
        
, H1 E0 e0 M4 E$ I- m        while(sda)                          //在一段时间内检测到sda=0的话认为是应答信号! m6 ]9 A- ?% D4 d  C
        {        : n4 @  X1 v# t+ y/ K
                if(0==errCounts)
/ {, Y# f# {7 e2 Q! I                {
4 r6 b# j7 W. m) T" Y                        scl=0;                  //钳住总线
6 Z: l+ ~9 C7 N                        _nop_();- Y) ]" v* m2 W7 _
                        return FALSE; //没有应答信号
# T# e7 v9 Y# }  B( `3 r                }0 _( M# J" p1 a7 O/ P& Q9 N+ V) J- p
                errCounts--;
  f5 Y; d6 _6 G* n4 S        }

+ i% A" N( q0 z* M5 k7 v        scl=0;                             //钳住总线,为下1次通信做准备 + G) c+ {. |1 y& H. g/ H" O; j" R
        _nop_();* r, A+ n% U7 }. P0 w$ _" R
        return TRUE;             //成功处理应答信号/ r# P9 q( i) D
}

, K7 x+ A9 C; qvoid iic_init()                     //总线初始化
; ~$ N4 O1 r9 t{
4 c( A9 Y7 r7 Y4 I; }        scl=1;5 ~, n7 ^( y3 k
        sda=1;
8 Z" ~# y6 M( _& G7 Q5 {        delayus();
$ C4 o! b' x0 J- r}

5 O, G( k" Q2 N1 K  Svoid iic_sendACK(bool b_ACK)  //发送应答或非应答信号, Q  Z9 V( x9 P( O5 v
{/ z# `% |8 ]: c8 F& s# i9 i& b
        scl=0;                        //准备* g8 _6 u2 P1 _7 o* s+ o
        _nop_();

$ m  p" Y6 G: Z; H! u) I) Y        if(b_ACK)                //ACK        发送应该信号
- G* \- m+ B% A        {
+ S$ c' S6 C" G  t7 a! z                sda=0;; H; L# ?  W* |( g
        }
' s8 T, T7 U* P) t        else                        //unACK        发送非应答信号
+ X1 X0 H0 B# S" ~        {$ `% n, C: A3 q3 c2 C
                sda=1;8 s$ X$ z$ u/ k9 K
        }
$ C+ t# q+ U) k2 \
        _nop_();3 S: G2 C/ M: l; U! y
        scl=1;
. ]2 s- R  z* B8 c* ~        delayus();                 //大于4us的延时
3 U4 \: ?( d- \) |0 h4 e0 Z        scl=0;                    //钳住scl,以便继续接收数据        
; G2 F$ P% m1 I0 K        _nop_();; n# z3 B. D7 X: r- {
}

3 s( s/ n4 }+ K9 b9 b9 ovoid AT24Cxx_writeByte(u16 address,u8 dataByte)//向24cxx写一字节数据+ o- H4 O4 f# Z+ u
{+ k; Q  ]  H( k7 b8 e$ z& L: [
        u8 largePage     = address/256;          //24c04是512字节(寻址范围0~511),largePage最大值是1
* G& e* c1 Z% n  T/ l1 w, `        u8 addressOffset = address%256;   //largePage=0的话地址范围是(0~255)
0 z4 u: [" G. W        iic_start();
9 r) d  \( U) n: L0 t. G5 T        iic_sendByte(0xa0|(largePage<<1));//控制字,前4位固定1010,后三位是器件地址,末位0是写
6 p- W# u& e" L        iic_checkACK();                                      //mcu处理应答信号5 f: F- V0 u& j
        iic_sendByte(addressOffset);            //指定要写入的器件内地址在        largePage块中的偏移. m  C7 h; ?# @! a0 D6 L: o5 `
        iic_checkACK();5 w* n9 Z. k% n
        iic_sendByte(dataByte);                   //写数据! m9 g( t( a* U$ z; K- u
        iic_checkACK();
5 u/ f# n: Y: W' F) E        iic_stop();+ V" v) I0 m" `: w/ K5 Y; k
        delayms(2);        9 e2 u( m. R% h" f
        //按字节写入时,24cxx在接收到停止信号后将数据擦写到内部,这需要时间
8 ^5 G0 k5 J4 H6 s# A        //并且在这段时间内不会响应总线上的任何请求,故让mcu有2毫秒以上的等待        ) p4 s( `% a5 g9 I4 a) J0 O
}
9 U1 @) I( T- F" c* ?; j3 S
void AT24Cxx_writeData(u16 address,u8 numBytes,u8* buf)//写入任意长度数据(最大256字节)
3 @. ^5 l/ B) X' q/ L  A{6 i6 T  B% y9 i, T
        while(numBytes--)
( Q9 f$ o2 m" \        {
  }& X" N( ^; Z$ A) O' b# o" `. K6 W                AT24Cxx_writeByte(address++,*buf++);; F; d4 X1 P/ z5 W+ L
        }
3 q$ {8 Y. u# _' a2 c! a6 e; B}

; ?0 C  [1 B, E) r# A8 V, Ivoid AT24Cxx_readData(u16 beginAddr,u8 dataSize,u8* buf)//读取任意长度字节到缓冲区buf中6 k& z& {1 G; \6 M  D" V$ I
{
& \& D: Q5 V# e& I        u8 largePage     = beginAddr/256;        //计算largePage,256字节为一大页5 e8 B$ ]0 T4 ]- X7 q& [; r* I; u* m
        u8 addressOffset = beginAddr%256;        //计算相对于largePage的偏移
  s+ u; ~  j1 f& R+ t1 W3 n        iic_start();                                                  //起始信号
, }; \. z( P) \6 k; m; W        iic_sendByte(0xa0|(largePage<<1));        //控制字,写
$ F& d  y/ o" `7 l8 R        iic_checkACK();                                                //处理应答信号. e; L3 Z) P  _$ \* e
        iic_sendByte(addressOffset);                //要读取的目标地址偏移
( L+ O4 w6 ]9 H% x4 G" W        iic_checkACK();                                                //处理应答信号          Z8 ~1 C9 t2 A& ^; T
        iic_start();                                                   //发送起始信号
, R3 ?6 O% D1 ~/ S        iic_sendByte(0xa1|(largePage<<1));        //控制字,读
3 d% Q6 d4 Q9 j6 d1 h        iic_checkACK();                                                //处理应答信号
7 u" Z$ ?4 Q/ N! O& `: g        while(dataSize--)                                        //读取dataSize个字节,最大256个字节% o" q. G7 Y  r4 }9 Y8 D9 b
        {                                                                        //dataSize用u16类型会暴掉ram的
3 s% Z, }4 G, ?+ O) i9 q                *buf++=iic_readByte();                        //读取一个个字节并保存到缓冲区buf中+ ~* v* `0 I" m& U0 I
                iic_sendACK(dataSize);                  //发送应答,当dataSize为0时mcu发送非应答, U' |5 ~/ [( M8 M- L8 b+ S5 g0 j
        }
3 Z: y6 H; x5 b3 p: y1 v        iic_stop();                                                        //发送停止信号
  p/ [8 m" ]- ?}
, z, x8 i+ Z, \3 |- T  @
$ t% a2 I# V" W* D( o# e9 l

0 P$ S: j( d. b6 Zvoid main()//测试, I$ V  u) O$ c$ ~' o( S; f8 L
{2 b8 O' C$ O2 J$ l$ d9 z, }
        u8 buf[3];                                                                                //接受数据的缓冲区
1 D$ S6 v0 j& j6 z, I        u8 arr[7]={0x06,1,2,3,4,0x55,0x33};                                //待写入的数据
( x/ I' p1 T6 s4 X5 O/ g                                                
* |( z4 h( ^( ?0 R        iic_init();                                                                                //总线初始化4 K$ P4 A0 h# j2 D, ~% P2 E" E$ z
        AT24Cxx_writeData(0x00+256,sizeof(arr),arr);        //向指定地址处开始写入7字节的数据

' o( Y2 O4 O. w7 C- G& @' c        P1=0xff;                                                                                 //调试代码,用P1口的led显示
  m7 r  a# D0 a$ D$ J1 g/ ^% v$ e        delayms(1000);                                                                         //调试代码
  B3 |9 Q8 M+ a- v" F1 r0 z5 k
        AT24Cxx_readData(0x00+256,sizeof(buf),buf);           //从指定地址开始读3个字节
! o0 v3 }; j6 g9 \" s        P1=buf[2];        //也就是2                                                                        //led灯显示数值8 l/ F4 O4 [3 Q- o
                                                                                        + l! `7 V) A6 \3 a( W2 S& X! |
        while(1)
! k5 Z* F5 B; _2 Y8 G. U" |        {1 v3 H4 P0 H+ j( c5 Y7 \! N& q" R
                P1=~P1;
4 X5 I. b* ?# R/ T( U                delayms(500);               
9 r1 P, M- H) @- o: g' \        }
4 V4 G; s' U0 Z9 [) j: b, S}7 O" X! W# a9 q8 c" K" o! Q( ?2 ]
6 U4 {8 b( r- {0 _/ B% X; s
' }0 i4 d* i  N" |4 J2 U; X0 W' q

7 I6 }; V5 z: E9 p' ?+ Y# m7 W2 r3 `: a+ z. U! f. W0 o

. g2 }  A: S; r$ L; f8 O$ A3 H
" Y8 d, \1 b" `. b
# o5 T: t" G3 \" O3 d
//my51.h中主要用到
4 W5 q7 V/ F  W  ~1 t+ _3 h$ u. G5 e#include<reg52.h>

0 e3 O: x; D; N7 V5 g1 g' o#include"mytype.h". @( v. l8 z5 g2 c, ?% N0 I
void delayms(u16 ms)     //软延时函数
3 P: |& b! p+ M( a9 A2 X  V{
+ |* J% e, `' r6 l& A        u16 i,j;: I( m; C0 A% S6 J& |: A
        for(i=ms;i>0;i--)
/ k$ `7 D; a3 {        {
; u3 O! l, t/ u# }) w        for(j=113;j>0;j--)
4 M  L: _6 x8 b& @# s3 p) z& k        {}) ?$ V7 Q) _5 O/ Z% d
        }1 S. w8 `; D( L7 _9 B! G
}

9 E5 P$ a# T/ c# j& D5 R2 j% D% |' B: o5 W

2 j" T% L% Z& e6 R  d" J: j4 z+ n. s" J& ~5 h
1 j% l4 U& l( O7 c

7 C5 G! J1 \# `! }' n9 X1 Q
6 o, U1 n) n8 i3 S) U% T" q对代码进行了改进
7 Z8 E4 P# z9 J; N. d4 i6 q去掉了在写数据时的
, z  ]$ ~- H! D+ n1 f" wdelayms(2);
- B/ `, [- j  Z& T6 R$ H这句软延时代码低效 ,而且没有保障
' c3 m3 x2 ~, k( m- p/ A
改成加一个检测函数 , k/ V: j% }8 |' y6 E1 @
bool check_icWriteComplete()   //检测eeprom是否对内部擦写完成 1 @) d( B3 P8 b7 @
{
( D1 a1 ~  A% q9 Z. K6 j$ o0 z iic_start(); # n; U- |% q6 R$ S
iic_sendByte(0xa0); & j$ y/ @& \0 H+ e
return iic_checkACK(); , Z4 ^1 B. H  L  s6 p) c$ P
}
5 o2 C. G- B9 @
0 b  j% r, H( Y$ A5 F' E

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-8-3 13:38 , Processed in 0.109375 second(s), 23 queries , Gzip On.

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

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

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