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

【经验分享】STM32F7 硬件IIC驱动

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
目前只实现了主设备模式,一般也只用到主设备模式,IIC如果不能使用硬件方式,读取大量数据的时候效率很大,由于只有1个字节的缓冲区,根本不能使用中断模式(实际使用过程中,IIC会造成100us以内间隔的中断,单片机根本扛不住的),所以建议数据少就直接阻塞,1个字节也就几十us,数据多直接用DMA,将线程阻塞,等待DMA传输完成,而不会阻塞CPU(上传的代码没有实现DMA部分,便于理解)。
+ q6 `5 M- g1 t4 ]  q' Z* o
0 u, e1 i* c  {; O, Y1 O- P目前已经做了完善的错误处理,读写操作前都会清除中断,遇到错误会软复位,所有位置均做了超时处理,防止程序卡死,目前只测试了几个字节的读写,大量的,长时间的读写均表现稳定,目前手上开发板没有eeprom,无法做大数据的连续读写,如果你在使用过程中遇到问题,欢迎指正。5 T  ^  Z0 G$ t: k! U

; v8 Z6 r) v3 O1 g6 {: B7 I9 f& H下面是IIC读写的时序例子,可以先熟悉一下,这样比较容易上手,哪一个环节出了问题也要调试。
; S5 _) R2 o% v& r; m8 K+ F0 P2 R, w$ J$ K5 y. j1 W
20200216194202434.png
+ w' N' k* w0 ?* c
5 X( H: t* J: k2 l. N% H1 O
20200216194219185.png
0 ~" d# x) A2 o4 [8 t
  `/ l" H" S0 j) q* l
20200216194234908.png
4 G! f  M8 O1 U5 `
- i  _8 W3 e  t$ y$ I+ P
8 a' q0 y; d8 ?) P( ]5 x2 G  x
下面简要说明一下STM32F7硬件IIC的驱动设计方式(建议先百度学习一下IIC的时序要求):8 X7 }8 H8 S& V

2 }. A+ Z' W7 |0 Y- z[基本的初始化]( |& O0 A+ G# `" e& c5 g! g

) P0 L1 g- h$ X5 W1.初始化IIC时钟,IO(IIC IO必须设置为复用开漏输出,这个很重要)。
  y9 o" Z: d: M' n. j( A; h
8 [* C  y! E4 |* q: J1 b2.CR1先赋值为0,复位IIC.
; L) I2 a! k" |2 B) _+ q
. n- ]0 A) H% W3.除了TIMINGR寄存器需要自己计算设置好,其余寄存器全部复位为0
7 Q5 \; _0 n/ k3 R
6 n- t8 d5 [) p, R. P0 u& J4.设置CR1使能IIC。1 U9 o6 @5 o8 M/ D& D! O4 w; e/ \
  L. x: |! d: c' G
注意:上面说到,IIC的IO必须初始化为复用开漏输出,我之前初始化为复用推挽输出,测试很久,只要一启动传输,就会立马收到NACK,然后是STOP中断,数据根本没法发送,弄了好久才发现是这个IO初始化的问题。0 w6 [$ H6 d# B, k! @( C1 p  m
: ]2 z, B% ]( Q5 [3 f# p! R: Y
7 ~1 {& n, d+ u
' [1 H7 d0 g1 u* w0 x2 |7 G/ A
[读取]
# y; x; t$ ?& W7 l4 {7 A3 Y; G3 P% l( h
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。  i3 I! t# S; C: x! A9 F8 g

$ T9 [# m3 N6 _% |, `8 V2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)软件STOP,写模式,启动传输。
, K  p- x) X0 ]
: y% M& a* d) O, T3 x! O3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。, H6 {5 ?' x& u5 q! |; o$ a

$ e& E$ U! M( M7 S: P4.等待TC置位,意味着上面的1-2字节的寄存器地址以及写完成了。8 T  |8 e0 v) G( y5 y$ T

! W- e! X) \) j; F5.根据要读取的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。4 i  J. E+ t- k$ S) l0 n$ b5 L0 M: _

$ O2 l/ n6 v. `8 x% O. H4 |: W8 k6.设置了从机地址,要读取的数据长度,之后设置方向为读取,然后启动START(从写切换到读要重新发送START,这个跟软件模拟是一模一样的)。
+ `4 b) f! t) @7 W2 w  X
8 c! r' [8 _2 ~3 u  s# P7.循环一个字节一个字节的读取数据,字节读取需要等待RXNE有效,只有读取RXDN寄存器,直到所有数据读取完成。) F# e" ^7 f7 s, N) b1 e0 o3 ~7 n
! X- B6 Q( R) U& p7 N( R
8.读取完成后等待STOP有效,因为前面在最后一包数据读取的时候使能了自动STOP,这个时候检查STOP是否生成。
5 ~- z0 e9 l9 F+ g8 ^! y0 Q6 _
9 i0 E) G2 M3 X9.需要注意的是,所有的操作都要给超时,并且是自己可控的,绝对不要有死循环,之所以一直说STM32的IIC死机很大程度上都是由于这个地方没有涉及好,我的程序设计方法是:一旦出现了异常,就复位IIC,如果不复位就会导致下次进去的时候IIC一直忙,因为还处于上一个通讯过程。
. x4 C2 ]9 q; h% T
6 L6 [' Q$ G5 a% S5 r" [% H6 q2 |9 X. E+ O/ s2 E8 `4 @

: ^5 @7 Z5 r- ^/ ?* K- `[写入]
+ O- `: f. ~; m$ X) w9 O
6 P2 |; {" u. A: c1 C1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。3 I, W# A7 ]9 N! o& g" q
6 _: ~- M; V  t
2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)自动重载,写模式,启动传输。
: n# \$ q6 ?9 c) D( V
- @, |) m& K; g2 J' U- X3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。$ U& B) \1 V9 |8 `- Y: S% z

