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

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

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
目前只实现了主设备模式,一般也只用到主设备模式,IIC如果不能使用硬件方式,读取大量数据的时候效率很大,由于只有1个字节的缓冲区,根本不能使用中断模式(实际使用过程中,IIC会造成100us以内间隔的中断,单片机根本扛不住的),所以建议数据少就直接阻塞,1个字节也就几十us,数据多直接用DMA,将线程阻塞,等待DMA传输完成,而不会阻塞CPU(上传的代码没有实现DMA部分,便于理解)。
3 q0 |/ Z$ B( v; h: Y5 b8 G
& O; M/ k  ^9 ]9 f' V目前已经做了完善的错误处理,读写操作前都会清除中断,遇到错误会软复位,所有位置均做了超时处理,防止程序卡死,目前只测试了几个字节的读写,大量的,长时间的读写均表现稳定,目前手上开发板没有eeprom,无法做大数据的连续读写,如果你在使用过程中遇到问题,欢迎指正。  ^" B5 i1 b; `8 `2 W) H
8 Y1 [" Z9 r5 a. q
下面是IIC读写的时序例子,可以先熟悉一下,这样比较容易上手,哪一个环节出了问题也要调试。
6 P2 m( |/ K0 C- {
/ d' o# V0 `/ u) l! x
20200216194202434.png

( S9 T. p# {- f( p9 }9 W3 ~
6 @; z# }, W) i- |! t, Y+ Q
20200216194219185.png

9 O, g+ o9 G. C/ ~8 q0 S
9 u% m, v% [. X# s; o
20200216194234908.png

- x' t- l: P3 M6 u/ @: U8 k
+ ?8 q; E6 O7 u# f$ i: V0 Z9 s7 ?, x5 Z" g, ?' ]9 T' b
下面简要说明一下STM32F7硬件IIC的驱动设计方式(建议先百度学习一下IIC的时序要求):
4 S# e/ K, T4 x) b
2 A  \- s% |0 L+ r6 J6 _- k[基本的初始化]
; E5 C5 \, Y  o
4 Y" k$ x5 V/ n& @1.初始化IIC时钟,IO(IIC IO必须设置为复用开漏输出,这个很重要)。  ~% A) x1 R( O0 Q1 g* ^

' u( D1 A5 A- v. m7 p2.CR1先赋值为0,复位IIC.
2 b+ ~- T- p8 [( l4 Z: h+ ]2 ]* y* D: L; _1 N6 n
3.除了TIMINGR寄存器需要自己计算设置好,其余寄存器全部复位为08 {' b  c8 b/ J
8 c$ X" j$ e2 O3 Z: Z& G
4.设置CR1使能IIC。  r  a" x0 H' \. c  R0 }5 O$ Y8 `
; M4 L; _5 ^+ ]  R; u6 L5 Z
注意:上面说到,IIC的IO必须初始化为复用开漏输出,我之前初始化为复用推挽输出,测试很久,只要一启动传输,就会立马收到NACK,然后是STOP中断,数据根本没法发送,弄了好久才发现是这个IO初始化的问题。
. L0 `  }/ E& r. |  g. ^( p0 {' Z% V, ~+ T

" f+ ~. [8 M1 _* h4 n: I6 s
# M1 ~1 K" u7 f& b[读取]
3 o) @3 W" I- _6 f8 N8 R
) H$ m! I* m* p6 w5 _0 \3 s1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。  F0 J( n( i1 A! W2 U& [
( {' t2 c: W' d8 z
2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)软件STOP,写模式,启动传输。. ?2 y1 ]5 P9 e& {8 p
3 X5 w+ V( q% n& {
3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。5 Y7 T/ v+ q0 J8 K; K! U# m6 }

; Q) [+ r/ }/ x& w5 y3 ]4.等待TC置位,意味着上面的1-2字节的寄存器地址以及写完成了。
$ [/ f6 D3 C* F$ Q
9 q4 J2 O; @& W# H5.根据要读取的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。" k8 [8 [5 n. Q" d  J

7 X( k6 C4 b" u* Q; O6.设置了从机地址,要读取的数据长度,之后设置方向为读取,然后启动START(从写切换到读要重新发送START,这个跟软件模拟是一模一样的)。7 U; {0 e' _- E! l4 p7 x

% r1 [, o! P$ W( z7.循环一个字节一个字节的读取数据,字节读取需要等待RXNE有效,只有读取RXDN寄存器,直到所有数据读取完成。+ l& K8 k& h2 t+ m5 Y
3 X; ]5 A# C1 `4 \) F
8.读取完成后等待STOP有效,因为前面在最后一包数据读取的时候使能了自动STOP,这个时候检查STOP是否生成。2 Y# Y9 f3 n+ ^' o9 [0 _+ `

/ ?7 N4 S# J, {1 p4 U% b; _: }0 i9.需要注意的是,所有的操作都要给超时,并且是自己可控的,绝对不要有死循环,之所以一直说STM32的IIC死机很大程度上都是由于这个地方没有涉及好,我的程序设计方法是:一旦出现了异常,就复位IIC,如果不复位就会导致下次进去的时候IIC一直忙,因为还处于上一个通讯过程。
! k+ A# f5 O9 p: a6 m
* I9 m+ X' I) x: D' i! ~. P, v  \2 [2 b
/ \4 l- U" A/ O9 l7 @7 w! J( N
[写入]
  Z( n5 B. k2 h- f( ?4 O' e
* {. F; C, n5 U4 b1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。
0 n5 F1 |2 s4 Q8 Y6 I1 W7 H; U5 e0 {6 z; H6 l2 i$ K5 ~8 Y
2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)自动重载,写模式,启动传输。
+ o1 {3 Q, H" d6 ^
7 @2 t( O: W* ^; p, |# k3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
$ f7 `* a% N5 u0 e6 E
6 m  x/ ]- n  f6 R1 g4.等待TCR置位,意味着上面的1-2字节的寄存器地址以及写完成了,已经发生重载了,后续可以继续写入数据了。
+ m' g: K( n3 n$ _, t1 @1 M
; @+ v7 p- T: f; O; c' }2 {% ?. _9 G5.根据要写入的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。: r$ h  d+ B* D3 g0 H/ }. v7 L
$ `8 R) g8 V! f( j
6.设置了从机地址,要写入的数据长度,之后不用切换方向,不用启动START(都是写,不用重复发送START,这个与读取有区别)。
  s' u/ Z' J! \" E9 _
0 G# c1 d) R1 ~" I6 k4 j5 @7.循环一个字节一个字节的写入,字节写入与步骤3一样,等待TXIS置位,就可以写入数据到TXDR。
& u$ j8 a' A# b) \$ i9 B3 x$ p* v
0 g/ h8 I' h9 r8.等待STOP有效,因为前面在最后一包数据写入的时候使能了自动STOP,这个时候检查STOP是否生成。4 _  S2 g. B. ?7 I; e" A: d

0 @8 B* I. y! ~! i9.需要注意的是,所有的操作都要给超时,跟读取一样。2 D5 J( S2 I6 b: s  x
7 S1 I  R  n, e  z

  h$ E7 x4 W# H) }, h: m# d. x  n: t8 Z  R
注意:IIC的读取实际很短,超时也不用给很长,以标准的100KHz通讯时钟速度,一个字节大概在90us左右,超时可以给个5-10B时间,也就是450-900us左右。
% H8 p) O3 s) ?
2 k2 g. R6 p: f4 }; R, ^; O' ]1 }8 p, w0 [

* F& l8 `4 K* e  ?好了说了这么多,具体的看代码中的注释,直接上代码(我只测试过I2C3,其余的理论上都是一样的,就是IO初始化部分有区别,别的通道没有硬件进行测试)
: f8 r8 E" c3 S
; q0 c3 I- D9 U9 D$ X
  1. /*************************************************************************************************************
      b) L$ F6 q; o6 Y2 O8 t
  2. * 文件名                :        stm32f7_iic.c. o. l/ a8 V8 Z! D
  3. * 功能                        :        STM32F7 IIC接口驱动
    - }6 y/ y* y: o% }/ N( h
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>, S2 B8 y# H& v7 y! O1 x" e
  5. * 创建时间                :        2020-02-09
    1 P. A+ t% P/ K- v
  6. * 最后修改时间        :        2020-02-09
    8 R5 T$ A- Z- r. B' S3 X
  7. * 详细:                        只支持主机模式,7bit地址,默认APB1为IIC提供时钟
    ; I; \+ J& `4 s7 C
  8.                                         涉及到读写1字节的超时时间是us,其余的是ms- ]; }6 J/ O/ \- C2 q, a
  9.                                         注意:IIC的IO必须初始化为复用开漏输出。
    ! E4 ], U. R! x6 j* |1 s& }
  10. *************************************************************************************************************/          H! l4 K1 Q" H# t* o# h+ w
  11. #include "stm32f7_iic.h"4 R" `2 e, E- u' ]3 T5 }$ F9 g/ W5 p
  12. #include "system.h"
    . T0 u4 W4 ~( s! L* z* p
  13. #include "dma.h"* V& U8 g  `% [6 A/ x

  14. , @3 r  c7 N# Z2 }7 d' W+ }& b4 h" F, [
  15. #define IIC_FLAG_MASK  ((uint32_t)0x0001FFFF)        //中断标志掩码. n7 f  ^' O2 u: C  g( ~* }
  16. ' y9 |. g: z0 k1 H7 Z) B
  17. //自动结束或自动重载设置(重载与自动结束只能二选一,或者都不选)
    . i# I9 t, W# j1 X# t
  18. typedef enum
    ' i- R+ h& l% G7 _( `! H# u- Q
  19. {5 T  y; _1 E5 f; U* s& `; D
  20.         IIC_SOFTEND_MODE                =        0,        //手动结束,并不开启重载
    : S4 J9 i* [* A0 y+ L
  21.         IIC_AUTOEND_MODE                =        1,        //自动结束,用于最后一次通讯完成后自动发送STOP结束通讯
    " c" o6 E' A4 M% o! \" V
  22.         IIC_RELOAD_MODE                        =        2,        //后续还有数据,本次通讯后自动重载,重新设置后继续通讯
    + p+ n5 C" p  l* v& }- ~) z
  23. }IIC_RELOAD_END_MODE;9 Y, `, c5 Z2 f6 W. K' C: _

  24. . V$ K; T  l6 |( ~! m3 y
  25. //读写与开始模式控制
    ) C) T: n3 V9 R& ~3 k; K. f: q) V
  26. typedef enum4 W) \5 I9 @1 y7 L/ q7 u1 U
  27. {. |; d  T2 n$ r% O6 O2 V: b
  28.         IIC_NOSTART_WRITE                =        0,        //没有开始的写-用于后续数据的写入! _; p3 Q. Q5 D. g5 a* m
  29.         IIC_NOSTART_READ                =        1,        //没有开始的读-用于后续数据读取9 S; Z6 x. C( S; G0 B
  30.         IIC_START_WRITE                        =        2,        //生成开始写-用于通讯开始时,写地址或数据/ e, x$ G. f  s( W4 W( x
  31.         IIC_START_READ                =        3,        //生成开始读-用于读取数据时切换到读取方向,并读取后续数据, V4 D/ ]# S( b' R: n, k$ F
  32. }IIC_START_WR_MODE;; w- h7 q5 |% v
  33. 1 M) Z5 w/ Z) p4 M
  34. //IIC句柄
    , A: F: f8 Z9 j( d8 I/ r; U' E0 |
  35. typedef struct# q' K7 y! Q! m9 u
  36. {2 \0 k4 r+ m3 q5 B1 A9 x. s2 D
  37.         IIC_CH_Type ch;                        //当前通道5 n" }; E: Q6 o+ }7 Z
  38.         I2C_TypeDef *I2Cx;                //当前通道外设结构体* q) V" j0 h6 n$ Y2 f
  39.         u32 TimeOutUs;                        //操作超时,单位us
    7 A6 a# R; K6 w- l: Z$ d& J
  40.         u16 Speed_KHz;                        //通讯速度,单位KHz
    ( D/ Y" y5 W% U/ ^* W# q& u
  41.         bool isMasterMode;                //是否为主设备模式-目前只支持主设备模式* ?1 y  y* P. ^% \+ y
  42. }IIC_HANDLE;7 T: g/ F/ _9 k2 L8 G  W

  43. 6 _+ {5 a) |- L5 O) a3 v
  44. //IIC外设结构指针6 Z3 D) o0 _0 X7 _/ d
  45. static const  I2C_TypeDef * const I2C_TYPE_BUFF[IIC_CH_COUNT] = {I2C1,I2C2,I2C3,I2C4};
      v6 K0 w% ?0 D8 w2 s
  46. //IIC通道句柄定义
    $ x$ P. Q& g# ^* P* K0 ]
  47. static IIC_HANDLE sg_IIC_Handle[IIC_CH_COUNT];
    9 C+ [. w( k3 \& s- B  v! C
  48. . @8 l6 y$ E0 f) Y
  49. //发送NAK9 d% I) C+ U$ {/ _! k& A
  50. //static __inline void IIC_SendNAK(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT15;}
    1 T$ E( y$ O" Z/ p
  51. //发送STOP5 N7 H- W  m) b8 ~* i0 d' P; r9 N" ?
  52. static __inline void IIC_SendStop(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT14;}7 o: S& W1 M) L6 K
  53. //发送START
    + f# ?8 F$ Q9 ]" z  S2 |. J) F
  54. //static __inline void IIC_SendStart(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= I2C_CR2_START;}7 ^; p3 R' R) ?/ `' d& w
  55. //获取中断状态
    - g7 H6 n* K6 k1 z) Y
  56. static __inline u32 IIC_GetISR(IIC_HANDLE *pHandle) {return pHandle->I2Cx->ISR & IIC_FLAG_MASK;}
    4 L- F9 N2 U0 i0 T6 J, I- {3 {
  57. //清除中断状态
    4 N6 u, i+ t( \- r9 \- h7 @8 v
  58. static __inline void IIC_ClearISR(IIC_HANDLE *pHandle, u32 IsrFlag) {pHandle->I2Cx->ICR = IsrFlag & IIC_FLAG_MASK;}$ {& E8 m$ E, T+ c
  59. //复位CR2寄存器0 |* w: R' i: `8 r. P! \
  60. static __inline void IIC_ClearCR2(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 = 0;}, m7 C- |2 k1 u+ W5 a  `+ Y, r% y

  61. 0 Q/ h2 g5 k' s9 {
  62. static void IIC_SoftReset(IIC_HANDLE *pHandle);//硬件IIC软复位(会使能IIC)' Q+ g- r2 F' w; @6 w1 g
  63. static u32 IIC_CalculationTiming(u16 Speed_KHz);//硬件IIC时序计算! e3 ]1 s$ ?6 H# N' j! O% B: ]( m

  64. ! }& O% S  u; p. }$ f
  65. + `$ a5 A! E4 k- \
  66. /*************************************************************************************************************************
    $ R' Y5 b; C% Y% R7 v. U
  67. * 函数        :                        bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)
    0 o9 g) P3 m7 ~# j+ P# \2 T4 f
  68. * 功能        :                        硬件IIC初始化
    ( z0 a0 P( d6 G. ]% c4 `' F
  69. * 参数        :                        ch:IIC通道;Speed_KHz:速度10-1000(如果速度是100,则按照SMBUS时序);TimeOutUs:操作超时us(0:自定计算超时)
    . o2 M! P/ A+ G9 P8 ?
  70. * 返回        :                        IIC_ERROR8 I, L$ e1 p/ a7 B; s' _8 Q% q8 E
  71. * 依赖        :                        底层宏定义4 M( b, C& B; @! U
  72. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>) n) p) Y0 d: e) T/ L$ V  T
  73. * 时间        :                        2020-02-15  k# ]5 J. y( `9 y5 ], @
  74. * 最后修改时间 :         2020-02-15
    + k0 H9 R- @# ]2 i' }' ]
  75. * 说明        :                         速度只是个大概的计算值,设置为100KHz时会严格的按照SMBUS时序,其余的不保证SMBUS兼容,正常情况下只要时钟速度符合要求,  Z8 b3 H8 c1 z# I" H2 i2 d0 i, S+ g
  76.                                         时钟上升沿到来前数据以及稳定的切换了即可保证通讯稳定性  u) f$ u$ ~/ c( v8 I* g. L3 s
  77. *************************************************************************************************************************/% q, G: s5 w3 Y% S8 s: G) F
  78. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)
      A! R6 m" \$ g' f8 G# N  E
  79. {0 K4 `+ E$ e9 c2 W4 ^  e  `
  80.         SYS_DEV_CLOCK DevClock;1 }. f+ T& N( z( h, K. m1 I* i
  81.         IIC_HANDLE *pHandle;7 ^# D3 @/ z( I  j
  82.         
    ( _' n4 }1 B! b3 ?; G" K3 ?! c
  83.         switch(ch)
    6 g! w0 W" B6 t# p
  84.         {, I8 e2 u3 U# n0 O/ M
  85.                 case IIC_CH1        :        //IIC1
    : f3 l6 O" ^' y" Y8 H
  86.                 {& k6 X3 C( \- k& M/ n! f- i+ y
  87.                         RCC->DCKCFGR2 &= ~(0x3 << 16);        //清除设置,使用APB1作为时钟源4 M* v4 m  j, b* r7 S! [* X; w
  88.                         DevClock = DEV_I2C1;7 E8 k) N6 z' b  H) a
  89.                         //初始化I2C IO
    1 C. w4 `' b5 f$ D# c" u
  90. #if(IIC_CH1_IO_SELECT==IIC_CH1_PB6_7)        //I2C1        使用PB6/74 L+ y  Q! p$ X  t
  91.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    % Z' r, |  X' @; u
  92.                         SYS_GPIOx_OneInit(GPIOB, 6, AF_OD, SPEED_25M);                //PB6# D; A; I7 F% Y3 {9 }/ T3 }
  93.                         SYS_GPIOx_OneInit(GPIOB, 7, AF_OD, SPEED_25M);                //PB7
    + G; l9 ?" v! p  l1 e, \8 |2 |
  94.                         SYS_GPIOx_SetAF(GPIOB, 6, AF4_I2C1);                                //AF40 [  Y! T5 c, Y4 w" d! s
  95.                         SYS_GPIOx_SetAF(GPIOB, 7, AF4_I2C1);                                //AF4
    ( T& S) H$ E/ W5 O9 q
  96. #elif(IIC_CH1_IO_SELECT==IIC_CH1_PB8_9)        //I2C1        使用PB8/9
    ( [4 G7 p/ z4 [# j) r
  97.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    ( N" z; A' a9 t3 s+ f
  98.                         SYS_GPIOx_OneInit(GPIOB, 8, AF_OD, SPEED_25M);                //PB8. @% U. L2 X; X  {
  99.                         SYS_GPIOx_OneInit(GPIOB, 9, AF_OD, SPEED_25M);                //PB9
    " y/ G0 F' k" _* v* F
  100.                         SYS_GPIOx_SetAF(GPIOB, 8, AF4_I2C1);                                //AF46 ?& c6 s2 u5 |9 D2 |& `- Y
  101.                         SYS_GPIOx_SetAF(GPIOB, 9, AF4_I2C1);                                //AF4
    / {( a; y" F6 l9 e- K0 [5 M
  102. #else* Z8 S% u( t( V& I
  103.                         #error("无效的I2C1 IO选择");- m# r8 W3 y* i( {% b/ c
  104. #endif //IIC_CH1_IO_SELECT
    . Q* Y$ s( X& p7 ~3 F) G  m$ e/ n, @
  105.                 }break;0 b; `5 P5 O4 a
  106.                 case IIC_CH2        :        //IIC2
    . m/ V8 y1 z# H3 }' F) p: @2 w; ~
  107.                 {$ g& F5 f6 G0 O1 D$ s
  108.                         RCC->DCKCFGR2 &= ~(0x3 << 18);        //清除设置,使用APB1作为时钟源
    # |; }" [% s+ A
  109.                         DevClock = DEV_I2C2;" j, I, L, {, Z
  110.                         //初始化I2C IO
    ( {" H+ _+ O3 ~' B+ m; T1 Z  p6 V5 n
  111. #if(IIC_CH2_IO_SELECT==IIC_CH2_PB10_11)        //使用PB10,PB11  v' L1 n! g& R
  112.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟7 Y& m0 n, ?' {1 m5 b0 B- I3 C
  113.                         SYS_GPIOx_OneInit(GPIOB, 10, AF_OD, SPEED_25M);                //PB10
    2 B; m* ]$ i" Y8 g* L; f& W
  114.                         SYS_GPIOx_OneInit(GPIOB, 11, AF_OD, SPEED_25M);                //PB11
    ) i0 m# I: Z  X9 k
  115.                         SYS_GPIOx_SetAF(GPIOB, 10, AF4_I2C2);                                //AF48 i+ B) W% Q% t! w: ?0 ]
  116.                         SYS_GPIOx_SetAF(GPIOB, 11, AF4_I2C2);                                //AF46 k2 x0 @; b, l' {, y
  117. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PF0_1)        //PF0,PF1" v: y% v- Z8 C
  118.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟
    2 e( Z" `/ s7 f
  119.                         SYS_GPIOx_OneInit(GPIOF, 0, AF_OD, SPEED_25M);                //PF0/ U8 V5 p/ ?: v/ w' i
  120.                         SYS_GPIOx_OneInit(GPIOF, 1, AF_OD, SPEED_25M);                //PF1
    0 c1 h8 F0 t2 y
  121.                         SYS_GPIOx_SetAF(GPIOF, 0, AF4_I2C2);                                //AF4
    - ]* e7 P4 x+ _% T( V
  122.                         SYS_GPIOx_SetAF(GPIOF, 1, AF4_I2C2);                                //AF4/ S) X4 T9 ?+ D7 w) ]% _
  123. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PH4_5)        //PH4,PH5; P8 s- L2 l( j4 P) m8 r
  124.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟" ]5 O5 p( o# ?, a6 ~' Y- B
  125.                         SYS_GPIOx_OneInit(GPIOH, 4, AF_OD, SPEED_25M);                //PH46 Q5 e% f8 g, y( n# E
  126.                         SYS_GPIOx_OneInit(GPIOH, 5, AF_OD, SPEED_25M);                //PH55 @' s+ ]! t4 E* {) A0 G
  127.                         SYS_GPIOx_SetAF(GPIOH, 4, AF4_I2C2);                                //AF4
    ! f1 L5 E) a: s
  128.                         SYS_GPIOx_SetAF(GPIOH, 5, AF4_I2C2);                                //AF4                        5 {7 t1 W0 q/ S; c, F% X. r5 S
  129. #else0 R4 c3 ?3 F% C$ W
  130.                         #error("无效的I2C2 IO选择");! H" K4 l1 t! y0 y2 o! \- q
  131. #endif //IIC_CH2_IO_SELECT
    8 R3 O( Z7 f* D. i5 b# p. `: U
  132.                 }break;                        1 O8 E( U0 G( f* m5 a7 M& T" z
  133.                 case IIC_CH3        :        //IIC3
    2 Q% e! g6 x* u) H: O
  134.                 {
    3 K( P; H! E8 e2 n! u# q
  135.                         RCC->DCKCFGR2 &= ~(0x3 << 20);        //清除设置,使用APB1作为时钟源
    ' D! D4 d3 _4 [
  136.                         DevClock = DEV_I2C3;
    * p( d8 \, m! z
  137.                         //初始化I2C IO
    ( r  r8 s- b3 l
  138. #if(IIC_CH3_IO_SELECT==IIC_CH3_PH7_8)                //PH7,PH8  f) N. [3 @' k- L) J" @. L
  139.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟, V/ \. c. [2 Q- _4 }
  140.                         SYS_GPIOx_OneInit(GPIOH, 7, AF_OD, SPEED_25M);                //PH78 v8 `) `5 V' t0 R# P, ^; I
  141.                         SYS_GPIOx_OneInit(GPIOH, 8, AF_OD, SPEED_25M);                //PH8
    0 [, S# m5 N& l( v# n
  142.                         SYS_GPIOx_SetAF(GPIOH, 7, AF4_I2C3);                                //AF4) F  A5 X; M# V' g! d7 _
  143.                         SYS_GPIOx_SetAF(GPIOH, 8, AF4_I2C3);                                //AF4
    0 \6 @+ @1 G$ M3 N
  144. #elif(IIC_CH3_IO_SELECT==IIC_CH3_PA8_PC9)        //PA8,PC9
    6 j1 }4 P7 Q  u& ]" R
  145.                         SYS_DeviceClockEnable(DEV_GPIOA, TRUE);                                //使能GPIOA时钟( ~$ T# r6 f, U7 @
  146.                         SYS_DeviceClockEnable(DEV_GPIOC, TRUE);                                //使能GPIOC时钟
    ' C% N, C6 F, d5 N' v
  147.                         SYS_GPIOx_OneInit(GPIOA, 8, AF_OD, SPEED_25M);                //PA8* K7 i1 s% Q$ K0 o
  148.                         SYS_GPIOx_OneInit(GPIOC, 9, AF_OD, SPEED_25M);                //PC9
    " D# B' x3 r0 n$ [
  149.                         SYS_GPIOx_SetAF(GPIOA, 8, AF4_I2C3);                                //AF4# s" P# E: j$ M6 \9 o2 B" x+ n
  150.                         SYS_GPIOx_SetAF(GPIOC, 9, AF4_I2C3);                                //AF4                  X0 Y- E/ {% T3 X/ Q% Z. \
  151. #else
    , A# w/ P7 |/ [! m+ m
  152.                         #error("无效的I2C3 IO选择");
    " V  C) f2 {1 p3 c0 o6 Z
  153. #endif //IIC_CH3_IO_SELECT                        
    ( ~( s. Y3 _- Z( ^6 M- g' R
  154.                 }break;                        
    1 r, i9 ]- D# r) S3 h. U8 T3 C  X$ V
  155.                 case IIC_CH4        :        //IIC4
    , G  a6 Z6 I4 R0 e' y
  156.                 {
    + p0 L- E# g6 u/ K- j: |* Z
  157.                         RCC->DCKCFGR2 &= ~(0x3 << 22);        //清除设置,使用APB1作为时钟源
    6 N3 H. g) P, ~% l$ r, d
  158.                         DevClock = DEV_I2C4;% T. k  p! P! t% f0 H. ~
  159.                         //初始化I2C IO
    + G# \! b$ @4 H1 X2 S- O3 K
  160. #if(IIC_CH4_IO_SELECT==IIC_CH4_PD12_13)                //PD12,PD136 w' `) V' J# @; P( @/ I
  161.                         SYS_DeviceClockEnable(DEV_GPIOD, TRUE);                                //使能GPIOD时钟2 E1 Q& B) ^. @# ?! p0 I8 o
  162.                         SYS_GPIOx_OneInit(GPIOD, 12, AF_OD, SPEED_25M);                //PD12; d- [: v2 y" z, v% F
  163.                         SYS_GPIOx_OneInit(GPIOD, 13, AF_OD, SPEED_25M);                //PD13
    / k0 I# G5 Q' U" b1 f0 D
  164.                         SYS_GPIOx_SetAF(GPIOD, 12, AF4_I2C4);                                //AF4
    , h* R. ^, J8 W. b
  165.                         SYS_GPIOx_SetAF(GPIOD, 13, AF4_I2C4);                                //AF4! H% w* k6 R' X5 s; M; T
  166. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PF14_15)        //PF14,PF15
    % X& D' F' m- ~0 J5 @9 B
  167.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟% D% M6 M. g# W, C
  168.                         SYS_GPIOx_OneInit(GPIOF, 14, AF_OD, SPEED_25M);                //PF14- u7 E8 Z4 h% _! T
  169.                         SYS_GPIOx_OneInit(GPIOF, 15, AF_OD, SPEED_25M);                //PF15, Z3 i% p3 u9 @- w8 ]. G
  170.                         SYS_GPIOx_SetAF(GPIOF, 14, AF4_I2C4);                                //AF4
    + v" o6 y' d6 j7 P( G$ ~
  171.                         SYS_GPIOx_SetAF(GPIOF, 15, AF4_I2C4);                                //AF48 l4 y7 o! F6 b2 {' v
  172. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PH11_12)        //PH11,PH12
    6 V% }) o! d! F" t
  173.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟) a, J8 ?$ v7 L: K& v
  174.                         SYS_GPIOx_OneInit(GPIOH, 11, AF_OD, SPEED_25M);                //PH11
    * X+ d! H; C& S
  175.                         SYS_GPIOx_OneInit(GPIOH, 12, AF_OD, SPEED_25M);                //PH12
    8 j/ n  s( g* S; G& g
  176.                         SYS_GPIOx_SetAF(GPIOH, 11, AF4_I2C4);                                //AF4
    3 ]* L' z1 R, K& x
  177.                         SYS_GPIOx_SetAF(GPIOH, 12, AF4_I2C4);                                //AF4                        ' n4 Z: O" y3 a4 r
  178. #else
    $ {- I( I; t, Q, W
  179.                         #error("无效的I2C4 IO选择");' [7 G! O3 g) s
  180. #endif //IIC_CH4_IO_SELECT                        ( {4 O' I2 o5 M- X6 t; D. k$ C
  181.                 }break;
    2 w3 E- D( Q; F/ `! L
  182.                 default:& ?! r2 u8 h7 c
  183.                 {. {* w8 b! T; ^2 F3 b
  184.                         DEBUG("初始化IIC失败:无效的IIC通道%d\r\n", ch);5 x# I+ |3 G9 c  ?6 a* Q) g$ d, g
  185.                         return FALSE;* X% f3 l) Q" q, n
  186.                 }
      I) [% Q) m& S/ \$ z$ E
  187.         }& ?$ q! O" g9 v. Z
  188.         pHandle = &sg_IIC_Handle[ch];                                                        //获取相关通道的句柄+ W* s- b! U! Y3 \5 N" A% ]; j- Q
  189.         if(pHandle == NULL)
    ( ~: b; Y+ q9 h# e- Z
  190.         {
    ! g3 Z  r) ~- v: R9 j
  191.                 DEBUG("初始化IIC失败:无效的IIC句柄\r\n");1 N/ N, J' M( x4 u+ x! a" m5 f
  192.                 return FALSE;3 Y0 T; f) i9 q2 X8 }' ~
  193.         }6 I# e/ K, C1 N( |. A
  194.         6 r  L4 `( x5 X! q3 T9 F% P
  195.         SYS_DeviceClockEnable(DevClock, TRUE);                                        //使能时钟( V3 t  u: z* H4 N5 S8 ?
  196.         SYS_DeviceReset(DevClock);                                                                //外设复位5 w  I7 }/ u7 a! q0 s
  197.         pHandle->I2Cx = (I2C_TypeDef *)I2C_TYPE_BUFF[ch];                //外设指针
    . r" `" \+ D1 e# `. K2 B3 B7 v. ^
  198.         pHandle->I2Cx->CR1 = 0;
    8 ^2 G* j0 K& s- L- B1 @% I' l
  199.         Delay_US(1);                                                ; l& [9 T; l' ?
  200.         pHandle->I2Cx->CR1 |= 2<<8;                                                                //设置噪声滤波器,关闭所有中断
    ( O9 C& |) Y, j  l9 G
  201.         pHandle->I2Cx->CR2 = 0;. k) c7 A* Y5 d2 V( u, T2 x$ e  j
  202.         pHandle->I2Cx->OAR1 = 0;
    9 w2 g2 z- Q$ R+ M6 w! r) V
  203.         pHandle->I2Cx->OAR2 = 0;
    + m( ^& F% f4 n6 f, F
  204.         if(Speed_KHz > 1000) Speed_KHz = 1000;2 N3 _& p6 U; J% A
  205.         if(Speed_KHz < 10) Speed_KHz = 10;- [# w( J9 |5 [) S
  206.         pHandle->Speed_KHz = Speed_KHz;                                                        //记录速度  k; V( x( ]. W
  207.         if(TimeOutUs == 0)                                                                                //需要自动计算超时时间,时钟周期*10*10 6 ?5 V& B8 ^/ f5 t! _: r4 [8 h
  208.         {
    , ]* L4 \8 S% C& }5 f- q
  209.                 TimeOutUs = 1000/Speed_KHz;                                                        //时钟周期3 b! T8 V8 a1 n. A5 i' n7 I
  210.                 TimeOutUs *= 10;                                                                        //字节周期
    # @" j4 G; T0 s7 R
  211.                 TimeOutUs *= 10;                                                                        //超时时间为10个字节时间% ]& w' h# i& D/ z' D
  212.         }
    2 ~0 ~. B, ]% s7 R+ g: ]+ ~/ \
  213.         if(TimeOutUs < 3) TimeOutUs = 3;9 }5 v1 ~3 i$ H5 T. ^3 u
  214.         pHandle->TimeOutUs = TimeOutUs;                                                        //记录通讯超时时间  v  ^5 `, B9 [. h
  215.         uart_printf("IIC超时时间:%dus\r\n", pHandle->TimeOutUs);
    % x# r2 p% W# \5 I& ]/ z8 o& C. S$ [
  216.         pHandle->I2Cx->TIMINGR = IIC_CalculationTiming(pHandle->Speed_KHz);//0x40912732;                                        //时序
    - _4 d# r& q3 V4 T  g! ^
  217.         pHandle->I2Cx->CR1 |= BIT0;                                                                //使能IIC
    % l+ e+ ~) L8 W8 T  {6 w/ O' N  l
  218.         pHandle->isMasterMode = TRUE;                                                        //主设备模式. H9 }8 q1 A/ o. G0 Z0 T7 Z
  219.         Delay_US(1);
      U* Y' U# W4 h3 A! H2 P
  220. ( `- r' Q7 t" w
  221.         return TRUE;% Y6 X# l9 b' m$ j) V) `' ]! _9 q+ y0 r
  222. }
    3 y. J3 ?% I3 f& r2 i. v2 ?6 {

  223. 5 V/ A: N: W  s% h, ^+ _9 m# _

  224. % |' j. a" H& K
  225. /*************************************************************************************************************************
    ( F& Z3 F6 @9 j- o8 @+ R
  226. * 函数        :                        static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)
    9 D3 n- O" S  y# ]+ [1 w8 e5 a
  227. * 功能        :                        检查是否有NACK中断状态,如果有则清除掉
    / ]9 B4 d  F- p6 ?# x. A# I
  228. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us. O; o: ^" B' B0 t
  229. * 返回        :                        IIC_ERROR
    2 \0 ]4 p; \+ `* U+ ^+ I6 q9 D7 ?
  230. * 依赖        :                        底层宏定义
      |) `, h6 _7 x
  231. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>; \+ D. C& v/ J- V6 {2 q
  232. * 时间        :                        2020-02-15
    8 A9 V1 `6 `1 a5 L
  233. * 最后修改时间 :         2020-02-15% W/ L, i& K) B9 ^4 u
  234. * 说明        :                         如果有NACK中断,则先产生停止位,然后清清除掉所有的中断,并复位IIC,然后返回错误
    5 H! F: G; a  t, O4 g
  235. *************************************************************************************************************************/  
    # E& L( f8 M3 ?; h( v
  236. static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)
    * X+ {* f6 v6 Z3 l/ u: j! s5 A
  237. {
    " p* M; V0 {  i  k$ j* X
  238.         IIC_ERROR Error = IIC_OK;; F0 Q: t5 Z* ~9 g' j
  239.         
    ; a# Q7 F8 O* M
  240.         if(IIC_GetISR(pHandle) & IIC_FLAG_NACKF)        //接收到否定应答标志
    ! G+ t7 I* O- ^0 \+ i" J  E+ m5 k) P
  241.         {2 M8 z& q1 v. ]
  242.                 uart_printf("NACK : IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);
    $ Q( D8 F+ F) c" @  C6 }
  243.                 uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);# i, C& ?& w  _8 R. b* N% D6 N3 D+ g
  244.                 uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));, n0 l! o) u% h' N/ ?6 o/ s
  245.                 //主设备下,如果没有开启自动产生停止位,则手动产生停止位) o% I6 c9 `' X/ f# x: _7 ?1 V
  246.                 if(pHandle->isMasterMode && ((pHandle->I2Cx->CR2 & I2C_CR2_AUTOEND) == 0))
    . X  H6 j2 A$ j; h: v  e% G7 i; A
  247.                 {$ g; E9 y& [- ~5 N  T5 Z1 Y
  248.                         IIC_SendStop(pHandle);                        //send stop4 o2 d: k) v4 S$ [$ n, @9 f
  249.                 }
    - L0 w$ H2 w3 f, ~6 J" k/ e1 }
  250.                 //等待STOP标志有效6 I* {5 x: h! H" \6 U4 `3 N- O
  251.                 while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
    ( Y* t+ a1 l. u9 c* b2 V
  252.                 {3 k7 Y7 S# l% k/ L2 t
  253.                         if(TimeOutUs == 0)                                //检查是否超时了; I1 |  i! Q1 ?0 u1 R8 \* x# P
  254.                         {% ^% G) ]' W: S
  255.                                 break;* z! W& P' H. W5 z/ @, j4 ^
  256.                         }                        
    7 O( O! \. w3 X% D
  257.                         TimeOutUs --;: S7 v% I: @, Z- ?6 L+ g
  258.                         Delay_US(1);                                                //延时4 B3 T; b1 B+ z! y, O2 _
  259.                 }5 B$ [' q2 w7 h  L  D
  260.                 //清除相关的中断标志
    " O+ J: y( B3 B: z
  261.                 IIC_ClearISR(pHandle, IIC_FLAG_NACKF | IIC_FLAG_STOPF);        //清除NACK,STOP标志
    9 [, @5 f. s( i7 G8 ]. D
  262.                 pHandle->I2Cx->CR2 = 0;                                                                                //清除CR2寄存器
    # t+ m, g$ l( N  a1 I8 E
  263.                 IIC_SoftReset(pHandle);                                                                        //执行软复位
    2 K4 ^$ i! _. O6 F8 B/ {
  264.                 if(TimeOutUs == 0)                                                //没有超时,就是硬件通讯出错了
    6 m$ C3 e% H  F& J
  265.                 {; b4 o& h  w; Y3 ^6 r4 l+ I
  266.                         DEBUG("IIC发送stop超时\r\n");6 m' M' C3 y% F- b. `, b
  267.                         Error = IIC_TIMEOUT;                                //超时6 i% f  M# c5 V% J! Q: Y
  268.                 }7 h& |) E9 s9 Z$ ?$ @) A$ q' i+ H
  269.                 else1 B" S/ O" x$ H) n
  270.                 {
    ( @) I0 m7 {$ s4 B
  271.                         Error = IIC_HAL_ERROR;                                //底层错误0 d2 R' o* j3 J% |) O
  272.                 }  @  m/ a- z+ D# w1 U2 e
  273.         }
    # p- d7 n4 m1 a/ D7 n3 t
  274.         
    6 |, d, K8 {6 C+ I/ R4 O! S
  275.         return Error;
    6 n. b& B) y- C6 F; u' y% d
  276. }! t: `1 F2 U( p+ v9 I7 U
  277. & m& ?+ O* W; e$ S8 u

  278. ; V$ t( T2 S% Y( ^. |
  279. , M- |* T6 A  L+ b: n. p* j
  280. /*************************************************************************************************************************
      D3 C$ E; \2 L2 u( f
  281. * 函数        :                        static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
    6 a& K2 f8 Z& g% }" l) H
  282. * 功能        :                        等待TXIS中断有效(等待 I2C_TXDR 发送寄存器为空)8 @& a: Q3 x0 `
  283. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us
    - s& A" Z8 S' r7 F
  284. * 返回        :                        IIC_ERROR* K3 T9 G  U# G! [( _, E9 ^
  285. * 依赖        :                        底层宏定义
    ) L; ^9 t1 v9 B2 m" ~3 d0 A
  286. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    4 I0 ]" K/ P! \& {6 p
  287. * 时间        :                        2020-02-15
    5 K% u/ `3 Y% w' N6 y0 Y
  288. * 最后修改时间 :         2020-02-15
    . ^/ ?8 k, V, I3 ^+ n
  289. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的' H& x. S1 a/ @
  290. *************************************************************************************************************************/  
    ' L4 J# ]( [. C, Y0 Q
  291. static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)1 H5 z4 F7 n# F+ ?
  292. {
    ) H  v7 ~. l0 `: U, G( g0 ?2 Q8 L( A
  293.         //等待TXIS中断有效" s! w6 g6 J. ^# ?
  294.         while((IIC_GetISR(pHandle) & IIC_FLAG_TXIS) == 0)7 k- L; `2 I  X8 O3 p
  295.         {; z3 H0 a4 W- M' P- a% N
  296.                 //有NACK中断,进行处理
    9 z+ U5 R; [1 D
  297.                 if(IIC_isCheckNackFlag(pHandle, TimeOutUs) != IIC_OK)        2 Z' k9 O1 V- l) Y6 u  V* x: L6 n5 p
  298.                 {
    ; Q$ {4 d0 M& s# j+ O9 h" x
  299.                         DEBUG("检测到NAK错误\r\n");. L8 U, H, a( `$ ]2 g
  300.                         return IIC_NACK;
    , n! U2 Z3 B* A+ X! |% W) Q) O
  301.                 }, W( Q4 E3 U2 R0 v7 o
  302.                 5 g! k$ r7 C  o' T. O* z) \, L6 B
  303.                 if(TimeOutUs == 0)                                        //检查是否超时了6 L! w7 m" u/ ^; B( B/ [1 c$ z
  304.                 {
    & |5 T) T+ H% e4 m& p/ k. \5 m
  305.                         uart_printf("IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);7 g3 x; z: w8 {1 d
  306.                         uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);$ m& v$ O5 ]0 g4 S) E
  307.                         uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));3 |2 p1 [" a6 M- w4 }
  308.                         ( j+ ]& F& {' e+ m- P% A; I4 o
  309.                         IIC_SoftReset(pHandle);                //执行软复位
    8 t/ f8 ?- w6 b" w; I3 Y
  310.                         return IIC_TIMEOUT;                                //超时
    ! d2 M0 w: U  T1 ~2 u2 Y! |, c
  311.                 }                        
    ( X) P+ F1 \3 o  G1 ^2 \
  312.                 TimeOutUs --;9 p$ q: A( x6 r! k1 N0 s
  313.                 Delay_US(1);                                                //延时
    , i, f, y) J9 S8 a8 E% V
  314.         }
    # s0 z7 {( D0 J- `4 f0 I& J1 M: z
  315.         
    / m8 k6 N7 C& w+ r, v+ T+ F- N
  316.         return IIC_OK;
    $ ?0 p, c# `2 G; N6 r
  317. }9 a7 z  B, g9 i/ o6 v

  318. * q0 Q, S4 H1 t: I

  319. 8 C# a& r# g1 @2 m
  320. /*************************************************************************************************************************8 k, E' d$ Z$ e0 }. ]  G) ~) a
  321. * 函数        :                        static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)
    9 C. H7 x- m8 _5 V1 G! m
  322. * 功能        :                        等待STOP中断有效(等待 发送结束 )
    - v0 G' K! m* l/ c! c4 u7 [
  323. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us
    , J; C; q- J; s8 F8 E# C7 |
  324. * 返回        :                        IIC_ERROR# k$ {* y! Y; ]* g0 y" O
  325. * 依赖        :                        底层宏定义
      V9 y8 I( a1 ?( p" q
  326. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>, X3 R$ P3 ^1 N. b; W/ n! o9 r1 i
  327. * 时间        :                        2020-02-155 p/ s# O$ G  f) e0 x1 o
  328. * 最后修改时间 :         2020-02-15
    * v8 l4 q1 w* U! J" o& i3 }, S
  329. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的6 T# i) M+ X6 m. @; e( E
  330. *************************************************************************************************************************/    W; Z2 T, h# E, H
  331. static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)
    8 J  a' s4 D4 [* |4 r2 }; G+ z
  332. {
    7 n+ o3 ]+ O+ ?; V
  333.         //等待STOPF中断有效1 P( o2 ?6 U' {4 A6 i* @
  334.         while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
    $ h1 L. h) Z: @8 t+ Y# n
  335.         {
    ) J9 e% z, v7 n* _# X2 X- b! s
  336.                 //有NACK中断,进行处理
    * {; v# ]. g0 P. i
  337.                 if(IIC_isCheckNackFlag(pHandle, 5) != IIC_OK)        
    9 L9 D" n$ i3 P
  338.                 {$ ~/ c5 F) A+ c% r
  339.                         return IIC_HAL_ERROR;
    + A# ^8 U! n' j1 E$ u0 f
  340.                 }
      F! b: ~: m1 }9 B- N
  341.                 % v( i4 j- v- h1 j& K4 g8 h
  342.                 if(TimeOutUs == 0)                                        //检查是否超时了  J% y" P0 Z% V. H! l6 f
  343.                 {3 P! o/ C" f# k
  344.                         IIC_SoftReset(pHandle);                //执行软复位
    0 C8 Z! X, D2 b6 p1 t
  345.                         DEBUG("IIC等待结束超时\r\n");4 }, Z5 h6 Z1 [
  346.                         return IIC_TIMEOUT;                                //超时
      ^* ]8 }  t7 a. u/ _
  347.                 }                        
      f$ F$ k9 X% k
  348.                 TimeOutUs --;
    $ Z# ^; B# A: ]: m1 W
  349.                 Delay_US(1);                                                //延时
    6 f: b/ [: e1 X" S
  350.         }
    9 V: c  c* x- u' P1 j5 @0 e* @1 o( d( ?
  351.         
    + {) ^& h6 K: S! U7 q* @. T$ h
  352.         return IIC_OK;6 r' V9 [$ T/ M+ p" m: D
  353. }
    4 {7 W/ D+ u5 a2 `8 k

  354. ; ^5 v% c% F& K( F. s9 C) m8 D

  355. . q- h0 h4 R, O. n- l) ?
  356. /*************************************************************************************************************************5 R& O2 H1 \! Z6 F( J
  357. * 函数        :                        static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
    5 j3 o- A* S% \/ [7 `- f6 h- d
  358. * 功能        :                        等待中断有效
    * J- M7 p3 O0 k* e, B) m& C
  359. * 参数        :                        pHandle:句柄;Flag:需要等待的flag,见IIC_FLAG_xxx;isWaitFlagSet:TRUE:等待标志有效,FALSE:等待标志复位;TimeOutUs:超时时间,单位Us
    # L' V; ^& c  ^3 m1 {7 _" K
  360. * 返回        :                        IIC_ERROR8 j! r! H- E8 B8 \/ t9 L
  361. * 依赖        :                        底层宏定义
    ! ~. \, M; q; E# b; G
  362. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    " K" a& l; x. M) o
  363. * 时间        :                        2020-02-15/ S" b; {9 k2 W, P4 k, K% ~- w
  364. * 最后修改时间 :         2020-02-15. F& e6 k: k! X2 m& K# A7 k
  365. * 说明        :                         $ E! {9 ^* k4 b) K7 [  e3 G
  366. *************************************************************************************************************************/  
    ) Y, T! J+ G) S9 r3 O* q1 @
  367. static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)1 V; R# k4 [- p5 b
  368. {% b) e, {& x1 L, L) f% t! |
  369.         if(isWaitFlagSet)        //需要等待标志有效; {2 m9 {, L1 e4 d3 J# [$ P* b
  370.         {9 r! H; J. J2 V/ M- t
  371.                 while((IIC_GetISR(pHandle) & Flag) == 0)
    ; F( A) o7 _8 E1 i5 ^' l
  372.                 {0 F! W! x) m, f+ I" q2 \
  373.                         if(TimeOutUs == 0)                                        //检查是否超时了
    4 P! `! g0 d1 b5 p
  374.                         {
    ! y) W  ?( h9 p$ Y% V/ S( w" n7 {+ ^
  375.                                 return IIC_TIMEOUT;                                //超时# k* i# b( c' Y, w% e
  376.                         }                        * Y! f) _5 V8 g! w3 W5 k- ?8 c
  377.                         TimeOutUs --;
    9 E8 {- f' O+ Y" Y/ o' e
  378.                         Delay_US(1);                                                //延时% y1 M  x* N: T: \
  379.                 }
    ) \' _1 ]/ K' Z9 l* K
  380.         }8 w- H6 Y; D- A) A5 Z
  381.         else                                //需要等待标志复位
    6 S- k# h6 b' r7 ?0 K) V  \* [
  382.         {9 z+ G. b5 U8 M% b+ G/ u4 a. I
  383.                 while((IIC_GetISR(pHandle) & Flag) != 0)
    : E9 f+ u1 ?6 v2 C9 r: d# L
  384.                 {
    ) M" `$ q3 {9 q8 j" G
  385.                         if(TimeOutUs == 0)                                        //检查是否超时了8 e9 `' F  n: e( w! f( F8 c! m
  386.                         {
    6 t- ?: h! s: W
  387.                                 return IIC_TIMEOUT;                                //超时
    / ]6 Z$ N+ C3 R& b% \6 `
  388.                         }                        
      N  A# e& s6 H: ]4 ^3 ?
  389.                         TimeOutUs --;
    & X0 j7 ~5 G) n4 R% |; x
  390.                         Delay_US(1);                                                //延时# F3 O- ^* E7 b8 k- R
  391.                 }
      c2 A+ n0 ?4 b& |# ^. y% M& R# G3 Z$ y
  392.         }
    ) u* _& N0 c6 E: l' ?: t
  393. 3 E; g7 S" h& s+ M* q( [
  394.         return IIC_OK;- J* H# o; E% j% N0 D# I& {
  395. }3 b7 s8 [! T/ L4 M, ^3 A; {5 O0 p
  396. " h2 u5 Z/ Q, d3 x

  397. $ ~2 e$ H- u! e8 s/ ~; N

  398. 8 H' `. [# L# ?  }' g" B: {, r
  399. 7 t3 p& w# |0 n$ C  C- n. `3 \. ^
  400. /*************************************************************************************************************************: u7 u9 B* N( y1 p. Y, B5 [
  401. * 函数        :                        static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)
    % e! ]+ V; ]* h5 r0 U. J
  402. * 功能        :                        主设备传输配置(配置CR2寄存器)
    ) D& W% x( o; W; y4 ], f% q
  403. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;TransByteCount:需要传输的数据长度;EndorReload:自动结束还是重载设置,见IIC_RELOAD_END_MODE;StartAndWR:开始读写控制,见StartAndWR
    7 N5 Z1 o  |$ O- F. J% p/ s
  404. * 返回        :                        无" h6 P% m* h5 ?
  405. * 依赖        :                        底层宏定义
    * S8 @' J3 V; [" l
  406. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>, ]$ Q/ }" H6 p- V4 J; m
  407. * 时间        :                        2020-02-159 a/ C0 R# A! R$ v$ n7 \
  408. * 最后修改时间 :         2020-02-16
    & f* r5 R( ~& I- M& v3 Z4 C7 `9 V
  409. * 说明        :                         在往 NBYTE 中设置最后一次传输的字节数前,必须把 RELOAD 位清零便于后续自动发送STOP。/ E0 g; {& n- U5 y; Z) w8 _
  410.                                         当 RELOAD 位置 1 时,AUTOEND 位将不起作用;2 \5 S+ d' b, R! A" e9 R
  411. *************************************************************************************************************************/  
    " K* S, i( P* _5 `' [) _1 `1 i
  412. static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)1 j# H! J' L" n6 ]+ h- u
  413. {2 V# i- L6 b8 \2 M6 `5 v3 [
  414.         u32 temp = 0;% p- g9 f: ^: c" r
  415.         " J) _: f7 z0 Y* K( R, \; v
  416.         //先读取CR2寄存器的值
    ' o: H  y; a$ C5 i, C
  417.         temp = pHandle->I2Cx->CR2;
      F9 M/ R2 i& C9 U; C
  418.         //清除掉相关的字节: }) J8 x) ^- y5 f5 F. y# z
  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));
    1 z& v! z$ N! x
  420.         //生成配置数据6 c9 u" w3 @3 W! U6 d
  421.         temp |= (u32)(((u32)SlaveAddr & I2C_CR2_SADD) | (((u32)TransByteCount << 16 ) & I2C_CR2_NBYTES));
    / X' M+ _; O+ m) z" z: M- y% V
  422.         //重载与自动结束只能二选一
    7 w7 ]0 P' k8 w; s
  423.         if(EndorReload == IIC_AUTOEND_MODE)         ! y* Y6 N7 @; A+ t9 L1 i
  424.         {2 P, E, p7 [6 h8 f
  425.                 temp |= I2C_CR2_AUTOEND;        //自动结束模式
    ! [3 I& K, ?' u& ]
  426.         }
    % I+ F3 ~0 M& _. Q+ }/ {4 i1 b
  427.         else if(EndorReload == IIC_RELOAD_MODE)
    $ h& R& o3 M( p4 f' q% m
  428.         {, ^1 n3 P$ J; a; f9 l5 L
  429.                 temp |= I2C_CR2_RELOAD;                //NBYTES 重载模式
    9 G- K) C* L+ ^
  430.         }
    7 D$ [; `5 G) n* E7 @* A& v
  431.         
    ' I, D: _1 x6 j2 X' O* ~
  432.         switch(StartAndWR)
    # U% g; P. p7 \; V2 m" K8 \- a' y
  433.         {
    0 {2 L3 ^. V! {0 E# Y$ K$ c* B
  434.                 case IIC_NOSTART_WRITE        :        break;        //没有开始的写-默认就是这样的/ H, R' A! l9 Q6 f  h
  435.                 case IIC_NOSTART_READ        :                        //没有开始的读-用于后续数据读取
    % |0 }! e- Y; r1 s
  436.                 {
    0 Z" S' @! E5 k7 t$ j7 a% N
  437.                         temp |= I2C_CR2_RD_WRN;                        //读取
    7 Y) m0 v: p2 O
  438.                 }break;/ c2 ^8 O9 V) L. _9 o! p
  439.                 case IIC_START_WRITE        :                        //生成开始写
    : M, i1 ^0 Y& X3 T. b; s& ^
  440.                 {
    / g% b; ~+ }( D  K
  441.                         temp |= I2C_CR2_START;                        //启动传输
    / R) f: y2 C( z2 T+ ^. w
  442.                 }break;" D' x% E& z# U  M
  443.                 case IIC_START_READ                :                        //生成开始读        
    : N$ ]. ^0 m/ H- P7 `  {
  444.                 {
    ) O0 [/ V3 F% Q) a- ]& q6 a' A
  445.                         temp |= I2C_CR2_RD_WRN;                        //读取
    # N6 j, O1 }- p9 B+ f* X! B
  446.                         temp |= I2C_CR2_START;                        //启动传输
    1 d+ ]- _9 i9 d# S" z
  447.                 }break;
    ) C5 v5 k/ x% R- i' x: Q$ [3 i/ V
  448.                 default:break;; C, K9 p* C) Q* ~
  449.         }
    1 m2 K. R$ Q2 N/ Y, _6 ^7 z, o
  450.         
    6 k9 n. V4 K/ E
  451.         //uart_printf("准备写入CR2=0x%X\t", temp);
    5 C; s; N2 A4 k7 Y2 |
  452.         //更新到寄存器
    / z) E" o' V& }$ p: @: B# m/ {
  453.         pHandle->I2Cx->CR2 = temp;  //测试; w. l, }3 V. v& ]$ V
  454.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    . q  ]/ m8 B/ s: |; d& E; N7 ^" M
  455.         Delay_US(100);
    : ~* s) [2 G( s" _8 w' ]
  456. }
    1 X" O3 O/ ^% X5 {% C+ O/ n

  457. 4 `/ b! p: v' ~9 U
  458. 1 C3 |, a$ V, b$ l' s; i
  459. /*************************************************************************************************************************
    / ~6 X! W3 Z; A3 [( ^
  460. * 函数        :                        static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs): ~- I3 A" ?/ v5 E# x
  461. * 功能        :                        IIC发送一字节4 p" W2 [3 r- }2 {7 A
  462. * 参数        :                        pHandle:句柄;data:待发送数据;TimeOutUs:超时时间,单位us
    & F3 |' L" U; S; `: Z* U8 |
  463. * 返回        :                        IIC_ERROR
    2 w- U) o: C7 Q; o4 x
  464. * 依赖        :                        底层宏定义' [- U- N8 x- x! O. ^* h
  465. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>0 m5 z! h0 T( s! o% g* B  V
  466. * 时间        :                        2020-02-15
    3 c" J% A, L# s! ~: {9 I/ u
  467. * 最后修改时间 :         2020-02-16
    # J4 a' p4 ^- m: e! c3 n
  468. * 说明        :                         TXIS有效后才会进行数据发送,不会检查数据发送是否完成。  C4 N6 A6 ]5 ]2 @# d; q  ^" V- S6 ~
  469.                                         如果最后一个字节发送完成后不会再触发TXIS中断,只会触发TC中断7 J$ R  O# ^% ^" c6 ?' A
  470. *************************************************************************************************************************/  
    8 }( \7 ]$ _2 q9 u+ E
  471. static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)9 T/ X3 u: o* w
  472. {
    3 l* `0 B( c' g) N5 e2 e2 a) @7 G* R, E9 C
  473.         IIC_ERROR Error = IIC_isWaitTXIS(pHandle, TimeOutUs);                                //先等待可以发数据
    + k0 Q  s# s/ G1 |! J" L
  474.         if(Error != IIC_OK) return Error;+ D. ]9 f. k) h1 r3 ]# U9 f
  475.         pHandle->I2Cx->TXDR = data;                                                                                        //写数据到发送寄存器-不会等待数据发送完成        0 L4 Z; Z4 q# V, _1 N# o1 F

  476. & h; a& I2 E# P- X6 a5 o! L
  477.         return IIC_OK;) l) n" [* j8 D
  478. }
    ! r* @6 R: p; b8 [$ l5 N; h6 `9 `
  479. # V6 f, L/ P: n" f$ B
  480. /*************************************************************************************************************************' c1 s( j6 f4 ^' Z1 `2 ?
  481. * 函数        :                        static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    $ r0 r8 E  N2 _+ P$ I5 d/ B' @1 b
  482.                                                 bool isRead,u32 TimeOutUs), c& @0 O! m+ D0 X* z- H
  483. * 功能        :                        主设备请求发送从机地址与目标寄存器地址" |, u) e! Q% \7 T7 a5 S( f9 V8 F% g; b
  484. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;RegAddr:寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,
    3 p6 I* [0 Q. S
  485.                                                 FALSE:16bit寄存器地址;isRead:TRUE:这个操作是读取寄存器;否则是写入寄存器;TimeOutUs:超时时间,单位us2 v+ D' N3 i+ Q. z
  486. * 返回        :                        IIC_ERROR+ b* s' s4 ?1 r- J6 }
  487. * 依赖        :                        底层宏定义
    / P& O: @" @. L( s4 ?
  488. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>+ c" S$ ~4 f8 X; k# k) m5 u) m
  489. * 时间        :                        2020-02-15
    ; p/ O3 q; \7 U0 P* `- B
  490. * 最后修改时间 :         2020-02-16
      A0 I- d' `+ N7 G
  491. * 说明        :                         ( u# m( q7 J7 Z9 S, m$ U# y: |- `
  492. *************************************************************************************************************************/  4 W0 {" ^- C6 f* \" n! u3 \  |) h7 `
  493. static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,bool isRead, u32 TimeOutUs)
    ) v1 m7 O- \, q' f0 ~5 r
  494. {        7 Q# U6 e* C! i4 U
  495.         IIC_ERROR Error;
    9 j8 W1 k$ b- r: p9 n
  496.         ! n/ {" Y, N- b) M5 `, d
  497.         //uart_printf("WriteAddr1:CR1=0x%X\t", pHandle->I2Cx->CR1);
      Y8 G( \+ m3 n3 m7 Z  g% X
  498.         //uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    & w" b1 [6 T3 ]. t& g4 z
  499.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    , f3 s/ [* y2 M% p/ o9 _) ^* k4 D, f
  500.         //传输配置,并启动传输,发送起始序列,开始IIC传输了
    1 L) A/ e7 M9 n2 u8 y
  501.         //如果是读取则使能软件结束,如果是写则是自动重载& W9 B* D8 y8 c+ b2 r2 z
  502.         IIC_MasterTransConfig(pHandle, SlaveAddr, (is8bitRegAddr==FALSE)?2:1, (isRead)?IIC_SOFTEND_MODE:IIC_RELOAD_MODE, IIC_START_WRITE);        //传输相关配置-写,并启动传输  b4 z* d0 i& U2 R- R. |7 y
  503.         8 }8 }2 I, h" H9 `
  504.         //开始发送寄存器地址
    9 N$ S* s. H% J4 `, b7 q- n6 Y
  505.         if(is8bitRegAddr==FALSE)                                                                                                //寄存器地址是16位的,IIC通常是MSB高位在前,需要进行高低位对调
    # j" ~# M! C" c6 q
  506.         {
    / x( g9 c2 |( h+ T1 X
  507.                 Error = IIC_SendByte(pHandle, RegAddr>>8, TimeOutUs);        //先发送MSB-非最后一字节6 ~) a2 @; y  x' z+ g8 `. }
  508.                 if(Error != IIC_OK)6 u4 W- _. J7 W- t  r) o
  509.                 {. y/ @% E5 S% H5 l# R) [
  510.                         DEBUG("IIC发送寄存器地址MSB失败\r\n");
    9 F/ {* Q6 K9 g+ Q: E1 R
  511.                         return Error;
    + W7 ?; U5 j& J4 s, f+ X. K
  512.                 }        7 @. D0 \5 v3 F  q: F  o0 k
  513.         }
    ' @4 r- ?+ ?! }
  514.         Error = IIC_SendByte(pHandle, RegAddr & 0xFF, TimeOutUs);        //再发送LSB-最后一字节
    + s8 Z& s. p. Y2 z
  515.         if(Error != IIC_OK)
    % M( F; [5 ~& `5 t
  516.         {) Y% B& I5 k! w' {4 V+ q
  517.                 DEBUG("IIC发送寄存器地址LSB失败\r\n");* x- l/ X. N6 r
  518.                 return Error;, W9 D7 a) B2 t& i% a/ h  o! B4 j
  519.         }
    9 b' Q# m' V  @$ o) z6 U
  520.         //等待全部数据发送完成% H; v/ h8 V' \/ E
  521.         if(isRead)        //读取方向-非重载,等待数据传输完成 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。/ e' A7 R; F& @4 W& _, t
  522.         {$ K" l/ }1 F6 A: H1 _) B  E
  523.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TC, TRUE, TimeOutUs) != IIC_OK)
    $ V1 w! a& b" {7 v5 G3 J
  524.                 {
    ) x' ?' p: J2 e5 S1 L9 ]
  525.                         return IIC_TIMEOUT;
    ! D. J8 ^/ A' n: u8 m: |7 h1 b
  526.                 }
    5 t' f6 |' n- y
  527.         }        2 x/ x% h) n  N4 a3 B" |3 d  ~
  528.         else //写入方向,等待重载
    # L* v$ T/ s* K7 w
  529.         {' x) Z0 v# V3 _6 n# W: U
  530.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TCR, TRUE, TimeOutUs) != IIC_OK): m0 v# \# `/ o* M  n; G
  531.                 {
    0 \" i6 o* @' r
  532.                         return IIC_TIMEOUT;& o4 y9 m# i+ z+ A
  533.                 }$ B$ s! {8 F# q3 J8 ]% q
  534.         }
    . Z/ a5 h' Q: B
  535.         
    + L" G2 C; G+ n0 o/ G% R0 a" n
  536.         return Error;
    ' l; f! w$ ]( R0 e' i& o  q, o% q7 l
  537. }1 D% d* a; D% x) j
  538. , n. k7 [: H3 F1 x
  539. : p5 \0 h1 K0 u3 l0 h5 m$ i: E, ?
  540. /*************************************************************************************************************************
    ' A, C' p$ O- i/ c
  541. * 函数        :                        static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
    ) e( z5 A: P! }. \7 g! A+ c7 ~2 w9 o; X
  542. * 功能        :                        等待接收一字节数据2 l1 [8 P' \* y
  543. * 参数        :                        pHandle:句柄;pData:接收的字节数据缓冲区;TimeOutUs:超时时间,单位ms
    9 l6 v  Z, y# R$ }3 p8 y: j
  544. * 返回        :                        IIC_ERROR1 c8 q8 I/ R9 y5 l
  545. * 依赖        :                        底层宏定义  c3 z/ k3 U4 |3 {
  546. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>) c; X- a$ N% y+ ?3 f
  547. * 时间        :                        2020-02-15' w2 z5 I1 e0 |
  548. * 最后修改时间 :         2020-02-15
    - P* Y1 k) C1 q6 b! s* P
  549. * 说明        :                         当RXNE有效后读取一条数据,否则可能会超时
    # u" Q" |; u0 i- e. j0 f6 z
  550. *************************************************************************************************************************/  
    * e. m( C  K. L$ M  G, I
  551. static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
    2 A6 [( n; @+ v& W# ]' H4 A
  552. {
    $ E- U! e) |5 D
  553.         while((IIC_GetISR(pHandle) & IIC_FLAG_RXNE) == 0)        //等待RXNE有效
    # j6 d# }  j3 i2 i2 \4 Q4 N' n
  554.         {9 y' ]$ \2 E) P, ]
  555.                 if(TimeOutUs == 0)                                        //检查是否超时了$ I" [. \. g6 h- m" Z9 M
  556.                 {) P/ j' [9 G- F$ _3 e. _
  557.                         DEBUG("IIC等待接收超时\r\n");
    / x5 I# k1 b  j. l# s3 n" z6 B. O
  558.                         return IIC_TIMEOUT;                                //超时/ C  {5 N! Y) ~! @8 a
  559.                 }                        
    ; O3 d# v# q' P3 @; g" [; {& u) q
  560.                 TimeOutUs --;5 H% P2 q- C4 Z5 x7 E6 s
  561.                 Delay_US(1);                                                //延时* A9 w; x. ~5 s' _4 e$ O
  562.         }
    " e5 Z/ i9 j8 _! s
  563.                
    3 k5 K! a) f3 y& v2 U
  564.         *pData = pHandle->I2Cx->RXDR;                                                        //读取收到的数据: O; `2 `# F4 C& m' {8 ]
  565.         return IIC_OK;% T6 a2 A! r0 l, v0 A6 V
  566. }' m0 A/ a4 E3 _

  567. 1 O1 O) w" B/ v  f
  568. 5 Y8 n( y* `3 o
  569. /*************************************************************************************************************************
    & q% S& t- O5 t& E" \3 ~6 {
  570. * 函数        :                        IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, 0 y1 X% ~# r8 f3 s2 Z  E$ C/ M& X
  571.                                                 u8 *pDataBuff, u16 ReadByteNum)' G/ T2 O- w* O
  572. * 功能        :                        IIC读取寄存器(可以读取1个或者多个寄存器)1 Q8 z, K$ Z# Q( c8 x
  573. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要读取的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;! \6 [$ d: ~; m( }# [! Q& p/ D
  574.                                                 pDataBuff:接收的字节数据缓冲区;ReadByteNum:要读取的寄存器数量;. j# _# B% N3 @. A# \* V: O
  575. * 返回        :                        IIC_ERROR- N6 c" q. q9 t5 h- H# f5 H0 {* ?
  576. * 依赖        :                        底层宏定义
    1 b" a4 |' ]1 G0 I( ?$ m
  577. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    # F+ n' Z' u; a. R0 e
  578. * 时间        :                        2020-02-15
      ^8 [& [8 m' {- p6 C
  579. * 最后修改时间 :         2020-02-156 I2 r0 G, o; `
  580. * 说明        :                         读取的数据都是小端模式,如果是16bit的寄存器,请读取偶数个数据,并且需要另外进行高低字节对调最后组成16bit数据
    : \! @: z. @4 w) d5 G( \7 [
  581.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
    , _! A0 Z: ^: v% O
  582.                                                 增加信号量# E' J, x& _- L/ c9 \. t* P
  583.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在: [( w, V3 D* ^$ O+ H9 d  o' N$ F! I
  584.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。- t6 s+ [: l" z8 H: O
  585. *************************************************************************************************************************/. \* F; W. S! v4 P7 c$ I0 B
  586. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum)1 P: L  u1 `% S8 k# u) k
  587. {% o6 I" I+ Q9 M4 j. i$ G% g. I
  588.         IIC_ERROR Error = IIC_OK;
    4 F2 L/ k+ ^3 ^) [7 j; Z4 u
  589.         u16 ReadCount;% f1 ^. k* i3 ^, H* e/ ^0 x% J
  590.         IIC_HANDLE *pHandle;
    8 l: y/ {' ~; I, V! H5 `6 h
  591.         4 o+ J8 ~9 v6 J% M6 C# C
  592.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || ReadByteNum == 0)
    , f+ _/ T. K' j7 R
  593.         {
      |# l/ r- ?2 q) y
  594.                 DEBUG("IIC错误:无效的参数\r\n");) s  D2 c1 ]& }# l7 V
  595.                 return IIC_PARAMETER_ERROR;
    ' v, `. v5 [1 v: H9 a( O
  596.         }7 E7 Z8 ?8 p) Z. y
  597.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄
    7 R0 ]  B4 s& T- {7 K
  598.         
    2 f/ n+ B/ n) A
  599.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙
      `, t2 M1 o- I$ a  f
  600.         {8 h: E1 w( o* n5 E1 {/ b
  601.                 IIC_SoftReset(pHandle);$ d* y1 `- d7 T, i2 Q# b. E/ ^  U
  602.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");
    . U$ N! |3 [* V1 N* u
  603.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙! [, n) C: w) z3 n3 `; m* F
  604.                 {# i* h- t3 h" M0 g& r
  605.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");9 e2 c0 A9 h8 V" z
  606.                         Error = IIC_BUSY;2 r4 a8 M( A+ G. ?8 D
  607.                         goto end_loop;" N, {5 H4 [2 k1 H2 i! E$ h' r
  608.                 }
    : ^/ a( F" i/ `: l* @. C
  609.         }( _7 E8 }/ w/ j2 i
  610.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态, K( a7 q9 ?6 z
  611.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器
    & z+ R& F0 D0 S' E: U/ P
  612.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    4 }9 t, q4 h4 f8 c
  613.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,TRUE, pHandle->TimeOutUs);* o: F0 H5 X1 ^4 Y9 M1 m. r
  614.         if(Error != IIC_OK)' ^( p- X. E# t: \7 b6 ^
  615.         {
    % D* j7 L% t8 L9 V! T
  616.                 goto end_loop;( J( ]# W8 V8 m! M; x4 A; W
  617.         }% R: s2 @5 \0 v2 i+ C- K' C8 z7 A
  618.         //发送后续数据* o: Y! H% E$ s1 ]1 |# E
  619.         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取-后续还有数据,需要重载& H: q. x6 t* ~- A3 x3 @+ L6 T/ R
  620.         {
    ( U5 ?6 K- W4 v
  621.                 ReadCount = 255;        //本次需要读取的数据长度255
    ! _0 G$ h3 d6 d7 K7 u: L8 r
  622.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输                % @  @# T2 ?! s# }0 C& e2 K
  623.         }, z* v; n2 `+ v
  624.         else
    5 Q: g% t: Z/ a7 s8 ~
  625.         {+ J& r: D6 d8 H$ i5 w
  626.                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯后自动结束$ I3 `4 D) t5 N: m
  627.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输
    + D( J8 F  @8 l1 [
  628.         }
    2 H" D  l8 f. e" Z$ t
  629.         % D9 p, M; h0 v  X: y4 j5 |6 ]
  630.         //循环等待接收数据完成! t' m# j; N4 T8 G
  631.         do% Q5 o* O4 d/ W: D; d
  632.         {. C% c, C# U6 X/ A; M
  633.                 //uart_printf("读ISR=0x%X\r\n", pHandle->I2Cx->ISR);% r2 @9 U& Z& o: p" {6 f# w
  634.                 Error = IIC_WaitRxOneByte(pHandle, pDataBuff,  pHandle->TimeOutUs);                                        //接收1字节数据
    0 L+ g: H9 N8 C( F
  635.                 if(Error != IIC_OK)6 B2 D; Q! K* t4 a0 S1 [8 P& G- f3 w
  636.                 {
    & W- l5 }( L) D6 p. W+ G
  637.                         goto end_loop;
    " u$ i/ H0 q& V; l
  638.                 }
    + }9 R2 \- }+ h& v5 x
  639.         ( M: Z6 Z# o! Y3 y* K! y( K- i
  640.                 pDataBuff ++;/ _8 B. b% ]) B4 l) A4 x( }  O) c
  641.                 ReadCount --;
    ( k. ^! x. s0 m" r+ v( S8 x( ~, s
  642.                 ReadByteNum --;$ |) T$ w9 F% \4 ~8 t0 ~. |" V4 v( r1 K
  643.                 if((ReadByteNum > 0) && (ReadCount == 0))        //还有数据要读取
    % e6 m) z$ i# u6 u0 ^1 P
  644.                 {
    ) T- R; P3 R9 I- ]: G& M1 Y
  645.                         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取3 i" P2 O, I) _- }. }
  646.                         {9 b; K9 _' l& I1 k
  647.                                 ReadCount = 255;        //本次需要读取的数据长度255-后续还有数据,需要重载5 n: {: J) ?) T8 w8 L5 c: d
  648.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
    ; D. N9 @, T7 `7 y9 u  {
  649.                         }7 M2 v$ Y+ V; j6 C* c# }- z
  650.                         else
    ' n) l( s, Y0 `  K$ b: L
  651.                         {9 D! @8 Q) W% ]1 Q
  652.                                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯,自动结束4 L3 J0 u9 x2 c% f
  653.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        & w  W! z" B1 b
  654.                         }9 g, Q( u6 g3 V4 b- |
  655.                 }1 x, t  D5 H$ v1 A5 K  Z" ~  Q
  656.         }while(ReadByteNum);2 }! d) K3 x( p, Q9 e1 d
  657.         //读取完成了,等待STOP位有效7 d+ d7 p5 {2 O" M
  658.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);; a& k, O! d/ O/ H
  659.         if(Error != IIC_OK)
    6 `3 ~5 E- ^9 q5 M1 v
  660.         {2 N8 L7 J/ `- d. {5 K
  661.                 Error = IIC_STOP_ERROR;
    4 A6 c+ ~$ J5 `, Q, O0 d4 J
  662.                 goto end_loop;( W) n% n1 J# Q% i
  663.         }        % |: v  W* ~7 N
  664.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    - S2 L; w1 S4 w
  665.         
    1 \) e- \) E, z& _5 `6 l! y' a
  666. end_loop:        & u+ `; w8 m$ @1 T) Z
  667.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        
    + b, E( ~7 r1 g
  668.         if(Error != IIC_OK); u: D( _- _% K5 k7 ]- Q
  669.         {
      o9 K! \: ^9 b) t
  670.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误
    ; g3 y6 P7 l6 o7 o8 m
  671.                 DEBUG("[IIC R错误]:%d\r\n", Error);, p7 K* ~$ W& l/ g; L2 V
  672.         }
    ' l7 g) a$ o; T! I4 i6 }, R
  673.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的3 Z) P% @; g6 r, i8 w& E- D6 F: S
  674.         {
    & N$ }, f* g' l
  675.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线; ~* ?0 H2 ?5 t6 {- A
  676.                 DEBUG("IIC R结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);                % p/ B2 }( r  L) K  O* K
  677.         }
    5 W8 I5 s! y  H0 M& g
  678.         & w( E, f. P/ U% A1 L5 Y$ \  }
  679.         return Error;
    $ O2 K! _* A$ N0 O/ }+ u0 V
  680. }, e8 y& T) s2 ?. G1 N

  681. / ]# g! C, S! t. Z* U; ^

  682. ( B  q0 B* K4 h% ]3 v5 Q
  683. /*************************************************************************************************************************+ |8 D: q$ ~  c
  684. * 函数        :                        IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    / S- x- e7 {& C" i0 R. K7 _
  685.                                                 u8 *pDataBuff, u16 WriteByteNum)
    6 ~: W. {7 L, w  ^
  686. * 功能        :                        IIC写寄存器(可以写1个或者多个寄存器)
    9 B/ }- \4 P8 s
  687. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要写入的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;3 f9 O  q% s/ T* Q" O3 W3 o: ~$ {
  688.                                                 pDataBuff:写入的字节数据缓冲区;WriteByteNum:要写入的寄存器数量;
    ' t# P: E2 `. J0 F* L* r# c4 p
  689. * 返回        :                        IIC_ERROR
    3 j; z7 w/ b4 `# I$ `
  690. * 依赖        :                        底层宏定义
    8 N2 o2 h. r0 C% b+ X
  691. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    2 Q2 R" x5 ^. S# l5 F$ \5 y
  692. * 时间        :                        2020-02-16; T  k/ U! I  z3 ^
  693. * 最后修改时间 :         2020-02-16
    7 n7 y: M& I& g/ ~% x
  694. * 说明        :                         写入的数据都是小端模式,如果是16bit的寄存器,请写入偶数个数据,并且需要提前进行高低字节对调最后组成高字节在前的数据buff
    2 Y. m; _9 t9 g- {
  695.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
    8 T$ i" Q, H- e, J
  696.                                                 增加信号量, O3 n5 M. P- o" {  n4 B8 g) s
  697.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在! D. M+ w+ r5 n9 @2 y2 B
  698.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。
    . X5 X: o+ E# V1 l* e0 Z- m
  699. *************************************************************************************************************************/
    % Q# C  k# n  k0 z* C6 x; }2 ~1 E  K
  700. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum)0 z  k  I1 \5 A" V, E
  701. {
    * Y+ Z0 @/ q: R* t; b% d8 \5 p
  702.         IIC_ERROR Error = IIC_OK;
    + o7 l, w# z6 c/ f
  703.         u16 ReadCount;
    ) [# i0 F; E4 G6 U; O& s
  704.         IIC_HANDLE *pHandle;, c# x; b3 s1 w  E8 G. v" D
  705.         ; |! n+ ?4 u2 }* G$ H6 _; e3 K
  706.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || WriteByteNum == 0)
    ) w! `& v+ P5 w1 _3 n. Y# y
  707.         {3 x; e+ l! K, l
  708.                 DEBUG("IIC错误:无效的参数\r\n");
    8 x$ G, B1 W( I( w' I- [
  709.                 return IIC_PARAMETER_ERROR;8 {' D4 M  P+ Y1 u7 i5 o9 ?
  710.         }3 W8 p. P% [6 `; T) y
  711.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄
    0 f7 J! Z" t; x
  712.         ( C6 P- E  ?/ r
  713.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙4 A1 R, j# `+ Q+ T/ ?" q) L% _
  714.         {
    ; A1 l# r, |( g3 {
  715.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");
    & \& U" Z. _1 g9 N
  716.                 IIC_SoftReset(pHandle);
    % f* P8 g0 {! B5 |- @
  717.                 ; r6 p& u4 U& u) z, _
  718.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)        //忙+ W7 h0 L5 J' V( v5 L" Z+ f
  719.                 {
    . I) S( _6 K4 I! ~; ]$ l
  720.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");2 ?& |2 G0 f) D  g7 r
  721.                         Error = IIC_BUSY;
    " |1 m" m2 |- e8 i' b
  722.                         goto end_loop;
    4 r$ \6 B/ N  R6 s
  723.                 }
    4 u1 {) J$ ?3 o; i7 C
  724.         }/ T0 L- a; L) c6 M" P  k
  725.         
    ) y6 D# K/ W9 m4 c& ]
  726.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态- m+ D7 J8 v% F0 ?/ m, a* o
  727.         IIC_ClearCR2(pHandle);                                                //复位CR2寄存器1 X+ N2 L7 |# s, i9 |: }+ P  a
  728.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START' {# R- G! a9 a1 h$ o
  729.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,FALSE,  pHandle->TimeOutUs);
    2 c7 Y* Q1 e  x; B
  730.         if(Error != IIC_OK)6 Y9 J0 D, l5 _/ d
  731.         {
    ) w) x8 `: n' C' @- U! X
  732.                 goto end_loop;
    , |1 p6 N/ t6 c. X# ^
  733.         }7 d0 H2 \: e: D3 A% d1 h
  734.         //发送后续数据4 r, \1 D1 m7 `* k4 v. X8 _
  735.         if(WriteByteNum > 255)                        //如果超过255字节,则需要分多次写入-后续还有数据,需要重载
    2 d, U- [1 J2 f' T; T
  736.         {' f2 U* g+ t0 q9 P1 S4 R
  737.                 ReadCount = 255;                        //本次需要写入的数据长度2553 c8 |% _2 S; Y+ x+ V7 w
  738.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入               
    3 U1 f6 }  w, Y5 A# q3 _2 w
  739.         }
    : ~6 Y* _* o6 s' ^% N" r
  740.         else
    ( t7 V3 f0 W0 l
  741.         {  @1 M+ F8 R+ M+ B4 J( ]3 u
  742.                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯后自动结束  \  P) y& ?' I" x" j" h+ ]
  743.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入
    ) G, ?) A! G' ?) d# Q
  744.         }7 C% b4 C/ p( I0 Y  l2 g8 }
  745. ; |; j8 L  {( s+ D6 y
  746.         //循环发送数据1 u# z$ \+ L! e7 t3 u* N
  747.         do
    ; G0 [- h. [3 g0 |. L, a
  748.         {
    * Y$ Y% E, u0 r5 V
  749.                 Error = IIC_SendByte(pHandle, *pDataBuff, pHandle->TimeOutUs);        //发送一字节
    9 Q9 S, I; C' P
  750.                 if(Error != IIC_OK) ' [' T2 t4 L& J1 ^
  751.                 {
    5 ~- w4 ?8 H( a9 T8 \9 c; y$ _
  752.                         goto end_loop;( d& E( V2 F* f9 w* Z- ~6 {4 A
  753.                 }
    0 l8 J+ D- O9 X3 }: ]; Z3 l
  754. . o3 D" ^6 X. ~  ~
  755.                 ReadCount --;0 E4 l; _8 G$ ?' |, W% e& f
  756.                 WriteByteNum --;
    2 L8 f3 V7 ~5 ?# [: k6 h
  757.                 pDataBuff ++;  f! b$ M1 j' \6 c. H5 s
  758.                
    & G, ?) D! v+ T
  759.                 if((WriteByteNum > 0) && (ReadCount == 0))        //还有数据要读取* k; m$ N7 s: Q1 O; W& g
  760.                 {& N6 @6 Q5 }' J. z  G( A
  761.                         if(WriteByteNum > 255)        //如果超过255字节,则需要分多次读取
    4 R" ^$ f2 s2 x# U9 |  G
  762.                         {
    ; y7 u. J. Y+ B7 ^9 F* @
  763.                                 ReadCount = 255;        //本次需要写入的数据长度255-后续还有数据,需要重载
    6 Y& U4 S5 _' t) |8 b5 U! v9 g
  764.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入
    & ^+ m. Z# t8 ]1 j7 ~7 n3 Q* @
  765.                         }
    % o# j+ G. D# Y3 t
  766.                         else! Y! i4 A0 L* @$ h! J- C" t; l
  767.                         {
    2 F; M2 z8 ~! {. S
  768.                                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯,自动结束" Q5 ]- m' @- Y; u2 V
  769.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入               
    $ Z3 q3 t$ v& o8 i7 V: N0 e$ `: x
  770.                         }- h  M  ~8 ^* g* b- r. u
  771.                 }9 `3 I) t6 r$ E
  772.         }while(WriteByteNum);        
    # m3 o$ O# R. A  A" {7 D4 \
  773. 9 a+ `4 r" M5 F5 i
  774.         //写入完成了,等待STOP位有效
    # j9 i2 ?' e  y
  775.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);
    ) }% a8 f5 c- d+ Y& b# L) v8 p# e
  776.         if(Error != IIC_OK)
    : c) b$ b  Q' r1 B  g" K! S
  777.         {
    / _( A7 y5 J: I* V% ~
  778.                 Error = IIC_STOP_ERROR;
    ' ?& O6 J! G. j/ W) o1 C- H
  779.                 goto end_loop;' `5 {) P7 ~2 S5 B1 G( m7 l- h
  780.         }$ l2 s# ~/ g+ m! ^
  781.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态( G  m8 _9 K0 T% A# w
  782.         
    % A* h) V5 Y& I9 L: i7 }6 ^
  783. end_loop:        + `, Y; H8 m' E, w
  784.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        
    8 @7 _/ S- L; G( j) E4 L' s% X
  785.         if(Error != IIC_OK)
    7 c1 U) ^0 ]0 d9 `8 U8 i5 M
  786.         {
    : I4 _3 a9 q6 _! V3 Y: {: C, a' E2 ?
  787.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误
    / _) y7 h) i6 Q( K. b
  788.                 DEBUG("[IIC W错误]:%d\r\n", Error);  G" ]- Z) L+ T5 v5 n
  789.         }
    7 N& h4 e4 n! t$ |* \- d' N
  790.         5 K" s9 j; I  T" M5 ^1 P& d
  791.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的& o! \; E4 q3 d/ h- A6 N
  792.         {8 Z0 h# q& R* \, L' ?" v: n
  793.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    , ~4 w6 P4 s; @% o" i
  794.                 DEBUG("IIC W结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);               
    5 r' m) `! x. ]: [, F0 q; [2 A7 B
  795.         }; M* f4 `, d4 t7 G! M* l! D
  796.         return Error;: c* [; I  c4 {4 x4 @
  797. }5 D0 C: i+ I/ Q: i
  798. ) m$ J% E+ n0 a; V; M4 `0 A/ Q: j

  799. , d: [0 @% b- E/ I! a6 R
  800. /*************************************************************************************************************************
    7 |& R* S2 ^" l/ l* J0 X
  801. * 函数                        :        void IIC_SoftReset(IIC_HANDLE *pHandle)- @9 Q) }5 y7 f) z& B% ^
  802. * 功能                        :        硬件IIC软复位(会使能IIC)/ k8 h. E4 B+ L) |- Z+ O
  803. * 参数                        :        ch:IIC通道
    ) l4 ?4 x; ?) {
  804. * 返回                        :        IIC_ERROR$ L3 k6 b; P6 K1 ~* a
  805. * 依赖                        :        底层宏定义& M; o" j* X) v8 `, x# Q/ Q# \
  806. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>0 D' T% I) F) q% D) a
  807. * 时间                        :        2020-02-15
    3 w4 N- x2 b- K0 C  G
  808. * 最后修改时间         :         2020-02-15- d0 o& P2 b+ n# n3 p
  809. * 说明                        :         IIC软复位;必须使 PE 保持低电平持续至少 3 个 APB 时钟周期,才能成功执行软件复位。2 f/ W6 I2 i7 c9 }% a
  810. *************************************************************************************************************************/
    ( ]! s0 A6 `' F2 F9 Y
  811. static void IIC_SoftReset(IIC_HANDLE *pHandle)
      V5 t6 B7 M7 P$ r# Y
  812. {9 S1 ~% d) K7 q3 G& ~4 N
  813.         pHandle->I2Cx->CR1 &= ~BIT0;                //关闭IIC后执行软复位
    ! d7 C6 r0 x6 @" e. c# Q( G
  814.         Delay_US(1);        3 ?( m9 j, U/ ]8 k1 k' Q
  815.         if(pHandle->I2Cx->CR1 & BIT0): T& b5 @6 n$ _* |/ @9 v
  816.         {
    . ?; {# E3 W, N
  817.                 DEBUG("IIC软复位失败\r\n");
    % u  A0 A; B% s! h# t- A/ j: W0 j, H6 z
  818.         }
    , i7 `; }/ O  B( \) e  W
  819.         pHandle->I2Cx->CR1 |= BIT0;                        //重新启动" y' f# U0 u& b' {. L  _9 g1 C
  820.         Delay_US(1);        7 F/ P# y* m  e" g: v2 F
  821. }& L% n: j2 r, b5 _  K

  822. 6 F! y8 Q* o6 x5 F

  823. 1 h& p" s! q% X: d7 b9 u  j

  824. 5 e8 @1 J) m7 k: t& S2 o0 t
  825. /*************************************************************************************************************************& j: \0 B; K! I5 }5 V) z1 |
  826. * 函数                        :        static u32 IIC_CalculationTiming(u16 Speed_KHz)
    2 c/ P3 z9 N5 l* r6 _
  827. * 功能                        :        硬件IIC时序计算
    4 M7 m  Q% r9 X  o, Z) r$ c
  828. * 参数                        :        ch:IIC通道;Speed_KHz:速度10-1000
    " q- W4 u. u3 o2 r
  829. * 返回                        :        IIC_ERROR
    & ^3 g) Y( @/ F! \, c* X
  830. * 依赖                        :        底层宏定义7 p7 H/ V1 {; i
  831. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>- u6 I3 V& h& W8 v4 w5 @3 i4 ]  i
  832. * 时间                        :        2020-02-15$ Q% X2 V( X2 s( q* m- [' V
  833. * 最后修改时间         :         2020-02-15/ m6 q9 i$ X9 j8 k* u
  834. * 说明                        :         IIC使用的是APB1时钟,将IIC总线时钟控制在100KHz        
    5 L% ~* u. `: e3 Q0 C  e
  835.                                         APB1时钟:最大不能超过45MHz        
    1 q/ f6 ?" z$ k5 t( ^+ @
  836.                                         如果速度是100,则按照SMBUS时序
    + M1 S! q" ]1 \$ S+ q0 U* w) A. V
  837. *************************************************************************************************************************/
    5 r& E. f# h" e# q* {
  838. static u32 IIC_CalculationTiming(u16 Speed_KHz)
    / |2 T( o% N- K  ?6 W, h% q
  839. {
    $ c3 G0 z9 i% v7 B4 {
  840.         u32 tTime = 0;+ `# x: p) o' R4 X- F
  841.         u32 temp;
    . o; C' y! j1 x6 u
  842.         u32 time_temp = SYS_GetAPB1ClockSpeed() / 1000000;                //先获取APB1时钟速度
    ( b5 a* m6 t/ Q; U
  843.         u32 Th = 1000/Speed_KHz/2;                                                                //计算高电平时间(低电平时间一样),单位ns
      s! x: e1 p( P5 k# K
  844.         $ Z! U. M8 _+ E" z! A1 G
  845.         if(time_temp < 20) time_temp = 20;1 C% c8 ?+ F7 ?7 }, s6 i! d
  846.         time_temp = 1*1000 / time_temp;                                                        //单位ns
    7 z' q: H5 P" v' c1 `" D
  847.         uart_printf("IIC时钟计算->APB1周期:%dns\t", time_temp);9 }1 g9 U; q+ J2 b9 b
  848.         if(Speed_KHz == 100)        //如果是100,则按照SMBUS时序+ K, |* c0 H2 H& V* r/ L7 F, f
  849.         {
    - _& u1 H( z* B+ U; p
  850.                 //主时钟分频系数固定为3! ?7 u* I6 B* d
  851.                 time_temp *= 3;                        //主时钟周期+ G1 G$ S6 y: ?# o  u" z# W
  852.                 uart_printf("IIC时钟周期:%dns\t", time_temp);/ @/ q  {7 \4 _
  853.                 tTime |= (3-1) << 28;        //PRESC,时钟预分配
    7 E0 v/ ]0 X: J& f
  854.                 //计算数据建立时间,要求最小250ns" O& V, D6 V" k2 g' N
  855.                 temp = 250 / time_temp;
    ' z8 @, O" }; O) R  B
  856.                 if(temp > 15) temp = 15;
    $ D- d/ p6 ]: l: c! Q4 W$ h/ @
  857.                 if(temp < 1) temp = 1;3 |1 R$ `; n4 w
  858.                 tTime |= temp << 20;) e/ S$ }$ b/ ?8 @
  859.                 //计算数据保持时间,要求至少300ns7 o% Y7 ^" g* I2 j; n# Q
  860.                 temp = 300 / time_temp;
    4 E8 T; r4 n/ i2 ?% a
  861.                 if(temp > 15) temp = 15;- r  ^3 W3 k& V4 E& s3 E7 b! w
  862.                 if(temp < 1) temp = 1;/ ]) T' u( }9 T
  863.                 tTime |= temp << 16;
    , E! |$ d  W7 l- ^& @
  864.                 //计算高电平周期5us
    0 L9 ?1 w7 u3 l0 g6 t" W# {
  865.                 temp = 5*1000 / time_temp;8 _! x) t5 M- k! u: H1 j
  866.                 if(temp > 255) temp = 255;
    ' Z- K/ `( k, s& I( {
  867.                 if(temp < 1) temp = 1;
    $ \/ k1 m' O1 f0 f( r
  868.                 tTime |= temp << 8;' W4 s# P* h. o' H/ I$ M4 r) u
  869.                 //计算低电平周期5us. O* x( W( F1 B& I0 P
  870.                 temp = 5*1000 / time_temp;4 v0 u4 E- K; F/ r2 }9 |& h
  871.                 if(temp > 255) temp = 255;) ?& E0 Z( i/ K  m0 \( t
  872.                 if(temp < 1) temp = 1;
    ' Q5 I, {7 z# G5 i6 ~' s* I
  873.                 tTime |= temp << 0;
    2 |- J+ f0 ~0 E; T- h6 P6 M$ u
  874.         }, b+ `3 o6 N1 s% |" I
  875.         else if(Speed_KHz < 100)
    & h7 V* T. L+ [7 u/ a( ~& k0 x
  876.         {  F! t* K. M  W' f: I
  877.                 //主时钟分频系数固定为6
    4 J# u9 j) O: }0 r
  878.                 time_temp *= 6;                        //主时钟周期
    ) c6 i+ B) F) L- @5 p: f0 K
  879.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    % {- `! E$ Q$ q2 g) p
  880.                 tTime |= (6-1) << 28;        //PRESC,时钟预分配/ g4 \: Y. X1 \9 T) Z  [( N4 k
  881.                 //计算数据建立时间,要求最小250ns
    ! F( {3 y6 m9 Y/ D; w! w, F0 e
  882.                 temp = 250 / time_temp;
    1 P6 z/ c7 E/ l: S' t
  883.                 if(temp > 15) temp = 15;
    ( f. k" l0 u* ~$ ~
  884.                 tTime |= temp << 20;, o9 p% E9 @$ B! T
  885.                 //计算数据保持时间,要求至少300ns
    7 E7 u: ?+ L6 _) ?) k* C& ~
  886.                 temp = 300 / time_temp;
      y+ {$ t6 b# x& f/ W# N/ e1 \
  887.                 if(temp > 15) temp = 15;
    ( Y9 b0 `) X8 f+ ?, Q* e$ q) I
  888.                 tTime |= temp << 16;. [. D6 h% c1 B& w$ Q" @  Y) s9 _
  889.                 //计算高电平周期Th us' ~- T  [- j$ a1 I
  890.                 temp = Th*1000 / time_temp;, V7 ~/ |/ F" C  @1 ?; w
  891.                 if(temp > 255) temp = 255;
    ; B1 j' r& T1 ]$ \7 }8 w
  892.                 if(temp < 1) temp = 1;2 J7 X7 r3 O9 k* _- Q2 \6 Y
  893.                 tTime |= temp << 8;# g9 H) E# W, c& U: F7 [
  894.                 //计算低电平周期 Th us
    ! Z4 K. Z& [8 P* m2 ?# H
  895.                 temp = Th*1000 / time_temp;' G2 g- }& U8 K) g5 A/ N7 `
  896.                 if(temp > 255) temp = 255;: @/ p3 A& S) Y9 d' @# h7 C& U
  897.                 if(temp < 1) temp = 1;
    * N8 u! b  f! ^# F& L) x1 M
  898.                 tTime |= temp << 0;! j" n8 Y& W; Q. p( _0 ^: `  b
  899.         }
    / d4 T6 T2 k4 Y0 x
  900.         else //>100& d0 U: z* e1 i6 j: F
  901.         {1 k; o( `+ n. H
  902.                 //主时钟分频系数固定为2
    , Y: O) [: Q2 @0 ~- i2 N  g
  903.                 time_temp *= 2;                        //主时钟周期! `! i# }3 a( X( u& l6 I
  904.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    , o+ F7 K/ E, e+ J" c% x8 e' h# ~
  905.                 tTime |= (2-1) << 28;        //PRESC,时钟预分配: |4 c- b+ n' ~" u& O* k, U8 @
  906.                 //计算数据建立时间,随便给100ns
    ! S, c6 W9 e# p; n
  907.                 temp = 100 / time_temp;
    6 C" P# p! I. ?0 ~& b; |
  908.                 if(temp > 15) temp = 15;! m9 `$ H3 c; v0 ^
  909.                 tTime |= temp << 20;: n* P  a% h. a: {1 {# Z4 j/ [, U
  910.                 //计算数据保持时间,给100ns
    * ~5 D* L) j( N/ A
  911.                 temp = 100 / time_temp;6 [4 d2 Y. R% I- Z# R
  912.                 if(temp > 15) temp = 15;: t+ c- e$ L3 [2 u2 C
  913.                 tTime |= temp << 16;- _4 }# B, g6 Y+ n! x: R( f, `- m
  914.                 //计算高电平周期Th us
    3 _6 B( f7 v  ~- @
  915.                 temp = Th*1000 / time_temp;. Q7 R. a$ n8 d& t9 h: Z
  916.                 if(temp > 255) temp = 255;1 E+ G2 _' b+ L$ F3 b0 b$ A' \
  917.                 if(temp < 1) temp = 1;
    + h% f; F4 R/ P! X, u2 Q
  918.                 tTime |= temp << 8;
    / Z( b; Y6 b2 U
  919.                 //计算低电平周期 Th us" _# U  e5 z+ M' ~% S' b8 r* u. \/ O
  920.                 temp = Th*1000 / time_temp;# }' U8 W9 C' \- l% H
  921.                 if(temp > 255) temp = 255;
    5 A  r# y" ^4 C: o4 p% B) a! ~
  922.                 if(temp < 1) temp = 1;
    * P+ p- s* d, v+ Z: [5 P- G
  923.                 tTime |= temp << 0;2 F1 I& G  h9 E5 b2 C8 S4 ~# d
  924.         }
    , R" g8 V1 g7 g5 V
  925.         0 d" ]/ N/ L6 B4 P1 p) S
  926.         uart_printf("时序寄存器结果为:0x%X\r\n", tTime);  l" \6 \; ~4 }7 A
  927.         
    ' D/ E! v6 l* {2 a
  928.         return tTime;
    ! x$ S# o3 t! r# G' P
  929. }
复制代码

7 m; ?. w7 Z3 t( ?& I; l& w- c* [9 r; g) Z+ l
  1. /*************************************************************************************************************" T' n% r! ~+ Z. z+ s, p) C/ h. s
  2. * 文件名                :        stm32f7_iic.h2 O( `; m/ ]: k6 e( s
  3. * 功能                        :        STM32F7 IIC接口驱动- b' U+ ]' v, k; x
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>, m3 @$ X, G1 M% @: S
  5. * 创建时间                :        2020-02-094 c) S. b4 _5 z- }$ k  \
  6. * 最后修改时间        :        2020-02-094 i5 D* g2 a9 m4 y
  7. * 详细:                        
    8 l0 ^$ Y+ c# q; @1 g
  8. *************************************************************************************************************/                # i; S- e; ]8 m) n
  9. #ifndef __STM32F7_IIC_H_; w3 A4 c" V; W$ i
  10. #define __STM32F7_IIC_H_7 O) C; I. O- K) D
  11. #include "system.h"
    3 g! R3 X& {0 Q* T& G+ o$ k* z

  12. 7 @) g- k" d% w
  13. //16位整形数高低对调4 G& G  V# q; h% [
  14. #ifndef SWAP165 d  |4 {6 {/ R3 z) Q" }4 e
  15. #define SWAP16(x)   (((x & 0xff00) >> 8) | ((x & 0xff) << 8))1 H  I8 D2 c/ v( C7 g% {
  16. #endif  //SWAP16
    " G+ C# ~2 F7 P, Q; X
  17. ( W8 @9 _4 i/ B6 j
  18. //硬件IO口选择6 H. ?" k: }! r: J4 P1 ~4 T
  19. //I2C1 IO定义与选择
    1 q7 j$ C: Z5 g, h. g6 `4 Z; N
  20. #define IIC_CH1_PB6_7                                0                                        //PB6,PB7
    * O( j5 M7 r6 t9 E: v& O- T1 Q3 {
  21. #define IIC_CH1_PB8_9                                1                                        //PB8,PB9
    0 I2 R/ h5 s  P0 V- m. q0 n- C
  22. #define IIC_CH1_IO_SELECT                        IIC_CH1_PB6_7                //选择I2C1 的IO        
    - D( ?, K$ t4 Z8 b$ e) ~
  23. : L4 [0 p! o  F4 [7 M: U7 Y
  24. //I2C2 IO定义与选择% D$ p8 @+ E, I
  25. #define IIC_CH2_PB10_11                                0                                        //PB10,PB11
    : P- O: m, r; U3 e
  26. #define IIC_CH2_PF0_1                                1                                        //PF0,PF1
    & z( Y( }* g/ y& U9 k5 I. A* C0 N
  27. #define IIC_CH2_PH4_5                                2                                        //PH4,PH5
    $ I" z; f; k! `& X! b
  28. #define IIC_CH2_IO_SELECT                        IIC_CH2_PB10_11                //选择I2C2 的IO
    % R  ~, f; F. j  x$ Z/ }6 q

  29. - Z- ^# L" c1 {/ P6 W
  30. //I2C3 IO定义与选择
    9 M/ p, A& l- B
  31. #define IIC_CH3_PH7_8                                0                                        //PH7,PH8
    5 ~; h7 W. s. C) A. e
  32. #define IIC_CH3_PA8_PC9                                1                                        //PA8,PC9* \: p6 h# {' G* g& r
  33. #define IIC_CH3_IO_SELECT                        IIC_CH3_PH7_8                //选择I2C3 的IO
    " I( a+ q5 s- j! e2 [1 \" {& h

  34. ( k7 ]0 j! D3 G
  35. //I2C4 IO定义与选择4 X  ?, Q+ |, g: n- \) n0 o: L$ _  y- l
  36. #define IIC_CH4_PD12_13                                0                                        //PD12,PD13
    3 R+ C$ @! r9 s2 i' n4 V+ j
  37. #define IIC_CH4_PF14_15                                1                                        //PF14,PF15
    ( U* l; b7 m. g9 [
  38. #define IIC_CH4_PH11_12                                2                                        //PH11,PH12
    7 n. e% L$ ?# @3 |7 n) K
  39. #define IIC_CH4_IO_SELECT                        IIC_CH4_PD12_13                //选择I2C4 的IO
    6 R; h% j) k2 k3 p
  40. 0 g- T% t' B# d+ x
  41. //IIC硬件接口选择
    * w3 W. y9 d: o/ K5 R# m
  42. typedef enum
    ! U1 q% C; c) h  h) O0 H& N5 P5 S
  43. {
    & O; `: c" z  B( [" E% K" i
  44.         IIC_CH1        =                0,        //IIC1  f4 o. P8 |' W) p2 \- T" }' p, x
  45.         IIC_CH2        =                1,        //IIC2
    ; R+ X4 b6 m6 M  N9 T
  46.         IIC_CH3        =                2,        //IIC3( G7 t6 r/ W5 I& K- ?$ S5 g  x
  47.         IIC_CH4        =                3,        //IIC4
      S7 j0 G+ ^: O4 G2 J
  48. }IIC_CH_Type;, a) r2 z+ y2 {8 o: Y1 j6 \  L1 @
  49. #define IIC_CH_COUNT        4        //4个IIC6 |+ A2 t, Z  E: h0 m8 v

  50. # u; X7 Z) X0 ]& k! y- X
  51. & y7 U, p2 @5 v& H# F. @, U
  52. //中断状态3 T" C  n2 Z, m) t. K* l/ @: S
  53. #define IIC_FLAG_TXE                    BIT0        //发送数据寄存器为空(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。
    . \7 K1 h& ?) J& {3 \+ b
  54. #define IIC_FLAG_TXIS                   BIT1        //发送中断状态(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1,待发送的数据必须写入 I2C_TXDR 寄存器。
    ( f9 u& S( T# U$ \8 B
  55. #define IIC_FLAG_RXNE                   BIT2        //接收数据寄存器不为空(接收器); 当接收到的数据已复制到 I2C_RXDR 寄存器且准备就绪可供读取时,该位由硬件置 1。读取I2C_RXDR 时,将清零该位。
    - u# [/ E6 \" U" f+ C* H
  56. #define IIC_FLAG_ADDR                   BIT3        //地址匹配(从模式); 接收到的地址与使能的从设备地址之一匹配时,该位由硬件置 1。该位由软件清零,方法是将ADDRCF 位置 1。
    8 c1 y" D9 S9 V
  57. #define IIC_FLAG_NACKF                  BIT4        //接收到否定应答标志; 传输完字节后接收到 NACK 时,该标志由硬件置 1。该标志由软件清零,方法是将 NACKCF位置 1。# u# K( e) p6 s1 m; G
  58. #define IIC_FLAG_STOPF                  BIT5        //停止位检测标志; 当在总线上检测到停止位,且外设也参与本次传输时,该标志由硬件置 17 E( _$ g# N) u
  59. #define IIC_FLAG_TC                     BIT6        //传输完成(主模式); 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 START位或 STOP 位置 1 时,该标志由软件清零。1 {8 P/ V  E& N) R# q) |: h
  60. #define IIC_FLAG_TCR                    BIT7        //传输完成等待重载; 当 RELOAD=1 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 NBYTES 写入一个非零值时,该标志由软件清零。! _# o+ S7 ]8 Y5 c+ G5 u$ n% C
  61. #define IIC_FLAG_BERR                   BIT8        //总线错误; 当检测到错位的起始位或停止位,而外设也参与传输时,该标志由硬件置 1。在从模式下的地址阶段,该标志不会置 1。该标志由软件清零,方法是将 BERRCF 位置 1。- I7 b7 F+ u( K+ }* w
  62. #define IIC_FLAG_ARLO                   BIT9        //仲裁丢失; 发生仲裁丢失时,该标志由硬件置 1。该标志由软件清零,方法是将 ARLOCF 位置 1。
    3 I9 V5 j" ^; k4 x% F5 B4 q8 t
  63. #define IIC_FLAG_OVR                    BIT10        //上溢/下溢(从模式); 在从模式下且 NOSTRETCH=1 时,如果发生上溢/下溢错误,该标志由硬件置 1。该标志由软件清零,方法是将 OVRCF 位置 1。( G) A0 M1 n& u/ L& k$ Y2 ]
  64. #define IIC_FLAG_PECERR                 BIT11        //接收期间的 PEC 错误; 当接收到的 PEC 与 PEC 寄存器的内容不匹配时,该标志由硬件置 1。接收到错误的 PEC 后,将自动发送 NACK。该标志由软件清零,方法是将 PECCF 位置 1。- V6 g1 u9 @/ ^5 F$ U& C
  65. #define IIC_FLAG_TIMEOUT                BIT12        //超时或 tLOW 检测标志; 发生超时或延长时钟超时时,该标志由硬件置 1。该位由软件清零,方法是将 TIMEOUTCF 位置 1。
    + f, J7 s, K" I9 S# \, y
  66. #define IIC_FLAG_ALERT                  BIT13        //SMBus 报警; 当 SMBHEN=1(SMBus 主机配置)、ALERTEN=1 且在 SMBA 引脚上检测到 SMBALERT 事件(下降沿)时,该标志由硬件置 1。该位由软件清零,方法是将 ALERTCF 位置 1。
    / ~/ f" d, ]( {4 F& Y- q
  67. #define IIC_FLAG_BUSY                   BIT15        //总线繁忙; 该标志用于指示总线上正在进行通信。当检测到起始位时,该位由硬件置 1。当检测到停止位或 PE = 0 时,该位由硬件清零。$ s  R% F# m8 B  U) z/ D" }1 Q+ {
  68. #define IIC_FLAG_DIR                    BIT16        //传输方向(从模式); 该标志在发生地址匹配事件时 (ADDR=1) 更新。;0:写;1:读' O! ]' C6 @( r

  69. , P9 S) p7 }9 p
  70. //通讯错误状态
    8 }: y' l! E6 F% M$ \; ?7 R
  71. typedef enum
    ) v9 E5 z! L6 K) f- G4 ?# w' \' T
  72. {
      T, c* f$ ~. V" Q
  73.         IIC_OK                                        =        0,        //没有错误
    * Z2 ~5 t, ]& @3 C. Q
  74.         IIC_PARAMETER_ERROR                =        1,        //参数错误! T) n9 C5 V4 a; _1 U- E
  75.         IIC_TIMEOUT                                =        2,        //超时错误,也可能是底层错误- I+ a# P" P7 E  X' H
  76.         IIC_HAL_ERROR                        =        3,        //底层错误
    ( |! X) t8 N3 ]9 F* H3 ^# O7 f
  77.         IIC_STOP_ERROR                        =        4,        //等待结束错误
    8 j( F. k; Q3 a7 I" J( X5 X: o" H1 g
  78.         IIC_BUSY                                =        5,        //硬件忙
    : y7 u0 R9 }" R- `% }
  79.         IIC_NACK                                =        6,        //收到NACK了
    6 s6 j0 l6 h% R' u0 e
  80. }IIC_ERROR;. E, e4 B1 o3 j, @6 J) z) v
  81. 2 r+ I) c1 r1 K1 R9 x
  82. $ I+ M  D0 L& g
  83. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs);        //硬件IIC初始化- h4 }7 f4 R1 W: R4 n- V/ g6 v
  84. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum);        //IIC读取寄存器(可以读取1个或者多个寄存器)" ?2 _3 q' N( o7 I- b
  85. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum);        //IIC写寄存器(可以写1个或者多个寄存器). y+ p$ g& A: p% U  h2 [

  86. : B2 N8 O1 b8 ~0 @- J
  87. $ G+ N8 m$ A% F, `5 [; I" M
  88. #endif //__STM32F7_IIC_H_
复制代码
9 h" P2 s- m  q6 Z% C8 r* g7 C

; B4 w, m# M2 }; p7 X//初始化
7 f7 `1 x5 B' |, [2 \; p3 G1 E  _2 ~7 M3 x; v. c* r, \( R& ?% t2 l
  1. IIC_Init(IIC_CH3, 200, 0);        //硬件IIC初始化
复制代码

0 _+ {7 A* R$ z8 {- f" N
7 T' k+ N% m! L% e" C4 U//调用1 H  t* y/ {/ m5 ?3 b
  1. 2 ]# N; j) N; r
  2. //触摸屏IIC读取寄存器接口4 F8 a% M+ k% g: ~! |& N1 ~
  3. bool TP_FT5336_IIC_ReadReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)/ F9 ?) Y0 `# c4 x( v9 D8 h
  4. {' e' ^. v& F) D' o& q/ w) N1 M- n
  5.         if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)7 O; ^: `4 a  F3 M4 ]* h" I
  6.         {
    5 g' m: f& _2 |3 ^
  7.                 return TRUE;( w7 S6 y) J* F
  8.         }
    7 r. P4 ]/ g( B$ f5 T* r$ u
  9.         else% I5 Y7 H& W0 G) K  i
  10.         {( `0 ~2 A4 ^9 v. F/ z
  11.                 return FALSE;
      v/ c2 X* {0 l/ S$ p& I+ {
  12.         }
    / U3 J# v, r; ]( C$ F, k5 ~# \6 F
  13. }
    " N% r+ m1 ]7 }2 d' E% m3 m

  14. 4 i4 x2 l; i- f/ l
  15. //触摸屏IIC写寄存器接口
    $ ?0 g* [% d+ F7 W
  16. bool TP_FT5336_IIC_WriteReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)$ o  n3 G0 ^" d* c- U
  17. {
    : ~3 s5 S% i7 Y& I2 A
  18.         if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)
    9 Z5 y: q  X6 _/ Q$ S3 Z/ r1 p: S& h) |
  19.         {7 P. T% S3 l& w2 I6 h
  20.                 return TRUE;7 s- v4 A9 W, @( A! R' i8 b
  21.         }1 }  p; g1 t/ r9 |
  22.         else3 T- `' z. \! s% l7 v/ B; F
  23.         {# ?$ Y9 c$ }. C' Y6 t
  24.                 return FALSE;" l5 ^' W* s2 F
  25.         }
    0 Q, S, p! y: ?; M' K$ {
  26. 0 }. _" Y, b9 b# b8 l: J' z
复制代码

. r" g3 U4 k8 v* P7 q" _9 Y4 V# K1 \/ P
/ z3 F$ a* e( m& Q% f# _
  W5 i5 d* J# i: a# R9 N: ~
收藏 评论0 发布时间:2021-12-11 12:00

举报

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