找回密码
 注册
关于网站域名变更的通知
查看: 650|回复: 1

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

[复制链接]

该用户从未签到

发表于 2019-1-15 13:44 | 显示全部楼层 |阅读模式

EDA365欢迎您登录!

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

x
硬件和软件兼容i2c协议的24Cxx系列EEPROM存储器
1 E% Q1 I/ o: t  N6 C& M$ X# [
2 I7 R6 @, C  t) [0 k# Y; K
4 y. S1 [* x+ G' h4 ]* [/ y. N- h# }2 W5 W8 F3 P) v2 C

% D+ Q/ i- Z( D/ @2 K3 z硬件上由于24c01的A0A1A2管脚不允许悬空,故暂时的想法是兼容24c02 ---24c16& S5 ~$ ]6 P8 g( A; W" d$ ]
使用一个dip8封装的芯片插座,A0 A1 A2管脚都悬空即可,换芯片方便& l3 Y; k6 \* `, o0 @. W9 H
软件上24c02地址只有8位,而其他型号是大于8位的,故地址参数使用16位3 l9 w( \. O  C+ r( H9 T
256个字节作为一个大页,即largePage,测试芯片24c04空间有512字节- b8 P0 e! @& a! V/ f

- ?8 Y$ y3 b6 W6 b1 F  J+ R% q上代码,求测试和讨论
5 u5 E# K8 W3 [3 N

* w; {; T+ F" I; r- h0 ]7 @6 m+ j+ S$ ^5 V6 `7 ~: m6 i& S% {. r
#include "MY51.H"
' i: k; l! {2 Q: }; \//转载请注明:  求测试讨论
" s$ k  @  d1 u//stc89c52rc,11.0592MHz晶振8 ~! t2 m  P  P) W) T; @& U8 C
sbit sda=P2^0;                //总线连接口定义
; g$ a$ O' e: d. n0 A, i  lsbit scl=P2^1;                //总线连接口定义

+ y  c0 [* ^4 j9 k# M: Nvoid delayus()                 //需要4个机器周期,大概4.34us6 ]# C9 p5 }  ~. }; d3 f. n
{  S# Y. G# C3 u$ ^1 t( W
        ;                                //晶振频率11.0592M,机器周期为1.085微秒& t) u; u' H- {9 D/ v" k
}
' s. P0 b* ?7 }; l8 \
void iic_start()          //启动信号
( w, c& J7 u9 @$ v{
% A( s5 r6 c4 f  n; f' U* C$ o! u        sda=1;- p) t) ^9 Y( l$ B6 J4 Q" e
        scl=1;  d0 A* O, d$ L/ e+ P5 D! F+ `
        delayus();                //sda和scl同为高电平保持4.7us以上
5 L- }! n7 G3 z6 p        _nop_();                //1.085us,共5.78us
% U! q/ \1 X1 @6 u        sda=0;                         //下降沿
( i8 A. X  G3 T' t* \, R        delayus();                //sda低电平保持4us以上        ,这里是4.34us满足要求
% S) x( i: P/ `9 s}
6 G, E: B+ W" n5 h& r0 _5 D
void iic_stop()                //停止信号; ]7 M  `3 y* E$ j6 w
{" N% Y: H2 x& k! {4 ~
        sda=0;_nop_();        //准备状态
" g( Z6 S" i( J; P/ E( M        scl=1;
# B6 o5 P) ?: U  n        delayus();                //该状态稳定时间要求保持4us以上
4 K* `' o' s$ g- R        sda=1;                        //scl高电平期间,sda来一个上升沿
4 |* G" r. S% }* R0 I& w        delayus();                //sda保持4.7us以上,4.34加上函数返回时间大于4.7us
0 e) u) f' R" F: W* B% z+ B: @1 B/ L7 T                                        //注:此时scl和sda都为1        + j/ i+ `6 S9 R5 e0 L
}
5 {; e' k: _  a/ m( H
void iic_sendByte(u8 byteData) //mcu发送一个字节
0 B2 ]) @  c0 F, p{
9 G0 @& k! y. h) u. }  |% P        u8 i;
4 L" ?7 F: K2 Y2 j0 I! r        u8 temp=byteData;+ t6 O3 E3 X  ]& D- r% W( u) r
        for(i=0;i<8;i++)5 N) S) h( U/ h- N
        {9 N" s" o5 E' |- Y2 D$ |7 k! T
                temp=temp<<1;    //移动后最高位到了PSW寄存器的CY位中$ w! w1 g5 a1 }4 V! o  v. u5 d  L
                scl=0;                         //准备
9 v2 P" I) A7 N1 Y+ N0 ?1 c- }                _nop_();                 //稳定一下3 w# t) V" q: M& C- u& F
                sda=CY;                         //将待发送的数据一位位的放到sda上
6 O) a* e6 L. z0 ]' a% Y: {$ L                _nop_();0 l5 d5 |$ n9 |% o& b: |2 z
                scl=1;                     //每一个高电平期间,ic器件都会将数据取走. T' K( W) Z" P1 [1 r( d
                _nop_();                & N! P* a& P* T$ y' L
        }

6 W- H: D% X& Y" d        scl=0;                                 //如果写成scl=1;sda=1就是停止信号,不能这么写& ~; a  b/ }* t( B. n
        _nop_();                                
9 k9 |* J, p; W. f4 H# k        sda=1;                                 //释放总线,数据总线不用时要释放7 |# v) `) P1 E
        _nop_();
8 ^/ x# q3 \8 H9 q" O}

7 }2 L; l/ G- L1 lu8 iic_readByte()                         //读一个字节
: ]( ^' v( `0 O' O* c, \9 {: }1 }) c{9 k, V6 A! _! b$ t! O. V
        u8 i,temp;8 q9 X' u$ ?+ n3 f0 D4 q$ c
        scl=0;                                        //准备读数据
! h  B# p" Z- u$ b        _nop_();! q% v! p  m+ H2 p
        sda=1;                                        //释放总线
- ^) q7 H+ w+ q% q        _nop_();
" |2 v0 n4 m& s9 e2 P6 j, G
        for(i=0;i<8;i++)3 I0 K2 E5 x' j3 K  I) z- l6 L
        {
+ C7 f0 c8 x, b6 d/ E1 g                scl=1;                                //mcu开始取数据1 L, W! R, i) F( ]0 A
                delayus();                        //scl为高电平后,ic器件就会将1位数据送到sda上2 z1 _$ W1 V, ]0 e8 o
                                                        //总共用时不会大于4.34us,然后就可以让mcu读sda了
. F/ i+ q, e2 R4 o- Z/ f                temp=(temp<<1)|sda; //读一位保存到temp中! O' x" X# @6 C( A% g
                scl=0;
8 n! ~0 b5 Q% @1 ]- @" h( v" u) ?, \                delayus();               
! s8 j1 C8 Z+ \        }
& D0 U  E( y* [8 [2 U; ^1 J4 ^) C7 Z! M        return temp;0 H( f+ I& d: C" ?, w$ a/ y
}
, Z. j6 _" q- W3 D4 E9 D5 s
bool iic_checkACK()                  //处理应答信号0 H# D8 e' ?0 r( q( p5 \* j
{. }" K# T1 {2 M+ E
        u8 errCounts=255;           //定义超时量为255次
# {4 k+ H, a6 K/ P! U+ Q7 l        scl=1;
3 f  w: L7 E' \: v, t        _nop_();4 J& j& u# w5 O; z# R" m$ L
        
6 g. x8 z3 l- D& ~4 h0 E. V        while(sda)                          //在一段时间内检测到sda=0的话认为是应答信号; i$ _4 c# \4 o- n: U$ a  Z6 l
        {        & T# w6 D+ V* z: j9 B
                if(0==errCounts)
' S6 ?0 @9 z* J! E) i% P                {! _; L; {9 H: b) r
                        scl=0;                  //钳住总线% j4 r  C% a+ M' H& ]# c  r' e
                        _nop_();) }0 U& S* u" [( [
                        return FALSE; //没有应答信号, X% G. T( l) R( F) K! ?
                }7 y& D1 P9 R! O
                errCounts--;
