你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32——IIC通讯应用

[复制链接]
gaosmile 发布时间:2020-6-4 15:27
  说到IIC(也叫I2C,其实都是一样的)通讯,是一种最简单的通讯协议。在学习STM32时第一个接触的就是串口USART通讯协议,接下来就是IIC通讯协议了还有的就是SPI协议,SPI我们下一章再说,这一章就说说IIC吧。很多模块都用到过IIC通讯,最常见的就是4针的0.96寸OLED显示屏,当然啦在学习STM32是我们一般最先接触到就是通过IIC来与EEPROM进行通讯,但是本章我们只讲协议本身。

; A8 P( M$ e8 n$ I" n& r1 p
一、 IIC 简介
8 c5 ^: M3 l9 i  e: F6 z) K& z8 j+ q* z

- R2 ^$ p. m7 I* @7 B9 Q; J- F
  IIC(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。它是由数据线 SDA 和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与 IC之间进行双向传送,高速IIC总线一般可达 400kbps 以上。
  k' |2 w5 `9 e- |, B! w  IIC 总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。$ F" O' Y3 n; Y8 ]9 b
  开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。
: q- S! i4 i1 G  x% G) ^) i$ d  结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。2 i& j0 l. E0 d& C4 B) t8 b! d
  应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。这些信号中,起始信号是必需的,结束信号和应答信号都可以不要。
5 x) [6 z/ u# I9 K' ~. H0 D
微信图片_20200604152455.png

7 x# j- F3 H. f$ W$ z* [6 R  IIC使用 SDA信号线来传输数据,使用 SCL信号线进行数据同步。SDA数据线在 SCL的每个时钟周期传输一位数据。传输时,SCL为高电平的时候 SDA 表示的数据有效,即此时的 SDA 为高电平时表示数据“1”,为低电平时表示数据“0”。当 SCL为低电平时,SDA的数据无效,一般在这个时候SDA进行电平切换,为下一次表示数据做好准备。每次数据传输都以字节为单位,每次传输的字节数不受限制。8 t! \( x9 V6 q) @
  如果我们直接控制STM32的两个GPIO 引脚,分别用作 SCL和SDA,按照上述信号的时序要求,直接像控制 LED 灯那样控制引脚的输出(若是接收数据时则读取 SDA电平),就可以实现 IIC通讯。同样假如我们按照 USART的要求去控制引脚,也能实现 USART通讯。所以只要遵守协议,就是标准的通讯,不管您如何实现它,不管是ST生产的控制器还是ATMEL生产的存储器, 都能按通讯标准交互。
# v7 s9 j1 c; V+ H) ]5 }6 k6 ~4 z  由于直接控制 GPIO 引脚电平产生通讯时序时,需要由 CPU 控制每个时刻的引脚状态,所以称之为“软件模拟协议”方式。相对地,还有“硬件协议”方式,STM32 的 IIC片上外设专门负责实现IIC通讯协议,只要配置好该外设,它就会自动根据协议要求产生通讯信号,收发数据并缓存起来,CPU只要检测该外设的状态和访问数据寄存器,就能完成数据收发。这种由硬件外设处理IIC协议的方式减轻了 CPU 的工作,且使软件设计更加简单。

% s2 F- }6 W- h4 ]1 l8 V
二、 软件模拟协议! w3 T9 Z# S9 s& c  B3 s- v

1 \$ v: c. M3 R! F' n

5 ^% t* s7 j- m* B* |" y6 X; R3 ]4 G1.IIC初始化函数) _8 Z* g9 [6 t  U+ ]# n' M- j6 b
$ l! n6 Y+ j! [" g2 L% X4 }* l' K0 ?4 o
& Y* e7 l+ W1 d: D  H. P" f+ F
功能:配置IIC的时钟线和数据线

void IIC_Init(void); h9 |/ M7 G' D( Z7 I5 C
{                         . P& c( V6 g" E, P5 S
    GPIO_InitTypeDef GPIO_InitStructure;3 z: G" M% @! L( D) V% O: O$ x
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE);         ' k$ ^; l6 K$ Z: Y, P5 a* T
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12;+ i4 h) t% [& b) J0 M. N0 J9 l$ a6 }
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出2 Y( X4 I6 H2 U
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;# h/ {8 @- F: O/ f9 D- J4 U& e
    GPIO_Init(GPIOC, &GPIO_InitStructure); 3 y% s. |7 S6 c" `9 [5 o
    IIC_SCL=1;
4 N. N. X- q; j    IIC_SDA=1;
0 f, p  P1 H7 n3 l}


