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