- r0 j3 X* b5 f! S( s2 W        }
% s4 p2 A0 ?; V4 {$ L
        scl=0;                             //钳住总线,为下1次通信做准备 . o/ L+ Z0 O8 @5 v% v7 P; B( r
        _nop_();) ~- m3 z7 E4 N7 D
        return TRUE;             //成功处理应答信号
4 B! I. a# u0 h% u; f" s}

6 a6 W+ V% ?+ a. q: b! E% t: D6 lvoid iic_init()                     //总线初始化, M/ D6 ^# ?) D' `" g* F+ T5 O
{) i5 L/ X" G8 Y+ W9 |4 I  ?
        scl=1;' s" O. _# h. B/ [% X/ t( f
        sda=1;
# i" U) g6 J# I        delayus();6 A" m3 h& @+ Q' v4 k4 b
}
# e' F9 W4 Y! P
void iic_sendACK(bool b_ACK)  //发送应答或非应答信号
. A; W7 y, y1 x{/ c) b0 m" x- G5 s( U# C, P! T
        scl=0;                        //准备& g1 \7 g2 Q4 l( B& c5 h6 b, v4 n3 z
        _nop_();
5 `2 D4 d$ s2 o( Z4 n# }
        if(b_ACK)                //ACK        发送应该信号
0 n2 C6 v! f- O1 H        {# J2 c# A3 e) [, |
                sda=0;" N' E3 g- H2 o
        }
. L0 Q  P8 [: v2 e        else                        //unACK        发送非应答信号
, k0 n' E9 s! f) x        {: L+ r# t. @" R( h0 U, Q
                sda=1;
  A  n+ f- o! {; m        }

: }$ `5 }5 ]# ?" y" {3 W# E        _nop_();
' l+ o1 e4 {8 f5 W        scl=1;
8 z  d' b# c0 s        delayus();                 //大于4us的延时! g' ]3 S0 ?0 [! b& W
        scl=0;                    //钳住scl,以便继续接收数据        
  @# g, t3 X" X/ m' c) D        _nop_();7 ^6 P# j% ^, P' l! w2 M% z
}

