STM32CubeMx入门教程(7) I2C的读写应用 - k& P v. O! ~
导语“本次 教程使用CubeMx配置I2C进行I2C总线设备的数据读写操作,使用EEPROM作为实验对象” 01 ------------第一节 系统要求---------- 9 K" f! T- c% A( s) E
•硬件 野火指南者开发板
( t' F/ A: m% G0 T•软件 8 B# G3 o+ v& v1 D7 o! V% I" ?
CubeMx & MDK & 串口调试助手 & e) I6 V# ^/ T! w
•原理图 : U2 c; e, l5 _4 ^2 ]
5 d8 G5 R3 j2 L' B8 \; i% [, H/ M
1 m( d: v8 s/ F# `9 a
' {0 K+ i- l* }9 V
R* K7 f. ]: C6 m e我们可以从原理图中得到使用的I2C1,AT24C02的设备地址的第三位是000,容量是256个字节。设备地址从下图得到: 7 b W+ e" v: Y$ M
. b, b$ m- x8 u* l
% R/ _" H% ~! y" K' ]8 R
& h4 s& u' F; G% `& G
不带读写方向的使用左移得到的地址为0b10100000->0xA0, 读地址为:0xA1,写地址为0xA0;
l; F$ p! Q m# Y# P; J注意:(1) 操作ATC02的时候,多字节写入的时候没写入一个字节,延时最小5ms, 多字节读的时候没有要求,页写入的时候每8个字节为一页,共32页。
1 D! v& j- ?3 W& m- z! M+ K02 ------------第二节 CubeMx的配置---------- ' t* g! f9 D- `- R U) {. V
+ z: S$ ]9 G- _8 J' z我们依然使用之前的USART的项目,在此基础上进行I2C的配置,串口的使用是进行EEPROM读写数据显示在控制台上,使用CubeMx进行I2C的配置: / }5 N& U' F& h# M& @4 A2 R. `8 N! j
; J6 v4 r1 A0 H9 n" q6 O" ?0 p, W; i; X
# q+ f: L1 C/ N! G) V2 x
I2C的配置很简单,完成上述配置后生成代码。 8 L% J$ F- f# w7 N# j+ S
, S9 e$ d6 d1 S
03 ------------第三节MDK的代码编写---------- 使用MDK打开CubeMx生成的代码进行应用代码编写。 (1)在main.c 中进行AT24C02的相关宏定义和变量定义:
q" {! D! `: m- #define ADDR_AT24C_Write 0xA0" u6 `/ ?/ S: J8 l/ D
- #define ADDR_AT24C_Read 0xA19 @' r8 w. |( U+ H3 e
- #define DEV_ADDR_ATC02 0xA0 //0x50 左移得到的。1 s! {' L9 l2 W5 q; X6 J
- #define ATC02_BufferSize 256 // 256
( I4 X* C9 n1 Z' Q5 V- E1 o - #define I2C_TIMEOUT 0xFF, N$ D( `* r" o8 S: r
- #define AT_I2C hi2c1
7 o& z0 V2 ]6 X% h' C - uint8_t AT24_WriteBuffer[ATC02_BufferSize],AT24_ReadBuffer[ATC02_BufferSize];
复制代码 8 F- L* ^% N# q" ] {
@ }1 R: E/ g8 a. u# ?. k2 p4 c8 M
(2) 应用函数申明:
% B( l% r9 U5 u$ R- HAL_StatusTypeDef I2C_Write_Buffer(I2C_HandleTypeDef *hi2c,\, r) c$ b4 @5 a/ K9 J, K
- uint16_t DevAddress, uint16_t MemAddress,\6 H& _; K Z8 A% N% G5 i; N# j* s
- uint16_t MemAddSize, uint8_t *pData, uint16_t Size,\
5 U! |3 t8 ~+ K( g - uint32_t Timeout);
1 }* v Q1 z" }, O; m - HAL_StatusTypeDef I2C_Read_Buffer(I2C_HandleTypeDef *hi2c,\) H v6 T5 s6 i [8 L+ }
- uint16_t DevAddress, uint16_t MemAddress,\
" |3 C9 L; m# c Y6 z6 c4 w# { - uint16_t MemAddSize, uint8_t *pData, uint16_t Size,\) l2 Q- c f; S5 p
- uint32_t Timeout);
复制代码
, Q& S. g& a; \" a4 ]0 c
1 }8 S8 B; L3 V- ]& k) kI2CWriteBuffer()是自定义的任意字节写入I2C-AT24C02的函数,I2CReadBuffer()是任意字节读写函数。这两个函数的实现采用HAL库的这两个函数: 1)HALStatusTypeDefHALI2CMemWrite(I2CHandleTypeDef *hi2c, uint16t DevAddress, uint16t MemAddress,uint16t MemAddSize, uint8t *pData, uint16t Size, uint32_t Timeout); - x6 g% p; u6 g, H
参数依次是:(I2C句柄,AT24C02的设备地址,设备中数据地址,数据地址的大小,写的数据,数据大小,超时时间) 0 s3 H8 e7 \4 n3 K
2)HALStatusTypeDefHALI2CMemRead(I2CHandleTypeDef *hi2c, uint16t DevAddress, uint16t MemAddress,uint16t MemAddSize, uint8t *pData, uint16t Size, uint32_t Timeout);
5 \ H, Z; l* u8 H& T8 I参数依次是:(I2C句柄,AT24C02的设备地址,设备中数据地址,数据地址的大小,读出数据,数据大小,超时时间) 9 v' J3 N5 k- B( q$ b
为什么不直接使用库函数呢?是因为在测试中AT24C02读写不正常,查看AT24C02的手册发现,单个字节写入没问题,多字节的写入需要每个字节延时5ms, 其实多字节的读没有问题,这个从新实现了下。可以连续8个字节的页写入,这个不需要延时。
5 d3 c+ y5 B1 C. B' _, v* G! ](3)多字节的读写函数: ( y, U) e8 i7 v: ~2 y
- /*这里自己实现多字节的ATC02的写操作*/ C, _4 U2 c+ w! k
- HAL_StatusTypeDef I2C_Write_Buffer(I2C_HandleTypeDef *hi2c,\9 q1 E' \7 l* H( g5 v+ q! ]
- uint16_t DevAddress, uint16_t MemAddress,\9 R' N6 O" F& u) B
- uint16_t MemAddSize, uint8_t *pData, uint16_t Size,\
) _( T& f0 A0 f2 k - uint32_t Timeout)# J6 z' R$ e6 d9 `
- {9 R2 b- z' P' @; q
- uint16_t count=0;1 `$ F3 U' M* ?
- for(count=0;count. Y e, A8 W A' l* k
- {
9 E" q `) \( `3 ]/ ?. j( z# w$ v - if(HAL_I2C_Mem_Write(hi2c,DevAddress,MemAddress, MemAddSize,pData,1,Timeout)==HAL_OK). u) Q1 A5 F9 ~ N1 ?1 P' S
- {0 {$ t, \" g. `! g) i, o
- MemAddress ++;
3 N3 y/ d+ {9 h - pData ++;- s5 C& W$ R' R. t* _
- HAL_Delay(5);8 v. ^& Z! d+ B5 z2 z
- }
" [8 P3 |/ \ I. F - else; H! e5 C; {) d) z* L* s+ u
- {
. A2 h- d4 o, v9 B1 t& C" Y - printf("i2c write is error \t\n");; z. n- D" c: W/ [
- return HAL_ERROR;' u' K) C$ e f; j8 j
- }; W% L3 x2 v! e# r1 U6 w% H
- }$ m) N7 N; |- D" U
- return HAL_OK;3 C" v( m0 r7 ~+ U, P
- }/ R/ ^8 N$ X# h# Z. {
- /*这里自己实现多字节的ATC02的读操作*/$ P' ^1 X0 L1 H
- HAL_StatusTypeDef I2C_Read_Buffer(I2C_HandleTypeDef *hi2c,\
1 M3 H0 p: T% p* b- r8 p5 A0 R - uint16_t DevAddress, uint16_t MemAddress,\
' V- G" ^+ W+ u; m8 n - uint16_t MemAddSize, uint8_t *pData, uint16_t Size,\( F; L0 M5 T! R3 y1 R$ x
- uint32_t Timeout). p! U ]# \3 J' W% D$ [$ D
- {6 c7 N+ P+ i: u: T) W! M
- uint16_t count=0;( m+ L6 n: E; A! d, W& w7 R
- for(count=0;count<Size;count ++)3 p* ^6 v8 {. C* b' B% X
- {, j# D9 X0 k+ @" c4 Y# ~
- if(HAL_I2C_Mem_Read(hi2c,DevAddress,MemAddress, MemAddSize,pData,1,Timeout)==HAL_OK)8 E: }6 }) \" ]* [9 O4 O+ M
- {
* L0 \2 K1 w; `: \5 ? - MemAddress ++;
- s* s( Z$ l; Q. ]6 L/ k4 b - pData ++;$ S# b& k# J K$ Z0 \/ k% `' t
- //HAL_Delay(5); h' I, D) E5 [
- }
8 |8 k1 P7 o e9 B1 Z7 Y - else
/ Y# l# v1 g2 v6 P* L3 d - {' m% E L. ]2 v% Z
- printf("i2c read is error \n");
2 a- p# y1 Y! y - return HAL_ERROR;9 v9 L7 ~: P7 m: |! y
- }+ @7 r& k8 M8 j$ }+ a
- }
( h1 i* z6 w1 l7 T0 ]4 b; X - return HAL_OK;
1 ?& \- l7 H2 H( W8 ^. t8 O - }
复制代码
8 v3 `+ o3 T- F4 C(4)在main函数中添加测试代码:
7 w4 i' S+ }; O1 C! y8 P- uint16_t num_atc=0;
8 s7 ^: j' a1 ^" c. T7 b - printf("this is test for I2C device read and write in ATC02\r\n");4 b* `( H1 _& ^2 p [$ U
- printf("/**--------------------开始I2C-------------------------**/\r\n");' D' g! \, |& U/ J: @/ b
- for( num_atc=0;num_atc0 i3 g& z; ?4 d( |: G% @. W
- {, e6 ~( f; |( d5 _
- AT24_WriteBuffer[num_atc]=num_atc;0 X. u4 M7 C( t9 i" Y' O/ W
- printf("0x%x\t",AT24_WriteBuffer[num_atc]);
. B" `# @3 `7 r) `7 X# Q# e2 O, j - }
8 w3 P$ U: [. G% | @- ~ - if(I2C_Write_Buffer(&AT_I2C,DEV_ADDR_ATC02, 0, I2C_MEMADD_SIZE_8BIT,AT24_WriteBuffer,ATC02_BufferSize, I2C_TIMEOUT) == HAL_OK)
+ y" Q) \/ r) W2 _# `( s - {% G* W7 p( C# Z. [1 r/ j! G
- printf("write i2c lots bytes is ok\t\n");
6 Q3 H/ L$ v& k - }/ z1 Y4 c# D4 c; h5 p: {4 `8 V3 _
- if(HAL_I2C_Mem_Read(&AT_I2C,DEV_ADDR_ATC02, 0, I2C_MEMADD_SIZE_8BIT,AT24_ReadBuffer,ATC02_BufferSize,I2C_TIMEOUT)== HAL_OK). H3 w6 j$ e, n! Y* o' f9 l
- {
: f/ n) X1 |+ `8 v - printf("\r\n EEPROM 24C02 read data Test OK \r\n");* g. `9 {9 S+ z/ y" D8 g
- }
6 |6 r9 i; K9 o% h. a, U - else
3 J z; j9 k% |/ B( P" }8 ` - {
) j l2 J" Y# V) W B - printf("\r\n EEPROM 24C02 read data Test False \r\n");
' |( j, ]- ^6 n% I# A5 ~" \3 S+ J8 J - }
+ |1 b1 ~5 Z" q5 Y4 A4 q - /*这里使用自定义多字节读函数也是正常的*/5 K3 L" V Q! p: k$ G
- /*
" e% Y- E: u. L; o - if(I2C_Read_Buffer(&AT_I2C,DEV_ADDR_ATC02, 0, I2C_MEMADD_SIZE_8BIT,AT24_ReadBuffer,ATC02_BufferSize,I2C_TIMEOUT)== HAL_OK)' I ` g9 ]( H* Q, k- h- u( R- n9 T
- {) O- h4 F: ~- I4 P! M4 F
- printf("i2c read lots is ok\t\n");
: M0 X; S9 [7 o! @ - }
& }/ F) T- B* L! J( ?) j - */1 P- R. P, X1 L. s v+ g
- for(num_atc=0; num_atc<ATC02_BufferSize; num_atc++)
* D+ ?8 @8 x, m; B5 p1 u1 A - {! t1 I7 F& E+ s: ~6 b
- printf("0x%x\t",AT24_ReadBuffer[num_atc]);
6 @% `5 U% D& V$ ]. l- f - }
4 Z2 A+ B( q2 B - if(memcmp(AT24_WriteBuffer,AT24_ReadBuffer,ATC02_BufferSize) == 0 ) /* check date */; x& ]5 P' M3 C4 d, B# h: x
- {
2 X' N, m5 `1 s% m: s* c - printf("\r\n EEPROM 24C02 Read and write Test OK\r\n");
* N `/ ~6 V3 ^* |8 W$ h( ?* j - }) e" T7 k o0 p
- else
0 Q3 X4 u. M9 D+ A5 d5 u0 J; m - {* i: }8 Y6 Z8 x! z! X
- printf("\r\n EEPROM 24C02 Read and write Test False\r\n");
3 L0 l5 a; T; o - } + m) N. O6 m6 h! a* \2 X
- printf("/**--------------------结束I2C-----------------**/\r\n");
复制代码
% C2 k+ E% t/ Z' q& S( l5 n
6 L& d) o' c v' O7 S# _$ {: v5 r2 V编译上述程序后下载。 04 ------------第四节效果演示----------
- k- o4 T$ |: R! H$ z使用串口观察写入的数据和读出的数据是否一致?
, ?5 Q3 P. ?9 \3 J2 Z# q; A, e5 R' E* B: g. `
可以看到I2C操作EEPROM进行读写都是正常的。 文章出处: 小鸟的早晨 4 y9 o& y. O3 M9 f: y: }* Z$ P
' p& K9 D# K& L s/ e |