# k2 ]2 [  @6 }% @7 ?( X$ _7 {
微信图片_20200604152459.png
  
       因为是软件模拟IIC那么我们选择IIC通讯的引脚就相对来说说比较随意,具体使用的引脚可查阅《STM32F1xx 规格书》,以它为准。这里我们就选择PC11、PC12作为IIC的数据和时钟引脚。设置为推挽输出即可。

) _$ _0 ?; f1 R. H% r3 M
2 G( U" T/ w0 s! o3 M
2.起始信号
) H/ _! ~; e9 R
4 W; Q- E  P+ }" y! B# X) e9 Z
, a. j/ B0 ~, Y3 P, G5 _! A
功能:CPU 发起 IIC总线启动信号void IIC_Start(void)
5 N3 F9 M2 |8 m2 E3 g& c4 [7 F
( j& Y4 F- b7 A9 _
{
& t% y& Q& Y7 F7 q6 g' O    IIC_SDA=1;        
" @$ H; O6 q1 P    IIC_SCL=1;
: H/ b; n2 m: x    delay_us(4);
2 k+ ]' O* e- Z6 O0 ~' y- J# L    IIC_SDA=0;//START:当 CLK 为高电平时,DATA 从高到低改变
9 a, w7 }! ]! [" {+ R8 d) X7 w    delay_us(4);    + z* f6 D, G7 e2 L- ~- @
    IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
' j! {! v" R- a    delay_us(4);, p) X+ m7 h  i! g% n! ]
}

" f/ _  a3 c+ I  起始信号产生后,所有从机设备就开始等待STM32紧接下来的从机地址信号。在IIC总线上,每个设备的地址都是唯一的,当主机广播的地址与某个设备地址相同时,这个设备就被选中了,没被选中的设备将会忽略之后的数据信号。根据IIC协议,从机地址可以是 7位或10位。在地址位之后,是传输方向的选择位,该位为 0时,表示后面的数据传输方向是由主机传输至从机,即主机向从机写数据。该位为 1时,则相反,即主机由从机读数据。$ J' H6 K) Y% M
; x) C; n$ e! \. f

2 ?; _! v6 z7 D3 L1 E$ U3.等待应答信号' Z& Y  ]+ D4 k+ T1 ]
  c+ `+ j+ k  Y2 Z) q
9 K6 C1 o4 J8 I
功能:CPU 产生一个时钟,并读取器件的 ACK 应答信号//返回值:1,接收应答失败  0,接收应答成功
$ _$ C& W3 D3 g7 @- N% N
3 m6 t) v- X" l  _5 w
u8 IIC_Wait_Ack(void)+ C* O4 k" p6 u& A) u1 d9 ^( F' V
{" V# D8 `' u# a+ a6 J
    u8 re;