8 V, b+ d! G0 n9 n! b% ovoid AT24Cxx_writeByte(u16 address,u8 dataByte)//向24cxx写一字节数据. R0 |) B! L# d& J5 P" f0 O7 q
{. J" v2 E" G7 S7 T
        u8 largePage     = address/256;          //24c04是512字节(寻址范围0~511),largePage最大值是1, [0 a* a4 Q4 U; q  ]/ ~: }
        u8 addressOffset = address%256;   //largePage=0的话地址范围是(0~255)
7 L: F  Y, ?6 _: K4 l        iic_start();  w- h" e5 ~4 }2 U2 O4 w
        iic_sendByte(0xa0|(largePage<<1));//控制字,前4位固定1010,后三位是器件地址,末位0是写" P$ k1 h, A; E3 v! v
        iic_checkACK();                                      //mcu处理应答信号! t- l6 v; W/ g
        iic_sendByte(addressOffset);            //指定要写入的器件内地址在        largePage块中的偏移
3 E! q$ x' i6 O$ o        iic_checkACK();
# m; K2 |  J$ ~# _* B  q* G. E        iic_sendByte(dataByte);                   //写数据
/ l* M/ i8 S! H6 T6 {3 B9 B& i        iic_checkACK();
; F% d3 K3 E& W; L        iic_stop();/ ]! X  K  s% Y% j7 q& v1 V! w
        delayms(2);          T, X% J( b" K& O
        //按字节写入时,24cxx在接收到停止信号后将数据擦写到内部,这需要时间
6 S" {! n* ]/ s: u3 F% G9 C- q& q        //并且在这段时间内不会响应总线上的任何请求,故让mcu有2毫秒以上的等待        : b& Q& M5 P1 f" q$ q
}
) p" u  p7 J: Q6 d) s% m! D
void AT24Cxx_writeData(u16 address,u8 numBytes,u8* buf)//写入任意长度数据(最大256字节)  n; h  B# P" a7 B% U: O6 P& R
{
+ \& K0 }$ j2 c        while(numBytes--)
( b4 I+ M' _( W! l$ h        {
# r: b! S3 H' S% L' s  T                AT24Cxx_writeByte(address++,*buf++);4 A, R/ t+ O  d; |/ X
        }
