|
STM32CubeMx入门教程(7) I2C的读写应用
$ d4 r3 p3 R: x8 Z" P8 U( n2 B+ X导语“本次 教程使用CubeMx配置I2C进行I2C总线设备的数据读写操作,使用EEPROM作为实验对象” 01 ------------第一节 系统要求----------
3 b( k# ]# ]: v- L5 O) u" U/ v•硬件 野火指南者开发板
# C. B. L4 ?4 n i) E9 O! e•软件 6 L" Y1 z, v- a1 \3 `
CubeMx & MDK & 串口调试助手
1 ] Q- r' T+ a% j# I•原理图 ( {0 R( g, b- H7 ?
/ i1 `8 i$ ^* S4 g8 f
E) T0 o3 G2 \# N1 Y' F6 C: D. S9 W4 X" c+ Z
9 m, C8 C8 N/ ~9 J/ d我们可以从原理图中得到使用的I2C1,AT24C02的设备地址的第三位是000,容量是256个字节。设备地址从下图得到: $ |( o- U. H; p; }# U7 A/ F& h$ y7 k0 l
0 @7 {$ P0 r0 ?* n- H
( a* p& `0 C4 M0 ?4 a0 S
/ ^ p, C: K6 h# x" d' ]不带读写方向的使用左移得到的地址为0b10100000->0xA0, 读地址为:0xA1,写地址为0xA0;
% U" \+ |" H. v- W! i注意:(1) 操作ATC02的时候,多字节写入的时候没写入一个字节,延时最小5ms, 多字节读的时候没有要求,页写入的时候每8个字节为一页,共32页。 " J. p3 | f4 O% F) e+ X1 `5 ]
02 ------------第二节 CubeMx的配置----------
% c. C& ^$ G) Q2 B/ n6 t6 w$ W W- ~2 Z7 m. r, C9 q
我们依然使用之前的USART的项目,在此基础上进行I2C的配置,串口的使用是进行EEPROM读写数据显示在控制台上,使用CubeMx进行I2C的配置:
# g6 c. F7 j/ C
0 |; I4 S. G8 u
8 l1 X2 n* m: J4 F. R
# }& F0 I) J& H* O9 gI2C的配置很简单,完成上述配置后生成代码。 : c9 ~5 ~+ k- e& q6 P# l
5 p M6 D( c$ O$ a4 J6 R. Y0 s3 @/ |03 ------------第三节MDK的代码编写---------- 使用MDK打开CubeMx生成的代码进行应用代码编写。 (1)在main.c 中进行AT24C02的相关宏定义和变量定义:
: B1 Y2 M4 q' I. d- #define ADDR_AT24C_Write 0xA0
2 P9 e" E8 G; M# g. A+ K* w - #define ADDR_AT24C_Read 0xA1
! i6 L# T5 N; r% L0 V ?( u+ A, B - #define DEV_ADDR_ATC02 0xA0 //0x50 左移得到的。 s1 O1 ?5 h! M; b+ @6 G
- #define ATC02_BufferSize 256 // 256
" h5 B5 c! F" _6 _. g+ I - #define I2C_TIMEOUT 0xFF& U) w# A5 W" A; q) u
- #define AT_I2C hi2c1
3 n, K% w0 l" _2 \5 G5 Y - uint8_t AT24_WriteBuffer[ATC02_BufferSize],AT24_ReadBuffer[ATC02_BufferSize];
复制代码 3 v' [" s& w; F9 X. _( D1 G2 V
0 b& Z. A/ y* d( }
(2) 应用函数申明: % X# w" [$ N0 d; a) P0 @. O/ L6 \
- HAL_StatusTypeDef I2C_Write_Buffer(I2C_HandleTypeDef *hi2c,\
5 c5 z T" T3 e$ n$ v& F - uint16_t DevAddress, uint16_t MemAddress,\
7 m/ H& o5 h$ ]* ]1 C& ] - uint16_t MemAddSize, uint8_t *pData, uint16_t Size,\
/ v1 K0 W8 H/ L" V9 a' ^, R - uint32_t Timeout);
+ ~7 n0 R$ D/ w; C3 s* [: u - HAL_StatusTypeDef I2C_Read_Buffer(I2C_HandleTypeDef *hi2c,\: p. \) e- Q1 `2 }4 x
- uint16_t DevAddress, uint16_t MemAddress,\& B# x# J9 f+ J( U; ?; r/ b
- uint16_t MemAddSize, uint8_t *pData, uint16_t Size,\
6 k2 Z3 e( x$ `. Y - uint32_t Timeout);
复制代码
. @. O4 B# n# ?9 v+ j
$ j$ _# E* e! @I2CWriteBuffer()是自定义的任意字节写入I2C-AT24C02的函数,I2CReadBuffer()是任意字节读写函数。这两个函数的实现采用HAL库的这两个函数: 1)HALStatusTypeDefHALI2CMemWrite(I2CHandleTypeDef *hi2c, uint16t DevAddress, uint16t MemAddress,uint16t MemAddSize, uint8t *pData, uint16t Size, uint32_t Timeout);
$ |* P+ a, f" S& u参数依次是:(I2C句柄,AT24C02的设备地址,设备中数据地址,数据地址的大小,写的数据,数据大小,超时时间)
& ]/ P- }, n5 M$ Q9 A9 j2)HALStatusTypeDefHALI2CMemRead(I2CHandleTypeDef *hi2c, uint16t DevAddress, uint16t MemAddress,uint16t MemAddSize, uint8t *pData, uint16t Size, uint32_t Timeout); $ c. D: m& T W2 m4 j1 L
参数依次是:(I2C句柄,AT24C02的设备地址,设备中数据地址,数据地址的大小,读出数据,数据大小,超时时间)
) x8 m8 {" A$ S# ~& O4 J( V3 W为什么不直接使用库函数呢?是因为在测试中AT24C02读写不正常,查看AT24C02的手册发现,单个字节写入没问题,多字节的写入需要每个字节延时5ms, 其实多字节的读没有问题,这个从新实现了下。可以连续8个字节的页写入,这个不需要延时。
/ k- O- O* N1 g2 ?. t(3)多字节的读写函数:
" J# K5 f" c7 h- Z, ]- /*这里自己实现多字节的ATC02的写操作*/4 S$ i3 b" n% A. p
- HAL_StatusTypeDef I2C_Write_Buffer(I2C_HandleTypeDef *hi2c,\
3 o, n% ]# i$ F8 L3 E - uint16_t DevAddress, uint16_t MemAddress,\
1 U! h' ]8 Q U4 c0 u' q - uint16_t MemAddSize, uint8_t *pData, uint16_t Size,\- {5 t; ~8 ^& w) o" j! k; j, Q9 u
- uint32_t Timeout)
- G# E" |9 v9 t7 ?" _4 r/ @: ^ - {/ B5 \2 Y. }5 A# e' |" L/ H/ u7 {+ q
- uint16_t count=0;
~ b5 h# x# ]0 N - for(count=0;count& Z$ x `, K+ V+ y
- {0 B) @) k. f+ m, L. x- i' [
- if(HAL_I2C_Mem_Write(hi2c,DevAddress,MemAddress, MemAddSize,pData,1,Timeout)==HAL_OK)
9 L- {6 D7 V/ K2 s3 z2 f( z - {
- b; ~3 s+ F! @ D - MemAddress ++;
T# P- |( I- G: m - pData ++;
# G: @! w. ^% v - HAL_Delay(5);7 V% [; R+ \0 g6 _* u/ [& ~, }% \! U
- }
! o3 p7 s4 T- |# w* M# N* N" _: | - else
* [9 ^/ O, y3 \$ L8 ? - {
# g2 a9 H! T8 ^& X4 n! e; x k9 [ - printf("i2c write is error \t\n");# B% s5 V K- ]
- return HAL_ERROR; P, R5 w) |" O4 u8 f" i$ G1 S1 e, T
- }
" l; D. n; M( I, D# j- } - }/ f- b6 q+ t V: T, U% M+ g# q
- return HAL_OK;
9 B6 v; e- j# y; w - }
) x. N1 ]4 ^# B9 c7 ]$ u" u# A5 H - /*这里自己实现多字节的ATC02的读操作*/
7 x9 |2 j( T+ s# m4 @ - HAL_StatusTypeDef I2C_Read_Buffer(I2C_HandleTypeDef *hi2c,\
' N5 g7 M* r, y7 p/ X( C$ Z - uint16_t DevAddress, uint16_t MemAddress,\
* y! x/ r# p+ j2 ~ - uint16_t MemAddSize, uint8_t *pData, uint16_t Size,\% Y- r M% q# \
- uint32_t Timeout)
6 c+ X7 a4 E Q% J - {3 ]1 [( W _2 R
- uint16_t count=0;
0 q2 @# O ]4 t - for(count=0;count<Size;count ++)
2 w* f/ ^# i, V' E( t - {* ~+ n& Y* m1 J' D2 @. H; ?
- if(HAL_I2C_Mem_Read(hi2c,DevAddress,MemAddress, MemAddSize,pData,1,Timeout)==HAL_OK)3 \% N+ B$ H; j8 R* Y
- {
- V3 h, X1 Z$ A) N# A& v9 Y - MemAddress ++;( K; r. V, B& n( p
- pData ++;
7 }+ P: w: {: {6 I- W3 p ~ - //HAL_Delay(5);( T) t- ~2 J* U5 q6 F: N
- }
! h* K! I# P3 c$ Z) O - else
/ s# s% y+ L5 A' M7 k( ]2 e" r - {
( u6 u/ v6 u! S% u3 n' ~) _: _' I - printf("i2c read is error \n");
8 h* ~3 P9 q1 @* ]) \% H# u' J - return HAL_ERROR;
3 I5 H, L5 G% E - }; V% j; l7 P' f. G' \" Q
- }& W% I1 _# N$ K; I, Q& x( \
- return HAL_OK;
9 |5 [( j# f; C8 i# \2 t _7 j - }
复制代码
( ^! g5 ~. T5 z7 R8 Z: g0 c3 h(4)在main函数中添加测试代码: 6 a. q# ?5 g6 w7 {9 U
- uint16_t num_atc=0;, w3 J: Z3 S( {. }! t5 c& S8 w7 B% n
- printf("this is test for I2C device read and write in ATC02\r\n");+ V/ G, y1 Z0 ^. N |
- printf("/**--------------------开始I2C-------------------------**/\r\n");2 B. f0 [3 q1 Y( Y
- for( num_atc=0;num_atc) D; N# S/ c& }, b4 N9 v1 x
- {
4 J1 [! Z1 U2 s9 a5 J# Q; V - AT24_WriteBuffer[num_atc]=num_atc;3 X4 h$ g% K& N6 t3 _! x
- printf("0x%x\t",AT24_WriteBuffer[num_atc]); $ e1 p/ K! Z6 g6 z
- }6 ~4 C7 x) j* c: n; A) _8 z
- if(I2C_Write_Buffer(&AT_I2C,DEV_ADDR_ATC02, 0, I2C_MEMADD_SIZE_8BIT,AT24_WriteBuffer,ATC02_BufferSize, I2C_TIMEOUT) == HAL_OK)/ S+ S. y* V, S* ~) [
- {& Z4 _* F5 i: A/ m' o0 q
- printf("write i2c lots bytes is ok\t\n");
: ^. L' ]2 M' ?7 S2 ? - }5 b- S/ J; h1 J8 ]' E- Y7 g) f
- if(HAL_I2C_Mem_Read(&AT_I2C,DEV_ADDR_ATC02, 0, I2C_MEMADD_SIZE_8BIT,AT24_ReadBuffer,ATC02_BufferSize,I2C_TIMEOUT)== HAL_OK)
, r* V2 t# L! D/ ] - {
% w* s( U/ z/ R4 x Q) ] - printf("\r\n EEPROM 24C02 read data Test OK \r\n");
$ @* g n# s3 s8 y/ E. z* S - }
$ k5 H5 T- I6 A - else
( K/ M0 P `5 m; d - {: V+ c" G( @) ^+ G3 p5 x5 d1 X
- printf("\r\n EEPROM 24C02 read data Test False \r\n");
3 [* V) i _+ Y* { - }( Y8 z2 e9 I+ ?$ s8 q5 M
- /*这里使用自定义多字节读函数也是正常的*/( M6 S, l& Q8 d1 a _
- /*
2 Y1 c, L8 ?, W9 w% J* c- Q4 P - if(I2C_Read_Buffer(&AT_I2C,DEV_ADDR_ATC02, 0, I2C_MEMADD_SIZE_8BIT,AT24_ReadBuffer,ATC02_BufferSize,I2C_TIMEOUT)== HAL_OK)
& v/ w( {& ?. P7 M, v0 N |: a - {) @/ m0 M3 _1 A9 Z! }
- printf("i2c read lots is ok\t\n");# h) k# c1 `! Z! K7 M) A
- }, V+ r) r* R1 K% }7 g6 N
- */) z; f( D' ?, H- d& T
- for(num_atc=0; num_atc<ATC02_BufferSize; num_atc++)
3 O% l0 g) V% y+ p3 Y# H8 M4 C. T5 g - {
& n+ `; I9 T3 D8 C; X S7 ~ - printf("0x%x\t",AT24_ReadBuffer[num_atc]);/ ~3 I. U8 z9 N c1 Z0 o' Y* W
- }( ~8 H: X* i4 _% O( Y0 D
- if(memcmp(AT24_WriteBuffer,AT24_ReadBuffer,ATC02_BufferSize) == 0 ) /* check date */
% }1 V( F! R% s5 z# ~ - {0 Z; d1 H1 y$ [& \- |8 B
- printf("\r\n EEPROM 24C02 Read and write Test OK\r\n");0 y0 q- a: ]& N7 C: I
- }+ C4 a6 ^9 t& @% @' [* ]* |2 R3 l2 Z
- else; r) F% P8 w) s9 r) }2 Y: F
- { c ?( O) H' v& I7 B) J
- printf("\r\n EEPROM 24C02 Read and write Test False\r\n");' v, @. I" w4 O$ f/ e9 T/ G
- }
/ g4 M: U1 Z' w! J8 y7 G - printf("/**--------------------结束I2C-----------------**/\r\n");
复制代码 1 @" j/ T- F2 E* d+ _ O. p
: ^* ^& {& v) e, }( ^- ~" E8 @0 q
编译上述程序后下载。 04 ------------第四节效果演示----------
! y: i0 ~% k& j$ y使用串口观察写入的数据和读出的数据是否一致?
5 N' e8 c; x; N+ {
& m/ T1 o2 O, j' Y可以看到I2C操作EEPROM进行读写都是正常的。 文章出处: 小鸟的早晨
4 Y7 r7 v9 i. i2 X9 K; p7 e! {( p, y9 Q3 w3 T
|