8 F  A& [$ V7 O# }0 ^    IIC_SDA=1;delay_us(1);//CPU释放SDA总线     
% Q7 R" W6 n& F3 A4 [    IIC_SCL=1;delay_us(1);//CPU驱动SCL=1,此时器件会返回ACK应答3 Z) G0 y! F# {
    if(READ_SDA){//CPU读取SDA口线状态- C# `) `- `' m( X( z
       re=1;! [$ C1 O2 L% V8 C- T
    }else{9 B; ~* I: l) A5 ~1 g
      re=0;
0 K, q+ Y/ h$ X0 J% B8 m+ Z    }   
9 {% [9 Q( @) H    IIC_SCL=0;//时钟输出0      # Y( M& o6 V6 B
    return re;  : N. p! O# `- k6 ]; E7 I
}
) A+ ^- j0 ^2 Z8 f
  该函数用于 STM32 作为发送方时,等待及处理接收方传来的响应或非响应信号, 即一般调用前面的 IIC_SendByte 函数后,再调用本函数检测响应。
8 A" }; H7 o( s
  STM32控制 SDA 信号线输出高阻态,释放它对 SDA的控制权,由接收方控制;控制 SCL 信号线切换高低电平,产生一个时钟信号,根据IIC协议,此时接收方若把 SDA 设置为低电平,就表示返回一个“应答”信号,若 SDA 保持为高电平,则表示返回一个“非应答 ”信号;在 SCL 切换高低电平之间,有个延时确保给予了足够的时间让接收方返回应答信号,延时后使用宏READ_SDA读取 SDA 线的电平,根据电平值赋予 re 变量的值;函数的最后返回 re的值,接收到响应时返回 0,未接收到响应时返回 1。当 STM32 作为数据接收端,调用 IIC_ReadByte函数后,需要给发送端返回应答或非应答信号,此时可使用 IIC_Ack及 IIC_Nack 函数处理,该处理与 IIC_Wait_Ack函数相反,此时 SDA线也由 STM32控制。
/ p  y1 a- @! ]* A# \/ O/ i0 }+ \0 y, ?2 X+ a) j
- ?5 C: m, s( c
4.应答信号9 |9 q3 u5 P/ _8 [" f2 x4 Q0 _

- d" o% O/ Q0 |3 o$ q" T

0 {% k% E4 i2 p. ]功能: CPU 产生一个 ACK 信号//CPU产生一个ACK信号) n' v9 l' T! v; S7 }3 C
, H4 ^, k( g0 J! j; t% a
void IIC_Ack(void)0 M% p7 m6 ~* o" S/ C0 A" {
{
* u2 J0 y+ w9 G0 C6 e9 k9 `    IIC_SDA=0;//CPU驱动SDA=02 l5 Y. y. I" K  U# \6 U% ]# b
    delay_us(2);
4 P( U3 x# h, G3 u    IIC_SCL=1;//CPU产生一个时钟$ W9 ]$ n/ u3 d" K& P- g; L# E
    delay_us(2);
9 f9 ?- Z6 U# v# v* M# J; R    IIC_SCL=0;5 ]9 V* O) b5 X  R  V; h$ c4 Z
    delay_us(2);
3 B& r& x3 a: ~/ _4 ?6 L; V    IIC_SDA=1;//CPU释放SDA总线) g% w! d% ?+ j/ }
}& S8 |+ w$ T) O/ M' i
//CPU产生1个NACK信号
4 c& C0 U; K" c8 R: m  f, l& Dvoid IIC_Nack (void)
8 Q5 t9 L, d6 x' z{
$ L" [" M& N( Y2 j3 I' y    IIC_SDA=1();//CPU驱动SDA=1& m& |# F  I2 e; c0 ~+ F0 m
    delay_us(2);* C$ W5 A. }3 Y# p
    IIC_SDA=1;//CPU产生1个时钟/ m  L- D% w. s4 Y0 i2 Y1 W+ V
    delay_us(2);
. x& z# q& R/ {  Y( j1 _# C. D    IIC_SCL=0;  T9 B! t! y, K9 F6 p0 q3 G8 q
    delay_us(2);   
4 L9 S' n" g3 k}

; R6 U9 {  G( M! h4 ^9 {  IIC的数据和地址传输都带响应。响应包括“应答(ACK)”和“非应答(NACK)”两种信号。作为数据接收端时,当设备接收到 IIC 传输的一个字节数据或地址后,若希望对方继续发送数据,则需要向对方发送“应答(ACK)”信号,发送方会继续发送下一个数据;若接收端希望结束数据传输,则向对方发送“非应答(NACK)”信号,发送方接收到该信号后会产生一个停止信号,结束信号传输。/ M8 D1 V2 T& s+ k9 C6 ]
  代码的具体流程就是:根据要返回“应答”还是“非应答”信号,先准备好 SDA 线的电平,IIC_Ack函数中把 SDA 线设置为低电平,表示“应答”信号,IIC_Nack 函数中把 SDA 线设置为高电平,表示“非应答”信号;控制 SCL 线进行高低电平切换,产生一个时钟信号,在 SCL 线的高低电平之间加入一个延时,确保有足够的时间让通讯的另一方接收到 SDA信号线的电平;在 IIC_Ack 函数的末尾,响应信号发送结束后,重新把 SDA 线设置为高电平以释放总线的控制权,方便后续的通讯。
' q! |) B  e+ b& L4 }- r' Y" {* m" \; y* x2 B9 g+ b$ b
3 e. t- N. w8 j" o
5.停止信号: z. B# r4 @, M6 G' D- R. O) w
6 q( S9 L* c7 w0 V/ U; z( w: Y+ V
) D# W/ b$ R! F7 V
功能:CPU 发起IIC总线停止信号{    - M. s+ l) \9 q# a7 o

/ w: S5 W; a  D" D$ o5 M    IIC_SDA=0;//STOP:当 CLK 为高电平时候, SDA出现一个上调表示IIC总线停止信号
& Y" ?2 R1 }. _    IIC_SCL=1;9 A8 T5 }6 X1 }1 G9 _
    delay_us(4);2 x" w. B. ^% N* B3 C
    IIC_SDA=1;//发送IIC总线结束信号                        
* t+ @# \( |: J6 n9 O}
$ [1 z% `( z5 \# D
  停止信号直接看是时序图就可以搞定了,在SCL和SDA都为低电平的情况下,首先把时钟线SCL拉高,再把数据线SDA拉高,IIC就会结束传输了。
- d# s( h" B$ Z' y# c, Q; k
  以上就是软件模拟IIC协议了,在平时的应用中我们实际上不需要掌握这些具体的代码,只要知道IIC协议的过程原理就行了,因为一般来说我们用的都是别人写好的代码,我们只需要会用就可以了,如果你的代码和我这些有出入也没有关系,只要能正常通讯即可,当然如果你的设计在过程中出现了一些问题,或者显示不正常,我们首先考虑的也不是底层协议的问题,而是你代码的其他问题。  H4 n& Z6 i: y( h- f- _& Y6 y
" b1 y+ g7 Q$ {( n' U1 \7 k

- U% u. Y- B- b0 G9 E6.IIC发送字节9 G- F) M1 ]* Z# H  \0 x/ i
2 f% \3 g0 r+ [& s' e

; l. n; |  w  m功能: CPU向IIC总线设备发送8bit数据void IIC_SendByte(u8 Byte)
7 @* G1 j: t6 X6 p/ A$ t. f
& f" |( J+ x, `. c% y8 q
{
9 F- x0 y3 y  M. c; v& |    u8 i;
0 f: c0 p6 F4 q" B3 C    /* 先发送字节的高位bit7 */
2 O7 M1 e0 U! j4 X: K# r/ s    for (i = 0; i < 8; i++)
: Z8 {8 |1 S" K2 O1 b0 b6 I  s    {       3 c7 w1 T/ f2 X% H. D
        if (Byte & 0x80); M3 D: `1 N1 N; M  f  {+ D/ a! z! p5 f7 f1 U
        {7 N: V6 z$ `+ W8 w6 H
          IIC_SDA=1;
4 N" Z9 ^$ {: x        }/ {# S9 e# u  M+ B$ J2 F7 e
        else1 J$ p/ N  F: \$ N0 A" z
        {$ Q8 w( T" W' d
            IIC_SDA=0;
' _6 @/ e! j6 b0 F) p/ ]        }+ a) ?# P$ F" J) S2 W3 i
        delay_us(2);. G: a7 w5 B8 N! _8 |
        IIC_SCL=1;% s' j/ B4 h2 @
        delay_us(2);
% I. Y. f& g4 s        IIC_SCL=0;
+ y3 N. p9 y, H! R, X! o& M        if (i == 7)+ K0 [" j( w8 q  y  o7 C5 M% h$ P
        {
1 L/ Q' O: V$ I% R" u2 b             IIC_SDA=1;// 释放总线0 |$ ^9 ]& U! z+ K
        }
" T$ t! g* [/ G( Z9 y        Byte <<= 1; //左移一个bit
. d* h+ k8 y- }  s9 k2 ~        delay_us(2);
0 L" ^1 _8 J% e6 }    }
- Q% i5 i4 }# V}
# Y) B, p/ b; C5 y/ Z4 e. h% H
  该函数以其输入参数作为要使用IIC协议输出的数据,该数据大小为一字节。函数的主体是一个8次的 for 循环,循环体执行一次将会对外发送一个数据位,循环结束时刚好发送完该字节数据。步骤分解如下:9 f5 z7 n/ T2 d( ?6 v9 v
  首先程序对输入参数Byte和 0x80“与”运算,判断其最高位的逻辑值,为 1 时控制 SDA输出高电平,为 0则控制 SDA输出低电平;接下来延时,以此保证 SDA 线输出的电平已稳定,再进行后续操作;之后控制 SCL线产生高低电平跳变,也就是产生 IIC协议中 SCL线的通讯时钟;在 SCL线高低电平之间有个延时,该延时期间 SCL线维持高电平,根据 IIC协议,此时数据有效,通讯的另一方会在此时读取 SDA 线的电平逻辑,高电平时接收到该位为数据 1,否则为 0;就这样一次循环体执行结束,Byte 左移一位以便下次循环发送下一位的数据;如次循环 8 次,把Byte 中的 8 位个数据位发送完毕,在最后一位发送完成后(此时循环计数器 i=7),控制 SDA 线输出 1(即高阻态),也就是说发送方释放 SDA总线,等待接收方的应答信号。1 N, C$ Z* r3 x7 r  `, ^9 i" K9 }

- Z. ~: _3 \& G+ z; h- u7 |

9 s- x5 Y5 t4 d) \+ A3 m7.IIC读取字节
9 v4 t( H6 @7 F5 ^; I+ s9 c( [4 H* ^5 y$ |% T' n, x6 Q4 k2 M

6 Z% I* g- s$ t; C* c功能: CPU从IIC总线设备读取8bit数据u8_t IIC_ReadByte(void)
0 [2 b( `& q/ ~! y: Z2 K- h, G

9 P; F3 f% D+ K& W; S, y, |& N{
; {" |: S) p* H2 ~" H    u8 i;8 d3 o# x( V3 ^9 N
    u8 value;
* `5 p% L& Z. a3 n    //读到第1个bit为数据的bit75 N; w* Z: \; v" a
    value = 0;' B2 k2 R+ p) u/ g
    for (i = 0; i < 8; i++)  r. q6 M+ U6 C2 ?+ K
    {2 l5 G& s3 V  J+ a  a  H" ?, h
        value <<= 1;7 Y& d3 `6 v& M( W( D, r
        IIC_SCL=1;8 I0 P9 k; c, B+ t4 X
        delay_us(2);# w5 X$ _! n! I0 v1 k; t7 W
        if (SDA_READ)
, O0 A2 c, T' v7 u5 s- y" K        {+ g) }$ d; C# S% @! e
            value++;+ A* ~' O* Q  o3 ^
        }: g: q1 Q) e# f8 n! F# v
        IIC_SCL=0;
8 {/ s- T. n( q3 T! ~/ d& S        delay_us(2);. W2 K' f* k& {3 G' a
    }
6 n6 S1 G( D- ~1 l4 e+ C    return value;, H2 M) w- a8 V$ n* y# |" z* F
}
8 ~, l1 g8 B9 G* t! q9 s7 T: ~( v
  IIC_ReadByte 函数也是以 for 循环为主体,循环体会被执行 8次,执行完毕后将会接收到一个字节的数据,循环体接收数据的流程如下:. I2 [' N( F% R
  首先使用一个变量 value 暂存要接收的数据,每次循环开始前先对 value 的值左移 1 位,以给 value 变量的 bit0 腾出空间,bit0 将用于缓存最新接收到的数据位,一位一位地接收并移位,最后拼出完整的 8位数据;然后控制 SCL线进行高低电平切换,输出 IIC 协议通讯用的时钟;在SCL线高低电平切换之间,有个延时,该延时确保给予了足够的时间让数据发送方进行处理,即发送方在 SCL 时钟驱动下通过 SDA 信号线发出电平逻辑信号,而这个延时之后,作为数据接收端的 STM32 使用宏SDA_READ读取 SDA信号线的电平,若信号线为 1,则 value++,即把它的 bit0置 1,否则不操作(这样该位将保持为 0),这样就读取到了一位的数据;接下来SCL线切换成低电平后,加入延时,以便接收端根据需要切换 SDA 线输出数据;直到循环结束后,value 变量中包含有 1 个字节数据,使用 return 把它作为函数返回值返回。
7 E4 G- I( Y. q( p: K# H
6 C0 Z1 }/ K; B& f6 J, t
$ E6 d6 H% e# r# L/ I3 ]1 m* ~0 E
三、 硬件协议
$ ?: b8 M) t/ z7 q6 X$ j- A! B8 @# t2 C% e! {- q7 Q. [

5 c; `" T: G, J8 _) b: q2 ?; L* j  相对来说,硬件IIC直接使用外设来控制引脚,可以减轻 CPU 的负担。不过使用硬件IIC 时必须使用某些固定的引脚作为 SCL 和 SDA,软件模拟IIC则可以使用任意 GPIO 引脚,相对比较灵活。  N1 I' J3 [  Z$ Q
: c) [4 j' B! Z. g5 M! R) Y2 H6 {
  STM32的IIC外设可用作通讯的主机或从机,支持 100Kbit/s 和 400Kbit/s 的速率,支持 7位、10位设备地址,支持 DMA数据传输,并具有数据校验功能。它的IIC外设还支持 SMBus2.0协,SMBus 协议与IIC类似,主要应用于笔记本电脑的电池管理中。9 M, Z* z7 ^. p. j/ r  K
  STM32 芯片有多个IIC外设,它们的IIC通讯信号引出到不同的 GPIO 引脚上,使用时必须配置到这些指定的引脚,GPIO引脚的复用功能,可查阅《STM32F1xx 规格书》,以它为准。

$ M1 e  q9 o' [7 Z6 ^( X 微信图片_20200604152503.png
. U  q7 P7 Q3 k: c4 x" Y1 S6 G
6 S: N( w( M' E! Q2 z) R
1 m+ V+ |+ Z) h& c$ wIIC初始化函数
4 J4 ~2 ^: {+ S2 E6 q
- ~  ~# B* |4 ~. g- R

4 z4 P8 |  z0 |void IIC_init(void)
) I% ~  C: k) B- i/ ]4 A! Z
7 v2 m4 z# |. C$ @. ~$ p
{2 K( v" o* }; e
    GPIO_InitTypeDef GPIO_InitStructure;
3 e( |; Q% w! ]* F. {8 _    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);$ L0 |; q0 I* y  m* [1 I
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;  o' \$ |% R. \
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
, J: C. S$ h8 y5 t& c    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;// 开漏输出 ( J. V! G( a, J( C$ n( H9 ^
    GPIO_Init(GPIOA, &GPIO_InitStructure);    `1 O6 C, a8 s( G" L) L4 f8 K% y+ l
    IIC_SCL=1;
9 q! o! G- k& ?: j# p# O3 _- {6 D    IIC_SDA=1;//给一个停止信号, 复位I2C总线上的所有设备到待机模式
% B8 v2 K9 D1 w) ]6 V0 j}

. U' Z2 Y( ~$ H. y; F6 z  因为是硬件IIC直接使用外设来控制引脚,那么我们选择IIC通讯的引脚就比较固定,具体使用的引脚可查阅《STM32F1xx 规格书》,以它为准。可以看到PB6和PB7两个引脚可以作为IIC的通讯引脚,而且PB6为SCL时钟线,而PB7则为SDA数据线,并设置为开漏输出。, |% j, K7 P; t9 D  X
  这里为啥设置为开漏输出的方式呢?/ q  Z5 V+ i! g
  这是由于使用的是软件模拟IIC方式,而IIC协议的 GPIO 必须的开漏输出模式,开漏输出模式在输出高电平时实际输出高阻态,当IIC该总线上所有设备都输出高阻态时,由外部的上拉电阻上拉为高电平。另外当 STM32 的 GPIO 配置成开漏输出模式时,它仍然可以通过读取GPIO 的输入数据寄存器获取外部对引脚的输入电平,也就是说它同时具有浮空输入模式的功能,因此在后面控制 SDA线对外输出电平或读取 SDA线的电平信号时不需要切换 GPIO的模式。; k( M. A( I2 a+ h, \( H6 g( g
  另外在硬件IIC协议之下,它的起始信号、等待应答信号、应答信号、停止信号都与软件模拟IIC协议之下的函数相同,在这里我就不重复说明了。
5 Y7 \+ o/ l9 U4 S  U9 a( J      总结:IIC通讯协议很简单,在实际项目中我们不需要掌握具体的IIC协议代码,只要会用即可,作为最常见且常用的协议,我们最好能够背下来或者有所了解。现在IIC通讯不陌生了吧!
' J2 a, J7 f4 v+ v2 D# s4 V
赞 收藏 1 评论1 发布时间:2020-6-4 15:27

举报

1个回答
李康1202 回答时间:2020-6-5 08:47:26
谢谢分享

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版