+ G9 W- D: d  f! C8 e2 t4.等待TCR置位,意味着上面的1-2字节的寄存器地址以及写完成了,已经发生重载了,后续可以继续写入数据了。
6 h! [1 x% K. g: T3 C- q* ^8 Q& K: G! L. @
5.根据要写入的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。5 L" b7 _6 k- I  l
' v1 i( t" n$ q! [3 }0 T
6.设置了从机地址,要写入的数据长度,之后不用切换方向,不用启动START(都是写,不用重复发送START,这个与读取有区别)。5 k# S- ]7 S- s8 I) u. a
/ p! f/ [+ f+ z* u1 y
7.循环一个字节一个字节的写入,字节写入与步骤3一样,等待TXIS置位,就可以写入数据到TXDR。
) \! L2 E6 ?( |' g: d/ O% _9 s/ k' C: B3 A/ W5 `; k
8.等待STOP有效,因为前面在最后一包数据写入的时候使能了自动STOP,这个时候检查STOP是否生成。
. V% m8 _* m; ~4 g  D7 ~! p  m* ~4 h' E5 K% \, C7 h0 ^: C
9.需要注意的是,所有的操作都要给超时,跟读取一样。
# n  i4 u+ P# A+ z& b* W. B/ t( E8 o; @9 Z. A2 @; ], h

( S8 ?$ Z, P$ \. {. `. @3 l6 u4 P0 Z& q6 C' B
注意:IIC的读取实际很短,超时也不用给很长,以标准的100KHz通讯时钟速度,一个字节大概在90us左右,超时可以给个5-10B时间,也就是450-900us左右。! \9 [+ Q! S+ ?* r- c5 R7 I0 S1 \

: Y8 a6 _+ ^6 |, ~( q( `
9 G. \# j( [% h
8 `6 p( D: G1 Y" I" ^4 R* N好了说了这么多,具体的看代码中的注释,直接上代码(我只测试过I2C3,其余的理论上都是一样的,就是IO初始化部分有区别,别的通道没有硬件进行测试)$ G, F1 x; p/ A& z% _5 y

0 O: H& g. Y) x/ `
  1. /************************************************************************************************************** i$ y1 L3 Q3 |  w5 a7 \4 l. z
  2. * 文件名                :        stm32f7_iic.c: W9 L7 c% M0 Z' {" e
  3. * 功能                        :        STM32F7 IIC接口驱动
    7 V% h1 }- w- l) a' f7 N) w# J
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a># z/ |6 P. h/ F
  5. * 创建时间                :        2020-02-09
    : x- H* G- v4 t3 ~) F; o
  6. * 最后修改时间        :        2020-02-09
    ! v: E, J4 j) l+ [
  7. * 详细:                        只支持主机模式,7bit地址,默认APB1为IIC提供时钟
    6 A5 c. M/ c$ i$ ~4 \
  8.                                         涉及到读写1字节的超时时间是us,其余的是ms3 a) X+ ^" j# p3 O  }9 C% e# L5 g% z
  9.                                         注意:IIC的IO必须初始化为复用开漏输出。' p$ R, c4 ^8 y$ m! t' D
  10. *************************************************************************************************************/        
    & ?$ p' W. A6 s* x5 r; `6 p/ ]
  11. #include "stm32f7_iic.h"
    & X3 r% b6 L! Q
  12. #include "system.h" 2 X8 f: K( X4 ~
  13. #include "dma.h"
    - S6 ?/ i: _: k7 \" e4 C

  14. # d% _1 i0 ~# q
  15. #define IIC_FLAG_MASK  ((uint32_t)0x0001FFFF)        //中断标志掩码
    % y" `- r, @% r6 C7 |# r5 _
  16. * l' s' ^% ]# L& a5 V* T2 m$ d* D1 I
  17. //自动结束或自动重载设置(重载与自动结束只能二选一,或者都不选)
    5 G$ e5 m" M: i: }3 u/ `7 Y  C. l
  18. typedef enum * K7 b6 ~; b/ r% g( B1 Z
  19. {1 @* F  f7 T$ G  Y
  20.         IIC_SOFTEND_MODE                =        0,        //手动结束,并不开启重载: D+ w2 ?! A* h6 _, s+ w2 I, x
  21.         IIC_AUTOEND_MODE                =        1,        //自动结束,用于最后一次通讯完成后自动发送STOP结束通讯: b$ E! o) X  P5 M" u! G5 _( ^
  22.         IIC_RELOAD_MODE                        =        2,        //后续还有数据,本次通讯后自动重载,重新设置后继续通讯' ?+ T$ w# \+ C, w( a
  23. }IIC_RELOAD_END_MODE;, {: s1 T" X2 H& z  l2 U5 O& ^
  24. 2 @1 E$ \0 T3 h& r3 d! _$ b- D3 r
  25. //读写与开始模式控制$ p; ]1 N- }  V! I% r
  26. typedef enum6 M0 s5 S: t" m- R) I& n
  27. {2 Z4 ]9 [( v/ M3 P  x
  28.         IIC_NOSTART_WRITE                =        0,        //没有开始的写-用于后续数据的写入. t* a6 U4 ~$ l. m/ ]8 [6 [( p
  29.         IIC_NOSTART_READ                =        1,        //没有开始的读-用于后续数据读取# K2 a4 `( _8 T6 G$ \  e
  30.         IIC_START_WRITE                        =        2,        //生成开始写-用于通讯开始时,写地址或数据
    0 B( A$ I0 n- T2 _7 M
  31.         IIC_START_READ                =        3,        //生成开始读-用于读取数据时切换到读取方向,并读取后续数据& ?$ `% s. \. J8 C9 g
  32. }IIC_START_WR_MODE;2 M. q* g' X  _/ W# v8 ]5 c5 i

  33. - ]. W! z8 D: s9 T
  34. //IIC句柄$ {8 g) b0 J5 N3 _5 y6 z
  35. typedef struct2 n7 G, E% K2 l( q/ r3 E( }
  36. {7 y/ c9 p2 T6 L
  37.         IIC_CH_Type ch;                        //当前通道
    ; C' T3 P1 l2 l2 |
  38.         I2C_TypeDef *I2Cx;                //当前通道外设结构体
    $ Q. r1 X& P! y/ J
  39.         u32 TimeOutUs;                        //操作超时,单位us
    ) a7 J4 {2 x6 Z% X/ h5 j* r) G
  40.         u16 Speed_KHz;                        //通讯速度,单位KHz
    % c7 M; ]% |: y) h1 t
  41.         bool isMasterMode;                //是否为主设备模式-目前只支持主设备模式
    1 D  V1 O; G, X: g3 a6 P6 a/ d
  42. }IIC_HANDLE;: b7 G! W- E8 {' {) z9 T# v0 Z* j
  43. ( m# ?) A( u# m+ b0 ^; y& G* i
  44. //IIC外设结构指针
    ! q7 I- v3 Q: @. B5 \& _6 D2 Z
  45. static const  I2C_TypeDef * const I2C_TYPE_BUFF[IIC_CH_COUNT] = {I2C1,I2C2,I2C3,I2C4};" K+ F% o9 k- i; T1 ?  p, O7 @
  46. //IIC通道句柄定义
    1 w# s! A% i$ a& b/ [
  47. static IIC_HANDLE sg_IIC_Handle[IIC_CH_COUNT];
    6 a2 {& O  y( ~( K, p
  48. : Z, H9 S% M* d6 i6 z
  49. //发送NAK
    0 A: g: J& w% @$ l
  50. //static __inline void IIC_SendNAK(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT15;}1 S& _0 b' \: V2 N: N/ ]% c$ O
  51. //发送STOP. [) a9 C; j6 h
  52. static __inline void IIC_SendStop(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT14;}
    : `5 ^, a) N4 y4 B( K( B* K3 |
  53. //发送START% ~# H% p. b7 T% M
  54. //static __inline void IIC_SendStart(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= I2C_CR2_START;}) S$ e2 h, {  w0 @, \& T
  55. //获取中断状态8 C& J4 a& A, B$ q8 C
  56. static __inline u32 IIC_GetISR(IIC_HANDLE *pHandle) {return pHandle->I2Cx->ISR & IIC_FLAG_MASK;}" \& _( C. e6 ~3 K
  57. //清除中断状态
    : y  N- P. \) J
  58. static __inline void IIC_ClearISR(IIC_HANDLE *pHandle, u32 IsrFlag) {pHandle->I2Cx->ICR = IsrFlag & IIC_FLAG_MASK;}
    5 J$ ^( _0 L& a. j2 d
  59. //复位CR2寄存器
    , [  K' T8 q' Y& f6 i5 X- e+ K
  60. static __inline void IIC_ClearCR2(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 = 0;}
    : Z; C* n; J6 R5 P+ l$ G( U
  61. ' G4 i9 s1 z/ v) J- k! G/ D
  62. static void IIC_SoftReset(IIC_HANDLE *pHandle);//硬件IIC软复位(会使能IIC)* q1 k+ v" q+ N& M, T& c
  63. static u32 IIC_CalculationTiming(u16 Speed_KHz);//硬件IIC时序计算; g. T0 \  L3 p  X* S$ i) E
  64. # B) k: W: B8 B' @5 x0 A

  65. 7 b0 s5 R0 O' I3 H& [$ J" L" I
  66. /*************************************************************************************************************************
    5 K/ E) I  I" K  V  w8 C( \0 R: s+ Y
  67. * 函数        :                        bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)
    0 \2 \: L$ D  z0 F
  68. * 功能        :                        硬件IIC初始化% M! F8 F$ `2 u
  69. * 参数        :                        ch:IIC通道;Speed_KHz:速度10-1000(如果速度是100,则按照SMBUS时序);TimeOutUs:操作超时us(0:自定计算超时)# m& w6 h  ?9 N$ f: q
  70. * 返回        :                        IIC_ERROR
    # g" n" l, U' J
  71. * 依赖        :                        底层宏定义# {2 t; S! M  N* Z
  72. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    2 l1 _$ [# K8 ]; |) y* U9 g7 l
  73. * 时间        :                        2020-02-15
    4 @! V" X$ h5 R
  74. * 最后修改时间 :         2020-02-15
    2 M0 F' ?9 |3 ?
  75. * 说明        :                         速度只是个大概的计算值,设置为100KHz时会严格的按照SMBUS时序,其余的不保证SMBUS兼容,正常情况下只要时钟速度符合要求,
    ! o5 h. o2 Q* d5 L+ K
  76.                                         时钟上升沿到来前数据以及稳定的切换了即可保证通讯稳定性
    9 J- Y# D* h' _6 n  X! |# q
  77. *************************************************************************************************************************/
    * c$ D& Z$ Y3 o* A1 k
  78. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)2 D$ Q4 v- C/ d4 ?! m0 F
  79. {
    + i+ U9 d# \% D3 M; E2 Y0 o6 x& J
  80.         SYS_DEV_CLOCK DevClock;
    . S; L: C( U" \: j9 N8 S6 f
  81.         IIC_HANDLE *pHandle;
    6 C8 Y8 r8 k: s
  82.         
    5 y& J! i$ c8 u
  83.         switch(ch)
    4 z8 t* \7 y7 h* L7 N. J& R
  84.         {
    % L# Q* H$ P  i8 J7 Z0 o4 z
  85.                 case IIC_CH1        :        //IIC1# z& I' P6 a0 p$ M3 e
  86.                 {
    9 _1 ^4 i. V# c
  87.                         RCC->DCKCFGR2 &= ~(0x3 << 16);        //清除设置,使用APB1作为时钟源
    8 g' p' R$ ]+ k' V
  88.                         DevClock = DEV_I2C1;# k; H5 ?& R. G: _. P5 `- k* x
  89.                         //初始化I2C IO8 e* Q% ^1 \9 k8 [. _* k
  90. #if(IIC_CH1_IO_SELECT==IIC_CH1_PB6_7)        //I2C1        使用PB6/7
    2 s; A1 n0 w0 e6 ?/ u& _
  91.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    . m! u" I+ O; Z2 j
  92.                         SYS_GPIOx_OneInit(GPIOB, 6, AF_OD, SPEED_25M);                //PB6
    & P! ?3 k; H: f, `; b
  93.                         SYS_GPIOx_OneInit(GPIOB, 7, AF_OD, SPEED_25M);                //PB7
      v  q& h5 ]) _! A- h  y
  94.                         SYS_GPIOx_SetAF(GPIOB, 6, AF4_I2C1);                                //AF4
      Q5 V, C! |2 ~( Z
  95.                         SYS_GPIOx_SetAF(GPIOB, 7, AF4_I2C1);                                //AF4
    * K* \# k4 |2 q
  96. #elif(IIC_CH1_IO_SELECT==IIC_CH1_PB8_9)        //I2C1        使用PB8/9
    1 C( R( ]* F" ?+ z9 v3 F  S, o" ^/ ~
  97.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟0 C2 n+ w- s% }4 F, n- d. d4 B. v
  98.                         SYS_GPIOx_OneInit(GPIOB, 8, AF_OD, SPEED_25M);                //PB86 v, _& _; ?2 Q7 x4 H3 h8 F% j
  99.                         SYS_GPIOx_OneInit(GPIOB, 9, AF_OD, SPEED_25M);                //PB9/ |2 B, Y  o6 q# O8 ]. ?2 K
  100.                         SYS_GPIOx_SetAF(GPIOB, 8, AF4_I2C1);                                //AF4
    ! @7 A# j* ^9 Y" {' V
  101.                         SYS_GPIOx_SetAF(GPIOB, 9, AF4_I2C1);                                //AF4
    3 K( p0 D! Q# M
  102. #else
    6 P, ?5 G' y6 A# @. G
  103.                         #error("无效的I2C1 IO选择");8 p! p# x/ P4 x+ l1 @. Y
  104. #endif //IIC_CH1_IO_SELECT
    ( O1 A" A4 I2 }* R! |$ V/ t# g
  105.                 }break;$ `1 z8 O/ x9 u5 o8 ?
  106.                 case IIC_CH2        :        //IIC2! j+ o1 K, C" ~' X7 K7 F/ c* T8 E" B
  107.                 {
    4 @+ d" E& ]% _7 ?" u: o
  108.                         RCC->DCKCFGR2 &= ~(0x3 << 18);        //清除设置,使用APB1作为时钟源
    : \. V: Y  o! G+ p0 f# d2 P
  109.                         DevClock = DEV_I2C2;( h- N7 X! }4 M9 R
  110.                         //初始化I2C IO
    " m, d7 f/ L5 a7 |/ t9 Q" ?4 J
  111. #if(IIC_CH2_IO_SELECT==IIC_CH2_PB10_11)        //使用PB10,PB11& p& X. r8 l" O, j  L0 e" d- p
  112.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    # t5 o, f7 s  b9 }( L6 W1 b8 w6 U
  113.                         SYS_GPIOx_OneInit(GPIOB, 10, AF_OD, SPEED_25M);                //PB104 X' X/ t; Z% B6 a* ~  Y
  114.                         SYS_GPIOx_OneInit(GPIOB, 11, AF_OD, SPEED_25M);                //PB11' ?* b( r/ ^3 m& i
  115.                         SYS_GPIOx_SetAF(GPIOB, 10, AF4_I2C2);                                //AF46 s0 A' p- X/ U, b- w, i
  116.                         SYS_GPIOx_SetAF(GPIOB, 11, AF4_I2C2);                                //AF4
    9 h, j6 Q3 M# d' }
  117. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PF0_1)        //PF0,PF1/ b# v) v9 y; M2 `5 [
  118.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟' G$ J# T: }7 y
  119.                         SYS_GPIOx_OneInit(GPIOF, 0, AF_OD, SPEED_25M);                //PF00 d7 `- w& S8 }3 M! k
  120.                         SYS_GPIOx_OneInit(GPIOF, 1, AF_OD, SPEED_25M);                //PF1
    9 `" H( F& \8 F
  121.                         SYS_GPIOx_SetAF(GPIOF, 0, AF4_I2C2);                                //AF46 I2 B, F; W! \# B( @' W6 f* t
  122.                         SYS_GPIOx_SetAF(GPIOF, 1, AF4_I2C2);                                //AF4( @( S8 u9 r' J) D( K
  123. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PH4_5)        //PH4,PH5
    # n& `' U' v7 M( I1 v' M6 I
  124.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    3 m- r' p3 p6 D# v& b5 O7 }
  125.                         SYS_GPIOx_OneInit(GPIOH, 4, AF_OD, SPEED_25M);                //PH4
    5 P3 p7 F! a' F7 M/ w! V6 Q0 E# h
  126.                         SYS_GPIOx_OneInit(GPIOH, 5, AF_OD, SPEED_25M);                //PH5
    + t. ?. w; H! N3 O- A7 q* d" |
  127.                         SYS_GPIOx_SetAF(GPIOH, 4, AF4_I2C2);                                //AF4
    ( G; m0 Y. W' {9 h
  128.                         SYS_GPIOx_SetAF(GPIOH, 5, AF4_I2C2);                                //AF4                        - ^* x. C+ G& S, I. d! j
  129. #else1 N+ I5 Q0 [0 n! g7 y, {4 @3 D4 X
  130.                         #error("无效的I2C2 IO选择");  S% a' v1 f4 [, |/ Q, F
  131. #endif //IIC_CH2_IO_SELECT
    6 _6 N6 b& A2 J* i/ U6 L3 A0 I7 C
  132.                 }break;                        : R) E4 ^5 ?3 {$ ]( f- c$ k
  133.                 case IIC_CH3        :        //IIC3
    8 l" C" V7 [' ]3 V1 ~  f. t9 a
  134.                 {) s- p  K0 ~8 f5 t, i, w
  135.                         RCC->DCKCFGR2 &= ~(0x3 << 20);        //清除设置,使用APB1作为时钟源) O% n& V3 }( A3 c! X+ e
  136.                         DevClock = DEV_I2C3;
    % t' t. f7 M9 Y+ e+ ^" m6 h
  137.                         //初始化I2C IO- j0 a, C8 R  ~3 h5 F
  138. #if(IIC_CH3_IO_SELECT==IIC_CH3_PH7_8)                //PH7,PH8/ R: X/ y) p+ l# c4 x9 k
  139.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    ) L/ Q9 Q* n; g
  140.                         SYS_GPIOx_OneInit(GPIOH, 7, AF_OD, SPEED_25M);                //PH72 X( Q' b, X- m7 ?
  141.                         SYS_GPIOx_OneInit(GPIOH, 8, AF_OD, SPEED_25M);                //PH8
    ( K  o) w! c' |; E6 ?
  142.                         SYS_GPIOx_SetAF(GPIOH, 7, AF4_I2C3);                                //AF4
    0 _/ W3 w5 _. T4 s) Z9 Q: `7 V1 t
  143.                         SYS_GPIOx_SetAF(GPIOH, 8, AF4_I2C3);                                //AF4
    2 `% c) G+ Y% o9 m- B6 _5 J
  144. #elif(IIC_CH3_IO_SELECT==IIC_CH3_PA8_PC9)        //PA8,PC9" ~. |  K" c$ N0 [9 R
  145.                         SYS_DeviceClockEnable(DEV_GPIOA, TRUE);                                //使能GPIOA时钟
    ) ^" L) o6 o+ |" H1 U
  146.                         SYS_DeviceClockEnable(DEV_GPIOC, TRUE);                                //使能GPIOC时钟
    : N! s0 l! L- ^9 G2 r/ M/ ^- S+ k& I
  147.                         SYS_GPIOx_OneInit(GPIOA, 8, AF_OD, SPEED_25M);                //PA8& s7 w% a. {. M& F1 E( q: l
  148.                         SYS_GPIOx_OneInit(GPIOC, 9, AF_OD, SPEED_25M);                //PC92 `+ d; V( o" X: s: H
  149.                         SYS_GPIOx_SetAF(GPIOA, 8, AF4_I2C3);                                //AF4/ b' D6 k3 t- {
  150.                         SYS_GPIOx_SetAF(GPIOC, 9, AF4_I2C3);                                //AF4                : \8 F' y$ H" V! \; T/ g9 q
  151. #else$ B7 R; X  j7 N( K
  152.                         #error("无效的I2C3 IO选择");
    . m) t  j  W) K! {
  153. #endif //IIC_CH3_IO_SELECT                        ) l5 x$ Z3 M: u5 ^
  154.                 }break;                        ; d' v: S/ N7 L) Q  C
  155.                 case IIC_CH4        :        //IIC4$ _0 L7 {5 d3 z2 j4 G* F8 _  x9 F5 y/ X
  156.                 {
      Z9 l1 k' J0 _0 B4 w$ I% W2 I
  157.                         RCC->DCKCFGR2 &= ~(0x3 << 22);        //清除设置,使用APB1作为时钟源
    4 g0 A9 y0 p& P  K
  158.                         DevClock = DEV_I2C4;
    ( a% L+ _* `7 j* Q+ P9 D
  159.                         //初始化I2C IO/ q  G/ p! r. B, m! f
  160. #if(IIC_CH4_IO_SELECT==IIC_CH4_PD12_13)                //PD12,PD13
    5 u1 q( ^4 o" `" K* T
  161.                         SYS_DeviceClockEnable(DEV_GPIOD, TRUE);                                //使能GPIOD时钟* R& r( g) i9 ^+ E( P, Q
  162.                         SYS_GPIOx_OneInit(GPIOD, 12, AF_OD, SPEED_25M);                //PD12
    8 a5 |. B8 c$ [: C) P/ s
  163.                         SYS_GPIOx_OneInit(GPIOD, 13, AF_OD, SPEED_25M);                //PD13' w6 D* v$ O/ [+ t! d7 {7 X
  164.                         SYS_GPIOx_SetAF(GPIOD, 12, AF4_I2C4);                                //AF40 H% N5 h+ z' S" {1 F
  165.                         SYS_GPIOx_SetAF(GPIOD, 13, AF4_I2C4);                                //AF4
    / u: I% k/ A/ s% |
  166. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PF14_15)        //PF14,PF15
    + t, ^5 V3 D5 O. {# H) [/ k/ p
  167.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟
    2 D3 _: i$ X% V: l0 P  G4 v
  168.                         SYS_GPIOx_OneInit(GPIOF, 14, AF_OD, SPEED_25M);                //PF14! b& _2 {5 S8 G$ m+ ]. L
  169.                         SYS_GPIOx_OneInit(GPIOF, 15, AF_OD, SPEED_25M);                //PF15
    8 B% K7 |, O, T7 [2 b
  170.                         SYS_GPIOx_SetAF(GPIOF, 14, AF4_I2C4);                                //AF4# I( z) w  a9 J
  171.                         SYS_GPIOx_SetAF(GPIOF, 15, AF4_I2C4);                                //AF4
    7 u( ^5 a7 h, }3 A% B- o3 f
  172. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PH11_12)        //PH11,PH12# U; _; v7 j0 V* Q! [
  173.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟2 p5 c( H* W5 M$ N" q
  174.                         SYS_GPIOx_OneInit(GPIOH, 11, AF_OD, SPEED_25M);                //PH11
      A5 N2 A0 g  j  v
  175.                         SYS_GPIOx_OneInit(GPIOH, 12, AF_OD, SPEED_25M);                //PH12  C# H9 A: R/ x/ @' N
  176.                         SYS_GPIOx_SetAF(GPIOH, 11, AF4_I2C4);                                //AF4
    0 S# k0 N! T8 x9 f" C
  177.                         SYS_GPIOx_SetAF(GPIOH, 12, AF4_I2C4);                                //AF4                        ) R' Q9 W7 \, h4 U5 ~
  178. #else
    ) _  ?8 m" u9 G" J7 q, H
  179.                         #error("无效的I2C4 IO选择");
    ' U. Q- `* I: w
  180. #endif //IIC_CH4_IO_SELECT                        ( x5 w3 r/ H1 t7 K' q2 N8 H
  181.                 }break;
    9 K! P2 x1 {" c2 K* w9 C
  182.                 default:4 m* M( X4 J# Q% k
  183.                 {
    * G/ R8 M% Q  U/ V1 F8 B
  184.                         DEBUG("初始化IIC失败:无效的IIC通道%d\r\n", ch);
    ' d8 e% k7 R1 I9 J" d
  185.                         return FALSE;/ J8 T) f1 O7 E9 l# e' I9 j
  186.                 }5 [, X" z3 k; y8 F2 _
  187.         }. ~- \% ~+ S+ X5 b
  188.         pHandle = &sg_IIC_Handle[ch];                                                        //获取相关通道的句柄
    / p: i0 s# Z5 S( p8 e$ o# b! A
  189.         if(pHandle == NULL)
    : k% u; E) w8 n  b/ w2 \6 ^
  190.         {
    2 R. V0 F4 H7 d" m' e
  191.                 DEBUG("初始化IIC失败:无效的IIC句柄\r\n");
    $ m; e$ j' E: x
  192.                 return FALSE;
    " S8 `2 m/ t3 ^1 o3 \$ k8 M$ K
  193.         }
    ( `. V2 @' m% j/ D4 P8 |
  194.         - D" B7 n3 b. l/ ]9 {* B
  195.         SYS_DeviceClockEnable(DevClock, TRUE);                                        //使能时钟2 q; L  O5 K& C
  196.         SYS_DeviceReset(DevClock);                                                                //外设复位- W3 r2 v7 K4 P; I  W
  197.         pHandle->I2Cx = (I2C_TypeDef *)I2C_TYPE_BUFF[ch];                //外设指针! v; a5 V, U7 ^0 s% ~! E9 S9 B) t: f6 p
  198.         pHandle->I2Cx->CR1 = 0;) W- t- r- v; c
  199.         Delay_US(1);                                                
      S4 k" E" C, T* v: ~' V% G0 m
  200.         pHandle->I2Cx->CR1 |= 2<<8;                                                                //设置噪声滤波器,关闭所有中断
    ) {9 y3 J; S3 l# r
  201.         pHandle->I2Cx->CR2 = 0;
    ! v/ X" I3 R9 O, T) e
  202.         pHandle->I2Cx->OAR1 = 0;7 R/ c5 m  l' R
  203.         pHandle->I2Cx->OAR2 = 0;
    1 y( T, w: D. m0 _5 j+ W
  204.         if(Speed_KHz > 1000) Speed_KHz = 1000;
    # K3 @" F; O; l: r6 r/ w
  205.         if(Speed_KHz < 10) Speed_KHz = 10;9 {* E; s+ q8 y6 A# y  k
  206.         pHandle->Speed_KHz = Speed_KHz;                                                        //记录速度
    5 K& U2 I4 n  l" w5 Q3 q) E( X* u$ a
  207.         if(TimeOutUs == 0)                                                                                //需要自动计算超时时间,时钟周期*10*10
    ; H1 K3 a+ t2 P8 K3 J" Y$ ~
  208.         {
    & E* g4 U$ G, ^
  209.                 TimeOutUs = 1000/Speed_KHz;                                                        //时钟周期
    7 ~' y8 X. s$ Y0 v1 B* w: |1 I
  210.                 TimeOutUs *= 10;                                                                        //字节周期& d/ O8 y- {8 ]2 W4 Y" ~
  211.                 TimeOutUs *= 10;                                                                        //超时时间为10个字节时间1 T( @% b* P  D
  212.         }: H7 w9 M% T, W& p
  213.         if(TimeOutUs < 3) TimeOutUs = 3;: S$ |8 l: z7 P8 {
  214.         pHandle->TimeOutUs = TimeOutUs;                                                        //记录通讯超时时间
      |7 E- l9 v( Z
  215.         uart_printf("IIC超时时间:%dus\r\n", pHandle->TimeOutUs);; k2 L+ ~0 d$ S, l& r8 B7 y
  216.         pHandle->I2Cx->TIMINGR = IIC_CalculationTiming(pHandle->Speed_KHz);//0x40912732;                                        //时序) |+ Y6 f, e9 l2 h
  217.         pHandle->I2Cx->CR1 |= BIT0;                                                                //使能IIC8 o3 {; h8 g$ p) X/ S5 I' D
  218.         pHandle->isMasterMode = TRUE;                                                        //主设备模式
    3 D9 ?# T0 J9 |
  219.         Delay_US(1);# K  O7 E" \# z$ B& \

  220. $ @* A9 A9 E% m/ f; S2 h7 \' `& i7 F$ r
  221.         return TRUE;* m$ D  j( u. D
  222. }* _+ k% W2 f7 h, o1 X. K. f9 \
  223. / E$ Y7 {) W9 T4 k( Z8 v

  224. 2 w, v- l2 b. J( @9 ]
  225. /*************************************************************************************************************************: B& f8 u. u, h: g
  226. * 函数        :                        static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)8 ]9 V: u! A5 C3 m- w9 S
  227. * 功能        :                        检查是否有NACK中断状态,如果有则清除掉8 X1 T9 L2 S# p  T
  228. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us" S: K% Q' }& f8 D: e
  229. * 返回        :                        IIC_ERROR1 S8 v- U8 q6 \4 I. D
  230. * 依赖        :                        底层宏定义0 f% J4 v1 A# f1 W8 Y+ C5 N" i
  231. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    , G/ y% X$ E7 g. S
  232. * 时间        :                        2020-02-15: e8 R* m3 _- ^5 k- O
  233. * 最后修改时间 :         2020-02-15
    + @( E1 I# B1 N
  234. * 说明        :                         如果有NACK中断,则先产生停止位,然后清清除掉所有的中断,并复位IIC,然后返回错误/ _$ ]" o5 P( s' ~# s( \
  235. *************************************************************************************************************************/  , k* F1 M5 G4 o  A( t
  236. static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)8 B7 p7 a1 I7 m6 e8 H5 F/ d
  237. {
    ( @) q4 T6 }3 j' ~8 n0 q
  238.         IIC_ERROR Error = IIC_OK;1 I9 o1 i0 h" j
  239.         
    ' H1 L, z) W* q* J* R" [& [
  240.         if(IIC_GetISR(pHandle) & IIC_FLAG_NACKF)        //接收到否定应答标志9 x. l2 b& G9 {; t$ L; S& s
  241.         {  A0 n1 M5 @- ^8 V& p7 c; t- |! @
  242.                 uart_printf("NACK : IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);4 }2 g. T8 @0 N1 ~7 _1 t2 A) o
  243.                 uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);4 `/ N! I* d: e% Q0 [  G8 h9 t: N
  244.                 uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));/ \9 w+ C& L* v6 X4 I
  245.                 //主设备下,如果没有开启自动产生停止位,则手动产生停止位
    4 c1 V5 k1 y/ K; P$ M0 g
  246.                 if(pHandle->isMasterMode && ((pHandle->I2Cx->CR2 & I2C_CR2_AUTOEND) == 0))
    1 t+ @/ O! n  g
  247.                 {) y3 t8 x; Q1 x; t3 ?6 b9 L
  248.                         IIC_SendStop(pHandle);                        //send stop
    , j& Q3 N4 U. ^6 J' y1 m+ I
  249.                 }
    ) U& ~$ {. F7 `# E3 }4 }& a' |
  250.                 //等待STOP标志有效
    * E: t# s7 y& ?& m
  251.                 while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)9 w/ W7 E( b  J' W- `
  252.                 {1 f7 C$ A6 e* @" D0 u6 P. J' ?
  253.                         if(TimeOutUs == 0)                                //检查是否超时了
    ( }7 x/ C# |" G  d* o
  254.                         {# _/ N& \6 A( t( G9 \/ N" t: D
  255.                                 break;" H& R8 |% s, S( }( R$ d5 G/ N: }8 W
  256.                         }                        1 e. o; d, R, C" l" R  }6 {
  257.                         TimeOutUs --;% n% f% a/ H8 X' W  R% @( w
  258.                         Delay_US(1);                                                //延时
    3 g1 O2 N. c4 s# k
  259.                 }; V' I* q  D2 ]# z
  260.                 //清除相关的中断标志# \4 B& }& k( c& L8 L6 l. ?4 \3 O8 d
  261.                 IIC_ClearISR(pHandle, IIC_FLAG_NACKF | IIC_FLAG_STOPF);        //清除NACK,STOP标志+ K/ A; f; v0 a' P
  262.                 pHandle->I2Cx->CR2 = 0;                                                                                //清除CR2寄存器6 E3 T  A! S6 k0 q
  263.                 IIC_SoftReset(pHandle);                                                                        //执行软复位
    9 w+ o" N  O$ {. U* d
  264.                 if(TimeOutUs == 0)                                                //没有超时,就是硬件通讯出错了1 f+ C5 R! F4 @3 e8 T/ {" t
  265.                 {
    7 c( f8 m% Q2 O! X
  266.                         DEBUG("IIC发送stop超时\r\n");/ Q4 G$ m5 s8 k  H1 |2 ]
  267.                         Error = IIC_TIMEOUT;                                //超时
    ) _" O  L) |. y# Y3 g8 \
  268.                 }3 `" b2 o0 ]- h; |% H3 M% W
  269.                 else
    . L+ k. H# k9 T$ m+ Y" V
  270.                 {
    + r" ^8 x* V6 P' h0 u
  271.                         Error = IIC_HAL_ERROR;                                //底层错误" C. B9 x- Q3 K) X/ y7 g/ F: B
  272.                 }
    9 t9 g3 j: m0 L( O9 ?. Z9 I8 \
  273.         }0 d: D3 K. O% ]" |/ a8 s
  274.         
    $ x* G+ m& A6 N4 X
  275.         return Error;( n: p; r* J$ A) {# _4 ^7 ?
  276. }
    ) Y/ S1 o4 {' @4 D$ j8 Q

  277.   J& _- f% Z4 S* r% L3 R: L1 n
  278. 2 K  P/ |8 k4 y

  279. . S+ T0 H8 P  s
  280. /*************************************************************************************************************************/ `& Q7 E+ D& C, v, Z
  281. * 函数        :                        static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)' b1 M( q- ^: O. e; f9 ~  {
  282. * 功能        :                        等待TXIS中断有效(等待 I2C_TXDR 发送寄存器为空)
    : u3 C1 X1 _; P9 b* }8 P7 S; d
  283. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us
    , c0 M4 g+ Z0 T7 e
  284. * 返回        :                        IIC_ERROR
      A% I4 W  c% J$ u: A- a2 T" `( V
  285. * 依赖        :                        底层宏定义, @. Z* ^& ]4 J! i' {
  286. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    % d2 D' p8 l) @$ H
  287. * 时间        :                        2020-02-15
    . `8 ]0 |/ M4 B, E
  288. * 最后修改时间 :         2020-02-15
    " [) ~- B2 m  l% v& t
  289. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的
    ! c2 F1 A7 |8 g$ k- w/ O8 w0 D
  290. *************************************************************************************************************************/  & _, }0 y& U  x! J
  291. static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs); |0 \& r: l( X7 _+ e
  292. {
    # T- x9 V) j/ c* f$ b
  293.         //等待TXIS中断有效' Y5 P1 J" x0 Q6 H
  294.         while((IIC_GetISR(pHandle) & IIC_FLAG_TXIS) == 0)
    0 e8 k, b3 B1 z2 ?. _) [
  295.         {
    ; E  _$ q  \: ^% e9 ^/ r6 {
  296.                 //有NACK中断,进行处理
    0 i0 C% v6 [" D  G% x
  297.                 if(IIC_isCheckNackFlag(pHandle, TimeOutUs) != IIC_OK)        2 m, u* b% O0 U  {$ i; n
  298.                 {! I# G+ S7 R3 u! Z8 K" z- J
  299.                         DEBUG("检测到NAK错误\r\n");
    2 T7 v1 G; M) W8 s% ]/ }% P
  300.                         return IIC_NACK;0 G1 \8 \  J( Q0 B% ~
  301.                 }
    1 q3 v% S; t# u* s" _1 w
  302.                   m2 r  d! a# b& J% `2 |
  303.                 if(TimeOutUs == 0)                                        //检查是否超时了
    - z/ d4 g5 h! _% ^
  304.                 {2 n& E: R! `0 J1 A0 l- k) J  a
  305.                         uart_printf("IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);
    : z; r7 W: B0 O! `& I
  306.                         uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    3 F" \' @4 c5 U5 h; s5 X7 `" G
  307.                         uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));
    4 J8 W& C7 y, o8 ~
  308.                         . \, Z% k9 `3 m, @: ~* O* ]
  309.                         IIC_SoftReset(pHandle);                //执行软复位
    - k5 m6 t3 E3 W: V& U
  310.                         return IIC_TIMEOUT;                                //超时
    3 \: Z  K, t3 J; a  T6 |
  311.                 }                        / x! |0 r7 H, `7 B$ G& ]6 B
  312.                 TimeOutUs --;# a( l  Q, L( j/ C4 |( I7 O
  313.                 Delay_US(1);                                                //延时# k5 Y* @$ S. {7 Q" {. X6 G4 z5 ^
  314.         }
    + h  u/ D$ p. d0 w
  315.         
    " _! g/ L5 _, |4 ]
  316.         return IIC_OK;
    2 _6 N5 r' n4 T$ F4 U9 K5 j4 `5 P
  317. }) w0 e, P$ t# J

  318. ; x: @6 J! L! w; j9 e8 J
  319. ' O: [- S+ F8 j! K0 A
  320. /*************************************************************************************************************************, w# X5 [' q; q" \8 A# J
  321. * 函数        :                        static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)
    ' Q4 h/ v& R  M) ^5 u3 v8 J
  322. * 功能        :                        等待STOP中断有效(等待 发送结束 )1 N: k) a9 S: U; Z7 M
  323. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us8 Z  v3 i. F* v4 K3 g4 v
  324. * 返回        :                        IIC_ERROR1 @+ C! g$ Y6 k+ y3 f  v, ]* y
  325. * 依赖        :                        底层宏定义
    3 V( R6 u6 F# ~
  326. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    & Z, p1 h5 w# g" ~: A
  327. * 时间        :                        2020-02-15! A2 |- ^1 O( ^. E! x
  328. * 最后修改时间 :         2020-02-15
    0 Q  ]' {* Q8 Q9 V
  329. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的
    2 S: A% o! [1 B+ I8 R6 r; Z
  330. *************************************************************************************************************************/  : P% `; f. {0 H2 q
  331. static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)& U6 Q) R( |1 e5 J. g! _
  332. {8 g/ `+ a# V% W) @$ n1 e1 ^
  333.         //等待STOPF中断有效$ e$ P! e0 D9 [6 w! X6 A2 |( y
  334.         while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
    & N, b, V/ w, S9 {' U8 P6 E
  335.         {/ P% b- X7 P" K! ?5 T& }: M1 b
  336.                 //有NACK中断,进行处理% T# L$ _: }$ v
  337.                 if(IIC_isCheckNackFlag(pHandle, 5) != IIC_OK)        " z) ?7 a, F% R( e* `/ h1 l, V" A
  338.                 {3 `( t, p: O. H- W' h" N
  339.                         return IIC_HAL_ERROR;
    7 [/ y6 y, N% a
  340.                 }
    * u0 q+ f( v9 p8 M0 v
  341.                 ' M% g$ L8 W4 k4 s: F% N9 t
  342.                 if(TimeOutUs == 0)                                        //检查是否超时了
    / \: \) }6 A% u' l4 u
  343.                 {
    8 e2 {9 V5 T# V, T* q
  344.                         IIC_SoftReset(pHandle);                //执行软复位
    0 o- h, ?0 O6 o# Z+ ^& U
  345.                         DEBUG("IIC等待结束超时\r\n");6 u. k  P, |2 }  L" Q
  346.                         return IIC_TIMEOUT;                                //超时7 L4 j; ^# [9 ?$ X/ |' E* k7 Q7 b
  347.                 }                        3 T, u  C3 e) l+ w
  348.                 TimeOutUs --;0 a* |& B0 [' m8 U1 l+ c4 t
  349.                 Delay_US(1);                                                //延时
    6 N7 o# x# m# C% x6 o; Y8 \
  350.         }# a6 Y% L4 L! [5 s7 `! B% A# I
  351.           e- g- _! p% G$ b
  352.         return IIC_OK;- s6 h, w; \' c8 x6 k0 b0 l
  353. }7 U  p/ r. q$ l; @/ r
  354. ; o4 R. a3 M& l
  355. * x& h2 C6 G8 _# h* B
  356. /*************************************************************************************************************************
    + x0 Z* I0 R1 \7 G9 i, O  A) Z
  357. * 函数        :                        static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)1 q* T4 u; O6 z, o% |# U+ y
  358. * 功能        :                        等待中断有效
    : i5 J& \& e2 C7 u- }+ ^8 _, `
  359. * 参数        :                        pHandle:句柄;Flag:需要等待的flag,见IIC_FLAG_xxx;isWaitFlagSet:TRUE:等待标志有效,FALSE:等待标志复位;TimeOutUs:超时时间,单位Us
    $ v, _- ?  k+ u& ~( p' Z2 D# A# U
  360. * 返回        :                        IIC_ERROR" B* Y2 D, F( |! l+ e+ v
  361. * 依赖        :                        底层宏定义) d7 I$ U  G2 i0 W4 P+ f3 T
  362. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>: n: {% a! v. {7 s# {
  363. * 时间        :                        2020-02-150 b1 c4 H4 b; V
  364. * 最后修改时间 :         2020-02-15
    ; Q0 r0 K$ F; z9 Y: G8 H
  365. * 说明        :                         ; s7 c9 o* ]9 ^) X: |  P: p* v, k
  366. *************************************************************************************************************************/  
    2 m: j& a2 b2 m2 M
  367. static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
      [+ R# m5 }8 K; \: _
  368. {
    8 H' S  w  p! }, E/ h) P* |
  369.         if(isWaitFlagSet)        //需要等待标志有效; F! W: t/ O: l$ B, o, K
  370.         {
    ) Q+ l  y9 ]6 O$ B+ y" g" v
  371.                 while((IIC_GetISR(pHandle) & Flag) == 0)* i2 C1 q2 Q* @4 g: z
  372.                 {, j* i/ I0 @- ]- h7 f
  373.                         if(TimeOutUs == 0)                                        //检查是否超时了2 b4 ^+ d' g8 s2 z1 D# `: s
  374.                         {. c) k- e3 |6 N' [# ]! j" p$ h0 c
  375.                                 return IIC_TIMEOUT;                                //超时3 U9 l4 x7 B% {" q* [& h7 g' A7 k
  376.                         }                        
      \1 `, a1 [, B$ i$ A( P; T
  377.                         TimeOutUs --;% M( h7 d. Q. q5 o! A2 O0 r
  378.                         Delay_US(1);                                                //延时0 q9 M1 r  [4 _6 m. m5 f
  379.                 }, n1 G% E6 ]; g
  380.         }
    - Y% ]& g) j1 r/ P
  381.         else                                //需要等待标志复位! q/ L9 o( V; L# j4 {" q
  382.         {
    3 U5 |: m% v8 {1 y! a) x& H
  383.                 while((IIC_GetISR(pHandle) & Flag) != 0)
    1 Q1 F& }! p0 k5 \2 Q/ p9 K
  384.                 {. d0 a/ R6 q. {% U6 d
  385.                         if(TimeOutUs == 0)                                        //检查是否超时了
    ; ~' y. B  L) p/ y5 t
  386.                         {
    7 `" h. n( O, S( W, A# V) x
  387.                                 return IIC_TIMEOUT;                                //超时
    % _& g7 F1 T* a0 J  p& i: Z
  388.                         }                        * F3 Z3 Y8 a7 K0 n
  389.                         TimeOutUs --;0 t' {! o, @  X
  390.                         Delay_US(1);                                                //延时
    " e3 L$ J+ n! P2 u) U9 B
  391.                 }
    8 h; {- m( N. s
  392.         }
    " I/ y1 G$ O9 C1 Y
  393. 7 Z9 S# T7 b7 f# K- x4 {$ s
  394.         return IIC_OK;3 s# t  d: t$ Z( {; ^: z
  395. }( k- C4 x$ k( f) @" A) K+ a
  396.   a% o) k. ?2 {1 |
  397. " A: X8 e6 x# T* J- m6 [, Z

  398.   z6 [# `' K: ?

  399. * Q" t+ C0 q, w* p5 s% d
  400. /*************************************************************************************************************************( q; Y( \  V) n" H" i- a
  401. * 函数        :                        static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)
    0 P% E  A6 i; n( j/ N
  402. * 功能        :                        主设备传输配置(配置CR2寄存器)* W- t' g" V' H! V- x- w8 y
  403. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;TransByteCount:需要传输的数据长度;EndorReload:自动结束还是重载设置,见IIC_RELOAD_END_MODE;StartAndWR:开始读写控制,见StartAndWR' h6 B: i) ^; J  j0 O
  404. * 返回        :                        无
    . B) h: O& j: y  ?
  405. * 依赖        :                        底层宏定义
    1 L7 o$ Q% f3 [4 w& m0 e' n
  406. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    % i: ~& U" a; G7 P8 L  y' B
  407. * 时间        :                        2020-02-154 ^! v. j: f5 a) s( X
  408. * 最后修改时间 :         2020-02-16
    * n0 {9 E" U  I# K: ~
  409. * 说明        :                         在往 NBYTE 中设置最后一次传输的字节数前,必须把 RELOAD 位清零便于后续自动发送STOP。
    3 }9 O5 g- R$ G. j+ {" V# h
  410.                                         当 RELOAD 位置 1 时,AUTOEND 位将不起作用;+ P5 b9 O7 Z9 |; m7 q
  411. *************************************************************************************************************************/  
    3 k  I" f* C! u) K' `6 x; o  x
  412. static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)+ Z3 N& b/ r1 ]2 }0 T
  413. {
    ; X( d0 p8 R+ w/ d
  414.         u32 temp = 0;
    8 y& l) x3 }- [0 N% P
  415.         ( d% N2 i: d  m4 i: Y& Q/ W+ l
  416.         //先读取CR2寄存器的值
    / X/ Y/ L  X- f( K1 K; v
  417.         temp = pHandle->I2Cx->CR2;
    6 E- v9 C( j# g0 w/ c
  418.         //清除掉相关的字节
    " F- I: S% q# ^0 n; D
  419.         temp &= (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND |I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP));
    : ?) u- ~* R: l6 ^- ]
  420.         //生成配置数据
    ' \) Z  ^' l$ c9 o
  421.         temp |= (u32)(((u32)SlaveAddr & I2C_CR2_SADD) | (((u32)TransByteCount << 16 ) & I2C_CR2_NBYTES));
    4 y# {- `3 H, n# ~/ Y
  422.         //重载与自动结束只能二选一3 c; A: W) Z* U
  423.         if(EndorReload == IIC_AUTOEND_MODE)         ! `, w" x5 }4 H- u1 b- \! ~& }- p0 i
  424.         {
    1 [: e" G. s$ \  [9 L% R6 R
  425.                 temp |= I2C_CR2_AUTOEND;        //自动结束模式
    / k: J4 \  ~: w+ |
  426.         }. e' T! f6 W/ Q
  427.         else if(EndorReload == IIC_RELOAD_MODE)
    4 S+ Y) p  H$ B
  428.         {
    ' a) D- [) s  C9 [5 C' }
  429.                 temp |= I2C_CR2_RELOAD;                //NBYTES 重载模式
    4 R  c0 Z1 ]$ B
  430.         }
    5 w& @8 U( U  A. f  w( I" y: W
  431.         
    ( C3 {% L9 @  Z: O( h. n
  432.         switch(StartAndWR)
    - j9 V" G# h1 m' G! G# ?6 q
  433.         {( w0 @) l! l& i8 z+ S
  434.                 case IIC_NOSTART_WRITE        :        break;        //没有开始的写-默认就是这样的
    : @7 i6 P2 x# i
  435.                 case IIC_NOSTART_READ        :                        //没有开始的读-用于后续数据读取- q5 q% |' g6 `3 D! O8 n
  436.                 {" Y! R  a1 `% _: K+ v9 [4 f% k
  437.                         temp |= I2C_CR2_RD_WRN;                        //读取
    4 F3 p6 K3 M* a! U0 Q2 Y$ y3 t
  438.                 }break;9 g. k7 ^+ Q1 A$ s
  439.                 case IIC_START_WRITE        :                        //生成开始写
    , t+ v. R2 Z$ E9 k+ ^
  440.                 {& Y( S% `2 b/ [9 P4 l# v5 b
  441.                         temp |= I2C_CR2_START;                        //启动传输
    7 ?/ T0 l0 G( f# L- t2 A' e) O8 T
  442.                 }break;
    " P1 }- }" Z$ k8 F
  443.                 case IIC_START_READ                :                        //生成开始读        8 M5 z8 O+ Z2 N1 Y( f
  444.                 {
    / L1 k' T. p# \
  445.                         temp |= I2C_CR2_RD_WRN;                        //读取, Q4 L/ q1 V4 }& w# v5 K$ Y
  446.                         temp |= I2C_CR2_START;                        //启动传输/ n* ]! K9 I% G( p1 F
  447.                 }break;$ |  f( }, f3 s5 p  H, \
  448.                 default:break;' \( z' B/ H6 [2 w* I
  449.         }
    , ]' K" h3 J2 z& k1 H" R. F
  450.         
    " h( N" m  m7 `6 ]: q4 E# ?
  451.         //uart_printf("准备写入CR2=0x%X\t", temp);) C5 _* o4 w4 r$ z$ O) T
  452.         //更新到寄存器
    1 z* i. t# G5 i- y# m/ O
  453.         pHandle->I2Cx->CR2 = temp;  //测试" `# X: U/ i: [" G% E
  454.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    0 C; r7 k. p5 A+ y
  455.         Delay_US(100);$ i8 W1 z+ H: `- F  {  m; b
  456. }( M; X4 |3 U+ T4 b; K" A

  457. & [4 ^: W9 D6 w+ e- Y

  458. ( v* [1 l( l! j% @7 s8 t$ O8 [2 R" X1 Q
  459. /*************************************************************************************************************************
    5 c/ }: @2 ]- N3 a/ O! }0 y* W
  460. * 函数        :                        static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)& J  U$ ~) T  u: E3 E
  461. * 功能        :                        IIC发送一字节
    3 Z$ @3 O& ]1 S2 g+ e! i
  462. * 参数        :                        pHandle:句柄;data:待发送数据;TimeOutUs:超时时间,单位us% W2 d0 H7 ^/ G& F, m+ M
  463. * 返回        :                        IIC_ERROR, X4 m# u2 A2 u, L7 E! b
  464. * 依赖        :                        底层宏定义! n2 ^7 e2 ]' l8 W
  465. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>; E& l; n: P9 D9 E. ~
  466. * 时间        :                        2020-02-15
    3 [- w9 h( q/ D* R; o/ i
  467. * 最后修改时间 :         2020-02-16
    : Z0 `) N. _/ n$ o" S. ]" v
  468. * 说明        :                         TXIS有效后才会进行数据发送,不会检查数据发送是否完成。; L3 u/ v* M! ~
  469.                                         如果最后一个字节发送完成后不会再触发TXIS中断,只会触发TC中断
    + A* _; m  L" b) d
  470. *************************************************************************************************************************/  ; G9 |3 X6 t6 S5 H6 I! F
  471. static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)
    ' W& q) ~: D( f# s
  472. {
      U4 [: P, s- G4 G+ ?
  473.         IIC_ERROR Error = IIC_isWaitTXIS(pHandle, TimeOutUs);                                //先等待可以发数据
    # i. |( Z- g4 R" O1 v% ]
  474.         if(Error != IIC_OK) return Error;
    / U) N/ q9 R# a( Z8 v( |- L
  475.         pHandle->I2Cx->TXDR = data;                                                                                        //写数据到发送寄存器-不会等待数据发送完成        0 ^  k+ p" ]- c) [

  476. 1 i: f1 L/ k* J( c: u1 K# [
  477.         return IIC_OK;. P( z4 Q' ~8 P! o
  478. }
    $ g8 Z5 {8 t, B" m7 D

  479. ; g* V' ]: |- W8 H+ ~& L. D; ]8 q4 K
  480. /*************************************************************************************************************************7 G- y: C8 O  G! l% A+ x
  481. * 函数        :                        static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    ( E& h6 _; U: J7 N* K- r2 L7 [
  482.                                                 bool isRead,u32 TimeOutUs)
    ; t# G; [4 D0 y5 A
  483. * 功能        :                        主设备请求发送从机地址与目标寄存器地址0 c' {  w; d9 F; M
  484. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;RegAddr:寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,
    8 W9 }$ j: g0 j- ]8 ?
  485.                                                 FALSE:16bit寄存器地址;isRead:TRUE:这个操作是读取寄存器;否则是写入寄存器;TimeOutUs:超时时间,单位us
      J4 H6 r2 C2 X! I! V% ?+ R
  486. * 返回        :                        IIC_ERROR3 l7 E5 r3 x, F' |
  487. * 依赖        :                        底层宏定义  K. }4 F$ s6 b: F8 w
  488. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    2 r- ~/ n) I& G- N
  489. * 时间        :                        2020-02-15
    7 d5 X: z. U4 `; r8 Q7 u
  490. * 最后修改时间 :         2020-02-16
    4 }& x, g: x0 E
  491. * 说明        :                         . A3 V1 `+ d; V7 z# t% J3 t9 g
  492. *************************************************************************************************************************/  8 Z2 K% Y( G0 Y1 t$ n+ ?7 I6 d
  493. static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,bool isRead, u32 TimeOutUs)
    5 G: Z$ `' e  ?1 J: _2 R$ U
  494. {        
    ' J4 |0 ^2 Q: ?, V7 W4 s' C
  495.         IIC_ERROR Error;$ e& ~. H0 i( @( P& f4 M( @4 ?
  496.         1 k8 _! A) Q3 |2 K" M% u& c; |
  497.         //uart_printf("WriteAddr1:CR1=0x%X\t", pHandle->I2Cx->CR1);
    # n6 ]9 z1 @( N1 H  Y! I
  498.         //uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    2 V8 j1 L1 P# q( \  x
  499.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    - ^: D  X1 r& m0 v4 P
  500.         //传输配置,并启动传输,发送起始序列,开始IIC传输了
    , |& G: T) [/ l4 x$ Z* ^
  501.         //如果是读取则使能软件结束,如果是写则是自动重载- T0 k( L3 h/ x
  502.         IIC_MasterTransConfig(pHandle, SlaveAddr, (is8bitRegAddr==FALSE)?2:1, (isRead)?IIC_SOFTEND_MODE:IIC_RELOAD_MODE, IIC_START_WRITE);        //传输相关配置-写,并启动传输
    * C* _' H% I+ u" I' {% J" M
  503.         
    # w  q3 i  L( K# Y
  504.         //开始发送寄存器地址+ L7 Z3 t' b! _) v( B; h
  505.         if(is8bitRegAddr==FALSE)                                                                                                //寄存器地址是16位的,IIC通常是MSB高位在前,需要进行高低位对调
    4 v+ i/ Z( f: U' {' k- z
  506.         {0 O  y* |; ?* W7 h
  507.                 Error = IIC_SendByte(pHandle, RegAddr>>8, TimeOutUs);        //先发送MSB-非最后一字节
    . }& M( X/ o+ _) V2 i- E
  508.                 if(Error != IIC_OK)
    / y0 {" U/ a6 y+ T- _4 ^- b, e4 x9 b
  509.                 {( ?& l/ {( m) R
  510.                         DEBUG("IIC发送寄存器地址MSB失败\r\n");' b4 A+ X* o% A- O5 t; [4 ]5 O5 t& |
  511.                         return Error;
    2 F4 C7 k% }& B* |* a
  512.                 }        
    8 W: R- t+ s, s
  513.         }
    * F7 I4 ~, M# I6 U0 M3 I1 c" Z
  514.         Error = IIC_SendByte(pHandle, RegAddr & 0xFF, TimeOutUs);        //再发送LSB-最后一字节/ |, u6 v5 e/ T; r5 t
  515.         if(Error != IIC_OK)
    # k, g$ R" M1 l$ _1 F0 T/ X0 [
  516.         {
    2 }6 ~7 G' o6 E: s/ |
  517.                 DEBUG("IIC发送寄存器地址LSB失败\r\n");# _$ W3 A) I! W) S- m
  518.                 return Error;6 X/ K7 Z. x: E# Z. |: z$ q7 [6 z1 ^
  519.         }
    7 L) G0 h, ?! i6 a! L* v7 Y9 _  \: t
  520.         //等待全部数据发送完成7 n& m- O: k: ]1 |6 q& o$ W: M% E2 O; T
  521.         if(isRead)        //读取方向-非重载,等待数据传输完成 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。% @8 l& r0 {: H& F. x5 D
  522.         {7 t8 q7 b% |+ O4 q, o+ [
  523.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TC, TRUE, TimeOutUs) != IIC_OK)8 P5 h' V+ V. F- z+ A* N; \0 |
  524.                 {+ y$ |! U0 [3 T& r
  525.                         return IIC_TIMEOUT;
    6 E7 B" O" J7 a  f4 n
  526.                 }8 @! O3 {2 q) X
  527.         }        
    + {! H( l! v3 g$ Q
  528.         else //写入方向,等待重载
    , D, }! t/ {: X( p. i
  529.         {
    * {8 T6 ~; n, X0 B' ~3 o, b+ w
  530.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TCR, TRUE, TimeOutUs) != IIC_OK)4 B- m3 E  Y' ]7 u8 c0 w" g, s
  531.                 {3 d1 E% z* V$ k( ?3 F# B* O
  532.                         return IIC_TIMEOUT;" s: j$ c# [1 b+ {: |
  533.                 }- k$ b0 {4 k  \' J' r; ~8 L
  534.         }# Y/ Q( Y$ I0 R1 ~) {
  535.         6 i9 n6 d1 y9 z7 k' Q5 B
  536.         return Error;
    , i% Q1 S+ _* M- {% T/ N
  537. }
    : ~( b4 \) `% ~  I
  538. 1 a" h0 C9 Q6 B+ x( j

  539. : a$ D% \& W# {# @8 z. H1 B7 U
  540. /*************************************************************************************************************************7 F' n2 H, K; M( [, r* [+ N+ r
  541. * 函数        :                        static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
    ; u4 X$ Z6 a; Q( M# e2 W: D
  542. * 功能        :                        等待接收一字节数据
    5 V6 x# @: P0 V% n3 W( A0 L
  543. * 参数        :                        pHandle:句柄;pData:接收的字节数据缓冲区;TimeOutUs:超时时间,单位ms0 L: a# h  ?) |0 T9 z2 L3 @( Q) ]
  544. * 返回        :                        IIC_ERROR
    ; O* M6 e" v3 e/ D. h) H* k* O! \
  545. * 依赖        :                        底层宏定义% M- j5 q( D) q* V1 K/ W1 Q( R1 M9 U
  546. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ' U+ c: P% d3 K
  547. * 时间        :                        2020-02-15
    . c6 @9 h: ?4 H7 a$ S! z; L
  548. * 最后修改时间 :         2020-02-15; L! m3 n' y4 D
  549. * 说明        :                         当RXNE有效后读取一条数据,否则可能会超时
    5 Q* t' h! p+ F. e7 u
  550. *************************************************************************************************************************/  2 a# f; g3 U, ?' S, \
  551. static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)1 ]( L/ X2 o0 T  ~; [
  552. {, n0 `# h: @. t; Q4 K
  553.         while((IIC_GetISR(pHandle) & IIC_FLAG_RXNE) == 0)        //等待RXNE有效2 Q; Z3 j( s  D6 ~9 Y4 T. C
  554.         {6 M4 u: m, z# N2 x5 e
  555.                 if(TimeOutUs == 0)                                        //检查是否超时了
    % Y8 s9 L) Y8 n4 I1 o5 a) Q+ \
  556.                 {  W4 x' s0 z6 H+ v  x( N
  557.                         DEBUG("IIC等待接收超时\r\n");
    . T* x; O1 p- V% ?
  558.                         return IIC_TIMEOUT;                                //超时( p  x& @4 T" f0 O
  559.                 }                        % T5 H: g7 j. m+ p
  560.                 TimeOutUs --;
    - B( j, e- O' F" H9 O% S
  561.                 Delay_US(1);                                                //延时
    9 j2 D& Y( H  K, x* y! P$ R
  562.         }
    - i. o  E. A  {+ m9 x. d) X- ]
  563.                
    2 R1 @  \" r6 |) n
  564.         *pData = pHandle->I2Cx->RXDR;                                                        //读取收到的数据
    4 E% P" |% t; d3 O( {% k
  565.         return IIC_OK;
    / h+ t) g/ z( u1 V( X7 Y
  566. }
    6 x3 n4 v% {  ~( c' O9 B

  567. 5 z. v* c0 e9 z( y( Z

  568. % W' k$ }2 h/ S: `: g" b
  569. /*************************************************************************************************************************+ T0 V) R8 |9 b; ^2 R1 Z: V5 ~
  570. * 函数        :                        IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    / _5 u+ s- e! h. O1 A: a
  571.                                                 u8 *pDataBuff, u16 ReadByteNum)
    : x' ~& k* u7 X% w0 |& E
  572. * 功能        :                        IIC读取寄存器(可以读取1个或者多个寄存器)9 x; G( U1 r- u* {7 M
  573. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要读取的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;
    ; J" \& L* t& Y% l  o/ y
  574.                                                 pDataBuff:接收的字节数据缓冲区;ReadByteNum:要读取的寄存器数量;
    " U. W* |1 {( u- j0 A/ z3 O
  575. * 返回        :                        IIC_ERROR
    ! `2 _1 g" U4 \$ B8 S
  576. * 依赖        :                        底层宏定义
    + d% _; n3 N* r1 z+ {/ F/ ]; t
  577. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>7 z3 q6 z  \3 U! A( n) y, M
  578. * 时间        :                        2020-02-15
    3 E! K, U6 N; H# D+ G$ p0 v: `) G
  579. * 最后修改时间 :         2020-02-15
    8 p9 T0 O5 d: R6 V, e! N! q& x3 m
  580. * 说明        :                         读取的数据都是小端模式,如果是16bit的寄存器,请读取偶数个数据,并且需要另外进行高低字节对调最后组成16bit数据! ^& ]! c) j* ]3 q  w
  581.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如# J) w. s- X5 t3 V
  582.                                                 增加信号量
    # p+ d' T& v5 J  T8 I
  583.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在: L& B0 [: F, [8 Q$ g
  584.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。) {, C; \. J9 ?, Z9 M
  585. *************************************************************************************************************************/
      v7 V. d$ z- V: C' R6 y8 X
  586. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum)
    ( m: L0 G; f* _8 f6 ^
  587. {0 m9 t6 E5 Y5 i& F: h# Y! x
  588.         IIC_ERROR Error = IIC_OK;/ E& C$ j* G0 K0 M+ n3 j
  589.         u16 ReadCount;
    ( |! O& a. V7 _# S
  590.         IIC_HANDLE *pHandle;5 e& W5 B4 W; }9 g7 y* O
  591.         & a. ^  l5 B; s# H# N& g" t
  592.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || ReadByteNum == 0)* G  V9 C) X6 L2 j6 Q3 N
  593.         {6 ]! ?; S9 A( D
  594.                 DEBUG("IIC错误:无效的参数\r\n");- ~  o' W/ Z6 P1 F9 U" ]9 M4 ~
  595.                 return IIC_PARAMETER_ERROR;# I% F+ Q, Q7 S  K) Y
  596.         }
    4 D- [! D% Y5 E/ R- f' w
  597.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄
    ( i' f+ S0 N+ ]
  598.         7 ~3 @# B$ v+ s' T
  599.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙
    6 y( c- @; b( y1 }$ k+ S2 Z
  600.         {
    ! D+ j! }0 o3 O( B
  601.                 IIC_SoftReset(pHandle);, b2 I, e5 \5 `: r3 m
  602.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");; X& H. a0 J* t4 R: d/ h
  603.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙0 c' F) T. Y& v. U/ |  h% @5 t
  604.                 {
    & A! d% D) X  f* h0 t
  605.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");5 `$ G: p+ {- U- \& P
  606.                         Error = IIC_BUSY;
    3 P& O. R# A0 _6 @1 G/ @
  607.                         goto end_loop;: }% e0 t9 y( l3 }. V3 ~5 G: Z: y, Z
  608.                 }
    ( q8 J" a8 v5 u% j8 Z+ S! A7 |
  609.         }
    " O4 G  d3 |$ e3 J0 S7 m/ V, I
  610.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    $ q1 g- K  g: X; V3 I
  611.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器
    ) W" E0 R6 s1 S
  612.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START1 n6 b* k0 g2 `+ N7 c
  613.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,TRUE, pHandle->TimeOutUs);
    1 b5 F% N% q$ ~0 Y3 G, ~3 P; G- q# \
  614.         if(Error != IIC_OK)$ t2 G8 N$ q( {; H8 F
  615.         {
    ; s% E6 E: F6 o/ c
  616.                 goto end_loop;
    / U6 }6 y0 O+ I, Z- l6 _( _3 T0 c
  617.         }
    3 I9 ?- P# B& p8 f4 B
  618.         //发送后续数据
    ' N1 p, i" L2 I  |
  619.         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取-后续还有数据,需要重载
    1 F" b8 t0 g, ^/ x
  620.         {6 _* c# s5 L9 o% H' a/ f4 n# c
  621.                 ReadCount = 255;        //本次需要读取的数据长度255
    . r6 y) D& u1 _4 I: k
  622.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输               
    * [5 q, I  f: ^6 N
  623.         }
    . k. C: [* i1 k6 K: W# a2 e- ^* D
  624.         else
    8 C/ E! E2 E% c5 w& K2 }% ]
  625.         {
    1 ~+ ~4 a/ \" Q8 I
  626.                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯后自动结束
    : [" g6 g/ f, ?: ?9 F: Z/ K
  627.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输
    ) @8 T, w* F  Y. a) L. j7 H  G
  628.         }
    + D( T; ~( l9 t& W' K
  629.         0 W; X/ t' F( J2 T. z
  630.         //循环等待接收数据完成, n2 F$ _: _- \. B
  631.         do  d# m% F" g8 q) f
  632.         {9 Z/ P2 l2 U9 h/ p
  633.                 //uart_printf("读ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    ' x4 ]" l9 h( n0 b7 `- j; J* I$ H) r4 k
  634.                 Error = IIC_WaitRxOneByte(pHandle, pDataBuff,  pHandle->TimeOutUs);                                        //接收1字节数据  f1 ]: F$ G7 j1 v
  635.                 if(Error != IIC_OK)' F7 X" r- K% o6 d1 ]8 ^4 k
  636.                 {
    ; }) o8 K1 K$ w7 H% [4 E$ M2 r
  637.                         goto end_loop;& H' O) ]4 E) T3 }) q& j
  638.                 }' ?4 |" i$ G3 X( {, p( M; r  z9 _
  639.         
    ' c* m' v* p# J$ q
  640.                 pDataBuff ++;$ @6 P* o- j% m* G/ l3 R+ m
  641.                 ReadCount --;: ^0 r3 x5 ^9 W6 {% ~$ B' r2 A
  642.                 ReadByteNum --;) f1 q, q2 Q. I1 E% h2 o2 z
  643.                 if((ReadByteNum > 0) && (ReadCount == 0))        //还有数据要读取; K6 ]+ w6 }6 i# H1 s: X# F! j: m
  644.                 {5 W+ a, `3 P# g& [
  645.                         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取% O5 h2 C- K* L: H( V
  646.                         {
    6 h! ]! Y2 l5 ~( m1 H4 P+ y% h
  647.                                 ReadCount = 255;        //本次需要读取的数据长度255-后续还有数据,需要重载0 v- D4 f* @( T  P% h0 F0 n/ L; j
  648.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        . k8 I2 S7 w! P
  649.                         }: P0 {; c/ J* e4 ^
  650.                         else
    4 l' z$ ^/ K/ F  b
  651.                         {" Q* |- V' B  \$ f  J
  652.                                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯,自动结束
    # t! V: l4 r6 R# B! P6 _9 w
  653.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        7 [; g' j4 k% {# _: b
  654.                         }
    ; q- ^- r3 D- E+ C
  655.                 }- x! Q7 u; p( m7 G' m/ \
  656.         }while(ReadByteNum);
    4 D) E' H4 |7 \7 ?  e0 ^* A- k
  657.         //读取完成了,等待STOP位有效
    1 y3 O1 @- W/ p6 Z2 {
  658.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);7 d9 w! n9 r2 e+ c' w/ M$ Z
  659.         if(Error != IIC_OK)
    4 {* W; P* _/ O, r1 A
  660.         {6 N9 S5 L$ e- d/ Q/ h; K7 G
  661.                 Error = IIC_STOP_ERROR;
    3 K8 }9 Z( E9 r6 X$ ]: w" s
  662.                 goto end_loop;1 l! |7 S# G. y% r* {
  663.         }        8 `' l) F" q1 ~2 r; c
  664.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
      F; I, k* F* k! l
  665.         7 I# t; u) T! u, ^
  666. end_loop:        / P# ?( j- w; c# Z
  667.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        6 q/ O+ j8 }7 j1 V5 Z8 ]/ z3 U
  668.         if(Error != IIC_OK)2 v0 t2 h7 M' p$ J; e
  669.         {
    $ b# T; E8 n: Y1 T' S
  670.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误) {' ~! o2 f0 q6 j7 f( T0 J
  671.                 DEBUG("[IIC R错误]:%d\r\n", Error);
    " I* c6 `1 G# N! w
  672.         }6 [) k' i1 d9 e' @, ?/ q/ F. w- o
  673.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的
    # U, a7 l( `3 j, T* `1 A
  674.         {
    - t: s/ }0 \3 k+ x2 Q7 E
  675.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线4 k. I: l1 h; A0 J, s! G6 Z7 s; X
  676.                 DEBUG("IIC R结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);               
    5 t; v  R# M1 S
  677.         }
    8 {* D9 }* Y) ~6 X3 I; w2 a
  678.         
    ! Z! w, R  l; D, Q$ }, ^# d! x
  679.         return Error;# ^) X% h& D% c" p
  680. }
    # @6 f$ S8 D) G0 Z, S: w3 d7 V0 O& p

  681. # a$ e9 n# L  V8 w5 o. n

  682. * Z2 H8 A" @* H3 H, k$ ]: j, @
  683. /*************************************************************************************************************************7 {# f1 j- D, j6 P' o
  684. * 函数        :                        IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    1 h4 d6 B% O# c1 [8 a0 f
  685.                                                 u8 *pDataBuff, u16 WriteByteNum)
    1 s4 S) G2 K  _  M. B9 L; E" {
  686. * 功能        :                        IIC写寄存器(可以写1个或者多个寄存器)
    # W4 p" h1 p# U0 c, K0 c- {
  687. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要写入的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;9 h( F0 e; H( L% W# D7 Q
  688.                                                 pDataBuff:写入的字节数据缓冲区;WriteByteNum:要写入的寄存器数量;
    6 V) S" s% @% z5 e' p2 ?/ y
  689. * 返回        :                        IIC_ERROR
    ! z% G+ B. n/ x; ]  }
  690. * 依赖        :                        底层宏定义
    + O& l6 w4 D# k8 Z% j; g, y
  691. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>. f" l# A9 ^9 F* K$ P3 Z6 B$ y
  692. * 时间        :                        2020-02-16" A1 d! t8 _7 b3 H% d3 v# E% ]
  693. * 最后修改时间 :         2020-02-16
    7 d" u8 f/ F. X" K6 X$ x2 N& C. d3 Z9 o
  694. * 说明        :                         写入的数据都是小端模式,如果是16bit的寄存器,请写入偶数个数据,并且需要提前进行高低字节对调最后组成高字节在前的数据buff
    + ~  p! c; D+ M
  695.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
    3 W8 {# Q9 B7 `$ k2 R9 Y/ q5 u
  696.                                                 增加信号量
    ; t) s& S" t5 H" E# K# A5 J0 r
  697.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在" @, |; ~/ |8 P% @* n# O  I+ i
  698.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。4 W& d5 }# i: [4 y
  699. *************************************************************************************************************************/
    # }  K  ?0 F, A) o
  700. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum)
    5 ^: C. Q1 J2 z, D+ p1 o6 P
  701. {
    6 l1 \' E, X$ i) [
  702.         IIC_ERROR Error = IIC_OK;/ }  }6 W* v# x5 F2 r
  703.         u16 ReadCount;: [% l7 [! x; X' Q; C. S
  704.         IIC_HANDLE *pHandle;
    7 m( m: Q* ]& ]2 G* _5 l
  705.         ) w+ W4 N$ Q$ t: l! ~, x
  706.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || WriteByteNum == 0)1 P' T' A8 n3 s( Q# S' z! L
  707.         {
    % e( s% `3 O' j6 Y. u3 @
  708.                 DEBUG("IIC错误:无效的参数\r\n");
    ' G- I( j/ X* K$ U# L/ J: m
  709.                 return IIC_PARAMETER_ERROR;
    + x  l7 H0 n  n4 R- M
  710.         }$ z4 t/ P% x6 c+ N; Z6 ]  i' c
  711.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄9 K6 c; V  e' t
  712.         * y1 E" S5 W1 H. J6 [0 z9 J+ D- u
  713.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙! j8 c6 m( \7 E$ [$ g. y+ d
  714.         {
    " E: c# b( I: w. l' P
  715.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");5 e3 P' X- a: }4 ]' }! h6 Q" N
  716.                 IIC_SoftReset(pHandle);) Y$ ]" d7 h9 m1 d$ q5 b0 Z
  717.                 7 A- q. j: e' Y  \. {+ _8 k% g* F
  718.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)        //忙1 f" V7 j, \" J/ s7 S# G- Z+ S' p
  719.                 {; }/ D. L/ V8 v$ T$ d9 c- K/ o' M
  720.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");
    ) \7 D/ }8 i- k
  721.                         Error = IIC_BUSY;3 S9 z+ j3 n7 x8 b0 F# v
  722.                         goto end_loop;6 G6 W$ M0 u0 \2 _0 m
  723.                 }/ s* L' v2 G7 _: L+ c. j8 }
  724.         }+ z  w$ X% y5 c) S* w$ E. ^7 B
  725.         1 |8 G: w6 r  u& c6 M2 D% m0 Y8 B
  726.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    + v2 K3 s3 E8 d8 s: K$ {
  727.         IIC_ClearCR2(pHandle);                                                //复位CR2寄存器9 f* ]- P; a' ?; n) A$ Z5 u+ h
  728.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START. w1 X! X# B- a# \2 E
  729.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,FALSE,  pHandle->TimeOutUs);) F* p* N% n9 q1 Z
  730.         if(Error != IIC_OK). t" V" g+ R# z  D8 `3 o4 |$ z
  731.         {
    . n( U0 C) }/ X; x* R: x
  732.                 goto end_loop;
    : a7 g( }, L. w6 C7 d% L
  733.         }
    # r0 J7 _5 u0 `) t/ x7 l2 U; ~
  734.         //发送后续数据: {  W  R; E/ T1 \% w# v: h+ {
  735.         if(WriteByteNum > 255)                        //如果超过255字节,则需要分多次写入-后续还有数据,需要重载
      c( G9 a& d/ u. [8 E: ~
  736.         {
    , N3 j; M4 G4 X7 |1 E, [$ W2 S
  737.                 ReadCount = 255;                        //本次需要写入的数据长度2555 }- h. S6 q3 a9 r2 k$ x6 q
  738.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入                3 z9 \3 j) ~# |9 {% C
  739.         }/ ^$ h8 _+ @6 {9 r, l) u/ a" K
  740.         else
    - k: O& f% W, E1 h8 x1 M1 K8 g8 \* q
  741.         {9 {' m$ [( C+ t$ j7 Q6 l
  742.                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯后自动结束
    % y+ B8 Q6 d6 w/ i% {0 v
  743.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入8 T3 d1 p9 w2 ~6 A/ L6 S
  744.         }
    - [/ b5 E. D- |4 _* p' w! D. |0 @

  745. + g4 O, L& d6 N  k% y: V2 U
  746.         //循环发送数据
    9 j. b8 i2 w1 ^* A3 A
  747.         do/ Q! B" i( ^2 q; e6 f
  748.         {
    & R, ^) i0 |0 ^, s& Y" }
  749.                 Error = IIC_SendByte(pHandle, *pDataBuff, pHandle->TimeOutUs);        //发送一字节
    . d6 A$ M$ I' p! |
  750.                 if(Error != IIC_OK) 3 Q/ G4 r; c8 @! {8 C
  751.                 {
    ( \$ ], k8 R! X; n. B% l
  752.                         goto end_loop;
    7 X. n" L+ c% U/ U- T) o
  753.                 }
    ) ]" V3 ]& Q8 r( X% X) ?6 z
  754. 1 R; [# L. O+ `# `8 O
  755.                 ReadCount --;
    0 v6 s/ a  a" T7 B" N+ }
  756.                 WriteByteNum --;7 H2 ^& [0 }8 X4 G, g" z# ]6 H, D
  757.                 pDataBuff ++;
      ^, ]# d" N. @4 M
  758.                 # |. |' c+ }  k# x, s  j
  759.                 if((WriteByteNum > 0) && (ReadCount == 0))        //还有数据要读取) Z# i2 ^+ M0 d' ?! z  x! C
  760.                 {
    ; k) k0 ~) q2 z1 O2 j. Q" F
  761.                         if(WriteByteNum > 255)        //如果超过255字节,则需要分多次读取
    ; V* C2 i- w* Z' o# a
  762.                         {
    . K0 v  ^% G5 J6 ^/ `* A
  763.                                 ReadCount = 255;        //本次需要写入的数据长度255-后续还有数据,需要重载( q; v! b$ I( y+ Z
  764.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入
    7 G, X$ l4 G( i3 D
  765.                         }
    1 Y) q/ w: `8 ^. n( I) f
  766.                         else, F) g2 U/ I: s+ I# F" R3 y
  767.                         {+ y# J$ G" _4 e5 f: x# `( ?# w
  768.                                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯,自动结束
    * P" Y" c+ C% h$ G# h% `! g/ O6 s
  769.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入                " X- S/ ?3 X1 E, P* z5 J/ q
  770.                         }
    / E/ c5 D; D! L" L
  771.                 }5 c4 g6 z% S: D3 T- @
  772.         }while(WriteByteNum);        % I" d# [, ?) d$ y3 d% x# V
  773. . ?# D9 t) |8 T7 g, m% }3 h" N
  774.         //写入完成了,等待STOP位有效
    ; W6 }6 C# l  D8 L# Z6 G& T
  775.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);, Q; _! n/ C2 O! e+ ~3 J
  776.         if(Error != IIC_OK)
    ! {" X) K: I0 D5 `1 M" Z
  777.         {0 b" G( B4 Y5 p3 I
  778.                 Error = IIC_STOP_ERROR;
    7 L7 r  {3 g# q* @$ w3 b/ r
  779.                 goto end_loop;& x, |5 O* T  G2 @* E+ c
  780.         }" M) `' m0 ]0 k" V* j
  781.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态5 P" M6 t, w0 \4 }- P  C
  782.         : K: x, N4 ?3 @( W: x# L# A
  783. end_loop:        
    : H# J, r/ _2 X! M2 j
  784.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        5 u- A1 R% _1 N+ g1 U9 D0 l
  785.         if(Error != IIC_OK)
    # L3 m. M  F9 W+ J
  786.         {
    9 M0 n. u4 x" Z$ l) z. D7 I3 }
  787.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误/ F( P: e4 w, w  b" i3 C
  788.                 DEBUG("[IIC W错误]:%d\r\n", Error);2 A$ I" u0 t# e& p
  789.         }# f2 C. A+ Q6 A6 e1 J% m
  790.         1 J$ r- U  y8 ?5 P& T( A! c
  791.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的
    : B; J& N. u# z- Q$ |/ g8 h8 E
  792.         {* H, a$ z9 K+ Z; E3 g) k7 `. s* Q
  793.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    . @6 o/ K- q$ Y0 k' M
  794.                 DEBUG("IIC W结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);                . u, [! f5 c, l5 C9 L5 L
  795.         }
    ' Y3 t5 ?' ^8 f' @
  796.         return Error;
    % e) [$ f3 c  p: \7 A& O/ a
  797. }
    ! ^! ~- e& ~2 p$ e: X- o! U4 _
  798. 3 t  x. G3 |( R2 H* ^  a
  799. * J) i: s+ \6 ~! t4 T9 U( F* D
  800. /*************************************************************************************************************************
    - n' ^. b( `  C2 @2 a+ L/ U3 O
  801. * 函数                        :        void IIC_SoftReset(IIC_HANDLE *pHandle)$ y) l9 H5 V3 W' |% e
  802. * 功能                        :        硬件IIC软复位(会使能IIC)
    1 D6 d" F# q+ F! Z8 E  O9 q
  803. * 参数                        :        ch:IIC通道
    4 ]+ T8 i, j1 F
  804. * 返回                        :        IIC_ERROR
    1 Z/ q( X  e; T: A) K' F; y7 ]
  805. * 依赖                        :        底层宏定义
    - U3 U6 P) o# R/ p2 u( q7 T9 D
  806. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>7 E0 Y! {' _3 J0 K! a
  807. * 时间                        :        2020-02-15# I4 `( |1 U& S" }( b" A
  808. * 最后修改时间         :         2020-02-15
    3 @/ W" }5 Q' q  K+ W0 R
  809. * 说明                        :         IIC软复位;必须使 PE 保持低电平持续至少 3 个 APB 时钟周期,才能成功执行软件复位。
    / T7 |0 a" x$ K! m
  810. *************************************************************************************************************************/
    3 u0 s% B8 v* V. u
  811. static void IIC_SoftReset(IIC_HANDLE *pHandle)7 p7 i7 U( j. `: u, P
  812. {" T8 w) r9 Y' m0 w! A
  813.         pHandle->I2Cx->CR1 &= ~BIT0;                //关闭IIC后执行软复位
    7 h! o7 a, A% ^; M1 C. Y
  814.         Delay_US(1);        
    1 e0 Q3 Q/ l6 M  q  V
  815.         if(pHandle->I2Cx->CR1 & BIT0)
    2 P+ {6 w( N1 X1 V
  816.         {/ }; l7 V/ K9 C
  817.                 DEBUG("IIC软复位失败\r\n");
    # g9 [3 L5 E' R6 z% R6 I
  818.         }
    0 d/ W( l) ?. s, `; a
  819.         pHandle->I2Cx->CR1 |= BIT0;                        //重新启动
    - l, z- M$ F4 V0 e, q: \: V
  820.         Delay_US(1);        
    1 v7 Q+ v( `' w0 V1 s
  821. }. r  q9 c  [' d& O5 \6 H

  822. : K2 p# u- ^; `2 i  \

  823. . e2 V2 B! J) ~% Q3 `8 z/ L
  824. % ~. S  j4 J; v, s9 U) z. G
  825. /*************************************************************************************************************************# e: P  W3 o# R( P) h+ ~
  826. * 函数                        :        static u32 IIC_CalculationTiming(u16 Speed_KHz)- v3 m+ ~# s1 ?  K( d: M* Y
  827. * 功能                        :        硬件IIC时序计算
    8 j; R0 o' D+ I/ o; L
  828. * 参数                        :        ch:IIC通道;Speed_KHz:速度10-1000
    : u$ C3 E8 S2 u+ q( |
  829. * 返回                        :        IIC_ERROR
    ! h; a! f4 `" }# g6 I$ ~" `
  830. * 依赖                        :        底层宏定义( d$ ?' A( C2 ?; h
  831. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>/ @3 t: v; R4 s* B  w1 S& o2 j3 {0 z
  832. * 时间                        :        2020-02-15
    ' H; r+ z# j; y( D* f1 L3 i3 a: E
  833. * 最后修改时间         :         2020-02-15
    : L; S5 O* ~7 b$ d' s% b9 i* x
  834. * 说明                        :         IIC使用的是APB1时钟,将IIC总线时钟控制在100KHz        1 ]' X8 u0 `4 `$ F+ j8 ~* C
  835.                                         APB1时钟:最大不能超过45MHz        
    % B! y3 U" ?8 i# V
  836.                                         如果速度是100,则按照SMBUS时序
    & U$ u3 e4 v5 B+ f) o' r5 T) b5 k
  837. *************************************************************************************************************************// ^8 @6 G" F4 M3 F+ @
  838. static u32 IIC_CalculationTiming(u16 Speed_KHz)& O# |# K/ m8 [
  839. {
    1 c; r- x# q6 X0 ?; E( I& }; i
  840.         u32 tTime = 0;
    . T1 H0 }; |+ S! z1 m5 n/ A
  841.         u32 temp;
    " Z6 Z& ?& M$ a. x: I9 Z
  842.         u32 time_temp = SYS_GetAPB1ClockSpeed() / 1000000;                //先获取APB1时钟速度
    2 b9 @, @. \+ I. E% C
  843.         u32 Th = 1000/Speed_KHz/2;                                                                //计算高电平时间(低电平时间一样),单位ns
    " a2 ?& A; x  [2 p% q0 c
  844.         
    5 U: ^. ]* J/ R
  845.         if(time_temp < 20) time_temp = 20;
    * {' E* F. Y" @+ H6 X6 w) h
  846.         time_temp = 1*1000 / time_temp;                                                        //单位ns
    - L( S9 T: V* n
  847.         uart_printf("IIC时钟计算->APB1周期:%dns\t", time_temp);& ?. x$ {0 `$ ?# r& q! a$ g- S
  848.         if(Speed_KHz == 100)        //如果是100,则按照SMBUS时序2 m0 J; l- i  C, }% \
  849.         {
    ! n3 B8 [3 [" Q0 W8 e4 A; K
  850.                 //主时钟分频系数固定为3% J0 t8 M, b0 t+ u8 z* H9 E$ r
  851.                 time_temp *= 3;                        //主时钟周期  L, ?. B7 x8 q1 `5 a
  852.                 uart_printf("IIC时钟周期:%dns\t", time_temp);6 D- i9 L! A. j9 z! u1 c# m6 o- z
  853.                 tTime |= (3-1) << 28;        //PRESC,时钟预分配
    6 E5 ^5 \8 O9 O2 ^, P1 {5 m
  854.                 //计算数据建立时间,要求最小250ns* N$ b/ C1 |* P% L# r( C- ]
  855.                 temp = 250 / time_temp;5 J+ F3 w9 e( z7 W/ U
  856.                 if(temp > 15) temp = 15;- H4 ]. a, v: V) M5 o& T0 ~+ f
  857.                 if(temp < 1) temp = 1;
    / Q1 U9 f, w" l1 a1 m$ |8 G2 m) }
  858.                 tTime |= temp << 20;
    " F7 F6 t, C' N1 I; B; r+ k
  859.                 //计算数据保持时间,要求至少300ns4 C9 o" y+ M& n$ Q  o6 I3 B
  860.                 temp = 300 / time_temp;9 K+ ?$ M8 [1 |( w
  861.                 if(temp > 15) temp = 15;
    5 i2 n; U/ j; u6 q* ]
  862.                 if(temp < 1) temp = 1;* Y4 W6 v; O) g# ?% o
  863.                 tTime |= temp << 16;
      C% [$ v& o4 y( [. ?& z
  864.                 //计算高电平周期5us/ |# b  R( I+ w, d/ ]  i6 c5 [, t2 d2 c
  865.                 temp = 5*1000 / time_temp;
    9 J2 T4 m: A. Y: `
  866.                 if(temp > 255) temp = 255;
    ' U& b& ^0 M: a9 e( ~- L
  867.                 if(temp < 1) temp = 1;+ q: w6 H4 J% H- d" U
  868.                 tTime |= temp << 8;( H% t; L' k  i5 u: f6 `5 M) M
  869.                 //计算低电平周期5us, m3 p6 C: M7 z
  870.                 temp = 5*1000 / time_temp;$ L7 j) p4 E* ?: O0 G: a
  871.                 if(temp > 255) temp = 255;
    4 t  {( j' U) [
  872.                 if(temp < 1) temp = 1;
    + B5 V8 T1 s# ?! h2 p
  873.                 tTime |= temp << 0;
    1 J7 ?& g# }! l" d
  874.         }
    : ^3 @1 v. I+ Y! o+ P
  875.         else if(Speed_KHz < 100)$ O" {# Z3 u' Y$ q4 A8 |( n
  876.         {
    * Y6 z. a2 T0 Y! X
  877.                 //主时钟分频系数固定为64 G/ m! f/ f/ P2 P3 J% ^* k
  878.                 time_temp *= 6;                        //主时钟周期$ h& h  Q+ R, i! }. ^. D, z
  879.                 uart_printf("IIC时钟周期:%dns\t", time_temp);$ a5 E  g, X$ v
  880.                 tTime |= (6-1) << 28;        //PRESC,时钟预分配+ c* e$ h7 P& F  y' X4 |  G. P
  881.                 //计算数据建立时间,要求最小250ns
    3 [: x! x' ?( P* ^6 q
  882.                 temp = 250 / time_temp;$ K2 _& E5 h( E3 X+ z2 l3 y
  883.                 if(temp > 15) temp = 15;- ~  W- f/ z5 n" D" n
  884.                 tTime |= temp << 20;
    8 T8 B  _# a* P8 q
  885.                 //计算数据保持时间,要求至少300ns
    0 M4 j5 _2 @& t+ V0 t
  886.                 temp = 300 / time_temp;# Q9 V3 ~, |, h* ]
  887.                 if(temp > 15) temp = 15;
    # L' D: ?' v/ y$ l5 M7 [* H2 I
  888.                 tTime |= temp << 16;
    8 W: `+ M* s; S' W: n- ]
  889.                 //计算高电平周期Th us
    ! a* r3 w( |  A
  890.                 temp = Th*1000 / time_temp;
    " P# Y8 c- p6 Q. g& N
  891.                 if(temp > 255) temp = 255;7 `5 y- a+ r' m, s$ y  x
  892.                 if(temp < 1) temp = 1;
    2 I% R6 h& F# m' W! U
  893.                 tTime |= temp << 8;
    . P* T% Q6 J+ t6 @( {2 G7 v8 i
  894.                 //计算低电平周期 Th us
    3 u, H) h, ~& C; I4 L% W
  895.                 temp = Th*1000 / time_temp;
    8 b/ F: b' X' }1 {0 z  e  l7 ?
  896.                 if(temp > 255) temp = 255;
    $ y# z. I0 y  p+ w
  897.                 if(temp < 1) temp = 1;
    ; h2 E/ j) c3 C5 e7 ^
  898.                 tTime |= temp << 0;
    4 Y5 J2 Y$ K& A4 F" z
  899.         }
    ' G7 m% n2 D4 ]: w
  900.         else //>100. ]% z, v0 l4 B7 ^, S/ a5 }
  901.         {6 B0 }: i3 n$ e6 M: \& s) ^& \% x
  902.                 //主时钟分频系数固定为2
    ) v' B: i5 I% Q3 @
  903.                 time_temp *= 2;                        //主时钟周期# r- D) f# }6 o# W4 [
  904.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    - j. x2 D& h2 ^9 H/ O
  905.                 tTime |= (2-1) << 28;        //PRESC,时钟预分配
    $ e3 ^; Y1 u; U$ \. h5 l2 e
  906.                 //计算数据建立时间,随便给100ns6 J4 H6 u& F! T8 B$ N" d
  907.                 temp = 100 / time_temp;
    ) j4 x4 ]0 L0 ~
  908.                 if(temp > 15) temp = 15;
    * r. M$ T; g% N! F; v% e
  909.                 tTime |= temp << 20;
    ; h, x+ N" \$ V( |
  910.                 //计算数据保持时间,给100ns+ z5 l- s9 j# P$ r
  911.                 temp = 100 / time_temp;
    + H1 ?7 ^3 {5 `. q7 k* d1 N
  912.                 if(temp > 15) temp = 15;" N9 w& j; R7 }9 p8 f
  913.                 tTime |= temp << 16;8 T$ Y! A, c' X) _- g1 s& c( I
  914.                 //计算高电平周期Th us
    " h$ R7 L/ b, E# S
  915.                 temp = Th*1000 / time_temp;% d( B7 A/ |. d8 M
  916.                 if(temp > 255) temp = 255;
    6 z- O! J6 y' N. S: ~7 E2 L
  917.                 if(temp < 1) temp = 1;, P8 e. u+ b" L+ A1 ]% N1 V
  918.                 tTime |= temp << 8;
    1 W. F! Z1 G; h
  919.                 //计算低电平周期 Th us
    : n4 [7 B0 b5 i' [9 x
  920.                 temp = Th*1000 / time_temp;$ k) {0 n, ~, H2 U8 L
  921.                 if(temp > 255) temp = 255;0 T( W- ?/ Q3 I: ?7 M( \8 G) F
  922.                 if(temp < 1) temp = 1;
    - g. d' Z0 ?$ l1 j1 N
  923.                 tTime |= temp << 0;
    $ ^7 ?! m) @. R+ ^/ `- s/ j: \
  924.         }
    . ?" I9 G. V; ]& r6 ?# O
  925.         
    ; H; h5 ~( }% Z5 o( }: F
  926.         uart_printf("时序寄存器结果为:0x%X\r\n", tTime);
    + A1 {, u. ]# s
  927.         $ C9 G9 Z4 q% [2 v  s
  928.         return tTime;
    2 @% v# t* e$ @9 Q" R
  929. }
复制代码
* ?& e& R1 c. A9 `3 y/ r
) y1 r: ~) G7 C! R# o: Z
  1. /*************************************************************************************************************0 x7 c! n: b0 U0 j
  2. * 文件名                :        stm32f7_iic.h3 l: D: ?! j4 P# @6 l2 Y& e
  3. * 功能                        :        STM32F7 IIC接口驱动2 {( k$ O! G6 \- ]0 X2 }
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>1 B5 C; {6 b7 }& S: f# s0 k; E
  5. * 创建时间                :        2020-02-093 m3 Z. F' }0 T7 f% t/ t
  6. * 最后修改时间        :        2020-02-09
    " F+ N& `! L0 e3 O% @2 n# \
  7. * 详细:                        
    ; [. k) P, T  R5 t  ]" H, W* d
  8. *************************************************************************************************************/                , K* x' k- u' l7 j9 D1 c& f
  9. #ifndef __STM32F7_IIC_H_8 C9 K" }. ~4 [  H. w5 k
  10. #define __STM32F7_IIC_H_! B, F9 W/ u9 S1 P7 r& I& l: U- p
  11. #include "system.h" . I2 G( {: f; _, P

  12.   l3 N0 N5 V6 U! H
  13. //16位整形数高低对调5 d% l& j6 K" |1 u& E6 E* ]" N
  14. #ifndef SWAP16! Z# x% M% j( i" M# g  t
  15. #define SWAP16(x)   (((x & 0xff00) >> 8) | ((x & 0xff) << 8))
    1 V" A1 E# J) b  e
  16. #endif  //SWAP16
    * }+ x7 E. X/ F

  17. 8 c: N0 O  C9 z% k  Q' j
  18. //硬件IO口选择
    ' Z9 t6 F. U! }, S/ y. i
  19. //I2C1 IO定义与选择1 ^. u! _' d' b. P6 Q6 N/ a
  20. #define IIC_CH1_PB6_7                                0                                        //PB6,PB7& f3 y$ D8 ?# P1 f8 q' q7 V
  21. #define IIC_CH1_PB8_9                                1                                        //PB8,PB90 c; \3 U9 o) y' G* m6 R+ e
  22. #define IIC_CH1_IO_SELECT                        IIC_CH1_PB6_7                //选择I2C1 的IO        ! }, f, p' F/ C
  23. : Q5 {9 h6 N( A: u4 N6 N3 v
  24. //I2C2 IO定义与选择+ b' f  i$ r$ r* _8 K" b2 Q
  25. #define IIC_CH2_PB10_11                                0                                        //PB10,PB11
    : n" q) S. m' V
  26. #define IIC_CH2_PF0_1                                1                                        //PF0,PF1
    # {) ]% C% b) }4 C
  27. #define IIC_CH2_PH4_5                                2                                        //PH4,PH5: T: e0 f: I& w) O
  28. #define IIC_CH2_IO_SELECT                        IIC_CH2_PB10_11                //选择I2C2 的IO' N  A: J5 `: G8 `5 v7 K
  29. 4 g, X$ W; `2 H! Y
  30. //I2C3 IO定义与选择- @0 q: F; X, j9 v/ B4 H: j
  31. #define IIC_CH3_PH7_8                                0                                        //PH7,PH8
      h! i, |. G- y/ u* B
  32. #define IIC_CH3_PA8_PC9                                1                                        //PA8,PC9
    ' {* y. ]" A0 S  \* [7 Q' t
  33. #define IIC_CH3_IO_SELECT                        IIC_CH3_PH7_8                //选择I2C3 的IO4 x7 R" J9 p6 c+ X
  34. 7 u& `* M: L5 K4 g8 ~. ^8 b
  35. //I2C4 IO定义与选择
    8 |# o0 R( ]# b
  36. #define IIC_CH4_PD12_13                                0                                        //PD12,PD13
    . V0 @9 ]6 s  M& p! Q' D5 ]# Z
  37. #define IIC_CH4_PF14_15                                1                                        //PF14,PF15
    2 d8 g: `- R" Z- f4 c
  38. #define IIC_CH4_PH11_12                                2                                        //PH11,PH121 R+ j3 Q9 T6 P/ o* h3 w4 f* |+ J
  39. #define IIC_CH4_IO_SELECT                        IIC_CH4_PD12_13                //选择I2C4 的IO. n' E2 j; D, {3 {- K4 B
  40. , s, E$ g; s% W) h! Q4 ]
  41. //IIC硬件接口选择
    , b+ N# h1 m9 C( _- m/ J) ^
  42. typedef enum2 ~" C. B+ Y: @3 L! Y! U4 ?6 Y
  43. {4 @' K+ u# z0 S4 w; L
  44.         IIC_CH1        =                0,        //IIC1
    & t* E: ^3 r" D' [# h
  45.         IIC_CH2        =                1,        //IIC29 h1 I" Q. c8 p" L: v
  46.         IIC_CH3        =                2,        //IIC3- u5 y6 s& |. k+ W  X, B- G
  47.         IIC_CH4        =                3,        //IIC4
    % D; d' ?2 X6 a$ m6 n) f
  48. }IIC_CH_Type;
    $ Q' P9 N4 e/ ^7 P9 @9 t% q: m
  49. #define IIC_CH_COUNT        4        //4个IIC
    ; q' w& Z3 h5 d1 h( Y
  50. + `" G- k6 q1 K  v: b, w! W
  51. 0 `3 d8 r' ^# Z' o0 `2 v
  52. //中断状态7 S9 o, w" Y; l0 E
  53. #define IIC_FLAG_TXE                    BIT0        //发送数据寄存器为空(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。$ K# O# J9 Y6 L# _1 R
  54. #define IIC_FLAG_TXIS                   BIT1        //发送中断状态(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1,待发送的数据必须写入 I2C_TXDR 寄存器。* q2 y( x8 D5 s$ M; a0 ?
  55. #define IIC_FLAG_RXNE                   BIT2        //接收数据寄存器不为空(接收器); 当接收到的数据已复制到 I2C_RXDR 寄存器且准备就绪可供读取时,该位由硬件置 1。读取I2C_RXDR 时,将清零该位。# s- Z! p% f# C8 J0 v, a$ M
  56. #define IIC_FLAG_ADDR                   BIT3        //地址匹配(从模式); 接收到的地址与使能的从设备地址之一匹配时,该位由硬件置 1。该位由软件清零,方法是将ADDRCF 位置 1。7 H7 V7 {0 @0 {
  57. #define IIC_FLAG_NACKF                  BIT4        //接收到否定应答标志; 传输完字节后接收到 NACK 时,该标志由硬件置 1。该标志由软件清零,方法是将 NACKCF位置 1。- B! z% O  N# b8 q, R
  58. #define IIC_FLAG_STOPF                  BIT5        //停止位检测标志; 当在总线上检测到停止位,且外设也参与本次传输时,该标志由硬件置 1  C& K& f8 [: }
  59. #define IIC_FLAG_TC                     BIT6        //传输完成(主模式); 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 START位或 STOP 位置 1 时,该标志由软件清零。' ^0 H9 b, Y7 P
  60. #define IIC_FLAG_TCR                    BIT7        //传输完成等待重载; 当 RELOAD=1 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 NBYTES 写入一个非零值时,该标志由软件清零。2 E  _7 H3 |9 B5 q4 A
  61. #define IIC_FLAG_BERR                   BIT8        //总线错误; 当检测到错位的起始位或停止位,而外设也参与传输时,该标志由硬件置 1。在从模式下的地址阶段,该标志不会置 1。该标志由软件清零,方法是将 BERRCF 位置 1。
    7 g5 c5 F, }( ]; b* g
  62. #define IIC_FLAG_ARLO                   BIT9        //仲裁丢失; 发生仲裁丢失时,该标志由硬件置 1。该标志由软件清零,方法是将 ARLOCF 位置 1。# `: F  G; b- \: V
  63. #define IIC_FLAG_OVR                    BIT10        //上溢/下溢(从模式); 在从模式下且 NOSTRETCH=1 时,如果发生上溢/下溢错误,该标志由硬件置 1。该标志由软件清零,方法是将 OVRCF 位置 1。
    8 }# H9 \1 }2 M# u: }# J
  64. #define IIC_FLAG_PECERR                 BIT11        //接收期间的 PEC 错误; 当接收到的 PEC 与 PEC 寄存器的内容不匹配时,该标志由硬件置 1。接收到错误的 PEC 后,将自动发送 NACK。该标志由软件清零,方法是将 PECCF 位置 1。
    ; y3 I* w- ~1 q
  65. #define IIC_FLAG_TIMEOUT                BIT12        //超时或 tLOW 检测标志; 发生超时或延长时钟超时时,该标志由硬件置 1。该位由软件清零,方法是将 TIMEOUTCF 位置 1。
    4 b/ ^. Y2 t! N7 g* o) Y
  66. #define IIC_FLAG_ALERT                  BIT13        //SMBus 报警; 当 SMBHEN=1(SMBus 主机配置)、ALERTEN=1 且在 SMBA 引脚上检测到 SMBALERT 事件(下降沿)时,该标志由硬件置 1。该位由软件清零,方法是将 ALERTCF 位置 1。5 f* ^7 k% W2 t* Y; g
  67. #define IIC_FLAG_BUSY                   BIT15        //总线繁忙; 该标志用于指示总线上正在进行通信。当检测到起始位时,该位由硬件置 1。当检测到停止位或 PE = 0 时,该位由硬件清零。
    " N, I% s8 ?9 n
  68. #define IIC_FLAG_DIR                    BIT16        //传输方向(从模式); 该标志在发生地址匹配事件时 (ADDR=1) 更新。;0:写;1:读' d( f+ Z, y& [* f& B

  69. ! R* q5 h$ I  s/ x. q
  70. //通讯错误状态+ s1 W' k2 z. n- z# J
  71. typedef enum
    . R- i2 \* b- c9 _' L- K: p4 f
  72. {
    5 q3 H: q. E5 K4 z
  73.         IIC_OK                                        =        0,        //没有错误7 g5 B4 v- H' ^  ~# L! ^
  74.         IIC_PARAMETER_ERROR                =        1,        //参数错误
    + q" z+ V* }3 c3 b, e3 [
  75.         IIC_TIMEOUT                                =        2,        //超时错误,也可能是底层错误' z1 L- h8 b8 Y! Z; `
  76.         IIC_HAL_ERROR                        =        3,        //底层错误
    4 s: J' z( \! V' F: J  [
  77.         IIC_STOP_ERROR                        =        4,        //等待结束错误2 S3 G) c) `' |3 F( V# k( M
  78.         IIC_BUSY                                =        5,        //硬件忙# q, _9 U9 N; R
  79.         IIC_NACK                                =        6,        //收到NACK了2 k5 p6 x, R# D  _$ B* R
  80. }IIC_ERROR;
    7 \9 S% P9 l4 f" C- W
  81. 1 n; `6 j& T5 Y

  82. 1 i$ n3 Z7 [+ [# ?0 ?6 t- c
  83. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs);        //硬件IIC初始化5 R3 I. |& z* O5 t6 e6 J0 c
  84. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum);        //IIC读取寄存器(可以读取1个或者多个寄存器)4 E: F# L3 G, v
  85. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum);        //IIC写寄存器(可以写1个或者多个寄存器)
    # P+ y0 E8 X, F) j* O

  86. # L9 J; H4 A& s
  87. ! G$ l  u* U8 `9 N  Y
  88. #endif //__STM32F7_IIC_H_
复制代码

$ W5 `; ^6 V) y. X% W+ L6 T+ j; {7 R. L3 g
//初始化; `. f$ q/ }' e7 K& T0 T4 K9 k. _

, D. g; C6 Z! l  z7 t8 a1 d
  1. IIC_Init(IIC_CH3, 200, 0);        //硬件IIC初始化
复制代码
3 ~$ I* X5 ?# q7 d
2 C; w2 S2 v0 L" V2 G
//调用4 ?8 J% {! B8 }, H4 U' t9 t& C' `

  1. - e/ U& S. E( _4 q  H, n+ k" v) z
  2. //触摸屏IIC读取寄存器接口6 h' K% b4 h3 d: y6 S5 i! Y
  3. bool TP_FT5336_IIC_ReadReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)# p+ m. X. U0 w) w- a7 i- ~6 Z
  4. {
    * H8 J, o  V( B4 P
  5.         if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)7 A/ y; O' j6 f2 P0 o/ O  |
  6.         {
    8 l; m& N3 \4 g( y& U- y' t0 P6 [
  7.                 return TRUE;: `' M) S0 ]& \7 e
  8.         }
    % |4 ~$ [7 H& z/ _
  9.         else
    7 c' o  M! x2 \( V
  10.         {
    & c8 q/ n5 @% U; W* [! }% _
  11.                 return FALSE;
    & s! b4 Q1 F; c0 b! _# T0 S. X
  12.         }- y& h; {4 f4 X. r" e7 N2 r0 Z
  13. }( k. t" Y+ K) B( U/ j0 A
  14. 2 J' i, o: Q' N  C
  15. //触摸屏IIC写寄存器接口
    " U7 j5 D) {+ I) n& S
  16. bool TP_FT5336_IIC_WriteReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)
    # [) t: d. J0 e% G
  17. {* F% }4 U. Q/ h  ^* I
  18.         if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)' R7 ^0 s4 z/ c, k
  19.         {
    ; m  E( \9 T8 u# w- k
  20.                 return TRUE;
    7 o/ f  C# v/ u) n. c
  21.         }
    % H& R  q9 Y% n3 |1 C8 j
  22.         else
      ?% H, L# T, `6 y
  23.         {
    8 E$ X# y3 s2 c2 h7 B% I
  24.                 return FALSE;
    % V3 ]! v5 T5 Z/ z  u, Z  X
  25.         }
    6 ^2 I! _9 r1 @$ D: r% w( j

  26.   k) B/ N. t5 ^9 v9 ~
复制代码
8 h% @; I. g$ [0 u2 l& j! m2 l

4 j+ h+ T( }4 d( b( W0 m; }0 Y
( o& {8 z2 S& d( H& V
收藏 评论0 发布时间:2021-12-11 12:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版