|
简述 IIC(Inter-Integrated Circuit)其实是IICBus简称,它是一种串行通信总线,使用多主从架构,在STM32开发中经常见到。 使用面向对象的编程思想封装IIC驱动,将IIC的属性和操作封装成一个库,在需要创建一个IIC设备时只需要实例化一个IIC对象即可,本文是基于STM32和HAL库做进一步封装的。 底层驱动方法不重要,封装的思想很重要。在完成对IIC驱动的封装之后借助继承特性实现AT24C64存储器的驱动开发,仍使用面向对象的思想封装AT24C64驱动。 $ I2 ?# i: V4 g) q: G
IIC驱动面向对象封装 iic.h头文件主要是类模板的定义,具体如下: - //定义IIC类
+ F1 I5 d- a/ f" A6 n - typedef struct IIC_Type; w- m+ P' R: f6 _# e' A
- {8 u" n9 T2 ?9 ?' \( {$ J. S
- //属性8 t$ p w+ h+ V% f. a
- GPIO_TypeDef *GPIOx_SCL; //GPIO_SCL所属的GPIO组(如:GPIOA)$ G7 c5 G4 T% B: a6 I
- GPIO_TypeDef *GPIOx_SDA; //GPIO_SDA所属的GPIO组(如:GPIOA)( N' U6 |$ A& E- ^- |
- uint32_t GPIO_SCL; //GPIO_SCL的IO引脚(如:GPIO_PIN_0)& e/ l* W* W4 T) y3 E
- uint32_t GPIO_SDA; //GPIO_SDA的IO引脚(如:GPIO_PIN_0)
. d4 q |* Y! S ^* L& L8 X - //操作% d9 B; c" T; `# r3 I6 h$ E
- void (*IIC_Init)(const struct IIC_Type*); //IIC_Init
; ~4 Z1 t+ V9 E1 w) m. u - void (*IIC_Start)(const struct IIC_Type*); //IIC_Start
6 H8 E( Q; W' Q; g8 I - void (*IIC_Stop)(const struct IIC_Type*); //IIC_Stop* c4 _* k/ D( _; n8 D/ G
- uint8_t (*IIC_Wait_Ack)(const struct IIC_Type*); //IIC_Wait_ack,返回wait失败或是成功
' O N0 p+ f. v) c" U6 d - void (*IIC_Ack)(const struct IIC_Type*); //IIC_Ack,IIC发送ACK信号
2 O+ v H) E# w - void (*IIC_NAck)(const struct IIC_Type*); //IIC_NAck,IIC发送NACK信号; u5 U; J, q: |
- void (*IIC_Send_Byte)(const struct IIC_Type*,uint8_t); //IIC_Send_Byte,入口参数为要发送的字节' U7 s" k! G- g4 Q f8 |; E
- uint8_t (*IIC_Read_Byte)(const struct IIC_Type*,uint8_t); //IIC_Send_Byte,入口参数为是否要发送ACK信号9 V- x% h9 L+ T) p/ T7 K* S
- void (*delay_us)(uint32_t); //us延时, ?- R# ~+ A( v
- }IIC_TypeDef;
复制代码 - D6 U/ W8 L& w+ i L
# A4 i4 k. q. t% c3 l) miic.c源文件主要是类模板具体操作函数的实现,具体如下:% L9 ^4 l u# Q# a, y
- //设置SDA为输入模式 h; @. V6 U5 e9 j& L+ |4 A9 m
- static void SDA_IN(const struct IIC_Type* IIC_Type_t)8 X1 K" s% b( d m9 l1 J
- {
! T5 n- k/ U* x+ J5 i - uint8_t io_num = 0; //定义io Num号& k& ` E) L7 w4 h9 F9 v8 {
- switch(IIC_Type_t->GPIO_SDA)& L% O, L1 `4 K" o& R9 y
- {' j7 h0 ^7 }+ _
- case GPIO_PIN_0:2 i' u: k& I& d
- io_num = 0;' Q; o+ F8 }; p9 n% a$ X: U
- break;/ @( `6 N% n7 |- U& j$ F
- case GPIO_PIN_1:
8 @: c7 Y& @. ^$ s - io_num = 1;
2 g4 e' i# Z# c9 H4 \$ b7 j o) j - break; 1 x6 K7 H' m9 O. y. i7 [9 v; P
- case GPIO_PIN_2:9 A& y0 N6 b. e( h7 w3 d
- io_num = 2;) f3 k/ \2 T, H) |: T4 B
- break;
5 K% C7 q+ x: D7 u$ F - case GPIO_PIN_3:4 \" n- @1 |+ \' W& e
- io_num = 3;
8 H: I4 X/ N; F: m - break;
, t- W1 o% v) e# b& k - case GPIO_PIN_4:
8 d3 j# Q& x% ~6 }) l - io_num = 4;. b9 s! n1 q h; z
- break;
* k7 K" v2 v) E' n# A# Y7 U - case GPIO_PIN_5:- i9 U+ ~7 ~! o. L+ t; r: n$ o, h+ u4 D! `
- io_num = 5;
B; y! i/ a6 I' W. F; b, ` J" a1 X7 y - break;
2 @6 j& D4 d4 u4 c5 c - case GPIO_PIN_6:
, [2 b! a: e) l8 v8 Q% v2 T6 E - io_num = 6;) R; [! f1 Z# {# c( y6 X
- break;
3 |) L& C/ ~2 c/ ~4 j( f# m - case GPIO_PIN_7:
8 Z" z+ |1 K/ B3 `3 S5 r - io_num = 7;
: s; o5 }7 P9 \3 k - break;
/ u* X( u* H2 t- e& e! a - case GPIO_PIN_8:# P1 z! Z" I5 z+ _! i) z( x
- io_num = 8;9 X+ B5 }* q* @$ ~' K( O
- break;
% ~ ~. P4 ?' ^! x6 f8 O( }! L; @% } - case GPIO_PIN_9:
6 ]- r1 I- v6 Q/ d a+ k - io_num = 9; S4 |7 O! k$ j0 p: F7 S
- break;
# }+ B f8 k1 A0 P+ q# c* P) X! U% D - case GPIO_PIN_10:3 C( R7 v! Y% I% n4 x% \7 P( G
- io_num = 10;
+ @) y% _5 Z: C- K - break;
) J8 }# p+ I% ]" \& i6 K - case GPIO_PIN_11:
* x0 r3 [2 o @$ p4 h - io_num = 11;
+ J9 o' m" a0 h- b% l1 y) y0 W - break; 6 I) R$ A5 ]; M1 X J
- case GPIO_PIN_12:
4 q7 |, u3 E3 k, a - io_num = 12;" Q. f! U* O. N* J. ]
- break;! Y# K0 i9 k& Y
- case GPIO_PIN_13:
4 |9 V8 ?' [' \( Z$ p0 U* D6 C6 B - io_num = 13;
4 o1 |4 e3 y7 w( N; m6 E - break;
4 M" x0 ]! f9 B- C7 H* r7 r - case GPIO_PIN_14:" G0 E! e; _5 y. q. d) D
- io_num = 14;0 U( `, j& e- l& ^3 j
- break;
) t! t: Q6 a& ^: O0 P, Z' M - case GPIO_PIN_15:; d9 |# h2 C9 T) }$ R: A$ G
- io_num = 15;
1 x7 _% s B- ^2 P$ _. X. Q* @ - break;
" P) X' K5 }% |6 ^ - }
$ w: z8 D) z& b - IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零
, \9 L9 U! Q6 J8 z+ \( c - IIC_Type_t->GPIOx_SDA->MODER|=0<<(io_num*2); //将GPIOx_SDA->GPIO_SDA设置为输入模式
0 e& o3 R3 _6 \. u; W; z - }3 m9 g0 ]/ L& P. k$ W& H
4 J8 A2 I, m. P( @2 H- //设置SDA为输出模式
9 Q+ F' U/ P) W. u - static void SDA_OUT(const struct IIC_Type* IIC_Type_t)
* ]; b/ ` S; e# X% r - {
6 |( c3 o1 `% G0 v! R8 j6 j9 b - uint8_t io_num = 0; //定义io Num号
6 G2 X5 P; |$ G! d4 d - switch(IIC_Type_t->GPIO_SDA)
6 l4 ?1 | R: S, \1 o9 o - {1 \- x" r0 S: v' T+ b
- case GPIO_PIN_0:
* Z6 s8 Q) X/ ]2 P- O' q$ G3 M7 R# c3 l - io_num = 0;0 C$ n w) O: S" C5 A# k6 v; S
- break;
! r1 y7 s( P. b+ Y3 v8 Z - case GPIO_PIN_1:
+ O; B* {: k6 a, k' O4 N/ m f/ L - io_num = 1;, M2 Z4 q* M9 w( A
- break; 5 i$ V$ u) \! u0 g4 F T
- case GPIO_PIN_2:
, s( l @6 _' |; P3 n - io_num = 2;' r0 G6 S3 n7 |2 F& v9 }2 z
- break;
3 ?3 X; h2 Q$ I- L5 Z$ P, n - case GPIO_PIN_3:
4 A. x2 ~# }6 Z' g/ k - io_num = 3;% B6 J/ e& M' S: R1 \3 U: w( ~# L
- break;* x8 C! T6 N% L" B8 t* Q
- case GPIO_PIN_4:9 X8 ^% X4 w+ ~5 s
- io_num = 4;
$ k& P' a$ q {$ x+ o - break;
. H, F+ p# E' `9 s% K7 d4 t8 Z& C - case GPIO_PIN_5:
* Y8 J. M- L' n5 j4 ] - io_num = 5;) s$ F f5 h& t* f* J+ O% ^$ |6 ?
- break;
) ]( \& }. \- k - case GPIO_PIN_6:
8 w1 B% [# C# `, o& a- g, I - io_num = 6;
( H! |9 |5 T. t X- A4 j2 K4 A - break;
( o! i# }$ M; \9 \6 h - case GPIO_PIN_7:
, G- N4 M9 V/ \4 S - io_num = 7;
4 W: s2 a4 h, g# B5 _ - break;
. L1 _# Q5 O$ w$ G* k1 d8 z - case GPIO_PIN_8:' b+ L q7 Q# S& V/ F
- io_num = 8;& V! `) ?3 n: `7 `, a: N
- break; 5 a5 R. I3 Q) M2 [6 {: h! }/ c
- case GPIO_PIN_9:' E: }" |- x; E
- io_num = 9;% a1 S1 d# M4 S2 {& L0 v( q
- break;# p d& h. O; Y* s4 J
- case GPIO_PIN_10:
: `: V4 E5 b" W+ L# z7 k# }# y - io_num = 10;) q* L4 B' {- ~4 v. R' c, e
- break;
2 y. T5 V( m8 B' ?0 i9 @ - case GPIO_PIN_11:; t( i" ?% q; V
- io_num = 11;
7 n" J9 m: n, r8 o1 R" e - break; 2 N$ y, h7 w4 i' C0 p2 v r
- case GPIO_PIN_12:) U2 x; y/ T/ S, A+ N* y
- io_num = 12;+ Q* y/ e* h+ U6 W) Q" b; q
- break;
0 @1 P7 t# R9 U3 L - case GPIO_PIN_13:
3 O- K$ h0 `( w) }7 m - io_num = 13;) }( A9 |1 V! v8 h
- break;; v E+ |! B/ W |) D% j! f
- case GPIO_PIN_14:. J; L4 }) {$ p
- io_num = 14;
9 p& s7 r/ s H9 A - break;
# G4 b# m1 V9 v7 i& E3 F - case GPIO_PIN_15:3 ]' L" Q% x& D# `7 x8 a
- io_num = 15;
4 C0 r- w+ x3 T - break;$ j9 }, @1 O C1 l( |: c+ n
- }! [6 w' }% _1 z9 g% d
- IIC_Type_t->GPIOx_SDA->MODER&=~(3<<(io_num*2)); //将GPIOx_SDA->GPIO_SDA清零
4 y2 y" C* w3 ~3 t$ p6 v - IIC_Type_t->GPIOx_SDA->MODER|=1<<(io_num*2); //将GPIOx_SDA->GPIO_SDA设置为输出模式) e$ W C4 s; y! U& o8 O: b
- }3 O8 b4 R' S1 p# c. b* d
- //设置SCL电平0 S; _, |# u2 K. \
- static void IIC_SCL(const struct IIC_Type* IIC_Type_t,int n), X( }- J; @ i- E4 v
- {9 X+ Y* ]3 v2 u& p4 f! h/ n
- if(n == 1)
- [( }+ O# `% B0 h1 { - {
1 V( ]) [6 c% D+ Q; w, T/ k& A: E - HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_SET); //设置SCL为高电平
) c a( s5 c% d1 p8 u - }0 i0 }% p* f2 _5 T0 S4 z4 ?
- else{
; [% E5 ?* _ {# E3 {9 [ - HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SCL,IIC_Type_t->GPIO_SCL,GPIO_PIN_RESET); //设置SCL为低电平
' e) |* N: E1 H/ } - }8 A' `+ U' [* b! ~* Y7 _
- }
8 ]/ f1 L" ~& M - //设置SDA电平( d7 X$ G* M: y( O' D) r( B
- static void IIC_SDA(const struct IIC_Type* IIC_Type_t,int n)
N3 z' w9 p% t8 Y, N - {
$ I$ P. H6 c* {% H5 s2 L1 A - if(n == 1)
% n8 d0 G8 t q6 { - {5 Z' _# z/ o8 V# o3 Y! n: _
- HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_SET); //设置SDA为高电平% G" B* E% U, _# R2 E- l
- }
) s( h7 G! _, @$ F$ A/ _ - else{/ P6 Y; C e: e9 D0 t- ^9 z
- HAL_GPIO_WritePin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA,GPIO_PIN_RESET); //设置SDA为低电平
9 X; d+ O/ Y: d! `9 p7 ` - }* ]& d3 m0 a1 f; K+ i1 l
- }' j( q. [ W3 R$ [5 p3 ^$ g; |! _' i
- //读取SDA电平. G) k4 g9 ?( c( u5 j1 P+ V* p
- static uint8_t READ_SDA(const struct IIC_Type* IIC_Type_t)$ j, ]. o! t3 z/ o! M
- {
8 W1 \1 a; Y, G$ `1 A% P - return HAL_GPIO_ReadPin(IIC_Type_t->GPIOx_SDA,IIC_Type_t->GPIO_SDA); //读取SDA电平
$ |4 M1 V+ L! } |7 l) K# b, w - }" i+ B; M; B* [6 [5 v' v
- //IIC初始化3 p3 n( \' x5 j
- static void IIC_Init_t(const struct IIC_Type* IIC_Type_t)7 l% E% n) }0 D0 i% P7 t$ C+ ~. F7 ^
- {
/ E0 l8 N$ q: y7 i- ~ - GPIO_InitTypeDef GPIO_Initure;
' c3 \% |! b8 Y8 a% I
. r7 R+ s1 C- T/ E- //根据GPIO组初始化GPIO时钟6 g( q- U y8 L: t% X
- if(IIC_Type_t->GPIOx_SCL == GPIOA || IIC_Type_t->GPIOx_SDA == GPIOA)% }% L4 H( l8 l5 P5 f$ A+ g
- {, d3 Q! h4 y0 r# z" H* V9 Q: e
- __HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟
7 [" y$ f: d: l# i8 z, `9 g - }
3 z2 z$ O- r; ?# |, \9 J - if(IIC_Type_t->GPIOx_SCL == GPIOB || IIC_Type_t->GPIOx_SDA == GPIOB)" n F4 S! }/ }/ ^. P1 [
- {( A+ j8 I d4 `# A
- __HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOB时钟3 C" j, L7 e2 F; f
- }
! B/ q7 U; W; ^+ Q M6 y! O - if(IIC_Type_t->GPIOx_SCL == GPIOC || IIC_Type_t->GPIOx_SDA == GPIOC)
- u- u$ a5 G% w - {2 Q2 H! R& T, _+ S5 ]
- __HAL_RCC_GPIOC_CLK_ENABLE(); //使能GPIOC时钟 A7 l% }, Y% s* u/ x5 X
- }) @3 m% j6 ]4 |. f/ j
- if(IIC_Type_t->GPIOx_SCL == GPIOD || IIC_Type_t->GPIOx_SDA == GPIOD)
# v2 A- B' [1 x+ H - {! X+ U7 ]4 g) V5 v- L9 P1 M
- __HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIOD时钟
. b1 r& U, R0 o. j# r- v - }0 o4 `$ y1 p/ D( N. H+ @! j
- if(IIC_Type_t->GPIOx_SCL == GPIOE || IIC_Type_t->GPIOx_SDA == GPIOE)
: m- b2 \# ^: P/ v7 f - {
, [' h# ^5 t9 V - __HAL_RCC_GPIOE_CLK_ENABLE(); //使能GPIOE时钟0 w0 a# F3 w% u2 M% P5 l; i0 _
- } 2 U- ?' U+ H$ K+ |1 C
- if(IIC_Type_t->GPIOx_SCL == GPIOH || IIC_Type_t->GPIOx_SDA == GPIOH). K% J, ~% K: L. |4 A" N
- {
9 |4 \% n: Q' F/ ?8 P6 x - __HAL_RCC_GPIOH_CLK_ENABLE(); //使能GPIOH时钟
- b9 ^" J( l8 f) h - } 3 |$ N" j! Y( I# r* W( w
- 2 ^9 M" D- m: n3 m% _* A8 ?& s, d0 c+ ^5 j
- //GPIO_SCL初始化设置 u$ ^' t, q% F
- GPIO_Initure.Pin=IIC_Type_t->GPIO_SCL;: [2 {! S; S3 b( m# i9 m; ]3 `
- GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出% B6 y2 E/ Z# y, Y; [+ a) `" t- p
- GPIO_Initure.Pull=GPIO_PULLUP; //上拉
0 r& @' R$ d- e - GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH; //快速( R7 T' n. s) u! _& `* y- ^
- HAL_GPIO_Init(IIC_Type_t->GPIOx_SCL,&GPIO_Initure);
, a6 D# L& i3 p! x8 G% Z! r7 _ - //GPIO_SDA初始化设置
# h' J: \" [2 L4 ^# t0 h; Q - GPIO_Initure.Pin=IIC_Type_t->GPIO_SDA;+ a# G6 D1 h: k: C, D
- GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽输出
4 M# G d7 b+ g1 o4 _ - GPIO_Initure.Pull=GPIO_PULLUP; //上拉
# Y9 Q$ U9 ]8 \. x% Q - GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH; //快速( O( S0 f" Q' d9 I0 [+ z) u
- HAL_GPIO_Init(IIC_Type_t->GPIOx_SDA,&GPIO_Initure);
6 [! w+ G0 L, l$ Q% p% t" b - $ z* E, x# ~) X! b4 G
- //SCL与SDA的初始化均为高电平& k" n3 k. ?' L+ d
- IIC_SCL(IIC_Type_t,1);
3 e9 g6 s7 _" Y2 Y8 o - IIC_SDA(IIC_Type_t,1);
4 D1 V7 |( W+ H; | - }
6 @! r- i% ?3 r. Y - //IIC Start$ g4 V, C' f* s* _
- static void IIC_Start_t(const struct IIC_Type* IIC_Type_t)
2 T! ^. o6 g3 I" e - {
4 N4 d" d8 f& M$ T. `+ Z - SDA_OUT(IIC_Type_t); //sda线输出
& y0 q" N! }0 T! x - IIC_SDA(IIC_Type_t,1);
& N. _4 Z5 j( U3 ~ - IIC_SCL(IIC_Type_t,1);( K( [. o7 p6 B8 z% A
- IIC_Type_t->delay_us(4);! Z% L; b" i3 l( Z. L3 s& Q
- IIC_SDA(IIC_Type_t,0); //START:when CLK is high,DATA change form high to low 4 N( u8 I* E$ Q1 V/ B& \1 j* v" j
- IIC_Type_t->delay_us(4);7 ~, O: U* r- R! O% @0 p* c u1 E
- IIC_SCL(IIC_Type_t,0); //钳住I2C总线,准备发送或接收数据 7 S% R& W) o6 B- Y
- }2 G# D$ L p! e+ p$ t8 {
- //IIC Stop5 E2 I& @* j0 Q3 I4 j, P
- static void IIC_Stop_t(const struct IIC_Type* IIC_Type_t)9 h, D6 r7 q- s" U" V/ j
- {
) L& m: B* g2 V# i& I. n+ I" ` \ - SDA_OUT(IIC_Type_t); //sda线输出% j& B( B0 R8 F1 O/ C+ C
- IIC_SCL(IIC_Type_t,0); v0 D) q! l9 y
- IIC_SDA(IIC_Type_t,0); //STOP:when CLK is high DATA change form low to high3 |% c/ Y8 j6 M7 W4 f, ~4 y
- IIC_Type_t->delay_us(4);- g. C. F3 S9 J) z+ \$ M
- IIC_SCL(IIC_Type_t,1); 0 J% B ?/ x2 p% A( K2 X( E
- IIC_SDA(IIC_Type_t,1); //发送I2C总线结束信号# C: t4 `1 [, c/ u1 L! W- o2 L/ h/ U
- IIC_Type_t->delay_us(4);
. }9 W$ m8 T( Z) @ - }4 Z. C( ], D: t
- //IIC_Wait_ack 返回HAL_OK表示wait成功,返回HAL_ERROR表示wait失败
: W8 X# w! j5 A9 k+ U8 a$ |1 [: | - static uint8_t IIC_Wait_Ack_t(const struct IIC_Type* IIC_Type_t) //IIC_Wait_ack,返回wait失败或是成功
4 ]6 w% f9 a4 D! D3 p; K - {
1 |3 p* d* Z; d$ N. }: J( X - uint8_t ucErrTime = 0;
5 e O! r3 M0 q - SDA_IN(IIC_Type_t); //SDA设置为输入 % ?. k$ S, p9 [3 }+ J
- IIC_SDA(IIC_Type_t,1);IIC_Type_t->delay_us(1);
! x# u6 `$ w3 ]$ b - IIC_SCL(IIC_Type_t,1);IIC_Type_t->delay_us(1);5 {- }! \" S! V" K+ p& _: U2 N7 w
- while(READ_SDA(IIC_Type_t))
7 _& P# H! |" z3 U: s m - {
7 N- P! j* Z, C& U; B% i+ Y - ucErrTime++;
0 b' M; V, p8 f! c9 c - if(ucErrTime>250)- [4 _' ?+ Q- Y0 g- H
- {
7 h+ m+ F7 P! F2 j& ?6 p' a - IIC_Type_t->IIC_Stop(IIC_Type_t);
; u- ?3 s: D% A, Z, X7 e - return HAL_ERROR;
' A9 _6 ~2 G' q( q* r - }
. Y& t; H$ @+ q- Z! E - }3 [. y' c' m4 z8 A$ @& u
- IIC_SCL(IIC_Type_t,0);//时钟输出0
3 v" U9 h' p5 w, L( V2 u - return HAL_OK;
3 Z# A3 v: v7 X8 Y( k- q l - }+ u: o+ o- X: i. O2 k" r
- //产生ACK应答
l) e% f- A2 w+ h+ x - static void IIC_Ack_t(const struct IIC_Type* IIC_Type_t)
) m, `- |9 W1 Y0 {9 x - {; |" i8 k. e" w T' B. `% W3 i
- IIC_SCL(IIC_Type_t,0);9 G6 P8 G: e8 V! y9 u- e D% P3 ]9 u/ X
- SDA_OUT(IIC_Type_t);% Z4 e, U& p5 k' k" B8 O6 o
- IIC_SDA(IIC_Type_t,0);! ^; R- t" Y2 j$ n
- IIC_Type_t->delay_us(2); 1 q- D8 n- o; F7 ?+ W) U! P# `- m
- IIC_SCL(IIC_Type_t,1);
. u, i) g1 b) ^& j- b! a* j - IIC_Type_t->delay_us(2); & h+ ~5 v: H1 {5 t8 F- a3 G
- IIC_SCL(IIC_Type_t,0);; y- ~, `7 ^, d5 T- k- I4 N
- }/ ^9 K2 k) K/ O, W9 S2 }
- //产生NACK应答
7 A* f* H) m/ N - static void IIC_NAck_t(const struct IIC_Type* IIC_Type_t)
4 }0 K. }: U* g x; H* `* k2 J - {% M7 B% N/ p* j* m
- IIC_SCL(IIC_Type_t,0);
9 P. C4 Z) e1 }2 g* d - SDA_OUT(IIC_Type_t);
3 K% T1 E& b+ M9 r. S, q - IIC_SDA(IIC_Type_t,1);
) z/ Y0 }9 F8 E: L2 w4 ^& W. D - IIC_Type_t->delay_us(2); 1 F5 s4 C+ i {& B9 J/ z! u7 M3 S
- IIC_SCL(IIC_Type_t,1);
6 i, B+ N$ N* r a g' V3 `1 e - IIC_Type_t->delay_us(2);
! l4 f4 }: v: ?* j - IIC_SCL(IIC_Type_t,0);
- M2 e0 A$ d% M: j - }
3 g# g0 k1 W5 {) d5 S# D+ g - //IIC_Send_Byte,入口参数为要发送的字节
- i4 L) a3 `1 g1 X! c - static void IIC_Send_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t txd)
5 i4 S/ o) b, \9 x& b# \( ~& _ - {
( R! B/ u6 ?2 [3 g$ ]0 B - uint8_t t = 0; 5 n! O& R, P+ `2 V
- SDA_OUT(IIC_Type_t);
7 l# n- \7 z) v* S, ?( `+ a - IIC_SCL(IIC_Type_t,0);//拉低时钟开始数据传输
, H* K# H9 F) A - for(t=0;t<8;t++)& w) ^" w& _4 L* g c8 A1 O" v/ p; N
- { 4 [. e h6 y# D# h) z2 ?0 g
- IIC_SDA(IIC_Type_t,(txd&0x80)>>7);
: d' ?) H0 w9 X+ r5 L8 J, r! K - txd <<= 1; " s q1 j$ r& {) i5 N$ ^
- IIC_Type_t->delay_us(2); //对TEA5767这三个延时都是必须的# A! m4 U. v: z U: K
- IIC_SCL(IIC_Type_t,1);: [/ i2 y4 v% S. c5 [3 R
- IIC_Type_t->delay_us(2);
2 N c% \0 j6 ~! C! ~5 H6 b - IIC_SCL(IIC_Type_t,0); ' z! C1 i8 S) r2 a/ x
- IIC_Type_t->delay_us(2); # D! D! L( P7 n. g( A
- }
! i4 } p0 _$ X" x% g - }
& h( T. T- c, J) S' e1 t+ D9 A - //IIC_Send_Byte,入口参数为是否要发送ACK信号2 |: M8 T0 i& y) Y& h2 r/ T
- static uint8_t IIC_Read_Byte_t(const struct IIC_Type* IIC_Type_t,uint8_t ack) - N+ h7 H0 ~5 P" a$ b
- {
! f8 c9 y% `1 ?- ` - uint8_t i,receive = 0;( |! f/ @2 K! ~" u& R+ X
- SDA_IN(IIC_Type_t);//SDA设置为输入: j+ v) [7 I' e5 m u* ?. [: l& ~6 @
- for(i=0;i<8;i++ )2 J$ ?4 r) h6 z+ k" A
- {/ n5 ?" O' e% `
- IIC_SCL(IIC_Type_t,0);
; ^. x9 X7 o6 |& x* ], O% D& G - IIC_Type_t->delay_us(2);% D B$ y: z3 K7 ^ N* D
- IIC_SCL(IIC_Type_t,1);0 ]$ O7 V; E8 x! y v6 S
- receive<<=1;
9 w. j v. s& K( ?, v: a - if(READ_SDA(IIC_Type_t))receive++; - c0 \; `. {% }9 O0 i
- IIC_Type_t->delay_us(1);& R m! V- G" L2 n; H
- } 9 T, }5 u2 D3 V+ o. ~4 k, W
- if (!ack)
5 U$ k) E1 u7 |* I - IIC_Type_t->IIC_NAck(IIC_Type_t);//发送nACK) p5 @1 l3 I. [
- else& J7 B0 M0 A7 g: @3 t
- IIC_Type_t->IIC_Ack(IIC_Type_t); //发送ACK
- V. R6 ]: F9 s6 w) Y& } - return receive;
4 ^" X) V, f9 A1 i1 }, u0 @ - }
' g2 V7 F6 K: |- y5 e' h: m6 {+ O - //实例化一个IIC1外设,相当于一个结构体变量,可以直接在其他文件中使用1 ^0 t/ Z) y. J$ x1 m8 R; m' w
- IIC_TypeDef IIC1 = {
& c x/ f" M- y/ o( y" S& b: G - .GPIOx_SCL = GPIOA, //GPIO组为GPIOA
' E. t' l7 Q+ l5 s) D1 o% |- S- Z" C - .GPIOx_SDA = GPIOA, //GPIO组为GPIOA
8 h; _9 J& K& f: [ - .GPIO_SCL = GPIO_PIN_5, //GPIO为PIN5! C* e" c) {* `5 o7 @
- .GPIO_SDA = GPIO_PIN_6, //GPIO为PIN6# b! l! o( K6 S% @
- .IIC_Init = IIC_Init_t,- K4 n4 ~1 n. `/ w* L+ L5 C
- .IIC_Start = IIC_Start_t,
5 G2 W0 a- B% V - .IIC_Stop = IIC_Stop_t,/ O, U/ k: ^: j, y
- .IIC_Wait_Ack = IIC_Wait_Ack_t,* v9 D* C9 w ^, L+ `0 h) g/ J
- .IIC_Ack = IIC_Ack_t,% _7 ` [& E& H; Z. `
- .IIC_NAck = IIC_NAck_t,5 ^1 ?, d% v& h: A2 X. ~# V* C
- .IIC_Send_Byte = IIC_Send_Byte_t,
. ~3 Z# F8 D8 E: A/ o+ y - .IIC_Read_Byte = IIC_Read_Byte_t,
0 g6 I/ P3 Z" V6 l0 ]% U" x, |3 h - .delay_us = delay_us //需自己外部实现delay_us函数3 y) Q2 H( E4 n
- };
复制代码
3 w3 G0 N. D( F3 a4 B% E 上述就是IIC驱动的封装,由于没有应用场景暂不测试其实用性,待下面ATC64的驱动缝缝扎黄写完之后一起测试使用。 ATC64XX驱动封装实现 at24cxx.h头文件主要是类模板的定义,具体如下: - // 以下是共定义个具体容量存储器的容量
7 j5 g, [1 w* g1 \/ q; P- |5 _1 c) W* S - #define AT24C01 127& {' r& h( [' G: c2 c0 e3 P
- #define AT24C02 255
* X- a; W U' N: L& y" ^ - #define AT24C04 5115 w1 G3 d7 D0 \# R" t3 @
- #define AT24C08 1023
4 `" e( i# h; n, o% |$ S - #define AT24C16 2047
, l0 h" m' m0 U3 t$ M$ o( J - #define AT24C32 4095
P8 p. T; }& C7 x2 S - #define AT24C64 8191 //8KBytes
- q/ B0 L0 W* U* L9 R - #define AT24C128 16383
+ X9 g- q% N3 N# L - #define AT24C256 32767
) M& v( w$ F0 |5 Y3 f8 [& T - 4 v1 z b* k- q" B0 o$ M
- //定义AT24CXX类
% a4 ]; Y9 D) B& g; K/ M9 V) |# E - typedef struct AT24CXX_Type
& k' B$ A/ h1 I* U) _( B - {
/ i& t. O& j5 P q0 h' z - //属性
" O0 [4 x; _ u. h* f7 J - u32 EEP_TYPE; //存储器类型(存储器容量)
% U0 l) s: X# D0 W3 @6 X - //操作: p5 Q% x/ K. f* ?8 I9 I8 F0 l
- IIC_TypeDef IIC; //IIC驱动& j0 A" {, Z# X: U4 h7 u
- uint8_t (*AT24CXX_ReadOneByte)(const struct AT24CXX_Type*,uint16_t); //指定地址读取一个字节, v0 c/ b: V! q0 y8 ~; r+ g
- void (*AT24CXX_WriteOneByte)(const struct AT24CXX_Type*,uint16_t,uint8_t); //指定地址写入一个字节6 d. p% `4 ^+ h r" t
- void (*AT24CXX_WriteLenByte)(uint16_t,uint32_t,uint8_t); //指定地址开始写入指定长度的数据% E7 b; f- V7 W7 W
- uint32_t (*AT24CXX_ReadLenByte)(uint16_t,uint8_t); //指定地址开始读取指定长度数据9 A5 }5 ~( K7 v8 B: I
- void (*AT24CXX_Write)(uint16_t,uint8_t *,uint16_t); //指定地址开始写入指定长度的数据
6 e6 G) h; c) U5 D( E. E - void (*AT24CXX_Read)(uint16_t,uint8_t *,uint16_t); //指定地址开始写入指定长度的数据
: b2 |* C, _! \6 D! m3 e; F - void (*AT24CXX_Init)(const struct AT24CXX_Type*); //初始化IIC
# W" H8 y) d9 ?) R" m8 h- ~7 B; o, P) { - uint8_t (*AT24CXX_Check)(const struct AT24CXX_Type*); //检查器件
4 C& B( t. p6 T* N1 o3 G - }AT24CXX_TypeDef;
; w( T9 _% @4 M3 O8 G6 o
. X4 _! O6 e* }5 P- extern AT24CXX_TypeDef AT24C_64; //外部声明实例化AT24CXX对象
复制代码
1 P% E5 s4 U( P$ D" r2 c& h
at24cxx.c源文件主要是类模板具体操作函数的实现,具体如下: - //在AT24CXX指定地址读出一个数据
' ^* \2 h# z- `3 E: y+ p - //ReadAddr:开始读数的地址
5 O: [3 M" A: Z5 h - //返回值 :读到的数据
: x8 ]" S! {4 Q2 ^ - static uint8_t AT24CXX_ReadOneByte_t(const struct AT24CXX_Type* AT24CXX_Type_t,uint16_t ReadAddr)
* D8 T: @4 g6 x$ O1 m. v5 B1 P - { ! O7 W: f% f# ?: o
- uint8_t temp=0; - V% j: M( X8 D: w
- AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC);
0 ?, M! s* A4 f# R/ M0 L. J - //根据AT的型号发送不同的地址
& ~$ ]) u& u1 h3 ?+ A% I - if(AT24CXX_Type_t->EEP_TYPE > AT24C16)
2 i# r" ]( W8 S; i7 Q# z$ Z3 } - {
+ P3 {8 l: k- P, o* N4 |! f; p - AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0); //发送写命令: ]' l" V/ e& u8 ^4 t
- AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);) a/ @- R5 A3 e6 p1 d
- AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr>>8);//发送高地址 1 S) [. [5 G! @- m% P
- }else AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((ReadAddr/256)<<1)); //发送器件地址0XA0,写数据 5 q4 c, [4 p/ A( J' X
- AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
' F6 J0 C! v n: G& o- E0 H - AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,ReadAddr%256); //发送低地址 Z7 L) W$ K- D
- AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
7 C$ y0 a4 o+ w - AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC); ) Q, B5 i' a8 J' @8 c/ L# N
- AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA1); //进入接收模式 - ~" k9 s8 w5 `
- AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
) i0 Y" o, n% z4 d O' w$ c - temp=AT24CXX_Type_t->IIC.IIC_Read_Byte(&AT24CXX_Type_t->IIC,0);
% \0 R, h8 E1 Q3 L E7 t* T - AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//产生一个停止条件 $ f b/ l" Q; d& `. x
- return temp;9 {7 I2 I3 y( E8 e$ P% |
- }
. b; b" h" L1 y- R, b - //在AT24CXX指定地址写入一个数据8 j0 ?# B; E2 q0 T4 o
- //WriteAddr :写入数据的目的地址
3 Q8 v7 m+ J: o3 N - //DataToWrite:要写入的数据4 ?2 C- V6 y% Q K# R9 m: K
- static void AT24CXX_WriteOneByte_t(const struct AT24CXX_Type* AT24CXX_Type_t,uint16_t WriteAddr,uint8_t DataToWrite)0 L3 |, C. u% S6 E- o
- { . E* D0 u8 t, c, V; n& U" V* r- p" O
- AT24CXX_Type_t->IIC.IIC_Start(&AT24CXX_Type_t->IIC); 3 H+ @0 }, M+ Z0 k! S
- if(AT24CXX_Type_t->EEP_TYPE > AT24C16). r0 [, j. D4 e. I" R0 _
- {
- ]# M; ~/ P5 X* b1 s# B - AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0); //发送写命令, H# f! `; X! G5 n8 r' e/ P5 r. h
- AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);. [* Q0 I* F% \3 o$ G5 c
- AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr>>8);//发送高地址 : E" U$ U" G$ T
- }else AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,0XA0+((WriteAddr/256)<<1)); //发送器件地址0XA0,写数据 2 G+ D- h# u8 ?& n3 I
- AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC); 9 D( H4 }- \; N% Q
- AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,WriteAddr%256); //发送低地址4 |3 N- }% P! u0 l5 [! h/ ~
- AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
( Y& E1 g% x6 y4 D, H - AT24CXX_Type_t->IIC.IIC_Send_Byte(&AT24CXX_Type_t->IIC,DataToWrite); //发送字节 Z9 C$ X; i- N& H E
- AT24CXX_Type_t->IIC.IIC_Wait_Ack(&AT24CXX_Type_t->IIC);
X7 }& c7 G" Z. t4 D- S - AT24CXX_Type_t->IIC.IIC_Stop(&AT24CXX_Type_t->IIC);//产生一个停止条件 3 ^* H- t. a( n- c1 [ m
- AT24CXX_Type_t->IIC.delay_us(10000);
2 ^4 d) j# U4 `/ T' ?4 I( | - }1 H ]+ D; }5 P2 w9 }
- //在AT24CXX里面的指定地址开始写入长度为Len的数据* c) l, ]: k2 H0 h
- //该函数用于写入16bit或者32bit的数据.* ^9 _$ e8 p4 _- i6 i0 m
- //WriteAddr :开始写入的地址 # ~+ y0 V2 w: i, G @; w
- //DataToWrite:数据数组首地址8 M4 y2 E$ I; `0 d, i1 w' N
- //Len :要写入数据的长度2,44 y o9 q* u: ?3 \0 G
- static void AT24CXX_WriteLenByte_t(uint16_t WriteAddr,uint32_t DataToWrite,uint8_t Len)
' q7 b1 q" s9 _% G) J& k+ K - {
. L/ r# W7 j* l0 q Q - uint8_t t;
4 p: u- }$ S7 \4 \9 m) ]$ K - for(t=0;t<Len;t++)
- \6 X* ]- k, x5 d8 u - {4 O( Q7 ?4 D* i/ z4 J
- AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);7 P: Y% W" f: H+ K! ]! r
- } # w1 M* u( f/ w% [, P: l' N
- }
) Q/ X2 u0 Z$ v. ?: j - //在AT24CXX里面的指定地址开始读出长度为Len的数据3 R* ]* N( T+ x) {* z' L
- //该函数用于读出16bit或者32bit的数据.
$ Z0 t0 x- t1 N4 z3 w1 E - //ReadAddr :开始读出的地址
" l# x+ S, {7 {% }, G, r5 M; M; t( r$ h - //返回值 :数据
: Y0 ]# n, Z8 c0 |- @ - //Len :要读出数据的长度2,4$ U0 H" e' y$ b E) ^8 y" K
- static uint32_t AT24CXX_ReadLenByte_t(uint16_t ReadAddr,uint8_t Len)) l' C/ a5 c. `! h! z
- {
4 j" j; z H) d( h - uint8_t t;
; i I; ^- l6 G$ o - uint32_t temp=0;) d% C, q% H2 G P `5 c
- for(t=0;t<Len;t++)
7 C1 ]5 C! X1 d; E, t3 J% ~8 o - {& }* s! ~+ H# b+ n
- temp<<=8;
: N) X5 _8 R J4 G8 { - temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1); # R% Y, v( @+ b9 g" Y
- }$ w% u$ j |7 Y- k# N+ C5 e5 Y% E
- return temp;
0 k7 w3 `% d0 _. B! o8 K - }6 _6 Y9 W0 q$ [" q0 X* F1 Q0 r5 t
- //在AT24CXX里面的指定地址开始写入指定个数的数据# _- \, `! a+ S: z6 M( b
- //WriteAddr :开始写入的地址 对24c64为0~8191: f& c a6 k4 l4 P
- //pBuffer :数据数组首地址
E3 N7 Y. @, \. ~ Q8 ], a - //NumToWrite:要写入数据的个数
* m5 H/ n# a( g* s8 n' \ - static void AT24CXX_Write_t(uint16_t WriteAddr,uint8_t *pBuffer,uint16_t NumToWrite)
: ?" X6 I. z3 z/ M& I - {8 \5 Y( {8 ]" }: h+ [: n6 ?/ \4 l
- while(NumToWrite--)" c+ c3 q( U4 p+ C# @. r6 j
- {
" N; ~: V+ v w0 F4 s - AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
" S7 k0 {% |$ O" P - WriteAddr++;
; ^* K1 t! `$ p9 O - pBuffer++;- w# K0 t/ p. d- K
- }
% ]) C; F/ J9 K0 v - }
+ f1 X4 _6 _% ]) ~ - //在AT24CXX里面的指定地址开始读出指定个数的数据
3 |# q% r* s% v* ~ - //ReadAddr :开始读出的地址 对24c64为0~81919 m6 M& c2 O1 `2 z9 _/ o
- //pBuffer :数据数组首地址: q( ?, F- X ?7 q
- //NumToRead:要读出数据的个数
8 d/ h, P9 y6 W. f$ p/ m' ~ - static void AT24CXX_Read_t(uint16_t ReadAddr,uint8_t *pBuffer,uint16_t NumToRead)- B: M0 K2 W! m' {' B
- {* l1 e' ?! u; u6 c+ S, k
- while(NumToRead)
1 A, ]+ y' G$ g. D - { Q. h( m" c4 a2 \3 Q! u' G
- *pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);
/ y$ J& P; B0 g1 o6 b - NumToRead--;
; R1 n7 l: Y( J/ Z& H - }
a; d' q9 d! P/ @% @ - }
' o. v: A8 l' W! z+ @ - //初始化IIC接口 v5 U; i5 }* D: P* a4 y
- static void AT24CXX_Init_t(const struct AT24CXX_Type* AT24CXX_Type_t)
$ H# m0 a: E/ y% M0 x. y, s - {
9 Y2 M. T X3 u* }# D - AT24CXX_Type_t->IIC.IIC_Init(&AT24CXX_Type_t->IIC);//IIC初始化
. |, O+ q# w1 o& j$ i- E' |# k3 } - }
& _0 E! R! P6 T) m7 U' y8 t - //检查器件,返回0表示检测成功,返回1表示检测失败- ?0 t9 j- b; z8 c
- static uint8_t AT24CXX_Check_t(const struct AT24CXX_Type* AT24CXX_Type_t) - @. g( ?8 ^: S y
- {
" C& e. _ i& a% v- t6 h8 I3 H - uint8_t temp;( `2 x8 a% s4 `! g
- temp = AT24CXX_Type_t->AT24CXX_ReadOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE);//避免每次开机都写AT24CXX 5 X" P) l# P$ N, p9 G. k
- if(temp == 0X33)return 0; # X, g- h& m- m5 v
- else//排除第一次初始化的情况
) p, D/ a& R) K - {
5 A$ O4 i$ B- @4 C6 J - AT24CXX_Type_t->AT24CXX_WriteOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE,0X33);
' o- w$ e9 h" D0 n4 z8 | - temp = AT24CXX_Type_t->AT24CXX_ReadOneByte(AT24CXX_Type_t,AT24CXX_Type_t->EEP_TYPE);( i6 d2 [6 d; B0 M1 o
- if(temp==0X33)return 0;
0 b. q7 I/ f8 g$ t. v) o! h - }
! m5 @& I1 J3 M7 }' g" _ - return 1;
# h1 n0 M. q# U/ _0 U: d" s - }8 f9 R0 V$ X7 k# t
- //实例化AT24CXX对象
% I I$ ^' Q/ I) f1 C - AT24CXX_TypeDef AT24C_64={7 m. g0 p, @( y3 h/ Y* N: ]1 H2 f& A+ |
- .EEP_TYPE = AT24C64, //存储器类型(存储器容量)# ]' b9 O7 t" H4 y+ Z* y
- //操作
4 X0 S9 o; ?" F a$ N9 V; [& O - .IIC={
) {, y4 K7 S, c$ q, g - .GPIOx_SCL = GPIOA,
! @# f2 e0 L4 _. P- p- N3 i0 @$ `/ P5 E - .GPIOx_SDA = GPIOA,* V3 Z' v( P. {' {5 w
- .GPIO_SCL = GPIO_PIN_5,
4 ]# o: T/ k/ o( I: F - .GPIO_SDA = GPIO_PIN_6,
# ?5 v6 q% e( K) ]$ {3 @ - .IIC_Init = IIC_Init_t,! i0 A( q3 z, y, m1 C3 L
- .IIC_Start = IIC_Start_t,
9 d) i$ H, V3 T @9 A8 d" h) C( g- A - .IIC_Stop = IIC_Stop_t,
3 k* x* e8 A3 d - .IIC_Wait_Ack = IIC_Wait_Ack_t,
/ [2 z2 O( j6 X9 }: v2 \$ P% S - .IIC_Ack = IIC_Ack_t,6 U+ u0 G3 l9 E1 a+ S& Z" @
- .IIC_NAck = IIC_NAck_t,. W( J6 ~9 m& u2 l$ g
- .IIC_Send_Byte = IIC_Send_Byte_t,, r7 @6 s7 C8 m7 [4 o& r
- .IIC_Read_Byte = IIC_Read_Byte_t,
% Q% W& R, c, k/ b - .delay_us = delay_us
. n( {0 _$ _) f8 h# ~ - }, //IIC驱动
4 f8 C* Q$ ?: b# M/ t& z - .AT24CXX_ReadOneByte = AT24CXX_ReadOneByte_t, //指定地址读取一个字节0 _, C! _9 K7 v. `( ^" a
- .AT24CXX_WriteOneByte = AT24CXX_WriteOneByte_t,//指定地址写入一个字节
* v% f) P G8 m: D' G5 z - .AT24CXX_WriteLenByte = AT24CXX_WriteLenByte_t, //指定地址开始写入指定长度的数据
7 r; ?% i: n: l9 i$ r - .AT24CXX_ReadLenByte = AT24CXX_ReadLenByte_t, //指定地址开始读取指定长度数据$ C; C" P8 Q4 l' N
- .AT24CXX_Write = AT24CXX_Write_t, //指定地址开始写入指定长度的数据5 O6 _" Q. n8 |1 d! r8 l8 O
- .AT24CXX_Read = AT24CXX_Read_t, //指定地址开始读取指定长度的数据# k- Z% @: k8 G; F! C0 u9 b
- .AT24CXX_Init = AT24CXX_Init_t, //初始化IIC2 C) Z# N5 c! n5 j1 T
- .AT24CXX_Check = AT24CXX_Check_t //检查器件
8 b9 T2 v& R; G" v - };
复制代码& r8 d; q* V% k& S) v
简单分析:可以看出AT24CXX类中包含了IIC类的成员对象,这是一种包含关系,因为没有属性上的一致性因此谈不上继承。 之所以将IIC的类对象作为AT24CXX类的成员是因为AT24CXX的实现需要调用IIC的成员方法,IIC相当于AT24CXX更下层的驱动,因此采用包含关系更合适。 因此我们在使用AT24CXX的时候只需要实例化AT24CXX类对象就行了,因为IIC包含在AT24CXX类中间,因此不需要实例化IIC类对象,对外提供了较好的封装接口。下面我们看具体的调用方法。
1 P: _4 f' B/ J6 }2 V" ~7 e6 ` 主函数main调用测试 在main函数中直接使用AT24C_64来完成所有操作,下面结合代码来看: - #include "at24cxx.h" //为了确定AT24C_64的成员方法和引用操作对象AT24C_64
. x& M- Y/ A# ]& q8 r* I N - int main(void)1 s3 i# v, c c# u
- {
, u, G: B$ F2 v2 I7 R7 p& y/ ? - /************省略其他初始化工作****************/
& L+ C2 U7 K4 C+ C - //第一步:调用对象初始化方法来初始化AT24C64
1 q: {) Z5 g5 M; e# R/ X - AT24C_64.AT24CXX_Init(&AT24C_64);, @4 C3 V' K: ^. z/ p$ Y6 ~2 R
- //第二步:调用对象检测方法来检测AT24C64
( x. _6 a8 D M - if(AT24C_64.AT24CXX_Check(&AT24C_64) == 0)8 ^; Y ?7 E9 X& `, j
- {- R& k, U. |2 r1 y9 j
- printf("AT24C64检测成功\r\n");
/ b( [/ q$ f8 q( i - }7 @5 @) |, I" c/ C0 o1 v) v
- else{
6 e& s/ g1 C& T* Y" O* Z, v - printf("AT24C64检测失败\r\n");
. ?( e T% `: O) V. \) W. x - }
, R4 n8 N4 L8 a. A8 i$ s/ a - return 0;
2 y0 P6 I9 t v1 ^ - }
复制代码& H* D' M6 q7 ]3 f
可以看出所有的操作都是通过AT24C_64对象调用完成的,在我们初始化好AT24C_64对象之后就可以放心大胆的调用其成员方法,这样封装的好处就是一个设备对外只提供一个对象接口,简洁明了。
9 \* t" T+ c. ?: f& O3 `8 s" K 总结 本文详细介绍了面向对象方法实现IIC驱动封装以及AT24CXX存储器的封装,最终对外仅提供一个操作对象接口,大大提高了代码的复用性以及封装性。 7 a W$ T" t& x9 {! f
+ v! e3 f# T/ f) k
|