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

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

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
目前只实现了主设备模式,一般也只用到主设备模式,IIC如果不能使用硬件方式,读取大量数据的时候效率很大,由于只有1个字节的缓冲区,根本不能使用中断模式(实际使用过程中,IIC会造成100us以内间隔的中断,单片机根本扛不住的),所以建议数据少就直接阻塞,1个字节也就几十us,数据多直接用DMA,将线程阻塞,等待DMA传输完成,而不会阻塞CPU(上传的代码没有实现DMA部分,便于理解)。' e0 b" d- {1 H3 b
$ B  J2 c/ H- q9 [4 _( O. t, Z9 W
目前已经做了完善的错误处理,读写操作前都会清除中断,遇到错误会软复位,所有位置均做了超时处理,防止程序卡死,目前只测试了几个字节的读写,大量的,长时间的读写均表现稳定,目前手上开发板没有eeprom,无法做大数据的连续读写,如果你在使用过程中遇到问题,欢迎指正。4 F) E5 D. W7 v0 J0 w
- j4 n" W: P4 C" n  R
下面是IIC读写的时序例子,可以先熟悉一下,这样比较容易上手,哪一个环节出了问题也要调试。% N; a9 T6 S2 `: p, e* m. j9 {

$ O( F6 z5 T' v  b3 u
20200216194202434.png

" m$ ]  e2 Z5 }) c) w- `$ Q; I& ?; A" j$ S
20200216194219185.png

, l, d3 A* c3 X7 y* X5 F0 G* X0 m; W* u: k( o8 H  {" j; K
20200216194234908.png
  c" k, b) ?+ ~7 @$ n) A# L

* O8 y4 ]. H+ W8 N2 {' w
: P7 J& b2 h) C& m+ h7 d下面简要说明一下STM32F7硬件IIC的驱动设计方式(建议先百度学习一下IIC的时序要求):  S& r  N+ v7 X9 x0 d' `1 Y) S. M
8 H# C3 ^, B' s0 K# V3 O
[基本的初始化]9 l( }" ^: G0 G6 B) p& f; ~0 H
) J6 m0 a$ W* i  G
1.初始化IIC时钟,IO(IIC IO必须设置为复用开漏输出,这个很重要)。
! d( J+ D) {) i8 |- L1 v) C2 x; u" [. K, u( z: r) E6 b
2.CR1先赋值为0,复位IIC.) ~! V7 [$ k/ R

8 }* w! u0 M, a1 ~; g# b/ Z4 u4 T3.除了TIMINGR寄存器需要自己计算设置好,其余寄存器全部复位为05 s8 E$ X9 Z/ p, o9 ~0 G+ `
2 D5 m  u+ j: O1 h' e
4.设置CR1使能IIC。4 X$ K" B4 b; _+ T5 I4 D

( c6 T- h. }* S0 F3 [0 ]3 o1 I注意:上面说到,IIC的IO必须初始化为复用开漏输出,我之前初始化为复用推挽输出,测试很久,只要一启动传输,就会立马收到NACK,然后是STOP中断,数据根本没法发送,弄了好久才发现是这个IO初始化的问题。
8 W. R7 B$ h! z4 [# p$ |8 ~& L. d/ Y9 R
* X6 m$ ?5 i; k
0 B+ e  B& \# H- J3 ^
[读取]2 _6 {2 F) j& D: [8 R

+ D- w- G' R) C+ x1 @1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。7 g8 r+ A6 }7 u- W

5 `: F# x) J0 w" z6 S1 N2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)软件STOP,写模式,启动传输。/ f4 s+ S; Z* M% P) B

' H$ T# u) I9 [. x' A- G0 Q3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。9 |  o0 d! N% l+ x5 @

, f  k' s  d* ]- }. R3 V4.等待TC置位,意味着上面的1-2字节的寄存器地址以及写完成了。4 f3 `$ P8 a) E7 Y

* u( Q9 l7 Y( F2 R- ^5.根据要读取的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。' h  x: s7 o3 J* `

) ]7 S) z4 K" @6.设置了从机地址,要读取的数据长度,之后设置方向为读取,然后启动START(从写切换到读要重新发送START,这个跟软件模拟是一模一样的)。7 _, R, g' v( w' ]4 {/ t
' k1 n7 Y0 K5 \# ~0 B( B. V6 A; H1 A
7.循环一个字节一个字节的读取数据,字节读取需要等待RXNE有效,只有读取RXDN寄存器,直到所有数据读取完成。0 s+ s! s1 }" y- d4 X2 {# b5 n
: f" [6 K% C$ B
8.读取完成后等待STOP有效,因为前面在最后一包数据读取的时候使能了自动STOP,这个时候检查STOP是否生成。
6 Z. `0 s5 S+ U& s, w4 M
, B. j3 _6 Z1 N) r8 h* j1 W9.需要注意的是,所有的操作都要给超时,并且是自己可控的,绝对不要有死循环,之所以一直说STM32的IIC死机很大程度上都是由于这个地方没有涉及好,我的程序设计方法是:一旦出现了异常,就复位IIC,如果不复位就会导致下次进去的时候IIC一直忙,因为还处于上一个通讯过程。, }: D: R5 f- {( f" K8 E; L1 l- N

4 z4 P2 j4 o4 [3 C$ `. c: Z# C7 ?( p- I2 }
- h: ]3 Q* l1 K/ ~: }  a; L. k* C$ Z
[写入]
. R, m1 ~  H& s+ m
' z( j  ^* }6 N; ]1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。% `2 c0 n8 M5 H' d7 T. @
" ~/ ~, z4 [5 g+ H% X. M
2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)自动重载,写模式,启动传输。
0 b6 p5 Z6 Q+ D( a4 w, i; J( n8 k5 l' b' Q) K- N" M
3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
" u! d+ f% ~7 A" ]5 f$ H  r* o: }& ^0 B
4.等待TCR置位,意味着上面的1-2字节的寄存器地址以及写完成了,已经发生重载了,后续可以继续写入数据了。- m" @9 A) n% E* ^7 Y  ^4 ^/ k
$ E# j. v. O6 C5 r! E4 ]
5.根据要写入的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。
# O& \. Q. V7 P+ f) I8 F& o) k  d
2 k3 k0 u; i8 R) d# M! v) {  b6.设置了从机地址,要写入的数据长度,之后不用切换方向,不用启动START(都是写,不用重复发送START,这个与读取有区别)。
; z% e. ~5 ?. c" n/ u$ y* _/ M9 s
- O1 I3 l- l) H% S9 v# o% Z7.循环一个字节一个字节的写入,字节写入与步骤3一样,等待TXIS置位,就可以写入数据到TXDR。# C5 L8 G5 |! Z( M; s( B

# g4 c" d( N! [+ [3 ~8.等待STOP有效,因为前面在最后一包数据写入的时候使能了自动STOP,这个时候检查STOP是否生成。* i9 j" _1 m2 t. d4 Y& y

