一、IIC的定义
_* q# V4 ?( E; L1 t8 o/ i I2C(IIC,Inter-Integrated Circuit),两线式串行总线,由PHILIPS开发用于连接微控制器及其外围设备。IIC是一种多向控制总线,就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实施数据传输的控制源。这种方式简化信号传输总线。
& r5 { f, e/ W# M9 U
: p; `8 X S$ H 它由数据线SDA和时钟SCL构成的串行总线,接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上,可发送接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps以上。6 z+ Q' j# u& ]' X
; m2 r0 i1 G: z' ]3 f( r
IIC是半双工通信方式。
- \7 I( F) Z! |6 [, M
) p% o$ c- k7 N' T) [3 t5 y二、多主机I2C总线系统结构
! |) d8 l6 Z: J: i
P5 W) F1 q$ t7 I
+ r$ c2 ~% y H
2 C2 ~ @6 I) D/ |$ }' w
2)多设备的使用举例
0 d1 m* z; }8 i% S4 I
2 U$ d8 Q7 _" l每个接到I2C总线的设备都有一个唯一的地址5 J; k5 u% w) E. p0 q. H
3 y3 w( ?5 V' n9 O) |9 s9 F
! V7 ~9 L' _% ?' _' y5 h. p6 v; p
% o4 ?0 Y0 ~, P三、I2C协议
. D: M4 x) n7 o& S( r2 j. [空闲状态
) f. R$ Q" d% X$ ~; v3 L2 q# t开始信号
% w$ N. y% S. t l5 j停止信号
: [1 q$ Z; G8 \* |应答信号
6 \* G- W4 ~* f4 `+ s( z数据的有效性
4 r& M0 `+ K0 B数据传输
9 n. H- i& N" L# S我们以斗地主为例:2 u6 `+ k- f- `- H& L
y+ G0 C( J% N/ U2 Z$ |
& W M7 E, v, h+ C1 h; q' y8 c( [* Q
1)空闲状态" j; c( \/ ^& |* @" F3 R) _& B
I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
4 g8 Z1 A* E1 I; v% D0 ~% j9 Q0 L% a4 E7 |6 O+ }
2)起始信号与停止信号3 l8 b4 Z' ?, \! Z4 O; q
起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。
* n& V" w! Z: Q& C停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。
- M$ Q8 e- d" S; S/ D6 z7 Z
! _' O% [% A' V/ L& k2 K# r
; f* C. H; U5 J( k- B) p' `
7 L" j$ Y0 I# f! V5 Z' o0 `2 r& k% O
3)应答信号ACK
2 E( s) x3 p7 v+ X发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 & s$ p) D( a% A4 S) g2 v/ i
9 j* }$ b9 V1 O( s% Z+ I* b1 O- V对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。
4 I3 f! D* F* p. w# Y
) ~6 s3 r$ n I* }( Y& q, L
* |% V- y! S* X6 Q! @: B' d8 t# L' W$ {
4)数据有效性
6 R3 x- X+ d. D9 F$ B3 B {2 y$ pI2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
! P" j, G ]! _& J( a# T' M5 v+ [- ~
即:数据在SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。7 y5 ?) K; t/ x9 J
7 Z! \* G2 t7 C. B: S4 w
1 \3 `! i& s# `9 @" Q- i, N9 Q: L
0 D) @ A, B, n5 l( O/ u
5)数据的传送
- S x# X* H/ c' B* B8 _$ X在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。% y9 _4 `. L! @# v" y
, O8 q- [8 L$ b- E5 u% ^2 @7 QSTM32F4的IIC代码如下:
4 A/ {" R& W+ T) j* Q8 v; Q- IIC.c
1 `7 @( m* N- L5 @: z1 K8 C$ C( x) L. H - #include "myiic.h"
+ _) k* J0 ?3 ?- A) F3 ~6 g) f, L - #include "delay.h"7 ~& P& j, Q6 z4 |( [5 M
- * l3 J* a; p9 I
- //初始化IIC5 l& _5 j; V7 `: ]3 A2 r3 }' p
- void IIC_Init(void)
' Q" G* c& g% R - { A6 o3 `( l5 a: _2 G& f) r1 J+ I% A
- GPIO_InitTypeDef GPIO_InitStructure;- {1 _* H9 y' I0 E u; ~1 l
- 8 P9 U6 }$ t+ y; E- n" L" l- v
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟5 p$ y6 K* L# ~1 a1 Z+ S* I# n
- 8 {% R% ~8 M# x* n
- //GPIOB8,B9初始化设置
: i- M% o+ c4 F# t - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;4 e( I5 B# s6 S" W
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式/ ^+ C- R! q0 \0 q' v
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
9 ~) @" k, v! p$ ]$ S5 P - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
* M! w- v" G- n- Y, X - GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉 E t& n2 R4 m6 L' l, D# Z6 D
- GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化* d) h' p. V+ H( r, d3 o4 `
- IIC_SCL=1;
% Q9 A: B; e( L: i' @ - IIC_SDA=1;
& X$ W ?2 k% u. V8 d$ S% c) M x - }
3 Y. |5 a0 U5 B# Z% }! ]6 c+ ~ - ' | k8 f/ z! Z# o# \: U) a
- //产生IIC起始信号+ @7 _: o! }; ]( F- a
- void IIC_Start(void)
3 I" D& q1 X! q2 f! X0 a$ z% f - {
( g2 U! [, w/ t; q% U5 y - SDA_OUT(); //sda线输出
: X8 A' Q0 Y" M* M4 ]# r - IIC_SDA=1;
$ H7 m$ d& @) M- d: U - IIC_SCL=1;+ V% {; I3 m G, Y( h F4 d4 i& x
- delay_us(4);
8 A e) Q+ H3 M$ Y+ s7 W. u - IIC_SDA=0;//START:when CLK is high,DATA change form high to low & j% W- O' O! }3 w2 t { P
- delay_us(4);
- o; B9 M; z, v$ F - IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 ) s7 @4 E3 o3 ~& V# Z
- }
6 l% B6 q7 ~6 l -
7 }/ k% `) m& m; L5 k; [ - //产生IIC停止信号6 T7 P+ X! ?; P/ j7 T5 c. n
- void IIC_Stop(void)
! S5 ^, A' v- _2 W" @2 r& X - {& h. N; z2 N$ S# t
- SDA_OUT();//sda线输出
! ? z* h# K, k - IIC_SCL=0;
1 n0 O' i5 H* H; M - IIC_SDA=0;//STOP:when CLK is high DATA change form low to high7 D& ?5 @( N Z9 |: ~
- delay_us(4);
# c9 ]5 q2 W! u6 c u8 p - IIC_SCL=1;
( ?% \$ t: w6 P1 p* H( b - IIC_SDA=1;//发送I2C总线结束信号
7 F* l r/ q2 J, K0 [1 l# S7 ^% y( f) O - delay_us(4); 8 l4 Q2 e, N# d8 X3 [ X( C/ _
- }& N' C0 z) a3 s1 m
5 i5 U3 ^' L5 _- e& f7 _- //等待应答信号到来
r6 T f: J: a9 b3 N& W6 t# ] - //返回值:1,接收应答失败; W0 m2 ^2 V9 }+ k0 R
- // 0,接收应答成功
3 ]/ t2 k7 i6 \. _0 M/ H - u8 IIC_Wait_Ack(void) P7 {! t( ]7 w9 ~. K. w3 ^
- {% a% d4 n# e3 u* a$ L
- u8 ucErrTime=0;
4 m% d$ S$ q2 O9 j, V: A - SDA_IN(); //SDA设置为输入 , D( H! D/ R- u, x3 v
- IIC_SDA=1;delay_us(1); ; L' s+ N& X& t, {+ _( M
- IIC_SCL=1;delay_us(1);
1 O! Y& b; _) {0 i5 ?8 V - while(READ_SDA)! t d' z/ I" W
- {
# R! a3 R, k5 s s - ucErrTime++;# G( y+ B U: B2 Q
- if(ucErrTime>250)
( @. ^$ E$ l: g3 u4 q* e5 J4 l - {
3 `) M7 l/ A4 @; l/ @ - IIC_Stop();6 O) E5 e8 @# n: T4 q
- return 1;
" S+ C* u: T% a. W9 M6 U - }0 A. {( e: R: Q
- }
- a6 \! n6 B. Z1 G# t - IIC_SCL=0;//时钟输出0 # \; M- y# {! n3 [( Y2 l$ K! V$ y
- return 0; - Z! L; y7 K: ~( q+ R- }
- } 2 x8 X) L1 m+ f. [% b
) R8 \8 }6 D( {5 D2 o% i- //产生ACK应答
7 E# A3 u3 h) r+ ^# _: M J - void IIC_Ack(void)# C1 Q+ M% o/ r7 Y
- {2 G2 L' I J' x3 D0 D- @
- IIC_SCL=0;
: b' {& {$ f& D- X - SDA_OUT();
, p/ }: |) K% I0 \4 H2 ~ - IIC_SDA=0;: Z% e8 ]' P, Y ?6 E% j3 j, S( d
- delay_us(2);
5 h0 V# f M3 i9 h8 E1 g+ V- m - IIC_SCL=1;$ V' y# _- H3 h7 k1 L* _
- delay_us(2);
& |0 y n- L! M, o* q" g - IIC_SCL=0;
7 b q3 N- J% B4 p - }. X9 D, U6 A4 Y2 }* W( y
- 2 `7 w7 u) t6 K$ s2 E) p& f
- //不产生ACK应答
% F7 ^5 [+ i E+ q, Z6 Y9 e+ L - void IIC_NAck(void)+ C7 R; i+ M# ^3 M+ H6 D% A
- {: X! a( y2 Q# w4 _7 o
- IIC_SCL=0;
6 `: j& r4 a, Z! X( v2 \ _6 y - SDA_OUT();
8 u2 `# V; J: I' d4 h( b - IIC_SDA=1;; ?" l$ u+ t% j: y
- delay_us(2);
, m% ]/ W. J2 @ - IIC_SCL=1;% u$ m+ p. g: `. ^1 d' r0 g
- delay_us(2);
9 C3 E# G% W" b# v8 @- X# ` - IIC_SCL=0;
0 c0 p. n! a; R - }
4 x/ c% A2 y7 B5 t0 \ - 3 m; u# k( @( r3 v7 h
- //IIC发送一个字节
1 ~" j1 d" ]+ z2 q - //返回从机有无应答$ y6 J( ?3 k: p4 [- E* t$ d7 D n# f
- //1,有应答% B6 q, v, @& H# g/ h+ _* r+ l: ^6 } {
- //0,无应答
+ |0 i4 Y, d0 y$ V) ~ - void IIC_Send_Byte(u8 txd)4 z* c0 J5 [* I5 e. X" ^, w
- {
& L/ [( t$ b, w0 p! C2 u - u8 t;
/ T9 j. f* a1 G7 y# E+ G - SDA_OUT();
3 g9 q' o5 {9 a8 L3 c" Q - IIC_SCL=0;//拉低时钟开始数据传输
0 t1 ^4 R3 r% Q$ A - for(t=0;t<8;t++)8 _- _3 Q4 b' m; A" w, q6 q
- {
% p5 j1 z1 R# M* y - IIC_SDA=(txd&0x80)>>7;
) x9 j$ M8 _5 J8 V - txd<<=1; ' P3 z0 B# F2 d
- delay_us(2); //对TEA5767这三个延时都是必须的7 v& P" S1 B8 G6 T" x% K# n3 ?, b
- IIC_SCL=1;
7 h8 _4 X k* C - delay_us(2); ) |7 f# ]2 `5 v2 p" `
- IIC_SCL=0;
! ^# E) m4 w6 Z" o) J2 M5 V - delay_us(2);: A l- z% P: h9 H6 Z1 R9 S" |% f
- }
+ E3 f7 w1 z9 o3 Y* | - }
% c9 c7 B) J+ r3 A! P5 } -
1 l: B+ Q" C* v. k1 s+ x/ E+ ?# R - //读1个字节,ack=1时,发送ACK,ack=0,发送nACK
3 T3 v/ P) b; f' U4 @4 R - u8 IIC_Read_Byte(unsigned char ack)
% k; @0 j3 H# g# H' _. T5 f' h# L - {
' E" n, X: s4 v, j1 l4 H - unsigned char i,receive=0;
9 \3 V' s* E; k - SDA_IN();//SDA设置为输入
! {( P/ N) P+ a% e - for(i=0;i<8;i++ )# l6 N$ W2 }/ A5 D8 U; P! p
- {
+ M8 A: d9 ?) n" [( y" l8 r - IIC_SCL=0;
* R' E! z8 Y2 D; ^' ^9 H - delay_us(2);4 G' @' ~5 f1 K
- IIC_SCL=1;8 y3 L! H! k1 C8 D
- receive<<=1;
' V. e: O* z7 j. C# |7 v4 H - if(READ_SDA)receive++; + [) s: I! x. z
- delay_us(1); * D9 }. H4 X* x% g- k3 \
- }
+ _2 d+ K* Y1 ?8 u1 d - if (!ack)
1 n; e) L1 D/ ?7 \ - IIC_NAck();//发送nACK* _7 ?0 C" d# W% x e
- else3 P6 ?, w" G' K/ D4 @6 J& g
- IIC_Ack(); //发送ACK 5 W; Z! W" r8 p3 Q3 s( {
- return receive;
8 d" S6 M9 _5 \9 b - }
复制代码 / |1 w+ ~' w( r+ m7 d8 c
9 X) _, ^6 `& T* ~0 l! s8 R4 J! i8 s( F. U- IIC.h. A9 B5 }# g- P1 S' {, q; j
- . ]; k0 ]' x ^& m2 Q" T# \0 E
- #ifndef __MYIIC_H
( {! R, v# ^. q s9 t - #define __MYIIC_H
( v# |/ `/ [1 a5 j# Y2 E* q% X: y - #include "sys.h" ' W+ C& `: c7 q
3 M% G. j8 D$ j$ e- //IO方向设置
# Y, K$ U5 }# z* B! I4 T. d8 f9 r1 [6 k - #define SDA_IN() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;} //PB9输入模式7 X4 Z8 U- |3 K( r7 q' {
- #define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //PB9输出模式
% a7 z9 Y {6 z. \ - //IO操作函数
7 U: V. j" U5 g* j% m! X- q - #define IIC_SCL PBout(8) //SCL; k0 V0 Q, N3 I2 t/ Q7 k
- #define IIC_SDA PBout(9) //SDA " H3 u, U8 G0 t' x7 o' V2 D }
- #define READ_SDA PBin(9) //输入SDA , F# _( e8 e! D( y7 Q5 Y3 X
" Y C8 y, i3 l% A7 P4 F$ M! U- //IIC所有操作函数
% e+ K7 w! H* L8 Q - void IIC_Init(void); //初始化IIC的IO口 * N1 N ?0 v# Z% G5 p% w
- void IIC_Start(void); //发送IIC开始信号
' E8 k8 ~6 |" ~: f4 O - void IIC_Stop(void); //发送IIC停止信号
G: C* Y0 ^ G [6 `$ g2 C: S! T$ W - void IIC_Send_Byte(u8 txd); //IIC发送一个字节' p) {" C2 w+ ^6 W
- u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
+ |3 K' c/ A6 K. G% j - u8 IIC_Wait_Ack(void); //IIC等待ACK信号+ d8 ?. Y; l. B% j+ x
- void IIC_Ack(void); //IIC发送ACK信号
+ K7 g6 }: W7 O: f9 E( q - void IIC_NAck(void); //IIC不发送ACK信号
* @4 @( f9 v7 W5 A) r5 p& B - : s3 H) a- b1 e! {. m+ `
- void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
5 i4 M8 B" L4 m+ V - u8 IIC_Read_One_Byte(u8 daddr,u8 addr); * p. U9 k5 Z5 ^* v/ f2 S1 S
* T! L1 H. ^3 \0 D8 B0 W- #endif
复制代码
& K; e# F6 Y& d1 I9 R四、EEPROM(24C02)的使用+ u& C& R1 S2 i5 r
总容量是256(2K/8)个字节。接口:IIC
/ Y# i+ Y! N( J6 d& ^! X( s, Y
芯片图:( l/ E* r; w! U& h
8 W/ Q' ^/ M, c4 f
& G8 q; k" C T6 N |& Z这里的A0=A1=A2=0
& s( }( G. U- V. K3 N% n4 |; g1 Y0 @' c E
' [$ {. [+ ?% f1 y8 |
* p# E& f0 s0 d. e* k- l
8 k- Z: T! e9 j0 u# _5 ~) J& |7 V0 _
24C02读写字节时序; ?% i2 \6 c+ w3 b9 l
. _& I* ^/ Y. w5 o写:
' E! a) v( q) F0 I% S9 e* b2 l
" z8 k( C* N" E! i- j# m3 s
- O+ ~& l9 l6 E4 n; b
" y g4 S/ `7 {) z" \: M: B读:7 {# A" t' [; t R
: {1 C' U- x: C3 d
* |3 C* j% S4 ~1 [
) ~7 a) ?$ B2 K/ l8 H24C02的代码如下:6 I& f+ C% G& C9 w
- 24cxx.c:
$ F3 {6 `) _- l7 L" N) p& S - #include "24cxx.h"
T: N. I$ M# Y' ~# n9 p9 } - #include "delay.h"
# m! t/ k2 N( a u9 Y i
6 a# y% d* G* E- k7 V8 d' w- //初始化IIC接口
; s* H9 s: |8 C2 }; i9 P2 D4 H - void AT24CXX_Init(void)
8 F7 H) o4 x: ` - {
& L" [4 Z. \& G; ^8 j9 g% H t - IIC_Init();//IIC初始化
5 @( t N: `( C( V" j& n - } C) K m# C" p2 q3 l7 k
- //在AT24CXX指定地址读出一个数据
% M- t2 z k ?0 Q- N4 i. m - //ReadAddr:开始读数的地址 0 `% m% T- g: d" a- [9 h! V3 i
- //返回值 :读到的数据
! T$ ^& g1 A( T) `% q3 Q - u8 AT24CXX_ReadOneByte(u16 ReadAddr)
6 l, ~" j$ ]8 ]0 L; a O - {
5 L7 f# ~- v8 F. N1 S" t! U% e# \ - u8 temp=0;
: x$ k* `2 Y6 n& v4 Y - IIC_Start();
, V% A4 K v. p* v - if(EE_TYPE>AT24C16)
+ J1 P8 X" M2 G1 ?1 \9 x* w# i - {' d2 V! @# k6 |: }/ ?: ]% i9 R
- IIC_Send_Byte(0XA0); //发送写命令
5 E" C0 s; y& K9 _: b2 V% j; A7 I - IIC_Wait_Ack();
! |5 `" E) B6 F" K( K! _# I; h - IIC_Send_Byte(ReadAddr>>8);//发送高地址
! c; u' a* }+ B; j - }else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1)); //发送器件地址0XA0,写数据 * m( F% }# V! d% V
- IIC_Wait_Ack(); / d+ Z! s5 R0 @* t2 F
- IIC_Send_Byte(ReadAddr%256); //发送低地址
7 R2 X. c) ?" t5 \5 } - IIC_Wait_Ack();
& p2 t L$ C. I7 Z - IIC_Start();
& b3 x2 l" y4 U% Q+ q4 m - IIC_Send_Byte(0XA1); //进入接收模式 7 G+ n$ g7 e: z- o
- IIC_Wait_Ack(); 6 d2 b _% H E
- temp=IIC_Read_Byte(0);
, p9 c* L- _& R; c% b - IIC_Stop();//产生一个停止条件
. Z" i f- A6 ]2 x - return temp;% ~$ k! [* c y4 b* A- m
- }
0 x- J2 d+ \5 ^! ^+ v1 Z - //在AT24CXX指定地址写入一个数据# _, X; @& ~* Y; ^
- //WriteAddr :写入数据的目的地址
3 w h, T) D. C, X* O3 U4 R - //DataToWrite:要写入的数据
9 C/ E+ K0 o4 O; w z - void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
3 f5 V! m. \4 I - {
' t# c1 \* M8 t/ C# e* Z/ v) f - IIC_Start(); % |! l& ~! U, u, Q$ l
- if(EE_TYPE>AT24C16)
/ k$ l& O n% K - {
/ @! O0 O' e R+ p9 r! d0 O) @1 z - IIC_Send_Byte(0XA0); //发送写命令6 X6 F2 k7 {+ D& @# G
- IIC_Wait_Ack();( Z& u- z- M s# M7 E/ C
- IIC_Send_Byte(WriteAddr>>8);//发送高地址 : ` a# s. V5 Q/ y) p D/ C m
- }else IIC_Send_Byte(0XA0+((WriteAddr/256)<<1)); //发送器件地址0XA0,写数据
. _0 |4 W) O5 V4 j4 g ? - IIC_Wait_Ack();
$ ~3 j% ~( c( f# H0 ^% U( a$ S - IIC_Send_Byte(WriteAddr%256); //发送低地址
4 `4 b$ l: i7 i! ? - IIC_Wait_Ack(); 7 h& V+ W! g/ X3 W
- IIC_Send_Byte(DataToWrite); //发送字节
, p8 M1 `- u+ B. l( Z8 v7 w* Z - IIC_Wait_Ack();
; P5 {% u. O# K - IIC_Stop();//产生一个停止条件 2 z7 F, ]. q, y' v
- delay_ms(10);
8 b# @3 z$ g1 u/ J* j - }
" Y1 m1 E, f, u; N; z i. y - //在AT24CXX里面的指定地址开始写入长度为Len的数据
$ d* Z/ O1 x4 h6 ` - //该函数用于写入16bit或者32bit的数据.
. P. x; K( E# E/ v, s- z, T- e - //WriteAddr :开始写入的地址 1 m# A$ f/ V$ b% T5 s0 | L9 l
- //DataToWrite:数据数组首地址" P$ ?3 k5 o( m, N
- //Len :要写入数据的长度2,4
) G& d0 Q1 u8 p - void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)" k, ?/ u* G6 d5 @) Y, A
- {
( k, M* w( H7 w, ^$ i - u8 t;- J9 V" P" {' J3 r* M N1 C; K3 m
- for(t=0;t<Len;t++)
' O, G' }( b' o2 Q6 h2 j/ O7 w: y! m - {
" s2 ^: N! {* D7 K, K - AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
- G. w* Z! W5 J# ~6 s - } ! b' V$ M& r# B) Y
- }6 l* k: h; [/ {- K7 K8 k
, M) j; A1 e+ r& \" k& E* b: |0 U- //在AT24CXX里面的指定地址开始读出长度为Len的数据
0 k w3 E' _( O2 k2 b - //该函数用于读出16bit或者32bit的数据.
$ ]6 q' d& P' y, j* a - //ReadAddr :开始读出的地址
% \ {$ c6 h2 x - //返回值 :数据
/ D5 _0 W! Z9 v - //Len :要读出数据的长度2,4
- U, t" l- _; C" e7 j1 v - u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
8 N' t0 E8 e, n( j% H; E6 F - { 0 R6 u8 ]+ ]; ~3 Q( d
- u8 t;
* m+ c1 D! n; }: V. e - u32 temp=0;6 {- f' \- r/ K1 r
- for(t=0;t<Len;t++)
( I9 N! q4 P/ P3 L; `, B - {) |* Y# r$ ]* ^: f( X# y
- temp<<=8;
! x# }, D: o8 I8 ]8 y3 I/ v j2 a - temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1); ) o2 O1 O0 I' Y4 T/ ~
- }# }9 ]( ~4 N3 [6 E4 y
- return temp; 6 v n6 I$ h9 J- ~2 h( s* s
- }
' k8 K% }- G' M5 W - //检查AT24CXX是否正常
/ r m# B6 N! b, J2 Q" L j' _# { - //这里用了24XX的最后一个地址(255)来存储标志字.
6 p) `; J. G2 W - //如果用其他24C系列,这个地址要修改
7 S" h$ k9 F$ A! r - //返回1:检测失败
8 T& f0 ]. U0 @ - //返回0:检测成功! L* D7 z% X( S! `0 {
- u8 AT24CXX_Check(void)
- ~6 @9 ^3 l1 i: T: [ Q5 A - {
1 Z6 {8 h$ ^- N8 V: a( i0 N - u8 temp;% T' K* }" X2 M; o- J, Z
- temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX 2 N& Y; {' u. S3 @( Z2 X/ y5 q
- if(temp==0X55)return 0; - e+ Z6 r3 \$ h; D; l9 F9 A& y
- else//排除第一次初始化的情况
4 y0 l# J& i' Y - {
+ h! y# l- O F - AT24CXX_WriteOneByte(255,0X55);0 j f5 a8 W5 S" T# o) y* x
- temp=AT24CXX_ReadOneByte(255); . d$ y1 m; m9 q2 }+ J
- if(temp==0X55)return 0;( d; j: k6 w8 D( Q" G3 V: y6 X) z
- }" V, x9 Z; S6 q% t5 n6 F; j! v
- return 1;
+ z& I @# _1 h% T' R; m4 ?+ n% a* n - }
/ O) ] B! M" m& c$ {6 p) W - ( b1 R: E3 I+ y, I+ h
- //在AT24CXX里面的指定地址开始读出指定个数的数据+ ?& w. z( P9 }& P& Q
- //ReadAddr :开始读出的地址 对24c02为0~255
& ]6 i9 V* F( M/ X" Z - //pBuffer :数据数组首地址
. ?% v" m* m% L, X/ M" G& Q) | - //NumToRead:要读出数据的个数
0 e' u$ G) O3 k% P6 K - void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
. I; @1 d1 B( q2 I - {
`) ^3 B' ~( H/ x$ L, v+ B - while(NumToRead)
* d/ y% I- l" U4 F, ^ - {
9 Y% `2 k8 U( F - *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++); 4 w+ E9 ]. |1 T) w# P' ^, P! S
- NumToRead--;! E) @" [0 K/ X! Y' t( H. G8 u
- }" Q5 L! c8 @' z8 }/ @$ U7 k; J' ^- t
- } 8 I7 F3 z9 t7 } V9 c* u0 l
- //在AT24CXX里面的指定地址开始写入指定个数的数据
; D0 c3 `! J# y' |, q1 t' c5 Z* j+ ~ - //WriteAddr :开始写入的地址 对24c02为0~255
3 S% ~* q$ Q2 y4 P - //pBuffer :数据数组首地址
1 L1 ^# a: }1 j% g - //NumToWrite:要写入数据的个数" W( T" |8 E1 }
- void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
5 \1 c& o- m: }: a0 z - { q, C% H6 d3 Q$ Z2 F( e3 H
- while(NumToWrite--)# J3 c* a" k6 W
- {
9 D4 z3 M2 C0 s$ N$ M - AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
: H/ X1 |. Q4 n& z, `& V - WriteAddr++;
. F* x4 V8 @8 |4 c - pBuffer++;
9 X% v+ X: | c - }
8 X5 c3 y" A P/ J0 \/ @% w - }
复制代码- 24cxx.h:
2 u" L% y' h6 b( u( ~ - #ifndef __24CXX_H5 \4 p( o ?. q* q3 l
- #define __24CXX_H/ H) f+ C9 z- ]7 e8 G
- #include "myiic.h" + {2 h' D9 @; ^, K) b+ D) o( J
& b$ n% I) o- A# n- #define AT24C01 127% ]3 Q" ]& n0 W" |+ U
- #define AT24C02 255+ `9 |0 r: t }( V8 v
- #define AT24C04 5110 N, W' @. K- p8 E, {6 J
- #define AT24C08 1023& R$ X" f9 u8 T2 P: W; k' _
- #define AT24C16 2047
3 H4 [8 ]! Z; G* y: \6 S% c - #define AT24C32 40953 ]$ Q, p! w! f3 k: n$ _# ~( ]
- #define AT24C64 8191
& `8 m1 w T" A# g2 X7 ^ - #define AT24C128 16383
0 z* g; P! w/ U) F6 o - #define AT24C256 32767 * I$ u ? P' U$ g' O
- //Mini STM32开发板使用的是24c02,所以定义EE_TYPE为AT24C02
5 @* {5 |. H6 w/ Z! f - #define EE_TYPE AT24C02: y; f K% d+ l8 e8 z& X
- 1 i! C# h8 W/ a% E/ `3 [1 q- n1 I+ t$ L
- u8 AT24CXX_ReadOneByte(u16 ReadAddr); //指定地址读取一个字节; }7 C& r4 S# w/ C: v1 `/ k
- void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite); //指定地址写入一个字节
6 _& S/ r' w- v4 A6 _% P8 M - void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);//指定地址开始写入指定长度的数据
& a. V. @; C9 P& e& }( ` - u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len); //指定地址开始读取指定长度数据& [( w& L& f1 m* u h, ~
- void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite); //从指定地址开始写入指定长度的数据
& V7 ]2 p& J* m# R& s2 ` - void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead); //从指定地址开始读出指定长度的数据
) K5 v0 l& L: e9 `, `- i. A) [ - ! S6 y/ z% U: Q* c ?7 ?& d
- u8 AT24CXX_Check(void); //检查器件1 O$ y1 R6 }6 ?, Z
- void AT24CXX_Init(void); //初始化IIC
' _0 Q) p0 J) N* _( g - #endif
' @0 P/ X& J! o: a! w( |& n4 N# { - G/ B/ s% }3 ]% W* C/ W- H
- main.c:4 C: t) I `4 C1 W/ c
- #include "sys.h"
8 J; m& R* Z: D% U6 I9 q - #include "delay.h"
, }' u* p9 ?$ |1 G6 L - #include "usart.h"; Y6 R0 k. z7 `, D8 y. j
- #include "led.h"
7 F) ~4 ~, L7 W6 a) ?. X - #include "lcd.h"2 D+ {( u, d4 u9 U9 O8 R/ b W
- #include "24cxx.h"5 K, j% |3 B' U; R4 h5 G$ {
- #include "key.h" % E- d$ o" _0 r, O; Y6 Z2 G
- , W1 ?3 j) R- A( W
- //要写入到24c02的字符串数组
# x. z$ N! p, K d3 ~& i - const u8 TEXT_Buffer[]={"Explorer STM32F4 IIC TEST"};- J& q' A: _1 v3 P" p
- #define SIZE sizeof(TEXT_Buffer)
# V5 J5 }+ y. V0 t -
6 P. R: |7 ?/ N3 t. b - int main(void)
0 d3 b) M8 j# h- Z- l9 w- E' z - { - U' |" a2 r- W+ j7 H" ]% j
- u8 key;- X7 Y2 [% P0 N1 [; X; L
- u16 i=0;! ^7 E. d, V- i- u/ p
- u8 datatemp[SIZE]; ! f2 V6 B( m% H5 m- m2 |
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
8 U4 I) G) O" i* x' g* L/ z& |6 ` - delay_init(168); //初始化延时函数 M6 v( f! }2 w% B' ^' Z; V
- uart_init(115200); //初始化串口波特率为115200
3 b$ ~$ o$ s' j* k+ N1 m! Q -
) `8 u/ E A) z6 l4 e. v0 r% n - LED_Init(); //初始化LED ! }; _$ W! Y8 I
- KEY_Init(); //按键初始化
$ E% w7 u# y' I" Z8 ~ - AT24CXX_Init(); //IIC初始化
4 s+ t4 }# p! v" s& g! c: c; G -
. {; o3 [( Q/ o) s - while(AT24CXX_Check())//检测不到24c02
, r5 t9 }7 M" B9 |7 G" X% {" f - {1 P! i0 `# R8 e+ F
- printf("24C02 Check Failed!");8 o, E1 e+ t. Z
- delay_ms(500); _8 p3 {8 E" k* L
- printf("Please Check! ");' t' s; N! Y4 v: c7 o, X
- delay_ms(500);
9 c! m" y6 w* n2 C, O& _& G# P - LED0=!LED0;//DS0闪烁
+ ]0 C# |$ g2 o1 W* ] - }9 [2 s4 v9 {4 z, B
-
^7 |& s1 y% B8 W - while(1)
) ?* s) y2 F4 _5 X - {+ A: h; H$ u- F7 i D9 ~, l
- key=KEY_Scan(0);1 W# y8 h* A/ \( r( V$ h) l- B
- if(key==KEY1_PRES)//KEY1按下,写入24C02
! c# _! f6 P$ ` - {
+ f, E9 D! @, R( c0 o - printf("Start Write 24C02...."); 9 N4 P9 x* W/ Q: W0 \
- AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE);
3 I4 t$ s! H' J0 j0 P# l - printf("24C02 Write Finished!"); //提示传送完成9 k1 H- {7 W: }
- }' P( c: X6 D. ?6 R5 f1 P
- if(key==KEY0_PRES)//KEY0按下,读取字符串并显示3 y. A7 U/ R: {2 b
- {9 n) h4 H- ]- a1 G4 c
- printf("Start Read 24C02.... ");
- U: o6 H$ Q1 h0 ^: i% j! m& A - AT24CXX_Read(0,datatemp,SIZE);
2 I; j c$ B' |3 j; y: m) l - printf("The Data Readed Is: \r\n ");//提示传送完成; x; D' {- f m- G* O! T! k) Y
- printf("%s\r\n ",datatemp);8 `$ p8 i1 v6 l$ W
- }
5 D9 f, D+ W& `1 b) c) g! X - }
B, d' u: e2 P$ m - }" Q" K K/ u0 W& P% H+ h
复制代码
$ ~. Q- ?' f# ]; X8 W- k" W, d
2 z# e1 s( K; K/ a' S) t& ?; _' n Z; B6 S8 |
|