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