- f8 e( X/ @* ?4 c9.需要注意的是,所有的操作都要给超时,跟读取一样。
3 P( k  g' R. H+ O+ P  c6 o; e4 c
7 e9 W) q4 L4 j1 x8 [/ h4 S: H" x8 _) v  ^; G& I
( L6 b: P8 w4 i2 m- E' u3 d; Z
注意:IIC的读取实际很短,超时也不用给很长,以标准的100KHz通讯时钟速度,一个字节大概在90us左右,超时可以给个5-10B时间,也就是450-900us左右。2 [! Z# b3 Z7 d* @

3 G7 w. Y$ F3 L0 V! ?, P* r
$ J' `, p6 d: N+ F$ o- j; Z% X  l4 |5 ^+ g8 f. y
好了说了这么多,具体的看代码中的注释,直接上代码(我只测试过I2C3,其余的理论上都是一样的,就是IO初始化部分有区别,别的通道没有硬件进行测试)
7 B6 d" q6 s: @0 P# |5 ~% g* a5 B* S
& o) k2 S7 \% b
  1. /*************************************************************************************************************
    ; b+ r$ g' K6 @( G4 u( g
  2. * 文件名                :        stm32f7_iic.c
    6 L: l: N: t6 e- {
  3. * 功能                        :        STM32F7 IIC接口驱动" D, T" ]3 |& O0 t
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    5 s5 e( k0 J' \* v5 U& g. o% u5 u
  5. * 创建时间                :        2020-02-09
    % w$ p$ k  t1 ^: G
  6. * 最后修改时间        :        2020-02-09- t2 d! F0 U! ~9 I
  7. * 详细:                        只支持主机模式,7bit地址,默认APB1为IIC提供时钟3 x( a: }! e2 D- Q- d% H
  8.                                         涉及到读写1字节的超时时间是us,其余的是ms$ R: O3 ~) ^, y2 P
  9.                                         注意:IIC的IO必须初始化为复用开漏输出。# j& M4 h# A0 t! @8 k) |+ K
  10. *************************************************************************************************************/        
    . {. Z) W$ I4 E1 G
  11. #include "stm32f7_iic.h"
    ' @4 w; p, @/ Y. i; t1 a0 e
  12. #include "system.h"
    9 W% N% v, d0 s& z/ T, ^
  13. #include "dma.h"
    ( r  I5 _' J( N: r5 J0 y

  14. " O  g4 N' |; P. s  ^8 i
  15. #define IIC_FLAG_MASK  ((uint32_t)0x0001FFFF)        //中断标志掩码1 H# H8 a& u2 n" {+ H3 Q

  16. 4 j( j* p- z$ ^0 b/ e
  17. //自动结束或自动重载设置(重载与自动结束只能二选一,或者都不选)
    2 c2 J* ?+ g3 E) b  z: \
  18. typedef enum
    9 Y- r/ R0 Z3 f3 @9 Y- i
  19. {& m* h2 \! ?# w5 R2 Y/ M
  20.         IIC_SOFTEND_MODE                =        0,        //手动结束,并不开启重载+ y& F! a, _! X, a; @4 C6 _9 l8 Y# G
  21.         IIC_AUTOEND_MODE                =        1,        //自动结束,用于最后一次通讯完成后自动发送STOP结束通讯
    " K- ?; ~2 x/ S/ o1 N9 b3 s) }
  22.         IIC_RELOAD_MODE                        =        2,        //后续还有数据,本次通讯后自动重载,重新设置后继续通讯
    " Q( E7 N$ m! F+ y# C& O* X+ F  `
  23. }IIC_RELOAD_END_MODE;- R( b0 B: e" g  ]
  24. ) D" `3 Q2 X4 f/ q, U( \! o9 @
  25. //读写与开始模式控制4 Q0 C; Z1 H0 e; b! ~; K
  26. typedef enum
    5 b; U$ s& \" H
  27. {; V1 S4 Z+ b2 q% E/ c; E( {
  28.         IIC_NOSTART_WRITE                =        0,        //没有开始的写-用于后续数据的写入5 G/ a! C9 y( ~  i6 G  a( F0 F
  29.         IIC_NOSTART_READ                =        1,        //没有开始的读-用于后续数据读取
    6 u) }! L, X, `% }# T2 P; w
  30.         IIC_START_WRITE                        =        2,        //生成开始写-用于通讯开始时,写地址或数据
    1 K, p- U% N  S) Z/ {% [! A
  31.         IIC_START_READ                =        3,        //生成开始读-用于读取数据时切换到读取方向,并读取后续数据8 |  L9 Z8 c  T0 Y0 h
  32. }IIC_START_WR_MODE;
    / w# t8 O% l1 M5 V& f

  33. " s# d/ a6 V' g% p
  34. //IIC句柄
    6 c$ X9 Q3 c* l9 Y
  35. typedef struct
    ; c# i/ K0 _# W3 T3 P0 l& r8 X: k
  36. {
    # O3 J8 D1 E+ p) o' c
  37.         IIC_CH_Type ch;                        //当前通道
    . }; u9 n! v7 A9 ~9 m/ J% s
  38.         I2C_TypeDef *I2Cx;                //当前通道外设结构体/ S+ @' Q- Q5 {  s1 t1 p( s
  39.         u32 TimeOutUs;                        //操作超时,单位us
    ( K5 @0 \  n- W" a4 y
  40.         u16 Speed_KHz;                        //通讯速度,单位KHz8 u: C( `7 \6 K! R2 ?
  41.         bool isMasterMode;                //是否为主设备模式-目前只支持主设备模式
    . Z* w0 i( {  T+ Q
  42. }IIC_HANDLE;/ B- Q5 X# O5 Y. v
  43. ' ?  p; \, [6 g9 m$ E" r
  44. //IIC外设结构指针
    ! q6 b9 z, i: g
  45. static const  I2C_TypeDef * const I2C_TYPE_BUFF[IIC_CH_COUNT] = {I2C1,I2C2,I2C3,I2C4};
    + f+ O6 N. l/ Q5 E4 S  N4 c
  46. //IIC通道句柄定义3 ?  \4 |% D7 Z& A7 {
  47. static IIC_HANDLE sg_IIC_Handle[IIC_CH_COUNT];( e% C" s6 G4 B3 M: h$ v
  48. - J" o1 L3 a# G( n- ~, {, t7 \+ M
  49. //发送NAK
    ( U: z9 B9 B4 K+ N( G$ C
  50. //static __inline void IIC_SendNAK(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT15;}
    2 ?( S3 x& b+ _' r# y! t
  51. //发送STOP5 ?0 `2 K* G$ i% e) L
  52. static __inline void IIC_SendStop(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT14;}
    & l5 |% j; R8 o4 V
  53. //发送START
    # D& s8 f3 l! f9 |' x0 C* |
  54. //static __inline void IIC_SendStart(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= I2C_CR2_START;}
    / B4 n7 {7 N* p
  55. //获取中断状态
      q  ]0 n0 }/ p; J& G/ `# {
  56. static __inline u32 IIC_GetISR(IIC_HANDLE *pHandle) {return pHandle->I2Cx->ISR & IIC_FLAG_MASK;}
    " {* M( e# W# H
  57. //清除中断状态  v8 w$ L5 C, C
  58. static __inline void IIC_ClearISR(IIC_HANDLE *pHandle, u32 IsrFlag) {pHandle->I2Cx->ICR = IsrFlag & IIC_FLAG_MASK;}0 y' L0 d6 e# R0 q5 d
  59. //复位CR2寄存器* P+ N$ [* Q: x! M
  60. static __inline void IIC_ClearCR2(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 = 0;}
    ) p0 @) ]8 p7 V: o

  61. 1 h& V: e7 p( ^/ ?( `# A9 a
  62. static void IIC_SoftReset(IIC_HANDLE *pHandle);//硬件IIC软复位(会使能IIC)5 E% `6 x2 @# j9 c8 W
  63. static u32 IIC_CalculationTiming(u16 Speed_KHz);//硬件IIC时序计算( I1 [" a9 V. e% m& A* a- L* \
  64. * d, l" \0 m3 |$ P4 ]

  65. : K( f' k! C" |1 r
  66. /*************************************************************************************************************************
    1 P5 x3 z3 Q) G' a; g: z
  67. * 函数        :                        bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)
    ) s! y/ G, [: [: P
  68. * 功能        :                        硬件IIC初始化
    7 k3 Z/ @( S& g7 Q  _- e6 p
  69. * 参数        :                        ch:IIC通道;Speed_KHz:速度10-1000(如果速度是100,则按照SMBUS时序);TimeOutUs:操作超时us(0:自定计算超时)
    . ]: ~& o" b( m6 @8 H/ \
  70. * 返回        :                        IIC_ERROR
    " P7 M8 z- p7 V2 v" x5 C
  71. * 依赖        :                        底层宏定义
    & ]  q% ]. `: ~/ d
  72. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>9 |+ k$ O! x( X3 }0 U0 x- z5 F
  73. * 时间        :                        2020-02-151 ?, P% k. W; S
  74. * 最后修改时间 :         2020-02-15
    5 y# J. F4 \2 k/ x
  75. * 说明        :                         速度只是个大概的计算值,设置为100KHz时会严格的按照SMBUS时序,其余的不保证SMBUS兼容,正常情况下只要时钟速度符合要求,2 `/ i2 E6 p: |5 U
  76.                                         时钟上升沿到来前数据以及稳定的切换了即可保证通讯稳定性
    8 b8 s% q# _& b3 i
  77. *************************************************************************************************************************/# u2 }+ ~: {% e- {  t1 {0 L  b
  78. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)
    ' T7 V  N5 X" j
  79. {
    - f( N) x  a$ X: {8 q) m4 T
  80.         SYS_DEV_CLOCK DevClock;$ b! b6 K+ a  ^6 b
  81.         IIC_HANDLE *pHandle;0 v6 z2 q* ?$ \# [- e, f3 r: F
  82.         
    " y- _+ w% f4 F% j# W0 a$ f1 l
  83.         switch(ch)% m  y  a9 q9 a5 Q
  84.         {
    & |! ?4 T( K/ X- @  F
  85.                 case IIC_CH1        :        //IIC10 w5 A5 Q2 r8 S1 S2 I# J
  86.                 {
    9 i5 w1 _3 J1 y' N7 ]: \$ m  Z
  87.                         RCC->DCKCFGR2 &= ~(0x3 << 16);        //清除设置,使用APB1作为时钟源' u. r9 ^3 S# ]& i0 f4 b
  88.                         DevClock = DEV_I2C1;( M9 x) k2 S2 K! h% ^
  89.                         //初始化I2C IO* t$ h; l4 V- P2 [' |
  90. #if(IIC_CH1_IO_SELECT==IIC_CH1_PB6_7)        //I2C1        使用PB6/7" ~6 {! B! H1 B4 _4 U. T
  91.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟, B5 g! Z' d! S6 B
  92.                         SYS_GPIOx_OneInit(GPIOB, 6, AF_OD, SPEED_25M);                //PB6: h! Y5 {( \- C! @  w& m
  93.                         SYS_GPIOx_OneInit(GPIOB, 7, AF_OD, SPEED_25M);                //PB72 W9 a) N. g% |. M
  94.                         SYS_GPIOx_SetAF(GPIOB, 6, AF4_I2C1);                                //AF4
    , Z; Y4 |5 n% ?& \& k
  95.                         SYS_GPIOx_SetAF(GPIOB, 7, AF4_I2C1);                                //AF4! F6 w+ K1 E! h4 W9 H
  96. #elif(IIC_CH1_IO_SELECT==IIC_CH1_PB8_9)        //I2C1        使用PB8/9
    . x1 Z7 H# a  N0 {
  97.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    4 W, `3 A" y9 |
  98.                         SYS_GPIOx_OneInit(GPIOB, 8, AF_OD, SPEED_25M);                //PB85 m: \" ]1 M7 z, z7 n( l
  99.                         SYS_GPIOx_OneInit(GPIOB, 9, AF_OD, SPEED_25M);                //PB9, T8 t* E/ I5 h; M6 I+ s5 ]
  100.                         SYS_GPIOx_SetAF(GPIOB, 8, AF4_I2C1);                                //AF4
    9 P- ~2 k, E7 V$ i7 P, U7 U9 R9 U
  101.                         SYS_GPIOx_SetAF(GPIOB, 9, AF4_I2C1);                                //AF4
    - j' b; a) @' E3 s
  102. #else% \% N) o7 S6 b! o
  103.                         #error("无效的I2C1 IO选择");2 A: t5 g7 C' q
  104. #endif //IIC_CH1_IO_SELECT# K9 P0 @7 H. I: M/ A
  105.                 }break;$ X+ ^$ j9 p$ Y, E; ^( `1 s, V, C. k
  106.                 case IIC_CH2        :        //IIC2
    , j2 ]+ d& }3 N
  107.                 {4 h! U2 J3 E, T# y; V  {
  108.                         RCC->DCKCFGR2 &= ~(0x3 << 18);        //清除设置,使用APB1作为时钟源& V! a$ o" \5 O7 D) s9 `
  109.                         DevClock = DEV_I2C2;
    # r+ B  X1 w) z7 n5 t
  110.                         //初始化I2C IO
    $ N. Z. i; `: ~' A8 D
  111. #if(IIC_CH2_IO_SELECT==IIC_CH2_PB10_11)        //使用PB10,PB11
    " K4 }% V0 I) v+ L$ I$ A
  112.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    4 k: C% u# m9 [* Z4 p2 l( ?
  113.                         SYS_GPIOx_OneInit(GPIOB, 10, AF_OD, SPEED_25M);                //PB100 k7 U! ?% V) c% B
  114.                         SYS_GPIOx_OneInit(GPIOB, 11, AF_OD, SPEED_25M);                //PB11$ ~( F5 I1 e& C
  115.                         SYS_GPIOx_SetAF(GPIOB, 10, AF4_I2C2);                                //AF4  o2 O& H6 C* v( H8 {' T4 Q& H4 _
  116.                         SYS_GPIOx_SetAF(GPIOB, 11, AF4_I2C2);                                //AF4+ j6 A$ A- Z; k* _& z
  117. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PF0_1)        //PF0,PF1$ N% K5 `6 j/ N
  118.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟
    5 z% Q: Z* p9 ^0 X3 K+ N; F: K/ ^0 @1 I
  119.                         SYS_GPIOx_OneInit(GPIOF, 0, AF_OD, SPEED_25M);                //PF0
    $ y) h: ]9 l! M5 O2 Y* b
  120.                         SYS_GPIOx_OneInit(GPIOF, 1, AF_OD, SPEED_25M);                //PF10 d! r: f3 }; S9 F1 |: H
  121.                         SYS_GPIOx_SetAF(GPIOF, 0, AF4_I2C2);                                //AF4
    % L' \' B( B) T
  122.                         SYS_GPIOx_SetAF(GPIOF, 1, AF4_I2C2);                                //AF4
    ; J- O  F2 Q3 L5 i
  123. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PH4_5)        //PH4,PH5+ j$ a( F* {) y' w
  124.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    7 a6 ]8 r- a1 a9 r+ l+ i
  125.                         SYS_GPIOx_OneInit(GPIOH, 4, AF_OD, SPEED_25M);                //PH4
    0 A) B* |/ y" G1 X( y4 ?
  126.                         SYS_GPIOx_OneInit(GPIOH, 5, AF_OD, SPEED_25M);                //PH56 n, u4 W% {' D9 m9 Z
  127.                         SYS_GPIOx_SetAF(GPIOH, 4, AF4_I2C2);                                //AF4
    - r# u, b# I4 T
  128.                         SYS_GPIOx_SetAF(GPIOH, 5, AF4_I2C2);                                //AF4                        
    2 w, J# m5 f2 {2 u8 n" u
  129. #else
    + F6 ^% G- t/ S% G! [2 L2 x
  130.                         #error("无效的I2C2 IO选择");( @. [+ a5 `: ~; W. P* [
  131. #endif //IIC_CH2_IO_SELECT
    5 v- @" b! w# K% B" T0 C% O
  132.                 }break;                        
    ( v6 S- U1 h5 N1 E% c
  133.                 case IIC_CH3        :        //IIC3
    - l; B' n: F9 ~& Z& n5 K
  134.                 {/ k3 h' L" l# o  I2 \
  135.                         RCC->DCKCFGR2 &= ~(0x3 << 20);        //清除设置,使用APB1作为时钟源
    2 C) J! t7 G* T
  136.                         DevClock = DEV_I2C3;! l! X) X$ c/ P
  137.                         //初始化I2C IO
    ! {6 w% `& H1 G5 y0 i
  138. #if(IIC_CH3_IO_SELECT==IIC_CH3_PH7_8)                //PH7,PH84 S4 `* Y' v, u) @
  139.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟6 t/ H: z# s" H
  140.                         SYS_GPIOx_OneInit(GPIOH, 7, AF_OD, SPEED_25M);                //PH7
    1 m# ?. G: h) ?9 o* D* l
  141.                         SYS_GPIOx_OneInit(GPIOH, 8, AF_OD, SPEED_25M);                //PH83 H, T9 o# C. j6 n
  142.                         SYS_GPIOx_SetAF(GPIOH, 7, AF4_I2C3);                                //AF4# X5 @/ z) [9 ^: m4 v1 q5 E
  143.                         SYS_GPIOx_SetAF(GPIOH, 8, AF4_I2C3);                                //AF4
    5 e, ]' [- {* U; G0 Y, p
  144. #elif(IIC_CH3_IO_SELECT==IIC_CH3_PA8_PC9)        //PA8,PC9
    - ?9 j: F4 ^# ~% |) X5 q. `- }1 n
  145.                         SYS_DeviceClockEnable(DEV_GPIOA, TRUE);                                //使能GPIOA时钟
    / }4 m% b3 V' B: o* |
  146.                         SYS_DeviceClockEnable(DEV_GPIOC, TRUE);                                //使能GPIOC时钟  t6 \5 \/ R5 r& j% I/ l& V" e
  147.                         SYS_GPIOx_OneInit(GPIOA, 8, AF_OD, SPEED_25M);                //PA8( j# ~% l) Y, I' }; J- X
  148.                         SYS_GPIOx_OneInit(GPIOC, 9, AF_OD, SPEED_25M);                //PC9
    - p% Y0 f$ o; R  B) j
  149.                         SYS_GPIOx_SetAF(GPIOA, 8, AF4_I2C3);                                //AF4. q# ]; E' w. Q+ s# s- d; F+ R& s
  150.                         SYS_GPIOx_SetAF(GPIOC, 9, AF4_I2C3);                                //AF4               
    / U0 f% E/ X) B$ o) h
  151. #else
    8 O8 l1 [7 N8 M, Q, g3 _3 X+ e
  152.                         #error("无效的I2C3 IO选择");; b- X/ Y  a: {% i
  153. #endif //IIC_CH3_IO_SELECT                        
    1 `' o6 ^$ F/ V+ j  }# U  E2 i
  154.                 }break;                        & p0 W2 H6 F1 C7 F* ?! V4 Z
  155.                 case IIC_CH4        :        //IIC4
    & g5 Z; W- `2 ~) A( x6 \# c
  156.                 {
    ! i6 E+ L* n5 A! A% L: k# g
  157.                         RCC->DCKCFGR2 &= ~(0x3 << 22);        //清除设置,使用APB1作为时钟源
    ; t- z9 h: S' I3 ?$ y! H* I+ C
  158.                         DevClock = DEV_I2C4;
    8 i' q3 a' w$ S- G! b
  159.                         //初始化I2C IO) P8 p, l# c( E" ^9 h
  160. #if(IIC_CH4_IO_SELECT==IIC_CH4_PD12_13)                //PD12,PD13& k' M5 G3 ?0 x5 E8 U- j- a
  161.                         SYS_DeviceClockEnable(DEV_GPIOD, TRUE);                                //使能GPIOD时钟
    4 O  e# i& P, h/ d
  162.                         SYS_GPIOx_OneInit(GPIOD, 12, AF_OD, SPEED_25M);                //PD123 ^2 y  h  |) h0 V# M3 P. \/ g
  163.                         SYS_GPIOx_OneInit(GPIOD, 13, AF_OD, SPEED_25M);                //PD13
    % e, S7 \3 F5 K  }
  164.                         SYS_GPIOx_SetAF(GPIOD, 12, AF4_I2C4);                                //AF4% ^: [, _7 F. i( q
  165.                         SYS_GPIOx_SetAF(GPIOD, 13, AF4_I2C4);                                //AF40 m6 R) x" R) F
  166. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PF14_15)        //PF14,PF15
    1 I1 v4 @& s% r, ]4 V! K6 z5 {7 l
  167.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟
    , ]% D' u9 R9 C- D: T
  168.                         SYS_GPIOx_OneInit(GPIOF, 14, AF_OD, SPEED_25M);                //PF14
    8 F7 \$ ?/ X+ k8 o! w9 \* x7 y  h" k
  169.                         SYS_GPIOx_OneInit(GPIOF, 15, AF_OD, SPEED_25M);                //PF155 o! s2 K8 h7 Q7 S* |: o% n- Z7 V% O
  170.                         SYS_GPIOx_SetAF(GPIOF, 14, AF4_I2C4);                                //AF4
    ! N' U4 }% v4 r. T4 n# [
  171.                         SYS_GPIOx_SetAF(GPIOF, 15, AF4_I2C4);                                //AF4: j( _3 T4 N) \" s+ v, k( g
  172. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PH11_12)        //PH11,PH12
    ) y; E) _; K3 k' U* W* A+ y
  173.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟2 U. V4 ~$ a" N6 K
  174.                         SYS_GPIOx_OneInit(GPIOH, 11, AF_OD, SPEED_25M);                //PH11
    " y0 ~# o$ j  R) W! \7 a
  175.                         SYS_GPIOx_OneInit(GPIOH, 12, AF_OD, SPEED_25M);                //PH12
    0 _7 e8 }2 v) O* q, b) a$ _8 F# @
  176.                         SYS_GPIOx_SetAF(GPIOH, 11, AF4_I2C4);                                //AF4! r$ ]1 c( \6 q" ~$ a- r) V
  177.                         SYS_GPIOx_SetAF(GPIOH, 12, AF4_I2C4);                                //AF4                        
    * q; f( J/ f% i0 z  W( J1 \3 p
  178. #else
    5 l0 I* J0 k& R  z
  179.                         #error("无效的I2C4 IO选择");
    + B9 R* `: @  p
  180. #endif //IIC_CH4_IO_SELECT                        
    0 b1 k' C: W$ |, s0 s. @
  181.                 }break;4 ^$ E5 {$ x9 U3 A1 ^+ k4 f5 \
  182.                 default:
    7 V3 h! i3 L: h* y2 X
  183.                 {6 }7 i. D  }7 ~( y
  184.                         DEBUG("初始化IIC失败:无效的IIC通道%d\r\n", ch);  Y  ~: C; H4 B1 E- w# G
  185.                         return FALSE;! o. \7 H) m) I. {& g; z
  186.                 }
      X1 P8 ~0 \5 n/ f7 @
  187.         }
    * E' P( ]6 B' e0 p( }
  188.         pHandle = &sg_IIC_Handle[ch];                                                        //获取相关通道的句柄5 t: n8 x; C2 h! Z/ t% }
  189.         if(pHandle == NULL)5 d5 U4 s/ d% z) K2 `4 N. q# e
  190.         {
    9 `5 V) b4 ?, \" @. p( r% b1 x/ D. e
  191.                 DEBUG("初始化IIC失败:无效的IIC句柄\r\n");
    4 l& s  C  g. j4 p
  192.                 return FALSE;+ _2 F- M, W, W( A6 \
  193.         }
    + c) _+ ]% V2 N6 \) @
  194.         
    $ R$ C: k/ r, Q$ G& W2 R) A0 p
  195.         SYS_DeviceClockEnable(DevClock, TRUE);                                        //使能时钟  p( X6 \4 S) Y0 [: M6 e1 N% y) `
  196.         SYS_DeviceReset(DevClock);                                                                //外设复位
    : |. S. b. B% q$ Y$ \# ]/ X0 q
  197.         pHandle->I2Cx = (I2C_TypeDef *)I2C_TYPE_BUFF[ch];                //外设指针
    3 p& p% X; ?* j" f
  198.         pHandle->I2Cx->CR1 = 0;
    ; l( d6 ^2 t; R. m* P) ^
  199.         Delay_US(1);                                                1 w- u9 d: X# T6 [- f1 L
  200.         pHandle->I2Cx->CR1 |= 2<<8;                                                                //设置噪声滤波器,关闭所有中断& W0 a9 J; Y" L$ w1 v8 Q+ I
  201.         pHandle->I2Cx->CR2 = 0;
    4 R$ B/ o; C2 R* W# \9 `9 |
  202.         pHandle->I2Cx->OAR1 = 0;
    * e4 b. g/ ]; j; f1 J
  203.         pHandle->I2Cx->OAR2 = 0;2 ~. U! O& U1 `$ u
  204.         if(Speed_KHz > 1000) Speed_KHz = 1000;& q' ~  c+ [5 U- ~
  205.         if(Speed_KHz < 10) Speed_KHz = 10;
    3 y. ~% _' |7 I/ f6 O
  206.         pHandle->Speed_KHz = Speed_KHz;                                                        //记录速度
    . W& R8 }3 C" Z8 n5 Y
  207.         if(TimeOutUs == 0)                                                                                //需要自动计算超时时间,时钟周期*10*10 & j/ y$ O4 K- ]/ ~6 O
  208.         {
    8 J+ g" K9 U* m. B
  209.                 TimeOutUs = 1000/Speed_KHz;                                                        //时钟周期
    * d, f: |+ o3 G0 f6 k& B; F% p! ]( _
  210.                 TimeOutUs *= 10;                                                                        //字节周期
    * ]4 [5 r  ^1 |) L+ p0 d6 z3 n6 X5 S
  211.                 TimeOutUs *= 10;                                                                        //超时时间为10个字节时间" S; k  v5 ?* U, ~' q/ t
  212.         }
    & ]6 C8 M* h9 m" @0 d( L/ [8 o$ n
  213.         if(TimeOutUs < 3) TimeOutUs = 3;0 ]% o) U& d, D  t1 `# _
  214.         pHandle->TimeOutUs = TimeOutUs;                                                        //记录通讯超时时间2 T- P& x# b/ e$ O. n
  215.         uart_printf("IIC超时时间:%dus\r\n", pHandle->TimeOutUs);
    + o1 T3 g. d! r& D
  216.         pHandle->I2Cx->TIMINGR = IIC_CalculationTiming(pHandle->Speed_KHz);//0x40912732;                                        //时序; r$ [; ?. Q. ~0 p, ?, ]( G
  217.         pHandle->I2Cx->CR1 |= BIT0;                                                                //使能IIC
    ! ]1 V- B; m/ h, s' x4 N) D
  218.         pHandle->isMasterMode = TRUE;                                                        //主设备模式
    ( {% l9 r) X8 m9 w& j: W& w. j
  219.         Delay_US(1);
    & h2 V" C2 h+ Y

  220. # V$ [; N/ |2 {
  221.         return TRUE;5 j% K$ w3 d- f* M
  222. }
    4 {5 M3 ^6 u8 t" D3 Y2 W7 c
  223. ; f: i4 x% o' Y& l) f0 K0 g6 x- G4 O
  224. 4 h; V. D# [5 p. _
  225. /*************************************************************************************************************************
    : F. a4 y, T* R7 P8 X
  226. * 函数        :                        static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)" r2 ]" D+ T/ L+ D- \5 o0 x
  227. * 功能        :                        检查是否有NACK中断状态,如果有则清除掉
      x2 q1 L+ j3 e. s+ w
  228. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us
    8 h9 w* P( a5 C' S! C
  229. * 返回        :                        IIC_ERROR' g: N* W. X6 `) [
  230. * 依赖        :                        底层宏定义
    & E; b: N  K' K. K0 \& t$ I) x
  231. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a># B: ^! V2 f/ K
  232. * 时间        :                        2020-02-15% F3 i/ i* h) ~0 G; D  s0 ^  z4 h
  233. * 最后修改时间 :         2020-02-15, g6 B% r* c+ A3 R  I% C2 O
  234. * 说明        :                         如果有NACK中断,则先产生停止位,然后清清除掉所有的中断,并复位IIC,然后返回错误
    , Z/ N, J; M) U% m& n4 Y0 |
  235. *************************************************************************************************************************/  
    * V* q) E- `, {5 G" K
  236. static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)7 a) S2 Z5 h' O' `8 a
  237. {
    " a! C7 I. |" G$ ~
  238.         IIC_ERROR Error = IIC_OK;
    1 z, |" y7 ^& ]1 H5 J8 F
  239.         5 ^1 H2 R! E( g8 x1 B" @
  240.         if(IIC_GetISR(pHandle) & IIC_FLAG_NACKF)        //接收到否定应答标志
    8 \" I- W1 X: s$ M
  241.         {
    2 [% M2 _& v. r" r  I. y
  242.                 uart_printf("NACK : IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);8 D/ E7 F6 h( w/ J5 @! j
  243.                 uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    0 u, T4 f: G+ Q
  244.                 uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));
    % q8 \+ K. `. u$ H# m2 y" i
  245.                 //主设备下,如果没有开启自动产生停止位,则手动产生停止位# |, k6 R3 r. M! z
  246.                 if(pHandle->isMasterMode && ((pHandle->I2Cx->CR2 & I2C_CR2_AUTOEND) == 0))
    8 @9 r& M# i# A( F6 a8 M6 {
  247.                 {  {& K' \4 L& n" [
  248.                         IIC_SendStop(pHandle);                        //send stop4 W( Z$ g9 s; c  B
  249.                 }0 n% u, d( `& |5 S5 V7 K
  250.                 //等待STOP标志有效
    5 L& l2 R" T) C7 W' ~) s
  251.                 while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
    ! w  Y* {0 j0 O6 J/ [1 H" F3 u
  252.                 {
    0 T, e& i! |$ r7 l9 o! j9 W8 P
  253.                         if(TimeOutUs == 0)                                //检查是否超时了6 }2 j' f) Q4 o, H) k
  254.                         {
    ( a, T7 {' a- i/ T9 d% W& V
  255.                                 break;
    ' A9 j& i! x" X- c* g1 i: O
  256.                         }                        . r4 c% h. y, L% r! \2 M
  257.                         TimeOutUs --;
    . ~: ~# [8 ~. ?+ G9 U5 ^
  258.                         Delay_US(1);                                                //延时
    , ?- E7 ^, Q8 D) z
  259.                 }
    , M+ H1 E, V4 q# [
  260.                 //清除相关的中断标志6 O+ ?. g5 v- X1 V
  261.                 IIC_ClearISR(pHandle, IIC_FLAG_NACKF | IIC_FLAG_STOPF);        //清除NACK,STOP标志
    % h: B# V( L7 n+ H% T, ~3 Q8 |
  262.                 pHandle->I2Cx->CR2 = 0;                                                                                //清除CR2寄存器; W' @( g, d! j
  263.                 IIC_SoftReset(pHandle);                                                                        //执行软复位8 C- h5 y5 }- P! H4 \# G7 N
  264.                 if(TimeOutUs == 0)                                                //没有超时,就是硬件通讯出错了7 G8 M1 L$ P6 T& g  B3 H
  265.                 {6 T) n, C; U3 T2 ~) L$ e3 O
  266.                         DEBUG("IIC发送stop超时\r\n");
    5 p& n0 i* v4 i6 z. S+ G7 X2 k
  267.                         Error = IIC_TIMEOUT;                                //超时' j. O- `0 K. D$ r( N
  268.                 }" i: |4 e0 w8 K( n% A- O
  269.                 else
    8 `; C5 V; c4 o6 N$ K  [3 |
  270.                 {
    , |( Q2 `  F2 T  t/ B0 g
  271.                         Error = IIC_HAL_ERROR;                                //底层错误; G5 }* j- s+ k$ n: }9 U' J
  272.                 }
    2 r, I0 }8 D" P; \; g) @1 z$ H
  273.         }
    8 b; S4 y! t; l1 t7 ]
  274.         + w3 J- ]4 a; E; q( \) w4 I
  275.         return Error;4 o  M" D$ Q0 e  l. I7 X; q" B0 d. d+ q
  276. }
    5 [7 z; a! h+ K* h/ p* c- F
  277.   k5 `+ I0 W3 L5 I

  278. / f- X, ~3 I$ F

  279. ' R7 ?1 J& p# i/ T7 B
  280. /*************************************************************************************************************************7 X& C  S* {1 t/ C
  281. * 函数        :                        static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)- _6 X# j& b7 [
  282. * 功能        :                        等待TXIS中断有效(等待 I2C_TXDR 发送寄存器为空)
    4 p  L$ L4 ~5 w$ J' Q
  283. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us- M% {6 V* i6 B9 ^- B5 ^4 ~
  284. * 返回        :                        IIC_ERROR: G$ i- E; R& {  i% a- K
  285. * 依赖        :                        底层宏定义
    % f' F6 S  _4 u# }% ]
  286. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>( {; U5 Z( `9 y( S  S' k
  287. * 时间        :                        2020-02-154 t  m. a8 I, K
  288. * 最后修改时间 :         2020-02-15, s/ Z* ~2 ^* I* F
  289. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的
    % t' W* v! a: i4 o  B( A
  290. *************************************************************************************************************************/  
    0 x7 U! m$ F: H; [9 Q* R* e, I
  291. static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
    ( v4 @4 u8 N: m$ a4 ^) K, }8 D
  292. {
    7 `7 }1 |; t/ v& i$ R; ^
  293.         //等待TXIS中断有效
    1 _0 m9 t2 K* }" h; }
  294.         while((IIC_GetISR(pHandle) & IIC_FLAG_TXIS) == 0)
    ) i  D; O0 K0 B- c/ F
  295.         {
    5 ~3 K& Z1 Z, ~
  296.                 //有NACK中断,进行处理( |/ e* u$ [' ]3 \5 e( @
  297.                 if(IIC_isCheckNackFlag(pHandle, TimeOutUs) != IIC_OK)        
    * j3 X( Z' d( u
  298.                 {
    , R% b/ u. U# Q; ]! [. o
  299.                         DEBUG("检测到NAK错误\r\n");9 |7 g5 ^) m: k  R; {, S/ J' I
  300.                         return IIC_NACK;/ d) Q5 K( P; B: J! r2 Q2 c" v
  301.                 }
    3 {& ~* k# A' Q: T3 s3 ]; A, N
  302.                 0 P9 Y8 Y* ^$ H- N* K" `
  303.                 if(TimeOutUs == 0)                                        //检查是否超时了
    " \, y# x  k1 m) y4 Z* Z
  304.                 {
    ) O1 ~. @+ N2 x+ |, s: o* L) h
  305.                         uart_printf("IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);! B- ]) ?) g+ ]& K8 d6 v2 k
  306.                         uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    / i& o+ _+ u4 e4 e
  307.                         uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));9 c% `! P. N6 o* Q! a
  308.                         4 t; z7 V6 s- h! y, W9 W* f
  309.                         IIC_SoftReset(pHandle);                //执行软复位
    " x# a* j) C" Q1 S% f/ ^8 m( g
  310.                         return IIC_TIMEOUT;                                //超时
    4 ]) Y- p' o) W
  311.                 }                        
    6 ?# I* K- Q1 Z5 }0 L
  312.                 TimeOutUs --;. f8 B) T/ Y/ N6 z- c8 h
  313.                 Delay_US(1);                                                //延时* ]$ F+ i' H; T, ^" p0 E
  314.         }
    1 r. M( S/ `  F; _1 V* L
  315.         5 }+ N# H; `$ j8 p* E
  316.         return IIC_OK;( a3 g/ ~$ {3 D9 Y+ p
  317. }" H0 g8 _4 N' q: u* ?. Q
  318. 5 {+ ]7 D' F) |  q9 d1 H5 D

  319. ' ~6 h2 E( |) [5 P5 S4 d
  320. /*************************************************************************************************************************. I; W2 I' L9 m# \9 [9 V" }
  321. * 函数        :                        static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)& U% V( \) _; E- A& e
  322. * 功能        :                        等待STOP中断有效(等待 发送结束 )
    " w0 _" ?% V% g
  323. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us1 R; s" b; T8 ?
  324. * 返回        :                        IIC_ERROR+ u! S" S5 }4 @- ^9 v3 o
  325. * 依赖        :                        底层宏定义1 J' e  _8 l/ s$ V
  326. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>' u9 d6 H* z! p( C7 v
  327. * 时间        :                        2020-02-15
    5 v  ?9 m: R+ H. d4 D- ?
  328. * 最后修改时间 :         2020-02-15+ y5 S% u# X# h" n3 D! k* H
  329. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的
    ; S6 b( k9 ~% \( K6 {% ^/ k
  330. *************************************************************************************************************************/  
    7 X* Z# Y) V% c+ H$ D
  331. static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)9 V. Z# P2 L9 D, U# O
  332. {
    " R& W6 B9 ~# d7 |
  333.         //等待STOPF中断有效
    5 s4 [+ V& z/ f! r% |( k* t
  334.         while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
    5 @6 a5 c6 y. q( v& V
  335.         {
    ' @! H3 m: F4 s0 {, M% e5 [
  336.                 //有NACK中断,进行处理5 \1 {3 c! h9 |" W% x
  337.                 if(IIC_isCheckNackFlag(pHandle, 5) != IIC_OK)        
    " [" W' H  ^$ J* T5 ]1 Z
  338.                 {5 S* ?1 g. p, U! k% s1 d' C
  339.                         return IIC_HAL_ERROR;4 d" A  n3 c; F! L5 O3 q1 V* c
  340.                 }" {) A+ a, w- D# X
  341.                
    4 u& E: W$ f. v. X* f0 c$ c
  342.                 if(TimeOutUs == 0)                                        //检查是否超时了
    + P2 J+ ^7 m: Y/ s9 ]
  343.                 {
    - f% F2 v4 ]* j9 V# Q% C
  344.                         IIC_SoftReset(pHandle);                //执行软复位
    9 X  B! h# c2 A* N
  345.                         DEBUG("IIC等待结束超时\r\n");3 l: ~1 O$ A; o  O" @
  346.                         return IIC_TIMEOUT;                                //超时$ o* y9 l1 C6 O; W; C* P
  347.                 }                        ) f- G4 y& K+ t
  348.                 TimeOutUs --;
    ' F4 w5 R6 X1 L) r. z; L
  349.                 Delay_US(1);                                                //延时8 c0 r# I! q0 s7 [+ C7 h$ m
  350.         }
    ; e6 \$ _) h# `, r0 L+ W
  351.         
    ' |/ I/ t; E. v  f$ _0 T! o1 T
  352.         return IIC_OK;! }1 ^9 n/ C$ v* ^! o0 ?
  353. }
    & Z$ o9 _  R6 n& z. e
  354. ) x. g0 Y% L7 W( C& z8 D. N

  355. 0 j8 H; ^' z5 V9 X
  356. /*************************************************************************************************************************% A7 m" @3 |/ n% `  r
  357. * 函数        :                        static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)+ b' A; i2 C1 f' v" l
  358. * 功能        :                        等待中断有效% Y" x2 d$ f; N) k6 N
  359. * 参数        :                        pHandle:句柄;Flag:需要等待的flag,见IIC_FLAG_xxx;isWaitFlagSet:TRUE:等待标志有效,FALSE:等待标志复位;TimeOutUs:超时时间,单位Us1 Y* v# c% L8 g
  360. * 返回        :                        IIC_ERROR- Z8 o5 I& i! k$ l
  361. * 依赖        :                        底层宏定义
    ( W* b4 m! K/ A! h
  362. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    2 N$ n! l3 v1 Z9 z: G: N9 w/ m
  363. * 时间        :                        2020-02-153 g" Y& I2 T% c2 ?4 T  k  f
  364. * 最后修改时间 :         2020-02-151 B; v0 |* l. Y7 N. u( d$ ?) y# C
  365. * 说明        :                        
    3 M4 i' K8 N7 U  v
  366. *************************************************************************************************************************/  
    , h) f' F9 G5 }2 ~1 |( q4 C' ~
  367. static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
    " g) N. }- `! K* L
  368. {
    7 u$ t2 S$ S  }+ a" J' I
  369.         if(isWaitFlagSet)        //需要等待标志有效/ Y2 O& g" e# _! t
  370.         {5 v  e  z2 x- Z, X  b6 m/ J. R9 e
  371.                 while((IIC_GetISR(pHandle) & Flag) == 0)$ s# v. F& d  q6 x& v( y. A5 L
  372.                 {- T: w. ^! B# I% ^1 k9 Y2 B
  373.                         if(TimeOutUs == 0)                                        //检查是否超时了" T& k+ ^5 ^0 D9 q. X# k2 m4 n- ]( S
  374.                         {% n( n- L4 `% O- ]% }
  375.                                 return IIC_TIMEOUT;                                //超时% f0 V" y+ k! d
  376.                         }                        
    4 j& c) [5 r8 Z1 q9 `' ?9 m1 }
  377.                         TimeOutUs --;
    ! Q  Q9 ^9 Z) [: S& c' o( k9 E
  378.                         Delay_US(1);                                                //延时( b# E* b5 k* d$ O' M" B& @
  379.                 }# u$ R. H8 D# `% z4 ]
  380.         }" y' e  v9 Q: {6 m3 P% c
  381.         else                                //需要等待标志复位% u0 P9 v  N- M: C: S" e5 w
  382.         {
    - R. J  N7 V) R7 F% n6 N$ L, d
  383.                 while((IIC_GetISR(pHandle) & Flag) != 0)
    2 G- b/ ~+ f, w+ ]7 x; @4 X2 V
  384.                 {
    / }: [9 i* Y* x, j* Q6 n! n! m7 |
  385.                         if(TimeOutUs == 0)                                        //检查是否超时了
    # B7 i8 y/ k1 [1 k
  386.                         {* [% Q  Y- b" |. a) z0 A7 e# Y' e2 X: t
  387.                                 return IIC_TIMEOUT;                                //超时( x: f0 K4 C1 v% W& }( g# l+ s
  388.                         }                        + N" u9 L" x) g1 d  [8 |
  389.                         TimeOutUs --;
    7 R# S* u9 d7 `; b( y$ i1 I
  390.                         Delay_US(1);                                                //延时3 @; ?; L  Q5 I+ C
  391.                 }+ @5 Z3 u% b, ^! `' ]2 A, N& D
  392.         }
    $ S+ h" g" h& N1 W/ L
  393. 1 `  Z" [* v1 |
  394.         return IIC_OK;
    ) [. T( c2 j" x
  395. }
    ; T# q% Y& s7 o0 H6 m

  396. . ~+ ~2 t, Y6 C& T+ u
  397. ' F" w1 K4 R# S4 y% P: W

  398. 6 X' z% D* C. Q
  399. ) c+ T3 n# u1 ~- r
  400. /*************************************************************************************************************************, R+ ^9 h0 ^/ `% z  i
  401. * 函数        :                        static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)
    7 Y0 d# y+ x+ \) Q
  402. * 功能        :                        主设备传输配置(配置CR2寄存器)
    2 L! z8 ?; a. e6 m
  403. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;TransByteCount:需要传输的数据长度;EndorReload:自动结束还是重载设置,见IIC_RELOAD_END_MODE;StartAndWR:开始读写控制,见StartAndWR# O) Z1 q2 I* [; [& D7 L
  404. * 返回        :                        无
    ; }2 g3 n/ O6 e
  405. * 依赖        :                        底层宏定义
    8 q6 L6 |- ~4 G
  406. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>6 \1 V0 z5 w( p' p
  407. * 时间        :                        2020-02-15* t4 b  t& c8 M7 N9 y; e$ e: p
  408. * 最后修改时间 :         2020-02-16& V5 s$ Z9 `3 }: o
  409. * 说明        :                         在往 NBYTE 中设置最后一次传输的字节数前,必须把 RELOAD 位清零便于后续自动发送STOP。
    2 y" y  u1 Z; K' u0 x
  410.                                         当 RELOAD 位置 1 时,AUTOEND 位将不起作用;. H- P% Z) J6 g! U( r" W7 L+ Q
  411. *************************************************************************************************************************/  
    ' ?* q6 K/ `5 T& L3 n: I4 h
  412. static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR): s' Q- M% Q+ r+ i& _" W! b9 R
  413. {
    6 z" \! E% @! k% u  u# N9 p- G
  414.         u32 temp = 0;
    6 u& b% e1 C& l
  415.         & v4 p/ X. u% \! t4 l( L# W
  416.         //先读取CR2寄存器的值' n' {3 \# R. J  y8 D* c7 ^+ V
  417.         temp = pHandle->I2Cx->CR2;2 J# ^/ L+ B0 j7 j  N$ s
  418.         //清除掉相关的字节
    0 Q( g% x& f" @
  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));
    8 p% k; X, X2 j' d- y, |8 p* w
  420.         //生成配置数据
    # q, Q5 m! A: m2 x8 N
  421.         temp |= (u32)(((u32)SlaveAddr & I2C_CR2_SADD) | (((u32)TransByteCount << 16 ) & I2C_CR2_NBYTES));+ q4 v4 P( _: K! R" `" Q
  422.         //重载与自动结束只能二选一9 R9 ]1 x& k# n
  423.         if(EndorReload == IIC_AUTOEND_MODE)         * m9 D' q4 o3 h6 K+ m0 x
  424.         {$ @+ T$ O4 [- R5 Z! R- A
  425.                 temp |= I2C_CR2_AUTOEND;        //自动结束模式
    " q3 j1 N! F; F- j# S! \* r/ S7 V
  426.         }9 f3 o; }0 O* p* S$ F* Q
  427.         else if(EndorReload == IIC_RELOAD_MODE)4 w/ ]) v3 i! Y: t3 z6 ?# ?
  428.         {
    2 I5 U# u4 o- ?: e  l; L
  429.                 temp |= I2C_CR2_RELOAD;                //NBYTES 重载模式
    ) p3 t7 m" Y, A. _' l3 c' m
  430.         }
    ( P$ \) m3 v6 ]6 T- W
  431.         
    & [) E. ?# E6 L
  432.         switch(StartAndWR)
    # ^! n$ N5 ?9 H1 t* X) F( D  K6 E
  433.         {
    + T- w) I, o. ^: i1 h: }0 T
  434.                 case IIC_NOSTART_WRITE        :        break;        //没有开始的写-默认就是这样的. k# V  z  Z" P) c. Z. Q
  435.                 case IIC_NOSTART_READ        :                        //没有开始的读-用于后续数据读取. `' j# N5 G% q, U8 @4 Q9 B
  436.                 {
    6 a- R1 e2 k4 C2 q) ~7 @
  437.                         temp |= I2C_CR2_RD_WRN;                        //读取: f5 a* `' q( ]; y  ?1 q3 N" m
  438.                 }break;4 b) L1 P7 n/ w( _- k  c& L- t9 q5 U
  439.                 case IIC_START_WRITE        :                        //生成开始写
    2 p0 T! s  l+ a
  440.                 {
    ' {: ^# B0 M0 c1 i6 X% t
  441.                         temp |= I2C_CR2_START;                        //启动传输
    - L& ^; g  w$ {% _0 i
  442.                 }break;2 c6 H; U# ]9 g' b( c
  443.                 case IIC_START_READ                :                        //生成开始读        " Q! s$ a4 L8 a- a5 }5 F1 n5 A; r
  444.                 {5 n( ~7 e: d+ K
  445.                         temp |= I2C_CR2_RD_WRN;                        //读取. ?) I3 A0 a( r; X* K+ q6 j- _" q
  446.                         temp |= I2C_CR2_START;                        //启动传输
    ( B  w) @! S9 }- G" {. i- }# q
  447.                 }break;$ |- @/ B  r0 j; k1 z, Q/ S7 r
  448.                 default:break;
    $ c% T1 K, u& \9 z% T1 }
  449.         }
    * N: f0 i. D3 W
  450.         1 |+ ]/ c: [+ e1 H
  451.         //uart_printf("准备写入CR2=0x%X\t", temp);
    8 t1 }: w7 _7 V% N1 J8 d
  452.         //更新到寄存器4 d' ^3 R  a/ S: B
  453.         pHandle->I2Cx->CR2 = temp;  //测试; I; k' S9 p* n
  454.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    2 A- v- J- T6 o2 {( V; g6 P
  455.         Delay_US(100);
    + e; U4 o+ C- d( ]* ^$ {3 K, B+ k
  456. }' [+ z% q' y8 s
  457. " A& J) L( X5 `1 n
  458. # n/ ]) L$ k/ K/ K7 S
  459. /*************************************************************************************************************************. U4 `! e: |3 y% S% D
  460. * 函数        :                        static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)6 t  k4 v6 _& ], c6 T- K
  461. * 功能        :                        IIC发送一字节
    ) x2 V% g4 s5 y/ e  D
  462. * 参数        :                        pHandle:句柄;data:待发送数据;TimeOutUs:超时时间,单位us
    6 x% n% [! T2 A
  463. * 返回        :                        IIC_ERROR
    1 |+ j! _; {# c& g0 }+ r' ^) Y
  464. * 依赖        :                        底层宏定义- a# H; j: u7 ]& A0 e  ~* A" U
  465. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>, a2 X. \4 _0 }) A, b$ |  m% k
  466. * 时间        :                        2020-02-15
    7 t8 O5 ?7 ?. Q! k+ ?
  467. * 最后修改时间 :         2020-02-16
    ( _, n% j8 p6 h1 V6 u- P% E
  468. * 说明        :                         TXIS有效后才会进行数据发送,不会检查数据发送是否完成。
    $ _& |1 I$ X0 E3 F/ [- R4 _
  469.                                         如果最后一个字节发送完成后不会再触发TXIS中断,只会触发TC中断2 h5 n6 E6 Y9 H# g
  470. *************************************************************************************************************************/  
    2 Z. [" ^# r+ y1 K* a5 [, ]
  471. static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)' i0 d7 p& U* n/ R/ m& p
  472. {; l( d; ?5 X$ W. \2 m( B6 U: [
  473.         IIC_ERROR Error = IIC_isWaitTXIS(pHandle, TimeOutUs);                                //先等待可以发数据
    4 W- ~: e  J6 ~7 b8 k
  474.         if(Error != IIC_OK) return Error;' o* A( A8 O' D& t2 L2 i7 K( R4 K
  475.         pHandle->I2Cx->TXDR = data;                                                                                        //写数据到发送寄存器-不会等待数据发送完成        
    ! ^1 E1 n) D& T  `# j$ {

  476. 8 X4 Y1 F5 r( x5 w6 g! R1 y7 R6 e
  477.         return IIC_OK;& Q! H! _2 _- A6 J7 A, x% B
  478. }
    : k/ _9 [( e7 V$ M, y1 Q1 a4 \

  479. * n- l9 l* e' A
  480. /*************************************************************************************************************************
    ; ]6 `6 }# p4 p% E
  481. * 函数        :                        static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, # \: Q# j! k$ s, ]# E
  482.                                                 bool isRead,u32 TimeOutUs)- G  Z0 q9 V5 R4 U5 D
  483. * 功能        :                        主设备请求发送从机地址与目标寄存器地址
    $ l4 j5 b2 C* W1 P+ r& A
  484. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;RegAddr:寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,
    , O9 C0 Z$ K& o6 X4 C4 q$ f' E
  485.                                                 FALSE:16bit寄存器地址;isRead:TRUE:这个操作是读取寄存器;否则是写入寄存器;TimeOutUs:超时时间,单位us) R4 a& p) a6 w, ~( l
  486. * 返回        :                        IIC_ERROR
    : m. }) J' {& ?, v/ M* `- D0 ~$ K
  487. * 依赖        :                        底层宏定义; f0 S" C; y- K; J. w8 C" {
  488. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>7 a1 u' h, y6 \3 I4 ^& W
  489. * 时间        :                        2020-02-153 k" L. T  R3 N2 G$ |! n# j. Q
  490. * 最后修改时间 :         2020-02-162 M) B. v# Y2 z% h8 d
  491. * 说明        :                         , ~# M- y! K: I* E! ]
  492. *************************************************************************************************************************/  
      P3 J7 P$ o" n* ?8 m
  493. static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,bool isRead, u32 TimeOutUs)4 V% m+ k0 [$ e; V9 d& s  E
  494. {        * P  I' \* D; m4 _; {" c
  495.         IIC_ERROR Error;& ?. T5 K, O0 P" k
  496.         
    - z: \' y8 ~  I( L; N) ~0 d7 m
  497.         //uart_printf("WriteAddr1:CR1=0x%X\t", pHandle->I2Cx->CR1);- ^* z0 \. I; `
  498.         //uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    ! ?# j9 u5 M9 A
  499.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    5 i) \- v5 z! F0 D
  500.         //传输配置,并启动传输,发送起始序列,开始IIC传输了
    # |+ q- {3 N! {& @* q
  501.         //如果是读取则使能软件结束,如果是写则是自动重载
    ; A. h! _) [; V4 W. y( V9 v# w
  502.         IIC_MasterTransConfig(pHandle, SlaveAddr, (is8bitRegAddr==FALSE)?2:1, (isRead)?IIC_SOFTEND_MODE:IIC_RELOAD_MODE, IIC_START_WRITE);        //传输相关配置-写,并启动传输$ G- q$ f0 l! P! I  N# g% M- z
  503.         6 \6 }; n/ u. C: d! Y
  504.         //开始发送寄存器地址' U4 d' R8 p" N' J
  505.         if(is8bitRegAddr==FALSE)                                                                                                //寄存器地址是16位的,IIC通常是MSB高位在前,需要进行高低位对调
    8 z$ |3 M  U4 K( Z: n7 O
  506.         {; b! E; V% K+ d* Z, _$ P
  507.                 Error = IIC_SendByte(pHandle, RegAddr>>8, TimeOutUs);        //先发送MSB-非最后一字节
    , B" P! F1 R/ \  D; `6 Y# z
  508.                 if(Error != IIC_OK), J: K* E, @0 ^3 R
  509.                 {4 r5 ~; Q; E4 I5 ]/ V6 a
  510.                         DEBUG("IIC发送寄存器地址MSB失败\r\n");/ }% T" C; {$ @1 T# l- Z: d6 r1 E; h8 c
  511.                         return Error;
    / t8 f) f% _! G3 W
  512.                 }        
    , Y* ?- l* f1 H, L& }" e
  513.         }/ a! ~+ z( l" D  {5 s  z/ ]9 Y8 z
  514.         Error = IIC_SendByte(pHandle, RegAddr & 0xFF, TimeOutUs);        //再发送LSB-最后一字节
    , i- n/ a; Z; D! v% x# ]9 S
  515.         if(Error != IIC_OK)
    1 g6 V" L" x7 g( ^8 Y4 p
  516.         {
    + Z9 N1 I" [) `# a+ v* z$ v' u
  517.                 DEBUG("IIC发送寄存器地址LSB失败\r\n");
    9 E, [' ?7 k8 |/ [9 \' G1 e
  518.                 return Error;
    5 d! K+ @7 A9 d1 i
  519.         }" Z6 @* _3 B- I. x; W
  520.         //等待全部数据发送完成
    - R4 {/ _) }! G7 x  O+ t- ]) I6 u/ A
  521.         if(isRead)        //读取方向-非重载,等待数据传输完成 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。
    % L( t  ]8 j. A' D% ^% {2 C
  522.         {
    6 K8 d3 q5 o) U4 R" Q" E) O  g& g
  523.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TC, TRUE, TimeOutUs) != IIC_OK)
    9 z4 P  r: ~9 |
  524.                 {' \8 d" Q" f& F3 w6 i6 q, {: o: f
  525.                         return IIC_TIMEOUT;
    # m5 C( c& n' }) a3 g# a
  526.                 }+ o6 t8 p5 k9 f! ~" k! e
  527.         }        
    . r+ g0 f$ N: T( z* U# i3 `6 P8 V3 r3 I
  528.         else //写入方向,等待重载
    4 t6 A  C. ?+ n" J
  529.         {
    2 u" Y3 Q0 z! e! H- c! H" }! I
  530.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TCR, TRUE, TimeOutUs) != IIC_OK)
    & ]% |: p. g, s7 d( s$ u
  531.                 {. N/ p6 A8 Q) j- K
  532.                         return IIC_TIMEOUT;* Z" v- \5 k5 w# R; p
  533.                 }
    ; |9 s5 Q+ P) t
  534.         }
    . R2 X5 S( |) t- d4 p: ]
  535.         
    8 s) e$ P! x+ F( Q" j
  536.         return Error;
    ! D) F- c0 k6 f
  537. }
    * o9 l) V8 l, P1 J- }

  538. - O( m" S/ Z) w
  539. * l2 c( Z& K' R1 k, a# b
  540. /*************************************************************************************************************************9 T: \% V2 k  _3 e! U9 }( s" o) ?) q
  541. * 函数        :                        static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)9 `' F% y7 F8 z- Q5 ?
  542. * 功能        :                        等待接收一字节数据
    : c3 D7 j) `; \
  543. * 参数        :                        pHandle:句柄;pData:接收的字节数据缓冲区;TimeOutUs:超时时间,单位ms: ]; i  o' X: I/ \9 U) L
  544. * 返回        :                        IIC_ERROR* d6 n3 q0 D* h  n, U* P5 B! H- l- c
  545. * 依赖        :                        底层宏定义
    1 l" g) G$ z5 B0 A% l
  546. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    4 n# d+ ?3 j0 k, {  h, B# Q9 z" K
  547. * 时间        :                        2020-02-157 \& R6 N% E& Z4 d, W# H
  548. * 最后修改时间 :         2020-02-15) @4 A/ C9 D# F3 H2 d  o
  549. * 说明        :                         当RXNE有效后读取一条数据,否则可能会超时
      h4 s+ X% A  C2 s: {: J8 g3 C; n
  550. *************************************************************************************************************************/  ( D% R7 a: L2 u
  551. static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)" N) B7 i$ [$ V0 G3 H' S- [( s; {
  552. {
    & g* v* x/ o; L
  553.         while((IIC_GetISR(pHandle) & IIC_FLAG_RXNE) == 0)        //等待RXNE有效
    , |5 r, J. V) J- v% ?' n
  554.         {
    ! A; n# n* M0 |* {' ~& b8 h5 W  F) B
  555.                 if(TimeOutUs == 0)                                        //检查是否超时了; l. I" `( {1 ^! a& @  A
  556.                 {! \/ R2 _: H7 I! k
  557.                         DEBUG("IIC等待接收超时\r\n");; ^& D. G! X, J  i) g4 u- y
  558.                         return IIC_TIMEOUT;                                //超时. u2 d2 {& {7 e, X0 Z
  559.                 }                        % D# E1 Z+ l" `4 _9 X5 Y
  560.                 TimeOutUs --;' K* X. ~. p/ B
  561.                 Delay_US(1);                                                //延时
    4 F7 \* k8 d* I
  562.         }
    - m7 `6 P0 C4 F' v2 S  b! ?' t! {
  563.                
    0 Y+ i# }, |; [8 C  r
  564.         *pData = pHandle->I2Cx->RXDR;                                                        //读取收到的数据$ X- i6 t& x0 P5 u+ _+ x' s, B
  565.         return IIC_OK;
    5 x2 X6 l8 N  E' g1 u6 Z( z  V
  566. }
    ; f/ {, u- Z% t

  567. 1 [  y" }  j( L% j4 J9 N) W
  568. : ^0 e# Y' t/ t! K
  569. /*************************************************************************************************************************; Z9 K( E" f5 b7 I
  570. * 函数        :                        IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    / n) R0 W9 s9 B: E% q
  571.                                                 u8 *pDataBuff, u16 ReadByteNum)! A% ~; q9 ~/ h) l3 s
  572. * 功能        :                        IIC读取寄存器(可以读取1个或者多个寄存器)/ k3 w4 V6 ]( W
  573. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要读取的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;
    ; ]8 G+ x. `: ]
  574.                                                 pDataBuff:接收的字节数据缓冲区;ReadByteNum:要读取的寄存器数量;0 }! C4 W' L: C9 k9 Z5 l$ `/ D( l
  575. * 返回        :                        IIC_ERROR8 n; o3 N, H4 R% w* K6 ?2 X: h7 X/ K
  576. * 依赖        :                        底层宏定义
      S' Z0 W& D- k2 f
  577. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    8 B3 F* X. R' W( ^
  578. * 时间        :                        2020-02-15
    # t3 p! b6 y* F4 s
  579. * 最后修改时间 :         2020-02-152 o; A1 H- K+ Z  r4 Z
  580. * 说明        :                         读取的数据都是小端模式,如果是16bit的寄存器,请读取偶数个数据,并且需要另外进行高低字节对调最后组成16bit数据2 d0 f. P8 c' {7 @# [9 w
  581.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
    & m; O+ {, l: d0 {" C0 |
  582.                                                 增加信号量7 s% Z" ^/ Q# S6 h& z/ S" B6 c5 |0 R  D
  583.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在
    / |4 Y8 ]1 D1 u! J9 Z7 d' ~
  584.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。
    2 \% a1 N, B- q0 L6 T% N( N! G
  585. *************************************************************************************************************************/
    . Q8 |4 n* b( T3 {: q1 L7 v* {
  586. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum); D. Z1 D& y' T3 H
  587. {
    , n7 K" h4 }6 c3 V6 D# f
  588.         IIC_ERROR Error = IIC_OK;/ u4 a+ @; a% Z1 L* T
  589.         u16 ReadCount;1 m$ m1 r, _7 r
  590.         IIC_HANDLE *pHandle;
      C& Y, F6 T( `
  591.         * Q8 m' J5 D" r0 P8 A
  592.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || ReadByteNum == 0)2 \2 p  {$ K- @2 [: l; M8 v0 d
  593.         {# v  u/ ]; z, E' t- }
  594.                 DEBUG("IIC错误:无效的参数\r\n");
    # s* b% N& A: R- K" C
  595.                 return IIC_PARAMETER_ERROR;
    . D* O" T- s; P. y$ [
  596.         }
    - e6 T  X6 q( C( A  N
  597.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄
    / |4 L! Y  ^. E0 U9 `% M+ i: N% m
  598.         
    " M6 G3 z2 |2 @- t/ A( F
  599.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙' W6 x! I# `# f
  600.         {
    5 c5 k: O, U+ T( L
  601.                 IIC_SoftReset(pHandle);3 `! K1 G+ x+ h: Q2 k% {6 X
  602.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");" U/ v4 k5 H6 l5 r. O  M
  603.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙
    ! ~; A& f% _! V/ |8 C4 O' U
  604.                 {
    4 [2 N% I. Z9 E5 h
  605.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");# W# r; T) }2 c6 `5 h
  606.                         Error = IIC_BUSY;7 `  d# H6 M2 g9 w* w  C
  607.                         goto end_loop;1 h3 \( J6 F. s3 J
  608.                 }
    # k4 A; U1 N" I& e- ~
  609.         }
    2 x$ ^2 a* O2 Z" k
  610.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态6 Z$ d3 L: ~# P7 v+ Z  [
  611.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器; R$ n8 \; w7 D' m5 `
  612.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    - H. n/ o* h8 M
  613.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,TRUE, pHandle->TimeOutUs);
    3 G+ a2 R, m' r- z. s
  614.         if(Error != IIC_OK)6 p; p+ z3 B  H, G
  615.         {2 T0 ]4 Z( ]% k
  616.                 goto end_loop;
    / N' Y+ ^6 Q" X& K7 ?  Q
  617.         }
    7 q. |! `/ j4 }' P( s
  618.         //发送后续数据, l9 F. d) x2 ?) U
  619.         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取-后续还有数据,需要重载; O$ |" R* B# U% Z
  620.         {
      ]% j4 i! H$ X9 ~/ ]% e1 ^3 y; y
  621.                 ReadCount = 255;        //本次需要读取的数据长度2550 k3 d( O8 r, _
  622.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输                5 {0 r) ^, l, @0 f( z
  623.         }- c# ^% J9 @4 ?. J- J3 Q' |0 g
  624.         else" @( P- [% s# l- ^+ q
  625.         {
    ( A5 V6 s  T0 l/ Y  B
  626.                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯后自动结束
    - M- R0 X6 ~0 ?' E" M7 m
  627.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输
    2 R( O% Q4 p- O& j
  628.         }2 Y" v  k' B  A% \' {
  629.         / y2 s5 i' ?, D( r! k/ m6 Y
  630.         //循环等待接收数据完成
    5 O+ V5 Z9 X4 \) Y. [
  631.         do, A, K$ A8 K; X* ~1 Q' t' K
  632.         {
    9 @$ h2 V4 j- ?
  633.                 //uart_printf("读ISR=0x%X\r\n", pHandle->I2Cx->ISR);0 R2 k" C1 ]* [! B% m
  634.                 Error = IIC_WaitRxOneByte(pHandle, pDataBuff,  pHandle->TimeOutUs);                                        //接收1字节数据8 e! k6 Q, k. R
  635.                 if(Error != IIC_OK)
    ; F6 [( H1 k: _3 c
  636.                 {
    & }% A. I+ P% p9 H+ [: D+ g# C
  637.                         goto end_loop;
    9 G& [9 D9 k$ g3 Q
  638.                 }; K. H) ^4 D/ K
  639.         
    $ }: @% }+ `( O7 M% K! e. U7 Z( F
  640.                 pDataBuff ++;
      p. K2 V! C( h
  641.                 ReadCount --;
    * W/ ~& u6 M# T+ A5 w! @) X
  642.                 ReadByteNum --;
    + S* [6 @5 c* f% N
  643.                 if((ReadByteNum > 0) && (ReadCount == 0))        //还有数据要读取8 Z/ g6 _2 m0 @( t8 s: U
  644.                 {% _" N/ a1 ?" o' g" C3 E/ ^  e
  645.                         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取2 k; N, [5 X3 z& I+ j; M
  646.                         {. V9 ^6 j! S4 r/ a& X- K9 k
  647.                                 ReadCount = 255;        //本次需要读取的数据长度255-后续还有数据,需要重载) o6 W- X) b/ \, U; P8 W- G
  648.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
    , @) \. x# a* N" `
  649.                         }% u9 q' B% Q$ o. }; M
  650.                         else, q0 r( d1 m' K$ J, |
  651.                         {
    1 W: Z& S1 x! N5 y( M; g3 ~  F! C
  652.                                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯,自动结束) Q! @7 i6 w2 I$ c9 E
  653.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
    0 M  D: H6 n/ V0 N' }  H5 f
  654.                         }, Y' X# U( N7 n- k, F& }8 M( Q
  655.                 }
    % O- _3 r( `( L* D2 |0 a7 x; X
  656.         }while(ReadByteNum);1 m4 k$ z5 J+ I& r
  657.         //读取完成了,等待STOP位有效7 F4 n2 d7 b' ]# d$ M8 N
  658.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);
    ( p; b9 z. o8 F0 v% d3 v
  659.         if(Error != IIC_OK)
    8 y. e+ G; U5 \2 h  m" Z
  660.         {* B9 {! m% G6 W( y
  661.                 Error = IIC_STOP_ERROR;
    8 {% Z0 n2 }$ f. C1 f8 Z
  662.                 goto end_loop;
    7 L! i8 ~/ D2 J) o
  663.         }        
    ' c& y+ b, d6 p2 C& A% E" o
  664.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态9 v: \3 g$ \1 {$ z0 W' }
  665.         
    ) w6 q; ?* c+ d8 f3 K' ?) `
  666. end_loop:        $ ]  D# o5 D1 j5 c1 z* |
  667.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        
    9 ~# p% z) k$ s' D! J. b2 V! N
  668.         if(Error != IIC_OK)! m8 Y) e4 D, D& M  W
  669.         {$ W2 p7 ?% f9 z3 N# g# S( d% }
  670.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误
    ) \$ X# ~! c  J4 ^
  671.                 DEBUG("[IIC R错误]:%d\r\n", Error);/ t' G3 l" L) U3 O, N
  672.         }3 v+ Y2 o% ~! n
  673.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的
    - g4 q+ u7 N: U$ S. g8 H
  674.         {
    & B2 |9 u6 N$ M) E; p- X4 {
  675.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    ! m! w, ]/ Q  B$ o! U
  676.                 DEBUG("IIC R结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);                ) t* ]' J" R1 ^7 p, t
  677.         }# f& z3 t' c) L5 G  \7 V* v
  678.         & d! f. f0 U0 Q
  679.         return Error;
    : q* ~" {7 i! u9 M! W2 a' t
  680. }
    3 j' O7 p6 n: ^7 [) D0 r) W, N
  681. % ]" i  Q( K8 N& y% G$ ^7 D

  682. # U4 m8 T0 e* r+ D( l4 a7 g9 o
  683. /*************************************************************************************************************************
    * E; L: N4 `: j4 M2 R' V
  684. * 函数        :                        IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    : @4 @- _( y( D' a
  685.                                                 u8 *pDataBuff, u16 WriteByteNum)
    . R& C" d, a0 ^) ?' f+ D2 z, d
  686. * 功能        :                        IIC写寄存器(可以写1个或者多个寄存器)
    ' y( c" s' N' D" h6 x. z5 D
  687. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要写入的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;: w9 m& H( i8 x4 C; e
  688.                                                 pDataBuff:写入的字节数据缓冲区;WriteByteNum:要写入的寄存器数量;$ ~# u( ?  J% \: i9 ~% X9 @& H
  689. * 返回        :                        IIC_ERROR
    6 D3 y8 }' M% T
  690. * 依赖        :                        底层宏定义" p5 ~3 T# C: I4 H  y
  691. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    3 K. n( x( B. K% p* V* t% G, c5 `
  692. * 时间        :                        2020-02-16& P! t8 U* t$ s* B
  693. * 最后修改时间 :         2020-02-16
    5 ]+ p. S; ^% G
  694. * 说明        :                         写入的数据都是小端模式,如果是16bit的寄存器,请写入偶数个数据,并且需要提前进行高低字节对调最后组成高字节在前的数据buff; e2 t; }$ }0 }- ?" @  }3 l' v; N
  695.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
      a, Z: t; N( ?/ U% R  }( u) u
  696.                                                 增加信号量# ]7 r4 N+ N' V4 l8 u  ~7 J
  697.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在
    7 j% w( j: d' [
  698.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。
    3 e1 T' d; n! \8 a1 c4 v
  699. *************************************************************************************************************************/4 E% R' L6 @- A# Q6 n7 j6 z; o
  700. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum)% Y/ L, e+ K! W+ ]" Q' s
  701. {, a2 o" b; d2 z" [) |
  702.         IIC_ERROR Error = IIC_OK;
    7 ?; a; W" G" l  y, ]% h
  703.         u16 ReadCount;
    0 z( k2 B$ S" Y5 b+ o9 \
  704.         IIC_HANDLE *pHandle;
    ' k: j0 W* v( a0 V
  705.         
    ) x# Q+ c- p4 v
  706.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || WriteByteNum == 0)3 n! h* H: z) Z  s$ a$ g  G1 g
  707.         {, A. Q0 _+ Z2 J& C* A5 t4 H/ y
  708.                 DEBUG("IIC错误:无效的参数\r\n");) P8 N6 M* @+ E- \. ?. h  ~% m8 s
  709.                 return IIC_PARAMETER_ERROR;
    0 s. P( V9 b" Y0 q1 _' l6 ]
  710.         }' x4 b. C0 m6 G6 |$ [3 y
  711.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄1 e. w5 R' b, k3 X6 k
  712.         
    " a) w% J* c$ b/ M$ B, q+ b
  713.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙
    3 C, m* I: u+ ~6 q0 z
  714.         {, e' D' \" r# f& i6 V
  715.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");
    2 }+ Z! M5 e  o7 S! |/ ^
  716.                 IIC_SoftReset(pHandle);
    * G* }3 U+ t' {+ E' @
  717.                
    ) z, c! u$ [) o3 E# Q3 t# y
  718.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)        //忙
    % t1 c7 I! C9 i, Z: c
  719.                 {2 a6 N# e$ n, `
  720.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");9 I8 @0 g4 t3 }
  721.                         Error = IIC_BUSY;; y4 z! _8 |  m" C7 m) {
  722.                         goto end_loop;
    ' q7 g" t2 n8 R( ~0 `: P
  723.                 }
    " x5 ], c4 s7 @+ I; A
  724.         }6 i" e0 B6 [. h" h' ^; w  z
  725.         # W# t: u. b& i3 f
  726.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态2 Y. t( W- F6 n0 S' {" N2 v' T
  727.         IIC_ClearCR2(pHandle);                                                //复位CR2寄存器
    0 C4 ?# D& T- \, m8 g- c6 C
  728.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START" L5 Q7 r$ X# ^% J* D) g
  729.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,FALSE,  pHandle->TimeOutUs);* j& }8 b+ R2 y  b. g6 U. F' Y
  730.         if(Error != IIC_OK)
    + W) j0 V1 L1 V& p
  731.         {5 V( L4 g3 a% f  _' I* I2 \
  732.                 goto end_loop;& O! z' x; n3 |, j! p
  733.         }
    ( R% @2 h* y% z5 d# m& x; `: G+ o# I
  734.         //发送后续数据
    ; a* ?7 S, D# u- }
  735.         if(WriteByteNum > 255)                        //如果超过255字节,则需要分多次写入-后续还有数据,需要重载
    4 X2 F% k4 @& N' M
  736.         {
    , M2 Q' D) D$ u/ L# K8 V
  737.                 ReadCount = 255;                        //本次需要写入的数据长度255
    : d2 w; v+ \- {# |+ v4 o
  738.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入               
      v9 H/ N& x: f* Q- T, `5 T
  739.         }6 B& a: P; ~" Q
  740.         else1 o& }- E4 ]$ n2 e& R. S8 V- `, f. S  e, s
  741.         {  K2 d2 `4 [2 e* O! N/ q" F
  742.                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯后自动结束
    ! I, d' U7 n( C8 [# i, x- d0 E! i
  743.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入$ z/ v. I( |9 [8 K% i7 ?
  744.         }
    % E3 V( A" b) _# P7 V" g
  745. 8 d+ [$ T: @6 Q; F! C5 R+ g5 b
  746.         //循环发送数据
    6 z; @& y: N9 d& K' M) E
  747.         do$ W% P4 w' c! {+ ]4 I2 l0 u
  748.         {
    $ b2 Q2 F8 p% A0 z. k. L
  749.                 Error = IIC_SendByte(pHandle, *pDataBuff, pHandle->TimeOutUs);        //发送一字节
    7 Y2 o* [6 W& n0 p3 P4 G1 N
  750.                 if(Error != IIC_OK)
    9 x' |# G- J/ m( Y' y* f: R9 @7 c
  751.                 {
    $ A, V1 f0 x/ J, U7 C* X  a4 \
  752.                         goto end_loop;% J$ b0 C- r5 j) |) M0 \
  753.                 }
    8 _5 U: O* J( k
  754. $ k8 r# y+ L  ^7 i: {2 }( j
  755.                 ReadCount --;9 t0 n9 R( O. Z* z( Y
  756.                 WriteByteNum --;$ H# Q* n; S, i
  757.                 pDataBuff ++;
    : A, q7 j% u7 q# a, f# P
  758.                 + F- U. r- C1 n* L3 d
  759.                 if((WriteByteNum > 0) && (ReadCount == 0))        //还有数据要读取' n- O! s$ _9 E1 W- U* i0 W
  760.                 {
    - Y9 A5 {, Q3 k/ [. g" J" J1 a
  761.                         if(WriteByteNum > 255)        //如果超过255字节,则需要分多次读取+ X8 g- ]3 ^1 p9 A
  762.                         {
    . V2 m8 U& }1 K) ?% M* \
  763.                                 ReadCount = 255;        //本次需要写入的数据长度255-后续还有数据,需要重载; R$ E, z. L7 l  ~1 V
  764.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入
    7 K/ ?) [7 `( l: u1 h+ L% }
  765.                         }
    6 m, D, I  Z- q5 c5 [! t+ t
  766.                         else9 v" S7 S, _8 E  a/ T) P, O7 @
  767.                         {/ ?. c1 h' t. T7 O. O' U6 n
  768.                                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯,自动结束, N% H0 M: N! i( Y/ A! q
  769.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入                3 J2 A3 C0 W& S# k/ X
  770.                         }
    # @: X; y* a: k
  771.                 }# l$ L' V7 r/ A% J6 T
  772.         }while(WriteByteNum);        
    # a. Z+ g2 i6 M. a

  773. 4 Z$ [2 @) V' J) G/ L
  774.         //写入完成了,等待STOP位有效
    & @' `) R+ ]" c7 ~& C% g
  775.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);
    3 ^9 Z4 g& ?: t2 F. a. D& @
  776.         if(Error != IIC_OK) 4 p2 ^0 \9 {9 }  G2 Q$ m/ }/ ~5 ]
  777.         {
    % |* Q! w5 L" K5 |
  778.                 Error = IIC_STOP_ERROR;& ?  d* v' \8 M0 @8 X
  779.                 goto end_loop;( j4 r" [. e4 D1 z' X" a
  780.         }  B/ L/ Q. ?% @* E! U! i1 f( h
  781.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态) f+ L3 L6 d3 F  c
  782.         : O8 z- H8 s; s! k: v
  783. end_loop:        
    % j& g: V5 W7 ?. r5 p: ?( ~: \4 R  R
  784.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        " j4 F9 Q/ n1 k/ g
  785.         if(Error != IIC_OK)
    8 |4 Y8 _1 r+ b' R8 Q0 x
  786.         {: H% N7 z4 P% f& E8 ]+ }% G
  787.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误
    / _7 a1 ^. `5 \8 H0 `
  788.                 DEBUG("[IIC W错误]:%d\r\n", Error);, N( p4 M; ?1 c# F
  789.         }
    4 W1 X! W* s5 d  q' E6 u8 ]" o- ~
  790.         
    6 k& f% J" t! m: T- ^9 H
  791.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的9 X+ T- Y/ u$ h5 q8 x
  792.         {
    1 L( C# r! t) R$ H* f
  793.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线! ]4 H$ _7 m& B* l4 a
  794.                 DEBUG("IIC W结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);               
    + d1 }3 k5 Z2 t; k& M  y% R( ^
  795.         }- J- e# S4 F: @  ~% ^
  796.         return Error;5 i3 _: ]& P1 Y  d) u; c
  797. }
    : M( c. ]2 i# d

  798. . o& t9 Y, H# Q# Q

  799. * ~7 f3 N. W5 g/ ?8 z/ @
  800. /*************************************************************************************************************************+ K( C$ C; {# ]+ T3 i! J
  801. * 函数                        :        void IIC_SoftReset(IIC_HANDLE *pHandle)
    5 s/ e! W7 Q& @% G( A, U3 `
  802. * 功能                        :        硬件IIC软复位(会使能IIC)
      }" q( j) \, q7 l  N3 R, r
  803. * 参数                        :        ch:IIC通道
    3 C5 m% |% }( i; }7 o
  804. * 返回                        :        IIC_ERROR1 t  R- ^$ U1 @  S& }# M3 z6 q0 D
  805. * 依赖                        :        底层宏定义) @0 Q3 u/ Y* v+ J8 C% T
  806. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>  o4 t$ o4 X0 T% `, h9 F
  807. * 时间                        :        2020-02-15
    6 G# o& S+ G' J* h1 \; M
  808. * 最后修改时间         :         2020-02-15
    1 T1 `9 Z% ^3 I+ C% r; V
  809. * 说明                        :         IIC软复位;必须使 PE 保持低电平持续至少 3 个 APB 时钟周期,才能成功执行软件复位。' l% R: Y3 s9 l. J1 D, z% ^! k) u
  810. *************************************************************************************************************************/4 O& x/ K- l7 W4 t/ r) ]  g& t1 w& m
  811. static void IIC_SoftReset(IIC_HANDLE *pHandle)
    & ^# h1 Z5 W4 f( q8 X& |- t0 y
  812. {5 T* {- ^3 l, s2 T2 M
  813.         pHandle->I2Cx->CR1 &= ~BIT0;                //关闭IIC后执行软复位
    ) [/ Z% O, B& q5 @& O
  814.         Delay_US(1);        8 c1 `3 r: U5 k" f* ~8 z, D
  815.         if(pHandle->I2Cx->CR1 & BIT0)
    - x7 `3 _0 I2 z5 ^' g- z
  816.         {
    2 G+ `0 A: C5 I
  817.                 DEBUG("IIC软复位失败\r\n");0 u! O# r( x1 s$ l: N0 [, ]/ s
  818.         }
    * `+ t/ F$ r6 }- ?6 z
  819.         pHandle->I2Cx->CR1 |= BIT0;                        //重新启动( s+ l5 d7 {5 y
  820.         Delay_US(1);        ; o3 `$ I$ l- v/ }" A
  821. }3 p/ R, A/ y# B  |7 M2 o
  822. 3 ^2 }; ^( h5 I0 t4 T/ O) a; i% |! E
  823. / `) x4 y( l! O' c+ ^
  824.   P/ J3 s; n: z5 G+ t& E  j4 |: J
  825. /*************************************************************************************************************************; E: K% W8 `5 V2 `
  826. * 函数                        :        static u32 IIC_CalculationTiming(u16 Speed_KHz)
    + Z% o% j/ N4 e
  827. * 功能                        :        硬件IIC时序计算& p. i8 _  ^9 L: S: c
  828. * 参数                        :        ch:IIC通道;Speed_KHz:速度10-1000$ J/ W4 d, f9 y& q2 U. k9 L
  829. * 返回                        :        IIC_ERROR) [' B9 [, c, H# r. m
  830. * 依赖                        :        底层宏定义
    9 ^3 k: F' P7 L
  831. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>7 h8 f, A5 D9 {, [/ Z
  832. * 时间                        :        2020-02-15
    : C% N% u! G) X1 o+ u2 C5 T, m
  833. * 最后修改时间         :         2020-02-15
    ' ]& h4 P. A+ d$ D3 E& n
  834. * 说明                        :         IIC使用的是APB1时钟,将IIC总线时钟控制在100KHz        ! C" h) q6 S" \
  835.                                         APB1时钟:最大不能超过45MHz        
    0 P9 _) l& z# C5 @7 a+ h: ^1 F
  836.                                         如果速度是100,则按照SMBUS时序
    / d) |8 H; e7 g/ T5 K
  837. *************************************************************************************************************************/4 a8 ?! O: m0 g" |3 L* M( k! _
  838. static u32 IIC_CalculationTiming(u16 Speed_KHz)
    3 P* B/ j1 [% P6 ~( O/ w, j
  839. {5 ^! R' u  i5 s- b9 j
  840.         u32 tTime = 0;, I0 x# |# t0 Z% W$ b: {. i3 W
  841.         u32 temp;  ^1 `4 t' d+ S7 `
  842.         u32 time_temp = SYS_GetAPB1ClockSpeed() / 1000000;                //先获取APB1时钟速度
    9 B% S2 N; a: o7 n
  843.         u32 Th = 1000/Speed_KHz/2;                                                                //计算高电平时间(低电平时间一样),单位ns- y+ U& Q% G' g& v; I) I6 L
  844.         * S$ B+ ?2 x9 M) W, F6 q% N+ w: S% M
  845.         if(time_temp < 20) time_temp = 20;+ a2 T7 S  S% D
  846.         time_temp = 1*1000 / time_temp;                                                        //单位ns6 V' K$ k& |) |- \# t) @- T3 |
  847.         uart_printf("IIC时钟计算->APB1周期:%dns\t", time_temp);
    4 c4 u0 p: i8 A" w
  848.         if(Speed_KHz == 100)        //如果是100,则按照SMBUS时序2 s6 V; Q& c0 o: g) K( u+ ^% c$ H
  849.         {1 {9 W( F2 A' c
  850.                 //主时钟分频系数固定为3' m* v& }, G2 D: o' D1 W# b
  851.                 time_temp *= 3;                        //主时钟周期
    $ V5 P: Y. ~* M7 A
  852.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    ( h% e7 J' n% _; c6 j8 T6 d
  853.                 tTime |= (3-1) << 28;        //PRESC,时钟预分配
    . w' B9 s. q/ k" x# O
  854.                 //计算数据建立时间,要求最小250ns
    4 {- [5 G/ J& a" y0 U
  855.                 temp = 250 / time_temp;( t2 j, _* \. |6 V, L
  856.                 if(temp > 15) temp = 15;! m7 W0 B: X7 j
  857.                 if(temp < 1) temp = 1;5 w4 h& k) x8 B6 V) j" Y6 n4 l
  858.                 tTime |= temp << 20;
    , d7 u* Q, @" e3 N# [
  859.                 //计算数据保持时间,要求至少300ns( p+ X- R! V; h3 Z- x8 \2 I
  860.                 temp = 300 / time_temp;  {$ u0 _" U. l) }2 `
  861.                 if(temp > 15) temp = 15;6 Z1 ^: x4 U) P3 [, X
  862.                 if(temp < 1) temp = 1;" Y7 N0 S7 [; z' Y1 a, Q1 U
  863.                 tTime |= temp << 16;4 k2 U& K( d, @. \. @' F- u% Y
  864.                 //计算高电平周期5us$ z, o( |% N9 {
  865.                 temp = 5*1000 / time_temp;
    + B& V0 A7 \' \" t- X) m
  866.                 if(temp > 255) temp = 255;1 w5 x8 h1 r. Z  U2 r- J1 H
  867.                 if(temp < 1) temp = 1;
    5 h, K9 C) K, x  B. Z, {
  868.                 tTime |= temp << 8;
    9 j1 r" @% i3 h$ c' o: V
  869.                 //计算低电平周期5us7 g  _- |7 Z, H2 k/ l( ^! F
  870.                 temp = 5*1000 / time_temp;4 U2 u7 K) A5 Y' U( a( R) j; N
  871.                 if(temp > 255) temp = 255;; M' m! k5 q+ J; N* l. V
  872.                 if(temp < 1) temp = 1;. l2 F" I4 d8 O* L
  873.                 tTime |= temp << 0;5 f* t" |( n: @- z  Q
  874.         }
    6 v) m) V" V# [7 d+ P5 P
  875.         else if(Speed_KHz < 100)
    ! H' R# n2 A& K4 Z! E4 d
  876.         {  {; Q2 B/ x4 {) _: {
  877.                 //主时钟分频系数固定为6
    4 j5 W2 a  s" Y  u
  878.                 time_temp *= 6;                        //主时钟周期
    1 e/ B! @7 U% x3 f$ o' y
  879.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    % E5 y0 _1 K. e  N3 l$ ^
  880.                 tTime |= (6-1) << 28;        //PRESC,时钟预分配, b& B/ t( f2 u2 l  V$ `# F, v
  881.                 //计算数据建立时间,要求最小250ns, ?/ e/ ^, D( C9 f7 V! s( T
  882.                 temp = 250 / time_temp;
    & P/ D! P" K4 f4 i$ G9 j
  883.                 if(temp > 15) temp = 15;
    7 y/ V2 y. D3 T+ @
  884.                 tTime |= temp << 20;( F, D( p! A; {8 S& J+ P
  885.                 //计算数据保持时间,要求至少300ns
    2 n8 h) u4 P% V1 d6 w& A! c6 Z- c
  886.                 temp = 300 / time_temp;
    9 k+ o+ Z# B0 q  O. X2 [3 F( L+ W
  887.                 if(temp > 15) temp = 15;
    8 ?8 ?7 ]7 t& |0 a4 L  A) Z
  888.                 tTime |= temp << 16;0 o! _( I* t* T4 h; y8 i7 h: U
  889.                 //计算高电平周期Th us4 P5 S$ [# d8 ]8 \2 q
  890.                 temp = Th*1000 / time_temp;) y2 c% P, `0 y2 L+ y' W
  891.                 if(temp > 255) temp = 255;
    4 j+ g0 a7 e( R- W5 H
  892.                 if(temp < 1) temp = 1;- Z6 q0 _4 A& r5 J" `
  893.                 tTime |= temp << 8;
    8 F# T3 P, q" s
  894.                 //计算低电平周期 Th us- w7 I$ Z0 }2 Z
  895.                 temp = Th*1000 / time_temp;4 h) f& p  x0 O8 T& R
  896.                 if(temp > 255) temp = 255;
    9 ?. \( L9 `: _( S4 P
  897.                 if(temp < 1) temp = 1;- j4 w' D6 E4 y/ s# X
  898.                 tTime |= temp << 0;
    ) q$ G. m. g6 }7 s' {
  899.         }' h0 k6 u, ?" E  F
  900.         else //>1005 X  \' y0 m, w# f
  901.         {
    2 j+ s0 T! j& U& @* ^
  902.                 //主时钟分频系数固定为2
    ; x: E1 B1 }6 O
  903.                 time_temp *= 2;                        //主时钟周期7 ?  A8 x: u" Q* s% O& i& O
  904.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    / e- J: W6 G/ E! w* r' r. h
  905.                 tTime |= (2-1) << 28;        //PRESC,时钟预分配
    - b6 w( P' p3 N; t; M5 ?
  906.                 //计算数据建立时间,随便给100ns
    7 N  z6 I' k- f3 D; O( U- F
  907.                 temp = 100 / time_temp;; k. r+ c7 _2 o, H2 E
  908.                 if(temp > 15) temp = 15;
    0 m5 Y: O3 L3 Z' u+ P# K  G
  909.                 tTime |= temp << 20;
    3 R9 P9 T/ [& l7 S
  910.                 //计算数据保持时间,给100ns) c% M" P' F! y8 n
  911.                 temp = 100 / time_temp;; }5 y2 j2 m) _" T# N6 p0 H
  912.                 if(temp > 15) temp = 15;
    2 ^9 a9 q& X! J" R1 Y& O
  913.                 tTime |= temp << 16;
    6 g+ [* j1 p5 O* @: j; @
  914.                 //计算高电平周期Th us' C8 D6 P6 w3 S' T5 h: [$ Y, n" c5 j. U
  915.                 temp = Th*1000 / time_temp;
    1 c% H! N- v; u2 u
  916.                 if(temp > 255) temp = 255;4 B. O' V8 R- z3 g; W7 I, D7 U
  917.                 if(temp < 1) temp = 1;; w+ t4 D( R; h& h* N+ K7 a
  918.                 tTime |= temp << 8;
    / T$ e7 w% r3 Y- M- j- [: O2 P
  919.                 //计算低电平周期 Th us
    0 y0 l  C' U8 t$ x7 m% H1 X
  920.                 temp = Th*1000 / time_temp;
    6 c* g" y. m; @* O- _! O. L9 P8 ?
  921.                 if(temp > 255) temp = 255;
    3 x: L* ~% w/ A
  922.                 if(temp < 1) temp = 1;
    * w- G, h* r+ a9 {3 {
  923.                 tTime |= temp << 0;+ j" C# B% Z! s1 K$ M' U
  924.         }
    $ J4 U  P. D" r8 }
  925.         
    . G4 @8 }7 S9 r5 A* @$ C+ |2 K
  926.         uart_printf("时序寄存器结果为:0x%X\r\n", tTime);; b5 A4 w5 ^) Y
  927.         
    9 ?/ j0 r: [- ?5 l/ Y
  928.         return tTime;
    4 }% y! R4 v/ o! N% Y0 x
  929. }
复制代码

7 i/ i; d) ^& D& h$ ?4 x9 p9 @7 ]; v6 f$ t8 B: v! J& ]
  1. /*************************************************************************************************************
    ! z. t8 y. k( ?+ e* c# T/ J2 i) w$ b" V% G
  2. * 文件名                :        stm32f7_iic.h
    4 N+ k/ q7 a; B7 L4 Z" k+ o% c( \
  3. * 功能                        :        STM32F7 IIC接口驱动
    4 z1 _& e& q3 V# j8 R# V; s; N9 q# e
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    5 J! ~( m% T! l2 B% B2 d* a) H
  5. * 创建时间                :        2020-02-09
    . b! X- B! {# Q
  6. * 最后修改时间        :        2020-02-09
    + x, c8 ?; [  D) a3 n* Q
  7. * 详细:                        ! b9 G9 ~0 H, A6 E6 X
  8. *************************************************************************************************************/               
    ( E; _8 e) z: H, ]  v
  9. #ifndef __STM32F7_IIC_H_
    3 ?; I. A; U9 t
  10. #define __STM32F7_IIC_H_: ^% c, u# L7 ?9 ?- m+ t
  11. #include "system.h" 3 S' u3 \8 h/ g, {8 E

  12. - j/ K4 P& A7 h
  13. //16位整形数高低对调
    & L1 P5 Z# b, Y- H: p1 p
  14. #ifndef SWAP16
    3 q( a8 B) ]* u2 C) n$ N; v$ ?" U
  15. #define SWAP16(x)   (((x & 0xff00) >> 8) | ((x & 0xff) << 8))# k! h! f2 M9 `/ H
  16. #endif  //SWAP16; D- I$ V) y2 y0 a
  17. % J2 L/ S$ H1 P$ _- C. r
  18. //硬件IO口选择
    - h7 C+ A# L# r: C0 {" k- p
  19. //I2C1 IO定义与选择
    5 G+ }3 ~: J$ [$ c% J! L
  20. #define IIC_CH1_PB6_7                                0                                        //PB6,PB7" s* d9 P, y3 a7 {" K0 }2 d
  21. #define IIC_CH1_PB8_9                                1                                        //PB8,PB9) A* T& @7 F8 J1 Q# V' S
  22. #define IIC_CH1_IO_SELECT                        IIC_CH1_PB6_7                //选择I2C1 的IO        0 u2 T* o, a7 V$ M# x) T1 M2 f
  23. / V' [" N6 u( |
  24. //I2C2 IO定义与选择
    - }& ^( G; u) H5 l1 g$ r
  25. #define IIC_CH2_PB10_11                                0                                        //PB10,PB11
    8 ?; j7 j, ?& s# h
  26. #define IIC_CH2_PF0_1                                1                                        //PF0,PF1
    6 A8 K/ w6 Q0 g% Y
  27. #define IIC_CH2_PH4_5                                2                                        //PH4,PH57 i; p/ n, g/ f+ i7 \
  28. #define IIC_CH2_IO_SELECT                        IIC_CH2_PB10_11                //选择I2C2 的IO
    8 ?0 d3 p+ \( Z5 l. g# z/ N
  29. ) u2 D8 Y0 p: h& L4 T- B  e) L) G
  30. //I2C3 IO定义与选择8 _1 r) Q; R  X( y. `* @# h* o
  31. #define IIC_CH3_PH7_8                                0                                        //PH7,PH8- r4 E! I: \. U" y4 T. i
  32. #define IIC_CH3_PA8_PC9                                1                                        //PA8,PC9
    / V$ J0 E" n: \' `+ ^  V. {6 o" `% t
  33. #define IIC_CH3_IO_SELECT                        IIC_CH3_PH7_8                //选择I2C3 的IO
    & {# {* \$ m) m5 D
  34. 0 [& ]9 f; B% z7 h) s( n8 z
  35. //I2C4 IO定义与选择
    6 c6 A) J% h6 [/ j  r# ?! @
  36. #define IIC_CH4_PD12_13                                0                                        //PD12,PD13
    1 r, \8 G% _& m- t( E& {) _  P
  37. #define IIC_CH4_PF14_15                                1                                        //PF14,PF15
    7 [& v7 }6 J  v4 @: K
  38. #define IIC_CH4_PH11_12                                2                                        //PH11,PH12
    9 N0 L2 G! ~# r  b) c
  39. #define IIC_CH4_IO_SELECT                        IIC_CH4_PD12_13                //选择I2C4 的IO
    ( j4 J' O" H- u$ |+ M
  40. : T8 |9 s( J* G) b% T& X7 s8 N
  41. //IIC硬件接口选择5 c; y) `* ~) u9 O- p
  42. typedef enum
    7 {8 P* a% v" c4 Z" h
  43. {# e, B8 p3 a( B0 @
  44.         IIC_CH1        =                0,        //IIC1% Y* V. N" q/ h; p
  45.         IIC_CH2        =                1,        //IIC24 I# ?' R; z/ V9 V/ F( n
  46.         IIC_CH3        =                2,        //IIC3" u( X/ ?1 J8 P4 y* @! P
  47.         IIC_CH4        =                3,        //IIC4% L8 A2 P( q: F" I
  48. }IIC_CH_Type;
    : Q; o* c4 o  k4 F, e  J9 B
  49. #define IIC_CH_COUNT        4        //4个IIC
    % P+ V  B! K' A9 f' C) |+ \

  50. - i2 T) c7 I: M6 K

  51. : x8 Q% V% U0 \2 N
  52. //中断状态
    - x  a5 A$ _- D! K& v# ~
  53. #define IIC_FLAG_TXE                    BIT0        //发送数据寄存器为空(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。& Z! b: X/ ~  S, H, S) |
  54. #define IIC_FLAG_TXIS                   BIT1        //发送中断状态(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1,待发送的数据必须写入 I2C_TXDR 寄存器。
    2 B% t( R5 _! }0 e
  55. #define IIC_FLAG_RXNE                   BIT2        //接收数据寄存器不为空(接收器); 当接收到的数据已复制到 I2C_RXDR 寄存器且准备就绪可供读取时,该位由硬件置 1。读取I2C_RXDR 时,将清零该位。& V; J* K; L3 S# k% R4 z
  56. #define IIC_FLAG_ADDR                   BIT3        //地址匹配(从模式); 接收到的地址与使能的从设备地址之一匹配时,该位由硬件置 1。该位由软件清零,方法是将ADDRCF 位置 1。3 s! {& V7 D4 [" J& D5 \  A9 K& F
  57. #define IIC_FLAG_NACKF                  BIT4        //接收到否定应答标志; 传输完字节后接收到 NACK 时,该标志由硬件置 1。该标志由软件清零,方法是将 NACKCF位置 1。8 y) i) o" p$ `+ j
  58. #define IIC_FLAG_STOPF                  BIT5        //停止位检测标志; 当在总线上检测到停止位,且外设也参与本次传输时,该标志由硬件置 1- d/ G* {' g4 d+ _
  59. #define IIC_FLAG_TC                     BIT6        //传输完成(主模式); 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 START位或 STOP 位置 1 时,该标志由软件清零。! n: Q3 s8 m9 l0 r/ e! [0 v. V; s2 z
  60. #define IIC_FLAG_TCR                    BIT7        //传输完成等待重载; 当 RELOAD=1 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 NBYTES 写入一个非零值时,该标志由软件清零。% m; `5 B7 G" }# i  T$ H: O
  61. #define IIC_FLAG_BERR                   BIT8        //总线错误; 当检测到错位的起始位或停止位,而外设也参与传输时,该标志由硬件置 1。在从模式下的地址阶段,该标志不会置 1。该标志由软件清零,方法是将 BERRCF 位置 1。
    4 D  ?5 A% a: k
  62. #define IIC_FLAG_ARLO                   BIT9        //仲裁丢失; 发生仲裁丢失时,该标志由硬件置 1。该标志由软件清零,方法是将 ARLOCF 位置 1。  Z! T' s8 M- Q& s7 ~2 h: a9 t+ T
  63. #define IIC_FLAG_OVR                    BIT10        //上溢/下溢(从模式); 在从模式下且 NOSTRETCH=1 时,如果发生上溢/下溢错误,该标志由硬件置 1。该标志由软件清零,方法是将 OVRCF 位置 1。" {: J5 W3 p$ r
  64. #define IIC_FLAG_PECERR                 BIT11        //接收期间的 PEC 错误; 当接收到的 PEC 与 PEC 寄存器的内容不匹配时,该标志由硬件置 1。接收到错误的 PEC 后,将自动发送 NACK。该标志由软件清零,方法是将 PECCF 位置 1。% [% l6 i' S* w$ {$ m
  65. #define IIC_FLAG_TIMEOUT                BIT12        //超时或 tLOW 检测标志; 发生超时或延长时钟超时时,该标志由硬件置 1。该位由软件清零,方法是将 TIMEOUTCF 位置 1。
    ( A. X3 d, n( ^- k
  66. #define IIC_FLAG_ALERT                  BIT13        //SMBus 报警; 当 SMBHEN=1(SMBus 主机配置)、ALERTEN=1 且在 SMBA 引脚上检测到 SMBALERT 事件(下降沿)时,该标志由硬件置 1。该位由软件清零,方法是将 ALERTCF 位置 1。; H7 r. n5 _" z% R
  67. #define IIC_FLAG_BUSY                   BIT15        //总线繁忙; 该标志用于指示总线上正在进行通信。当检测到起始位时,该位由硬件置 1。当检测到停止位或 PE = 0 时,该位由硬件清零。" k$ O% J, U! _
  68. #define IIC_FLAG_DIR                    BIT16        //传输方向(从模式); 该标志在发生地址匹配事件时 (ADDR=1) 更新。;0:写;1:读; i' r- [, e* R

  69. 7 D' P! @3 k; h! x6 Y5 W
  70. //通讯错误状态2 v( Q: }' p. s! o$ K. O, s& |  g
  71. typedef enum
    1 H! t+ Y" H. V3 ^
  72. {
    - n: s( e9 M3 v7 c( Z" m
  73.         IIC_OK                                        =        0,        //没有错误
    , c7 q! E- _! D
  74.         IIC_PARAMETER_ERROR                =        1,        //参数错误
    5 s; ]$ W2 P9 Y. V/ F! H
  75.         IIC_TIMEOUT                                =        2,        //超时错误,也可能是底层错误
    1 o; P7 ?" ^* g, w. `. G
  76.         IIC_HAL_ERROR                        =        3,        //底层错误
    % [5 V* l, T# d5 `  k& z
  77.         IIC_STOP_ERROR                        =        4,        //等待结束错误8 }8 f' c" u2 d% O8 D" n
  78.         IIC_BUSY                                =        5,        //硬件忙
    & T; J$ x- N, G
  79.         IIC_NACK                                =        6,        //收到NACK了
    2 Z8 I% k6 X. C; M: l  u/ N
  80. }IIC_ERROR;
    8 X; ^8 H1 y: I- _! l3 H7 h
  81. 7 q% ^, v* ?" O; Q8 G/ O
  82. 2 r( b8 P  Z2 x/ ~  _
  83. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs);        //硬件IIC初始化# A; R. y8 y0 B8 D# I+ ~5 a2 c
  84. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum);        //IIC读取寄存器(可以读取1个或者多个寄存器)4 }  [8 g! c" I$ T" W
  85. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum);        //IIC写寄存器(可以写1个或者多个寄存器)" t2 W3 L( U" X" _

  86. 2 O. Y( X# n: \0 L7 K8 \

  87. 8 Z& x$ }2 D' @3 _. I! ~6 I, f+ q( V" _7 {
  88. #endif //__STM32F7_IIC_H_
复制代码
% i3 S4 W2 o( k/ [
$ f$ o) Z3 F% D& R
//初始化/ p6 \5 s- n0 U5 u: b, \) J% G
, }; f% l2 v( X/ J/ |$ ?& e9 Y
  1. IIC_Init(IIC_CH3, 200, 0);        //硬件IIC初始化
复制代码
" z* N9 b# B( t4 g: e( l4 J

: a- b8 Z; R2 a3 b; M5 _" \" ?# K! A//调用9 L$ e7 v* m) g8 o# @. J

  1. 0 ]; B1 o" H8 \  G+ S
  2. //触摸屏IIC读取寄存器接口3 N# n6 w9 j9 x- v# D
  3. bool TP_FT5336_IIC_ReadReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)
    , \2 e: o5 d, W6 o# w2 V/ t
  4. {1 e# Q1 H$ D$ k6 r7 {+ ?9 w" W
  5.         if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)
    - n" P! s& }1 V% b) f5 I- C" o1 r
  6.         {% o7 B; C- \- m2 H7 E8 y
  7.                 return TRUE;
    + s6 E- @& ?4 ]* @
  8.         }
    1 ~9 C* H' f  e  g! x
  9.         else
    / T: C! i* k0 @! _: I; L0 J
  10.         {
    ) y/ f( }% B1 ?/ l& \5 f4 W
  11.                 return FALSE;
    ; {8 {3 e8 z2 z! i3 r3 m8 f% t$ C, {
  12.         }
    5 Y2 U5 d8 F9 B# [, [0 ^& H% v6 Q
  13. }
    ' B4 j& H+ _2 l' F/ b; P2 ~
  14. / l/ b8 u5 g1 k1 y2 f! C
  15. //触摸屏IIC写寄存器接口# ^( [3 O! Q6 C6 E) |/ Z
  16. bool TP_FT5336_IIC_WriteReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)
    6 g/ W- U$ C2 \, n
  17. {8 \: z6 L2 `7 S* y  O# [9 d
  18.         if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)6 Q3 T- J' |) X2 z# B
  19.         {$ T6 }4 K1 E2 N6 x; F
  20.                 return TRUE;' l4 u, p* Z. P* Y9 i  b
  21.         }
    8 \1 ?% Y; I! f8 t( n0 y
  22.         else; I5 I3 {4 N( ~' S8 u
  23.         {% x; B! c% z% \
  24.                 return FALSE;  K: p9 @6 o7 i0 K
  25.         }$ H2 X2 b# s& g! |+ j+ J" X- ]

  26.   o8 ?! ?/ W8 C; s$ y
复制代码

  E/ i6 u) p+ r% c6 m
  R% }* ~9 `& z2 v- \) ^1 c' m3 X% @$ s! \, N4 F6 P: K
收藏 评论0 发布时间:2021-12-11 12:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版