I2C配置顺序引发的异常案例
l I0 w" }0 m) k1 ]; E6 w% C5 S( S# |" F1 H/ B5 l
基于stm32的I2C总线通讯简介及使用操作(附代码); e/ E, L6 ?, k$ l; k
; z: a# p! V0 [1 i& C: A
分享关于STM32f103 的硬件IIC I2C 调试心得 {# e% d: C' _5 Y! U+ X
2 [" h( k" S0 f5 V& n* N* Z: C4 Q% u% m$ d
楼主前段时间苦调UV传感器,无奈硬件I2C怎么也用不起来,楼主水平还是太弱,无奈只好转入软件模拟I2C,不过话说模拟I2C的波形似乎要比硬件I2C的要好很多呢。调好的代码与大家分享下。。。源模板是哥们做好的读取E2的代码。
( p P# Z0 ^0 R8 h1 z" _- #include "stm32f10x.h"! q) f+ }) N" R v: E
- //=============================================================================== f3 Z- ]$ D8 Z/ u
- //GPIO 模拟I2C ,操作EP2ROM IC(AT24C02)
; m$ i) `/ S6 y* V d - #define E2PROM_SDA GPIO_Pin_76 L% L) U) g- |3 Q% W- C
- #define E2PROM_SCL GPIO_Pin_67 z$ c1 {/ R6 R4 S" F; n) U
- #define E2PROM_CMD_WRITE 0xa0
' ]. D5 y* o% d" M/ Z! R$ t - #define E2PROM_CMD_READ 0xa1" U( U+ p8 i0 Q. o. C3 [; X( B6 h
- #define I2C_DELAY 254 // : s6 J7 @ v" o7 w
8 \6 H. S! v& v, k5 e3 q- I2C延时
' T( @9 I4 C! e+ j - . K; m9 k' x- {: y5 g/ U
- static void' P! @) Y4 q, k+ B. V, r
- DelayMs(uint8_t uc)6 V& ?6 R s8 A. h. U
- {2 W, c* _- R3 [4 C
- uint8_t i, j;
- k' J7 D/ h- U* b- Y
0 u; E" G3 S9 U" }4 w- for (i=0; i<uc; i++) {0 J" e6 r% x1 X* Q5 U1 v
- for (j=0; j<I2C_DELAY; j++);
3 ~. K! d/ J0 b% p, B - }
7 j; e. t) q, ~; n - }: `1 p; u+ T: ]5 n1 s/ p
- /*************************************************************
2 a/ z# ^) ^4 D3 V" ^% E! d% f - *函数名称:I2CStart 7 Y% |8 m K/ O; c* p [6 N
- *函数功能:I2C开始信号
6 ]+ v9 P# R1 e5 J7 v8 U; [; ` - *输入参数: % k t6 T! t- d! D ~6 B: l
- *输出参数: - r1 N3 M, \6 z7 r( S& q% d0 P3 L
- *备 注:时钟线高时,数据线由高到低的跳变,表示I2C开始信号 ) ]; J5 l- b3 D1 m
- **************************************************************/
, `6 a! g: N/ b - void I2CStart( void )
% r- U" Q8 a: {3 W" P - { ) W8 _. z& T, c- V) ~% T" f& z
- GPIO_SetBits( GPIOB, E2PROM_SDA ); . q% f/ f4 d; u# s
- DelayMs(1); / T8 o" i( w" o) H2 f7 \% B
- GPIO_SetBits( GPIOB, E2PROM_SCL ); : @6 P3 Q* w' B: A" V; J5 |
- DelayMs(1);
: y8 T- w ~! p8 Y - GPIO_ResetBits( GPIOB, E2PROM_SDA ); : c5 U" D6 ]* X5 K$ h: I
- DelayMs(1);
& B5 ~' E% r8 H - 9 e2 h! F* E$ ]% h9 g
- GPIO_ResetBits( GPIOB, E2PROM_SCL ); 3 Z: I: |! i4 }9 F7 N
- } ; c$ f4 X# [4 O4 f# k9 A
- 9 @( e( i8 m& v( T
- /************************************************************* # l* V- G7 E. M6 o
- *函数名称:I2CStop * N+ @& y2 k8 `' o
- *函数功能:I2C停止信号 * ~: o9 `# Y2 l3 G" ~4 x3 l/ e+ A. }
- *输入参数: % n" _6 X/ [: p- I1 Y
- *输出参数: . V4 u$ b+ W% D9 r% I
- *备 注:时钟线高时,数据线由低到高的跳变,表示I2C停止信号
7 Y7 ~; H5 @: d9 H, u - **************************************************************/
, k- x, b3 X C, c - void I2CStop( void )
4 N+ Y8 {( m+ j+ `' |2 n# i8 _ - {
, T1 I8 }/ `7 v+ k( d- v! H - GPIO_ResetBits( GPIOB, E2PROM_SDA ); - ?1 w& a2 @) v, `8 O
- DelayMs(1); # P9 D$ W, R6 I. x6 Z& Y0 n
- GPIO_SetBits( GPIOB, E2PROM_SCL ); ( d8 A6 _ d" M6 L. |% H; Z! B. X
- DelayMs(1);
9 G7 T7 q4 F0 M" }; F6 R1 Q2 @ - GPIO_SetBits( GPIOB, E2PROM_SDA ); & O+ w# t: n' I
- DelayMs(1);
8 D @ k# T2 w2 R$ d) J
- y& E) h7 J1 {& D3 I, d- GPIO_ResetBits( GPIOB, E2PROM_SCL ); ; G& J/ P3 U* T
- } ( F( H/ T& A2 E' N8 q; v& C
- ( Q" S" C! n; D- R/ V* c
- /*************************************************************
' e$ X0 E# J: u( r7 ~& `! E6 y - *函数名称:I2CSlaveAck ; F5 y* J9 l! ~. i! M
- *函数功能:I2C从机设备应答查询
; @- i) `. [0 ~. i, h/ D - *输入参数:
: Z/ D5 ]+ X# L) a% l6 t - *输出参数: % H% o$ v0 f* M. n5 u
- *备 注: 7 h6 Z# {& Q1 Y- \1 S5 `
- **************************************************************/
% N* W, ^' q' Y) v% l1 }* V8 i0 Y9 @ - unsigned char I2CSlaveAck( void )
. t; K1 y: i$ j+ S' P; P - {
* W! p5 r/ t9 c! ]$ I - GPIO_InitTypeDef GPIO_InitStruct; ( H7 I" S/ m. L9 Q
- unsigned int TimeOut; " V8 e! L: } k0 h" ]5 ?! e
- unsigned char RetValue;
+ ^' s# I. l4 y0 V0 Y, p6 ^4 P - 5 Q, f: t6 e( L& B& E
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; /*这里一定要设成输入上拉,否则不能读出数据*/
# |+ r* r* b0 H - GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
% V* |8 i( b7 ]* ^ - GPIO_InitStruct.GPIO_Pin = E2PROM_SDA;
u! p/ O& l2 \# U6 N5 } - GPIO_Init( GPIOB, &GPIO_InitStruct );
) l( y. X* f2 s# `. F& A - 0 u/ L# ]& a0 |, s3 O$ t
- GPIO_SetBits( GPIOB, E2PROM_SCL ); 6 m \/ d4 T1 a
- TimeOut = 10000; 4 F1 C) O- i" A; @. v z
- while( TimeOut-- > 0 )
# X" r& {4 L5 g# p5 m, A1 e - { }8 \3 k1 S! I! Y
- if( SET == GPIO_ReadInputDataBit( GPIOB, E2PROM_SDA ) )
, {! u( Y$ J8 k' V2 b1 |9 Q - {
! n2 x( u' }2 g& d# w4 c - RetValue = RESET;
# a1 _! X+ J) K9 `- ] - break; % b1 q- [& l E4 V
- } 8 N4 H- N1 U0 N
- else 9 Z8 \# l8 a; \ b. |9 B9 _/ _; I0 s
- {
( h4 e7 X1 ?. z: T! b/ m - RetValue = SET; % U+ Q2 ~# o2 a$ [. ~( i
- }
2 f5 s, x* c9 i - }
! Y' p# Q$ p. q, G - GPIO_ResetBits( GPIOB, E2PROM_SCL );
3 A$ t1 ^' L! _5 W" \. e; q, q - 2 {6 {2 {9 H' [/ U
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
/ `" K N% d- p3 x8 Z7 N - GPIO_Init( GPIOB, &GPIO_InitStruct ); ! M+ f4 p( R% R/ U; {
- return RetValue; 1 Z H/ B, a3 Y' g! U* s
- } / t0 G6 R9 {! h f# V8 ?% R6 m
2 X- Y& v3 n1 d; s7 h- /************************************************************* ' a7 Q1 h7 q6 g. ?$ W/ R$ d
- *函数名称:I2CWriteByte
4 D) K Y9 p" |( C - *函数功能:I2C写一字节数据
8 i- a9 M8 m4 b$ |5 { - *输入参数: 0 d" r" ]3 y5 l* y9 C
- *输出参数: 7 n: v3 K8 c0 o! n
- *备 注: 2 c: J# E" \, f4 e) R! ^7 j/ R
- **************************************************************/
D% V0 g2 G' R. n( f - void I2CWriteByte( unsigned char byte )
; m2 B/ P5 r1 B \4 z+ z - {
' H! E& s# e* m) p - unsigned char i; % [" K1 `; g6 T X+ J3 a
- 8 M: `- K7 U/ K" S7 G( i7 H0 T3 M
- for( i=0; i<8; i++ )
: r) M, _% f8 B4 _/ d/ ?) C - { 8 W7 g' {: C: }* O
- if( 0X80 & byte )
! _) C: K# ~5 {9 M% i4 r6 K - GPIO_SetBits( GPIOB, E2PROM_SDA ); 3 d, r* y- j0 q) Z8 |& o* b
- else % F+ W' R: N1 s
- GPIO_ResetBits( GPIOB, E2PROM_SDA ); . T. [# Q; P" ~3 k3 s% s- I
- byte <<= 1;
* A/ A9 I8 g" r - DelayMs(1); 0 d: C6 ?( F2 b. K
+ n! M- ?0 p" P) D- GPIO_SetBits( GPIOB, E2PROM_SCL );
% f5 U1 P/ L J* r: a6 n D - DelayMs(1);
; u. g9 j; d1 g. u0 [/ j - GPIO_ResetBits( GPIOB, E2PROM_SCL );
5 D2 v& X: }" n6 n! v - DelayMs(1);
2 W7 ]% `3 a% h' O1 W5 \& x5 u3 C& u - }
( q8 I) Y& r" F5 P5 x# e - }
1 c c/ u' a; z( w$ l - + l! p% k( X2 I: V/ j- f4 B" ]
- /************************************************************* 1 A1 z: x$ R# e, D/ r( G" s
- *函数名称:I2CReadByte 3 H1 O" x) x' i7 U! @% x- @# H
- *函数功能:I2C读一字节数据 7 o! P! Q% @7 M. _ d6 L2 c
- *输入参数:
' S5 g6 E3 M# T5 m - *输出参数:
% k: k$ ~5 P% s7 N1 o2 ]" z9 l! G - *备 注: d$ A- K. H" S% f% A ~6 m
- **************************************************************/ 8 S. {0 Z4 C6 }
- unsigned char I2CReadByte( void ) ; M2 v. V! P+ `" L
- { " R; I: I" P& _# t
- unsigned char i;
) H7 f1 [4 Z2 E; I$ @( i - unsigned char ReadValue = 0; 2 e6 X. Q h" |2 R$ `4 f3 s
- GPIO_InitTypeDef GPIO_InitStruct; / C7 E0 p# m, N$ g. o% s2 K5 i
- unsigned char bit;
1 p' w0 L5 a( P y - ' Y% D. a( K& f6 }
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; /*这里一定要设成输入上拉,否则不能读出数据*/ 1 V, h( k5 @- H+ Y0 C) n- f- e
- GPIO_InitStruct.GPIO_Pin = E2PROM_SDA; & v; s! f" i( z* Y& P }& c* K& `3 v
- GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; . \) i5 p: K2 G" G9 h& f* [6 J4 C
- GPIO_Init( GPIOB, &GPIO_InitStruct );
1 q& i" e0 ? Z' Q - for( i=0; i<8; i++ )
4 N# R" Q) N: {1 U! r2 H - {
d% M) q6 p1 k+ R - GPIO_SetBits( GPIOB, E2PROM_SCL ); ! z0 j8 Q% p3 U
- DelayMs(1); : S5 U1 w! J7 n9 o! z9 T- u
- if( SET == GPIO_ReadInputDataBit( GPIOB, E2PROM_SDA ) ) 2 z3 Q \8 a- P0 a2 L6 K2 T; s
- bit = 0X01;
# F: m7 ?7 H8 N4 M - else / q) H' v/ U, a9 H. P4 y
- bit = 0x00; ) G2 z) D& d$ z# B2 R5 ]* m
-
1 k9 w- c1 i* g - ReadValue = (ReadValue<<1)|bit;
/ e0 B( A% Y5 M: p) {% D% J8 _ - GPIO_ResetBits( GPIOB, E2PROM_SCL ); - u. S. z8 h& } [0 w0 V: Q
- DelayMs(1); - O' F8 L) c1 E o4 i9 ?$ H. P2 J: i
- }
0 S, T/ v( s! y1 _% A. W - 1 h1 E: }! Z6 p) U' I* y
- GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; ! z) m2 t) p V* K* J# q
- GPIO_Init( GPIOB, &GPIO_InitStruct ); . K4 ~; ]0 {+ O/ k9 j
- return ReadValue;
3 h: j2 ^, ~% r5 J - } ! U" J3 A5 z& z
6 }: z" K* q. T" r- /*************************************************************
# W$ s/ M8 @1 W% @4 U# `1 K - *函数名称:E2promWriteByte
- E3 r# v7 s4 E- T, p: _* W - *函数功能:E2PROM指定地址写一字节数据 - _/ P* G1 H; q* N* E
- *输入参数:addr E2PROM地址
6 S- n2 ^; m9 Y% m5 c: f - data 写入的数据 ' {" Q) W) z9 X3 A' g6 ~/ h1 P
- *输出参数:SET: 写入正常;RESET:写入错误
, k: V0 q: _$ w' J9 I - *备 注: $ E- z+ [ v/ T, Y% S4 R
- **************************************************************/
0 h* Y( j4 r. [9 v - uint8_t E2promWriteByte( uint16_t addr, uint8_t data )
3 x* R5 L: I* Y q( T5 L2 z1 r - { / V6 J. K2 ~/ P/ {4 Q+ E
- //asm("CPSID I"); //关中断
f* |' [1 y( J: Y - I2CStart();
& {1 F1 L+ e5 G, Z& g - 5 m) C/ K" ^. {0 ?- ]- i
- I2CWriteByte( E2PROM_CMD_WRITE );
& c- q( C* ~+ B9 r; U$ C* v - if( RESET == I2CSlaveAck() )
7 D5 _8 R# w. p2 S% \2 l& }7 J - { 9 f. _2 |; x) q% J+ M
- return RESET; 9 Q! x# l) t- ~, T1 o
- }/*3 X+ Y9 R' t4 [- q# e1 C
- I2CWriteByte( (addr >> 8) & 0xFF ); ! F! ^) k0 l: k1 @
- if( RESET == I2CSlaveAck() )
2 u# r. m5 [. ]+ h - {
: H1 T( {( a, S4 \( z - return RESET; ' `1 F1 g& [$ l) ?) I2 G- G0 H- k
- } */
. w0 [: m) E s7 x9 y - I2CWriteByte( addr & 0xFF); 0 @ e1 L0 W& Y9 @+ N5 `
- if( RESET == I2CSlaveAck() ) . I( ~8 D; d, x( l: H
- { & |: M4 A7 d l R8 h" I+ |
- return RESET;
* S+ a4 F5 f5 p) y! G. ?+ i - } ( U# g- d# s& @
- I2CWriteByte( data );
% \/ ?: z$ e; O9 o+ G+ }. n; d% m, `+ v - if( RESET == I2CSlaveAck() ) 1 a* O9 R5 j# U# k( x
- {
: O3 a3 ~6 }' q4 n$ Z: d - return RESET; ( V p) t$ B1 u1 |, Q8 T: b. J
- } * p+ A& C. ~8 H6 \, U
- I2CStop(); S3 _0 K" y! i9 ~3 `9 I5 A
- //asm("CPSIE I"); //关中断
1 z% p6 Z. _5 F - # o& N# g- s% h! d+ l1 z) [& Q) m
- return SET; 9 X. U: |! n' a4 P) L7 d
- } 5 [! `4 A8 b# \4 ]& a( p
/ j& F; n1 r0 c1 B' \( g$ R- /************************************************************* 9 V3 N) _% l* j A# p; S% x$ ?' \ a1 b
- *函数名称:E2promReadByte ; Y, s4 U% u( }$ p! ] i8 S& ^
- *函数功能:E2PROM指定地址读一字节数据
1 y& d( F/ t5 p" f - *输入参数:addr E2PROM地址
/ ^+ L; a$ h% {5 \$ ^- r* W4 ^ - *输出参数:返回读出的数据
/ b! z$ ]0 C/ u1 y, b* l - *备 注:
) k; Z3 x+ q$ Y8 W- ^! ` b' |' } - **************************************************************/
7 ]6 a1 I- u/ z/ j7 d - uint8_t E2promReadByte( unsigned short int addr )
' P, Y) t8 y& [' M: [9 a) G - {
8 s, r& P' W1 `/ U) v, u. ~% G0 K! m' y - unsigned char ReadValue; 5 u0 `, d! e7 S5 r
- - g' x6 `6 t* S$ ]
- I2CStart();
$ ?% m8 }# P4 r ]' Q
X) y6 B" ]# N- g- I2CWriteByte( E2PROM_CMD_WRITE );
. h" Q' Z" n, [) {2 h - if( RESET == I2CSlaveAck() )
/ V3 q# _% x, D/ C5 _ - {
T/ l: J8 V0 Z( G) e& U9 H - return RESET; 2 T! n6 c: U! i3 l! }
- }/*' H4 O2 b# n: d. b* [9 s8 U
- I2CWriteByte( (addr >> 8) & 0xFF );
$ u8 U6 A/ z# y7 n/ W: i$ S - if( RESET == I2CSlaveAck() ) 8 @$ h+ ^0 b- I
- {
1 m+ r* r6 O6 | Q5 O+ C# j/ X- K - return RESET;
+ a% M" _4 w6 k% n3 x - } */
* A0 t& a; L# U9 S - I2CWriteByte( addr & 0xFF );
- S' v6 S8 Z! o) W# r. g - if( RESET == I2CSlaveAck() ) : V: q) V8 }. S7 p$ D: _) u
- { ) O8 C( [5 G6 F* e1 `) ^
- return RESET; 6 G& `7 G. ~+ _" I0 K* _1 R" t0 l5 ^9 C
- } 0 d6 k; O% i; x6 S/ `7 \+ h
- I2CStart();
7 g4 R' E! H1 m8 s; w- x% i - I2CWriteByte( E2PROM_CMD_READ );
0 e( k& K/ h0 a" F; l - if( RESET == I2CSlaveAck() ) $ \) A+ U S4 Y
- { / T# p! i7 E5 |9 D" m
- return RESET;
b& E8 T- _2 Y7 H: \8 `& Q - }
, K# ?0 H% e: S6 k2 F4 B - ReadValue = I2CReadByte(); # K- f3 P2 [, A
- I2CStop();
- f2 I4 e( d0 m; q - ; G- D5 n+ F& S' s1 E$ c
- return ReadValue; ) Q6 {* X7 D/ R0 \( ?3 h* ]
- }
复制代码
0 M) U. j, r$ h @1 d- g0 ^' j% g0 c5 ]0 H9 P9 S U
|
) }$ I+ Q7 }& G/ X
41.*函数名称:I2CStop 5 z9 S: T3 t* o5 a% C1 E, o
42.*函数功能:I2C停止信号
+ S- y/ H7 \$ O
43.*输入参数: 6 }" ^3 M8 w: H% n) R5 Z& g
44.*输出参数: ! I% n# I5 B; F
6 L& f+ f, K% F8 M# R8 t& T
45.*备 注:时钟线高时,数据线由低到高的跳变,表示I2C停止信号
46.**************************************************************/ v* V; d$ Z1 `3 D9 V9 f, |0 k# C
0 ]: H, V, [+ _ e" \6 M9 \ y, p
47.void I2CStop( void ) 5 ^3 C4 W8 A! D; p. V$ c
, S4 T H2 u4 u. T
48.{ 6 w6 k$ G- D W) [8 W
+ E2 q6 Z$ O. m" p
49. GPIO_ResetBits( GPIOB, E2PROM_SDA );
50. DelayMs(1);
5 O/ d) `$ d& Y2 o
51. GPIO_SetBits( GPIOB, E2PROM_SCL ); 0 M7 W7 `' V M
8 K/ {( ]1 [' \2 v5 c( \8 _$ N8 K9 e
52. DelayMs(1);
53. GPIO_SetBits( GPIOB, E2PROM_SDA ); - A! P/ Z' }1 T% k7 N
54. DelayMs(1); 5 @' T% h/ U# n- w* g; ~! p. O
, ^/ X% @ [8 k* U
55.- T: Q; |* g* a, n
- q4 T0 ^1 v2 K6 S1 `
///这句不要56. GPIO_ResetBits( GPIOB, E2PROM_SCL ); 1 y# c0 V, d. c- _9 S* v
" h7 U, O& g% X9 I2 o" \8 p0 a
57.} 0 o1 H8 U# L% j+ t8 X
嗯,十分感谢。。。
以后还是得和大家多交流,不能闭门造车,我那个硬件I2C自己吭哧吭哧搞了半个多月,也没结果
F4上的可用?' t* C7 F9 S$ Y( K/ z9 V. N
为什么我的就死活调试不通呢,从器件无法响应?
嗯,分享下经验" x3 j9 v2 H) x0 g8 s% K+ T! @
我们不能屈从权威
额,我一个4系列的也用的是模拟I2C,硬件的死活不通,记得有人给我说过是有问题,可是我的就是硬硬的不通,怎么破
每个人对资料的理解不通,你理解估计有极限
确实,所以还得仔细揣摩下,到底哪儿出问题了
嗯,多多交流
我是在加ST币的