1 K0 w2 s1 O! K4 q( n; m1 d# o}
  v# b% `" X* a/ {: n& I. ]
void AT24Cxx_readData(u16 beginAddr,u8 dataSize,u8* buf)//读取任意长度字节到缓冲区buf中
' K% m$ O3 D' O1 J{+ W* n4 A5 I* E) `$ B% l- M- l
        u8 largePage     = beginAddr/256;        //计算largePage,256字节为一大页; S2 S! f4 f& D8 P& D# h
        u8 addressOffset = beginAddr%256;        //计算相对于largePage的偏移
+ g: a" H% g; K% A$ U# i3 t' t        iic_start();                                                  //起始信号
( B6 c" F7 P9 y; ^3 O+ u* \        iic_sendByte(0xa0|(largePage<<1));        //控制字,写8 D; m% v+ f. [) I( R1 `$ i$ e8 D
        iic_checkACK();                                                //处理应答信号
) n" F+ P+ i3 ~        iic_sendByte(addressOffset);                //要读取的目标地址偏移) y9 D: Q1 t% ?& ~0 b3 O9 J
        iic_checkACK();                                                //处理应答信号          K: X! ^# F4 S  b" ]
        iic_start();                                                   //发送起始信号4 a2 c$ l5 T- t; q$ Q( \2 G
        iic_sendByte(0xa1|(largePage<<1));        //控制字,读
2 N3 [+ Q2 a* T+ U6 d( W0 ?% b        iic_checkACK();                                                //处理应答信号
4 p3 Q4 `2 `0 b( y$ `" l        while(dataSize--)                                        //读取dataSize个字节,最大256个字节1 a1 j% Y6 K  l
        {                                                                        //dataSize用u16类型会暴掉ram的
) e0 s7 b3 X% H5 w                *buf++=iic_readByte();                        //读取一个个字节并保存到缓冲区buf中/ {4 i1 v+ r' B: N8 E. ~( q1 g8 \
                iic_sendACK(dataSize);                  //发送应答,当dataSize为0时mcu发送非应答/ f2 R0 e  P' T4 f
        }
) i, T; Q( {) |8 D  h        iic_stop();                                                        //发送停止信号
" X. L. Z7 t0 b5 G0 I& y8 e' |}

0 |9 `& s4 Q6 E8 b5 J' O
4 W/ P/ l6 t( \2 A% O- s
# ~0 \0 K( ^9 e2 V7 ~! x. y
void main()//测试
* H# C! S$ @  r% P  w7 G{
+ I  V1 {* \& ]8 _8 B        u8 buf[3];                                                                                //接受数据的缓冲区0 y+ f) K1 j9 {: t5 E% K) {9 U
        u8 arr[7]={0x06,1,2,3,4,0x55,0x33};                                //待写入的数据! ~. [2 m$ Z, _  ]& w9 y( @7 f
                                                : p( i% v7 x* W3 x& `$ D" o
        iic_init();                                                                                //总线初始化& ?4 A+ A3 j# Y4 E. T& h2 k* E
        AT24Cxx_writeData(0x00+256,sizeof(arr),arr);        //向指定地址处开始写入7字节的数据
) H; Y' b% p" x' P) _
        P1=0xff;                                                                                 //调试代码,用P1口的led显示" H1 ]1 T' g. e' b' k2 a
        delayms(1000);                                                                         //调试代码
( ]$ U0 u% b, b% i# V4 s; p  M- ]
        AT24Cxx_readData(0x00+256,sizeof(buf),buf);           //从指定地址开始读3个字节
0 t" w; ]; M5 m4 D* p2 O* r9 Z        P1=buf[2];        //也就是2                                                                        //led灯显示数值
; Q, g: {4 G6 I$ L& t- e' m# U                                                                                       
) i6 V/ ^9 C4 a" V        while(1)5 S8 K2 _  `& W' g1 u6 U/ t! s9 G
        {
$ _- ?% q+ P/ H                P1=~P1;: \5 P: v' q% Q% P. i) I. `: W
                delayms(500);                ) D- ^) }8 a0 K7 C  N: ]
        }
8 e7 u+ ?* }. J1 f}% [3 i# _" |7 |$ p# N1 y
; H; }% L' a* W

" l5 i2 q7 R0 t9 ]! j: H) K" V- ?3 C. `! [, e! r# J
9 y- s6 P; l% K( |
" e9 e5 }* p7 b/ U9 Y4 c$ W  w
* f. j2 n6 r  \$ a

8 k" M7 |2 d7 O1 d
. g: @3 j3 S6 z2 H3 G' X; Z" k//my51.h中主要用到; i2 {7 o6 T  Z/ I' A: V1 K' Q  }
#include<reg52.h>

) r9 p* f/ N! T+ c  b% u#include"mytype.h"% _) A3 t4 n: }: A
void delayms(u16 ms)     //软延时函数
5 w; _" Y$ B9 ]* v+ G( ^+ q3 I( v{
4 z# p+ p7 @0 z8 l0 r% y        u16 i,j;6 h4 K9 Y+ f% J6 @: j
        for(i=ms;i>0;i--)
1 H  P5 @$ e  G% ?% M/ I& V/ N        {0 R+ N0 ~' y( P
        for(j=113;j>0;j--): a0 I! d( l2 O8 r" g: x
        {}1 `, D; T' w: {" D( _4 C2 i! c
        }
% G+ U2 G; y- _) g}
! Y/ {, E* r1 ~  {$ u/ c. o
$ P+ ~  q& k1 G7 V! Z
- X% T7 ?; K2 j# _2 `: S
! Q  L; W! O" U% D" Z

& Y( F. M3 [, {
3 m! u* T# ]6 y' h# B$ Y7 N5 Y2 N) E! W9 O  P0 Z) T6 _1 x. M
对代码进行了改进 / Q! r, x3 `4 x
去掉了在写数据时的 : |5 m0 o2 H0 o6 }' F' N" l: t
delayms(2);
0 A0 Z# {" ^+ H% _9 U& L' ~这句软延时代码低效 ,而且没有保障

+ ~; B2 H5 z: ~改成加一个检测函数
1 V4 j0 {2 P% G% W" V2 tbool check_icWriteComplete()   //检测eeprom是否对内部擦写完成 6 G8 p4 W' y1 E5 C5 O' S2 N1 K* ~
{
5 @% p: W7 u: Y0 U iic_start(); * I- v% d1 i# C% [! j
iic_sendByte(0xa0);
4 t$ N: g: i, f% d2 e8 y  k' l/ ?  Q return iic_checkACK(); 3 H/ L9 J0 p+ k1 u
}

) c# N, d  c. V7 l
0 y$ s- r( L" ]4 |" c4 ]

该用户从未签到

发表于 2019-1-15 23:29 | 显示全部楼层
这个不错,谢谢楼主分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-10-9 06:09 , Processed in 0.140625 second(s), 22 queries , Gzip On.

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

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

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