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

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

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
目前只实现了主设备模式,一般也只用到主设备模式,IIC如果不能使用硬件方式,读取大量数据的时候效率很大,由于只有1个字节的缓冲区,根本不能使用中断模式(实际使用过程中,IIC会造成100us以内间隔的中断,单片机根本扛不住的),所以建议数据少就直接阻塞,1个字节也就几十us,数据多直接用DMA,将线程阻塞,等待DMA传输完成,而不会阻塞CPU(上传的代码没有实现DMA部分,便于理解)。
& F' Q. o  Q5 ]0 y5 t1 M  D
* X* C* G0 `0 D7 W( ~1 {% I3 N目前已经做了完善的错误处理,读写操作前都会清除中断,遇到错误会软复位,所有位置均做了超时处理,防止程序卡死,目前只测试了几个字节的读写,大量的,长时间的读写均表现稳定,目前手上开发板没有eeprom,无法做大数据的连续读写,如果你在使用过程中遇到问题,欢迎指正。  {+ m/ [3 |5 D/ w

# e- ~( ^2 P8 J下面是IIC读写的时序例子,可以先熟悉一下,这样比较容易上手,哪一个环节出了问题也要调试。
5 B9 d- ]7 f. @* J! \6 u; u
: }0 M1 N9 E  w& V* A+ I2 d
20200216194202434.png

& G* P0 ^, k; B& z% T' n3 f: v" P! R7 j5 D/ z
20200216194219185.png
9 u  p# V4 m# [* b- I. S) E, K

6 b  w$ D" X1 \
20200216194234908.png
' h& u7 Z, X! z% B1 L
  t. e  a6 M9 z; ^3 x
* ~; [; U# }& N* ?
下面简要说明一下STM32F7硬件IIC的驱动设计方式(建议先百度学习一下IIC的时序要求):
6 R. X0 B: w% u( z5 o: I& v) _1 a1 a8 B4 ]! A7 d2 x3 w2 @7 }* I. Z
[基本的初始化]
  z% A5 F! \- W$ G5 ^5 _3 \; r1 O5 y  r' D4 \$ H8 _
1.初始化IIC时钟,IO(IIC IO必须设置为复用开漏输出,这个很重要)。0 b' U7 d2 a( Y1 n/ R$ e% V
; G; e: @% h! c2 l4 _6 z
2.CR1先赋值为0,复位IIC.
6 a# Y! ^4 D' ~! }( s1 u, j3 x. [# H; D/ r" h3 ~  o) T
3.除了TIMINGR寄存器需要自己计算设置好,其余寄存器全部复位为09 b) g" x2 O4 t

% Y8 i! \1 k1 H) P7 F5 a4.设置CR1使能IIC。
8 @' w, u8 x4 Z& n1 I: e" j( p3 \
4 I+ q( R. M! S4 k$ l注意:上面说到,IIC的IO必须初始化为复用开漏输出,我之前初始化为复用推挽输出,测试很久,只要一启动传输,就会立马收到NACK,然后是STOP中断,数据根本没法发送,弄了好久才发现是这个IO初始化的问题。5 ~# g( ^- w0 K; o, o3 Y, s% o
! u0 G; Y( c* `  N

, |3 i0 V* Q: _) ~  J/ D* ~
, n8 ~! A; E) D* `2 m7 b[读取]! j/ M0 x+ l9 u8 S
$ h# z, ~# I, H7 b) A5 o6 b
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。
, k5 }) t+ J0 Z% m1 \; i! D' v
+ T- R, @2 W; C9 H6 ~2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)软件STOP,写模式,启动传输。
0 g( r8 D1 T) v" @& N& k! G. g! }, K9 f$ h2 q. z9 \0 V0 X
3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
% G( p- u# ^; d8 @- y) H  p& D* \1 f* j& A5 \3 p7 M6 M- ^# [! q
4.等待TC置位,意味着上面的1-2字节的寄存器地址以及写完成了。
+ M* Z' M# U( a! U! L4 k! J
$ Y0 b9 d# H/ ]3 b5.根据要读取的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。9 n: \$ n$ O# W1 K& S5 A
6 L0 \4 I6 W% }6 L, y' Q' w
6.设置了从机地址,要读取的数据长度,之后设置方向为读取,然后启动START(从写切换到读要重新发送START,这个跟软件模拟是一模一样的)。
- C$ d4 u5 Y2 T  a! E  o" @+ D* W' W# v# L
7.循环一个字节一个字节的读取数据,字节读取需要等待RXNE有效,只有读取RXDN寄存器,直到所有数据读取完成。
7 B! B9 M0 z, ]( m& s2 |, Y% m" S
8.读取完成后等待STOP有效,因为前面在最后一包数据读取的时候使能了自动STOP,这个时候检查STOP是否生成。0 e& e9 x" G6 R6 y. N( J# W* `( q

$ k$ v6 E" p! ^2 E9.需要注意的是,所有的操作都要给超时,并且是自己可控的,绝对不要有死循环,之所以一直说STM32的IIC死机很大程度上都是由于这个地方没有涉及好,我的程序设计方法是:一旦出现了异常,就复位IIC,如果不复位就会导致下次进去的时候IIC一直忙,因为还处于上一个通讯过程。4 O$ j% V, D% w& o- u; ~
7 c2 g- O- S# w5 L/ X! f3 @, O3 t3 k) k
7 h) E9 z9 Z* r" }! D5 J, ]; ^2 |
+ X" \% R, d% Q. M: b. l
[写入]
* u" l% M; }1 \+ Y6 @4 F% D/ f7 M- y3 K, x3 b) ^$ d9 V* h% d
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。2 V! v3 \5 P; V

, z! N* x! \3 z+ F- L2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)自动重载,写模式,启动传输。
' I2 a: k! M  Z4 i
5 C* U" L5 P" P2 J" i1 Q: |( ~3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。7 k' Y+ t6 N& @8 Y0 @

7 K! }% a0 e% V9 M9 ~4.等待TCR置位,意味着上面的1-2字节的寄存器地址以及写完成了,已经发生重载了,后续可以继续写入数据了。
( ^- |& _' G, l- w
& q% Q0 Q! O' T) B7 w' X5.根据要写入的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。
8 K# j  L+ k) Q( A9 Y/ a+ g* P
5 n/ L0 ?; o3 N) G  z3 z+ T6.设置了从机地址,要写入的数据长度,之后不用切换方向,不用启动START(都是写,不用重复发送START,这个与读取有区别)。
0 P+ ^  o, t* X
4 b1 d* _/ u# q: F7.循环一个字节一个字节的写入,字节写入与步骤3一样,等待TXIS置位,就可以写入数据到TXDR。
- j4 ]- `( o2 @, m6 y, N5 P: v; L! |" m* x$ u
8.等待STOP有效,因为前面在最后一包数据写入的时候使能了自动STOP,这个时候检查STOP是否生成。
/ g* n( f& }1 i$ T# E3 j& o: [
) `# h4 V! m8 C( K9.需要注意的是,所有的操作都要给超时,跟读取一样。
9 Q- ^1 f! F( D" l6 \; G) u: d) B- V( U! t* d& x" Z2 D& q1 [

3 ]: r2 T$ _0 o+ y
* f+ W' j1 d8 G. }, L9 v) x0 O" ?4 A; d注意:IIC的读取实际很短,超时也不用给很长,以标准的100KHz通讯时钟速度,一个字节大概在90us左右,超时可以给个5-10B时间,也就是450-900us左右。9 I. E" m- S; M" t# \) _  z4 A

5 C# X2 x* r$ A
9 m4 v, t3 Z- Z3 X7 m( Y0 f4 G1 L; W/ h! _* L
好了说了这么多,具体的看代码中的注释,直接上代码(我只测试过I2C3,其余的理论上都是一样的,就是IO初始化部分有区别,别的通道没有硬件进行测试)  s; @+ u7 I. Z, o5 I

, x8 A5 r7 F5 ~" H  o
  1. /*************************************************************************************************************
    9 a  @/ m/ X5 P; z
  2. * 文件名                :        stm32f7_iic.c
    2 J7 m, G3 r% q( n  a! Z2 X7 k
  3. * 功能                        :        STM32F7 IIC接口驱动2 \( K7 c; r! H* Z& t
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ! B8 f$ c9 `% D3 D9 @
  5. * 创建时间                :        2020-02-09' T3 S# @6 X6 m; f8 V
  6. * 最后修改时间        :        2020-02-09! g0 P1 I0 ~4 ?0 c8 q+ s
  7. * 详细:                        只支持主机模式,7bit地址,默认APB1为IIC提供时钟
    ( I7 W8 i! l% p' o5 ~- T/ f
  8.                                         涉及到读写1字节的超时时间是us,其余的是ms
    9 P' o8 N  E; y
  9.                                         注意:IIC的IO必须初始化为复用开漏输出。/ d1 v3 U1 h! P
  10. *************************************************************************************************************/        
    ! l' R6 D2 x0 T# |$ A2 H
  11. #include "stm32f7_iic.h"# ?! q- S1 B% Q) y0 L$ y
  12. #include "system.h"
    ( n. N2 W- a9 {' @: T* G% X
  13. #include "dma.h"  l( g  }0 d" m+ u" Z# e

  14. - {( U, W) P7 K7 y1 z% `3 p
  15. #define IIC_FLAG_MASK  ((uint32_t)0x0001FFFF)        //中断标志掩码; j: |; Q7 O, @
  16.   o7 u% E9 [9 g5 x) V2 |% q
  17. //自动结束或自动重载设置(重载与自动结束只能二选一,或者都不选)
    - n, `5 J7 |9 \: a
  18. typedef enum
    + \; b0 D. z3 M8 T
  19. {
    & {. r. N* w+ L" u, k
  20.         IIC_SOFTEND_MODE                =        0,        //手动结束,并不开启重载
    8 r3 z' ^$ l: {8 D0 b4 l
  21.         IIC_AUTOEND_MODE                =        1,        //自动结束,用于最后一次通讯完成后自动发送STOP结束通讯
    ( R9 N/ O1 V* ~7 k( e7 }8 L- [' m. H1 s
  22.         IIC_RELOAD_MODE                        =        2,        //后续还有数据,本次通讯后自动重载,重新设置后继续通讯( @0 u+ C$ t. J$ ]
  23. }IIC_RELOAD_END_MODE;6 }5 ]! ?. M& P4 I

  24. ) {) b1 U+ K( b7 l
  25. //读写与开始模式控制$ X# p7 {4 x4 l9 e, r
  26. typedef enum
    & s& a* i7 `( s1 D& g" ]/ }( E. c
  27. {
    1 l9 H* n8 T2 j
  28.         IIC_NOSTART_WRITE                =        0,        //没有开始的写-用于后续数据的写入: |$ l8 l% `- s* N4 @; f
  29.         IIC_NOSTART_READ                =        1,        //没有开始的读-用于后续数据读取& |  q1 X9 j# I1 z! R
  30.         IIC_START_WRITE                        =        2,        //生成开始写-用于通讯开始时,写地址或数据
    ! \% v" H  a# f
  31.         IIC_START_READ                =        3,        //生成开始读-用于读取数据时切换到读取方向,并读取后续数据
    & Z' m% _; y5 T8 f
  32. }IIC_START_WR_MODE;& a  ]. d" x* ?* J
  33. 1 b- u$ ^3 |7 _$ @3 b' `! d0 x) y
  34. //IIC句柄
    # d9 G- _( J+ j3 i& x
  35. typedef struct8 b  F5 t. [$ s" R& j* t
  36. {
    + X( d4 }0 f' ]7 ^
  37.         IIC_CH_Type ch;                        //当前通道. p) v  }% o0 h- W7 `
  38.         I2C_TypeDef *I2Cx;                //当前通道外设结构体
    , H+ m7 O6 ]. Y  R; }4 z
  39.         u32 TimeOutUs;                        //操作超时,单位us2 z6 `5 X+ q2 q) r5 \3 O  f. \7 ?
  40.         u16 Speed_KHz;                        //通讯速度,单位KHz
    $ g* R) t, h  Q& D3 z
  41.         bool isMasterMode;                //是否为主设备模式-目前只支持主设备模式
    # r$ E3 G7 ], T  H8 [
  42. }IIC_HANDLE;: e% P" V, o, Z) k; `; n" G: s

  43. , u3 _( W* \0 r: p, H
  44. //IIC外设结构指针+ b% p9 n& \% \
  45. static const  I2C_TypeDef * const I2C_TYPE_BUFF[IIC_CH_COUNT] = {I2C1,I2C2,I2C3,I2C4};
    ! X. B; N( L/ \0 @0 ?3 W3 Z7 _+ W8 l# a/ r
  46. //IIC通道句柄定义; g& Q; _( ]" @$ s0 c# w4 o
  47. static IIC_HANDLE sg_IIC_Handle[IIC_CH_COUNT];. j4 H: |% o9 D8 H4 E# P7 w
  48. 4 Z, l+ d5 W- r
  49. //发送NAK5 t$ ]- \) f/ ^. |( Y! T$ p8 [9 x
  50. //static __inline void IIC_SendNAK(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT15;}: Z5 ]/ Z3 m# W& O# I' a2 V2 M
  51. //发送STOP6 q8 l( Q- t! O6 R' I( v) s* q3 j0 x
  52. static __inline void IIC_SendStop(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT14;}
    ! D4 [3 t; |7 l  C2 _
  53. //发送START
    ! r! z7 |6 r* s6 a
  54. //static __inline void IIC_SendStart(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= I2C_CR2_START;}
    + \0 g# P0 G/ m! O& w9 M
  55. //获取中断状态
    . R) ]6 W7 g, P. L* ?3 j1 i: D
  56. static __inline u32 IIC_GetISR(IIC_HANDLE *pHandle) {return pHandle->I2Cx->ISR & IIC_FLAG_MASK;}2 W5 l' d( t! D( g
  57. //清除中断状态9 u/ C3 s! s' U9 `
  58. static __inline void IIC_ClearISR(IIC_HANDLE *pHandle, u32 IsrFlag) {pHandle->I2Cx->ICR = IsrFlag & IIC_FLAG_MASK;}! Q( h8 [. \% }9 W5 o1 |6 V! K0 o. @
  59. //复位CR2寄存器
    , v! j) e7 N0 d, M+ h9 B
  60. static __inline void IIC_ClearCR2(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 = 0;}
    & I7 `" c; C5 [( T- x
  61. 4 h) @  S$ d6 {9 g( R
  62. static void IIC_SoftReset(IIC_HANDLE *pHandle);//硬件IIC软复位(会使能IIC)
    $ g( X; X4 M3 R2 E
  63. static u32 IIC_CalculationTiming(u16 Speed_KHz);//硬件IIC时序计算
    6 O- g* }: L  _1 I' W( m  k! z7 G
  64. , i; k* r* q: `! L2 r8 m' L# X$ y/ w
  65. ! D5 v8 F1 G% s9 g: Y) i
  66. /*************************************************************************************************************************
    . O( U* D8 G' u9 h
  67. * 函数        :                        bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs), [; T( s- F. Z; `
  68. * 功能        :                        硬件IIC初始化4 i8 ], M7 |7 d5 N( G, Q
  69. * 参数        :                        ch:IIC通道;Speed_KHz:速度10-1000(如果速度是100,则按照SMBUS时序);TimeOutUs:操作超时us(0:自定计算超时)$ L$ X+ ~# D- v5 o+ H" M
  70. * 返回        :                        IIC_ERROR
    ) R; ]( D& }- c
  71. * 依赖        :                        底层宏定义
    6 X$ L5 z1 G: {5 {5 g0 `
  72. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    / ~- c# k" |  ^+ Y+ ^: X0 z
  73. * 时间        :                        2020-02-151 g9 F4 W. k; z" l( t5 H
  74. * 最后修改时间 :         2020-02-15
    ; X0 S7 _0 G( ~. O
  75. * 说明        :                         速度只是个大概的计算值,设置为100KHz时会严格的按照SMBUS时序,其余的不保证SMBUS兼容,正常情况下只要时钟速度符合要求,& o2 n( e$ Y- k- `8 J
  76.                                         时钟上升沿到来前数据以及稳定的切换了即可保证通讯稳定性2 f& V6 ?4 x2 i4 f  [
  77. *************************************************************************************************************************/0 h5 e5 _5 G3 `5 K! z* Q: \
  78. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)3 X  E4 [1 P- B7 }  ?# I) X
  79. {
    7 Y3 o' ?- c4 ?# M$ N. i) _/ Q% y7 Y  E
  80.         SYS_DEV_CLOCK DevClock;- C5 t! [! k# e
  81.         IIC_HANDLE *pHandle;0 W  j' o3 Q, v. H% {. A
  82.         
    # n5 {. x" S1 ]4 [& [+ `
  83.         switch(ch)
    ( c9 c5 ]5 H  \7 s
  84.         {' l8 d$ e4 Y! n5 O
  85.                 case IIC_CH1        :        //IIC1& {: K  _, }0 Y7 j0 u' E" R
  86.                 {
    $ \4 ~+ k5 ~2 r: d# f" [
  87.                         RCC->DCKCFGR2 &= ~(0x3 << 16);        //清除设置,使用APB1作为时钟源3 [  ]5 l& [/ h
  88.                         DevClock = DEV_I2C1;" g7 H8 u9 ?( O
  89.                         //初始化I2C IO
    1 @* r6 k8 S+ }" v
  90. #if(IIC_CH1_IO_SELECT==IIC_CH1_PB6_7)        //I2C1        使用PB6/7  G/ n7 T3 @1 Z8 _
  91.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    1 o8 G; B! J  W* {) J: e% ?; o
  92.                         SYS_GPIOx_OneInit(GPIOB, 6, AF_OD, SPEED_25M);                //PB6
    7 K2 m; h5 n. Q% t' G3 s! {
  93.                         SYS_GPIOx_OneInit(GPIOB, 7, AF_OD, SPEED_25M);                //PB76 H6 j# [' |  f9 v9 @3 @
  94.                         SYS_GPIOx_SetAF(GPIOB, 6, AF4_I2C1);                                //AF4  P  G/ k6 k# e# x0 I( j
  95.                         SYS_GPIOx_SetAF(GPIOB, 7, AF4_I2C1);                                //AF4
    : s4 U) {8 I, K4 t
  96. #elif(IIC_CH1_IO_SELECT==IIC_CH1_PB8_9)        //I2C1        使用PB8/9
    ' Q9 z2 V+ `& [: V1 n0 w- j
  97.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    ; R1 L7 C1 r% |4 q
  98.                         SYS_GPIOx_OneInit(GPIOB, 8, AF_OD, SPEED_25M);                //PB8
    - |. L( V/ j  Q! e; X+ `, j
  99.                         SYS_GPIOx_OneInit(GPIOB, 9, AF_OD, SPEED_25M);                //PB9
    1 ^; |* r, l8 n4 J6 r
  100.                         SYS_GPIOx_SetAF(GPIOB, 8, AF4_I2C1);                                //AF4! H3 e6 Z" C5 C; r2 [& A
  101.                         SYS_GPIOx_SetAF(GPIOB, 9, AF4_I2C1);                                //AF49 i8 _7 n* g. J) Z/ y; c
  102. #else) [1 P4 J3 W7 O# n/ _6 W
  103.                         #error("无效的I2C1 IO选择");/ W* G- N% I2 c* q0 n
  104. #endif //IIC_CH1_IO_SELECT. j1 k( r3 C$ g  j! A, W
  105.                 }break;2 u, B- T/ b0 }
  106.                 case IIC_CH2        :        //IIC2$ e! f0 J+ F. r% c: x+ P! {) \- T: C# b
  107.                 {9 O, e, H. U7 [
  108.                         RCC->DCKCFGR2 &= ~(0x3 << 18);        //清除设置,使用APB1作为时钟源# J+ w8 J+ g, x% _9 N5 t" e
  109.                         DevClock = DEV_I2C2;
    0 r6 v& O( q+ E3 H3 s9 S
  110.                         //初始化I2C IO8 V3 c' u: z4 j4 v4 _. w- p
  111. #if(IIC_CH2_IO_SELECT==IIC_CH2_PB10_11)        //使用PB10,PB11
    1 y" z& \( W; V/ c: V& d; N
  112.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    * Y6 m' g( e, W" u1 Q+ m
  113.                         SYS_GPIOx_OneInit(GPIOB, 10, AF_OD, SPEED_25M);                //PB10  x" I3 D- ~* a/ V
  114.                         SYS_GPIOx_OneInit(GPIOB, 11, AF_OD, SPEED_25M);                //PB11% S: d5 z+ O% ~. G1 F3 e
  115.                         SYS_GPIOx_SetAF(GPIOB, 10, AF4_I2C2);                                //AF4+ [, q$ M# X2 y, q. i/ s, d
  116.                         SYS_GPIOx_SetAF(GPIOB, 11, AF4_I2C2);                                //AF4( {* `) W3 R3 r1 M- n) S4 W
  117. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PF0_1)        //PF0,PF15 K2 W. ?' e- ?, q2 [  |, e
  118.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟
    ' A6 l- ^% v& f& h: q& e1 s
  119.                         SYS_GPIOx_OneInit(GPIOF, 0, AF_OD, SPEED_25M);                //PF0
    % F/ U  _5 E' P7 c, @0 M0 z
  120.                         SYS_GPIOx_OneInit(GPIOF, 1, AF_OD, SPEED_25M);                //PF1  }6 ?) s7 J/ [4 i6 A, g
  121.                         SYS_GPIOx_SetAF(GPIOF, 0, AF4_I2C2);                                //AF4& ~( E  W  n& H8 H
  122.                         SYS_GPIOx_SetAF(GPIOF, 1, AF4_I2C2);                                //AF43 n: B4 U5 ~% B
  123. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PH4_5)        //PH4,PH5
    , v7 l; l8 O8 r. l4 t! Q4 i" g  Y
  124.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    0 ?" P- X+ d& A0 q) E/ d: n
  125.                         SYS_GPIOx_OneInit(GPIOH, 4, AF_OD, SPEED_25M);                //PH4
    % y+ q0 ]: K+ t
  126.                         SYS_GPIOx_OneInit(GPIOH, 5, AF_OD, SPEED_25M);                //PH5
      s! [! X8 q8 x8 f6 ~6 U5 N1 t
  127.                         SYS_GPIOx_SetAF(GPIOH, 4, AF4_I2C2);                                //AF4/ ]1 @& n! A3 f) s! @9 P: x- ]
  128.                         SYS_GPIOx_SetAF(GPIOH, 5, AF4_I2C2);                                //AF4                        1 F( s7 z4 j. n: x) i+ W
  129. #else
    3 l  q- w. X1 w- m: U
  130.                         #error("无效的I2C2 IO选择");- I+ R2 j( o6 ~0 g
  131. #endif //IIC_CH2_IO_SELECT2 d) [1 ~2 F9 }# [2 V( ]# Y
  132.                 }break;                        
    # ~9 i+ m. b. t2 i7 ?3 V/ c6 h
  133.                 case IIC_CH3        :        //IIC3
    ' N  D: f# A* w9 E5 `: }
  134.                 {/ |* k# b+ c  n
  135.                         RCC->DCKCFGR2 &= ~(0x3 << 20);        //清除设置,使用APB1作为时钟源
    - n4 B) k1 _* J9 \  l
  136.                         DevClock = DEV_I2C3;& i1 i1 u4 U/ g
  137.                         //初始化I2C IO" q2 z8 v1 y; r
  138. #if(IIC_CH3_IO_SELECT==IIC_CH3_PH7_8)                //PH7,PH8
    + @- q. q% T8 e7 O; R
  139.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟1 A. y+ ~1 D/ M( s1 H6 I8 U
  140.                         SYS_GPIOx_OneInit(GPIOH, 7, AF_OD, SPEED_25M);                //PH7
    4 c& }/ V( K# T. m
  141.                         SYS_GPIOx_OneInit(GPIOH, 8, AF_OD, SPEED_25M);                //PH8
    8 v& M; p9 k' E4 m2 X
  142.                         SYS_GPIOx_SetAF(GPIOH, 7, AF4_I2C3);                                //AF4
    / E" E0 [, i9 D, B) q3 S$ A
  143.                         SYS_GPIOx_SetAF(GPIOH, 8, AF4_I2C3);                                //AF4
    : B6 z& A) i$ R- }4 P
  144. #elif(IIC_CH3_IO_SELECT==IIC_CH3_PA8_PC9)        //PA8,PC9" [+ G# M. k; i
  145.                         SYS_DeviceClockEnable(DEV_GPIOA, TRUE);                                //使能GPIOA时钟9 O) r  Z% A# q5 o3 D9 f
  146.                         SYS_DeviceClockEnable(DEV_GPIOC, TRUE);                                //使能GPIOC时钟
    $ l4 l& F' c0 l; k8 x9 H# g; U
  147.                         SYS_GPIOx_OneInit(GPIOA, 8, AF_OD, SPEED_25M);                //PA8
    6 r# `2 c$ {% [0 J/ O. |5 Z
  148.                         SYS_GPIOx_OneInit(GPIOC, 9, AF_OD, SPEED_25M);                //PC99 ?6 E5 E! L% u/ Y$ C- m
  149.                         SYS_GPIOx_SetAF(GPIOA, 8, AF4_I2C3);                                //AF4
    0 x; S9 ~6 C( M. H# o8 E/ M
  150.                         SYS_GPIOx_SetAF(GPIOC, 9, AF4_I2C3);                                //AF4               
    # a+ Q- n0 X5 t# E8 v" J
  151. #else
    ! R* s5 N& t3 g  X0 {
  152.                         #error("无效的I2C3 IO选择");& Z6 t: U* K1 e7 o
  153. #endif //IIC_CH3_IO_SELECT                        0 [+ R0 x4 ~' C3 c5 x+ T
  154.                 }break;                        
    : N. y" f  {- k3 D% T5 E. b: q
  155.                 case IIC_CH4        :        //IIC4! B6 S# @" l; E% p
  156.                 {
    - a1 z+ @! h) X/ c
  157.                         RCC->DCKCFGR2 &= ~(0x3 << 22);        //清除设置,使用APB1作为时钟源
    . T9 M' J' }  }# O5 I3 [$ B
  158.                         DevClock = DEV_I2C4;: v" y. z& u1 C2 B4 h0 i  w  V
  159.                         //初始化I2C IO9 R# w* Z5 e6 ?7 J% k+ f, P4 ?
  160. #if(IIC_CH4_IO_SELECT==IIC_CH4_PD12_13)                //PD12,PD13
    # I5 i$ ^: Q7 d( W" E
  161.                         SYS_DeviceClockEnable(DEV_GPIOD, TRUE);                                //使能GPIOD时钟6 M2 j% X. `" y5 `
  162.                         SYS_GPIOx_OneInit(GPIOD, 12, AF_OD, SPEED_25M);                //PD12
    ; a6 N0 b7 i7 h: D9 {2 L9 t+ P
  163.                         SYS_GPIOx_OneInit(GPIOD, 13, AF_OD, SPEED_25M);                //PD132 h' o0 {6 j9 ?" s5 k* I
  164.                         SYS_GPIOx_SetAF(GPIOD, 12, AF4_I2C4);                                //AF4! F$ l2 s4 y1 r' N" z7 O+ i
  165.                         SYS_GPIOx_SetAF(GPIOD, 13, AF4_I2C4);                                //AF46 v7 g. B( r) E
  166. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PF14_15)        //PF14,PF153 R0 R% F* [$ @* `$ ]4 V' k
  167.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟
    7 j& y+ h! \8 ?# U" m) F: C. N
  168.                         SYS_GPIOx_OneInit(GPIOF, 14, AF_OD, SPEED_25M);                //PF14
    - Z% B3 j! Z2 ^& p! w
  169.                         SYS_GPIOx_OneInit(GPIOF, 15, AF_OD, SPEED_25M);                //PF15
    & z  P1 ]. j2 ~1 G
  170.                         SYS_GPIOx_SetAF(GPIOF, 14, AF4_I2C4);                                //AF4
    - M; q8 _! T$ X0 e- [' [
  171.                         SYS_GPIOx_SetAF(GPIOF, 15, AF4_I2C4);                                //AF42 t* W# Q9 n0 B) V9 h0 `
  172. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PH11_12)        //PH11,PH12
    , z7 l9 h  ], Z) E* C" i
  173.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    $ s2 V" B, K; [, I+ \4 F
  174.                         SYS_GPIOx_OneInit(GPIOH, 11, AF_OD, SPEED_25M);                //PH11
    0 ?' `( A% `. v' b
  175.                         SYS_GPIOx_OneInit(GPIOH, 12, AF_OD, SPEED_25M);                //PH12# ^" t4 `7 E$ m) y
  176.                         SYS_GPIOx_SetAF(GPIOH, 11, AF4_I2C4);                                //AF4. ]- u; g8 _  W! z
  177.                         SYS_GPIOx_SetAF(GPIOH, 12, AF4_I2C4);                                //AF4                        ) W+ |! Y5 r# a# V' q
  178. #else
    ( w& r( G& v9 h* o' H9 }+ z4 y
  179.                         #error("无效的I2C4 IO选择");. A7 y; T, j4 J( h& S& V
  180. #endif //IIC_CH4_IO_SELECT                        
    - y0 O* S4 R$ e: T4 S9 }0 z  F( _( b
  181.                 }break;
    ( a5 H* s" J# S0 F8 O8 k
  182.                 default:
    " [; D  m. [5 h1 C( j
  183.                 {! B( V# Z  A- y8 w" c/ c  i
  184.                         DEBUG("初始化IIC失败:无效的IIC通道%d\r\n", ch);2 G0 U* E" M! m) ]  B% v0 e
  185.                         return FALSE;
    ! j0 z2 d6 r$ J/ l, G2 ^; X$ K
  186.                 }
    8 N/ l) u4 e8 _/ r, u* G  r
  187.         }
    + K' s8 S" W; P( `# K0 m! j2 `5 ]
  188.         pHandle = &sg_IIC_Handle[ch];                                                        //获取相关通道的句柄
    ! d" I2 g4 K; w1 T9 c
  189.         if(pHandle == NULL)7 p, S+ K3 U* `* [
  190.         {. O9 y+ J9 ?' w; z# t5 d# a
  191.                 DEBUG("初始化IIC失败:无效的IIC句柄\r\n");. M4 K2 L0 f1 ?6 h1 l
  192.                 return FALSE;. G3 i- ^9 h9 I3 O& c# p
  193.         }
    $ q7 F$ d) e) d+ L# r# c, K
  194.         
    5 j+ J9 a  a) J" b& ?2 i% q4 W/ v
  195.         SYS_DeviceClockEnable(DevClock, TRUE);                                        //使能时钟
    ' P! j, B; g1 g1 k, j* a
  196.         SYS_DeviceReset(DevClock);                                                                //外设复位
    9 V3 A' `3 v$ b7 i3 \
  197.         pHandle->I2Cx = (I2C_TypeDef *)I2C_TYPE_BUFF[ch];                //外设指针
    $ a* e5 r, H0 o
  198.         pHandle->I2Cx->CR1 = 0;
    + @$ S  D$ L/ h- \6 Z
  199.         Delay_US(1);                                                ) R/ w: i+ o$ t& ~3 D: a
  200.         pHandle->I2Cx->CR1 |= 2<<8;                                                                //设置噪声滤波器,关闭所有中断/ H8 v0 q4 q: k- ]0 S. I! m
  201.         pHandle->I2Cx->CR2 = 0;, y/ [+ n" q( U8 T4 `: |* w
  202.         pHandle->I2Cx->OAR1 = 0;
    & q+ {5 M) o& ~% p$ X8 _+ w
  203.         pHandle->I2Cx->OAR2 = 0;' o9 J" j5 u6 A2 A0 U" I: p
  204.         if(Speed_KHz > 1000) Speed_KHz = 1000;
    $ r  o; e+ C  p& U# {
  205.         if(Speed_KHz < 10) Speed_KHz = 10;4 ?4 D3 F! Y- G* t) q( B
  206.         pHandle->Speed_KHz = Speed_KHz;                                                        //记录速度
    & z8 S- _  W5 _
  207.         if(TimeOutUs == 0)                                                                                //需要自动计算超时时间,时钟周期*10*10
    6 r& Q; O: I6 r+ d9 e- J9 b6 M
  208.         {
    . E( D" q* |$ w1 U. _6 w
  209.                 TimeOutUs = 1000/Speed_KHz;                                                        //时钟周期
    ; E$ f; q8 L, @0 F
  210.                 TimeOutUs *= 10;                                                                        //字节周期
    2 {- I/ {5 x* r$ }" }
  211.                 TimeOutUs *= 10;                                                                        //超时时间为10个字节时间
    - q8 a$ G" y8 M' ~: t1 S- F4 d5 b* T& P
  212.         }
    . c6 j3 Z# W4 a, Y% D
  213.         if(TimeOutUs < 3) TimeOutUs = 3;/ \; q& [; H0 T; x# f1 t
  214.         pHandle->TimeOutUs = TimeOutUs;                                                        //记录通讯超时时间. _: S; t, p/ C3 f, Z
  215.         uart_printf("IIC超时时间:%dus\r\n", pHandle->TimeOutUs);
    5 w# H6 b) Z& M- r! c! r" ?6 H
  216.         pHandle->I2Cx->TIMINGR = IIC_CalculationTiming(pHandle->Speed_KHz);//0x40912732;                                        //时序' }2 _% V2 A0 U( X2 s* H
  217.         pHandle->I2Cx->CR1 |= BIT0;                                                                //使能IIC* f9 g; D+ w4 f, l4 R$ E$ J
  218.         pHandle->isMasterMode = TRUE;                                                        //主设备模式
      `5 j* e( M* u& O7 o% s3 z: E
  219.         Delay_US(1);8 ~0 o9 G: c7 ~: s9 i

  220. 6 \2 o+ N9 e7 Z
  221.         return TRUE;1 O  Z6 `" a6 X$ j! x6 u+ |. b0 b% W
  222. }
    * a+ y; z8 F! W( U$ [
  223. . `: U& ?9 ]- A" `' c$ @

  224.   d1 n( q' g1 J2 K9 \4 q3 J
  225. /*************************************************************************************************************************1 K7 I" N# [' u
  226. * 函数        :                        static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)/ G* {9 P* p- l& H( [
  227. * 功能        :                        检查是否有NACK中断状态,如果有则清除掉
    ' L; m9 I- U& _0 G
  228. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us
    6 Z! Z! }3 w& e: t
  229. * 返回        :                        IIC_ERROR
    9 r: |) M% L. R
  230. * 依赖        :                        底层宏定义
    + y0 x0 z7 \3 b" u0 y  c
  231. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ' a3 A, r; q: V% V# V" {  p3 d& H
  232. * 时间        :                        2020-02-15/ V# R# `& Z; w2 b( x; M9 S
  233. * 最后修改时间 :         2020-02-15
    ( ~, x( B& g% f8 d) F. p
  234. * 说明        :                         如果有NACK中断,则先产生停止位,然后清清除掉所有的中断,并复位IIC,然后返回错误
    1 @, g' `5 I) P% r# m5 G5 d
  235. *************************************************************************************************************************/  9 L+ |6 s; ?$ i5 G" u  s* ?9 X
  236. static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)) ^$ `8 C% k9 F% @
  237. {7 ]: h: n8 O: {/ V( P
  238.         IIC_ERROR Error = IIC_OK;" W8 ]' F+ Q( I! a$ T8 k1 K# d4 i
  239.         
    . k. l. r- U( o0 h' Y$ P. |
  240.         if(IIC_GetISR(pHandle) & IIC_FLAG_NACKF)        //接收到否定应答标志
    " i5 L' k. g% _2 Y5 S" h
  241.         {2 N2 o) m: }: S# F2 b5 p
  242.                 uart_printf("NACK : IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);& X5 O. V0 D; r" N) ?, n( B
  243.                 uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    5 H' d" ?5 ^0 c1 z6 I5 a3 `
  244.                 uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));
    & y8 U1 u; c3 k. O5 t8 j
  245.                 //主设备下,如果没有开启自动产生停止位,则手动产生停止位4 f" i. |0 d( ^9 B$ K, N
  246.                 if(pHandle->isMasterMode && ((pHandle->I2Cx->CR2 & I2C_CR2_AUTOEND) == 0))
    8 F2 T% f! t5 A- Y4 f
  247.                 {
    " u" C6 E! p0 {) `+ ]
  248.                         IIC_SendStop(pHandle);                        //send stop, ?7 X* S2 d5 Z$ }9 H& ?' y6 o
  249.                 }) k, W9 O# V9 _3 k2 n4 }
  250.                 //等待STOP标志有效
    ; p+ J9 _6 p. @: N- ^, y( g; L0 k, f$ K
  251.                 while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)' x" P  c  E  R
  252.                 {
    ! z0 r9 `6 W6 E' E
  253.                         if(TimeOutUs == 0)                                //检查是否超时了( C8 J' ^) i" P
  254.                         {
    % ]7 C% L- z; R$ c% N% ^) F  ~6 ?
  255.                                 break;
    ( r0 L2 Q/ v( C" l2 }9 U" ]4 D5 x
  256.                         }                        ; J% K) i; D& c' p% y' a- F
  257.                         TimeOutUs --;& W7 b  `+ O; D7 l
  258.                         Delay_US(1);                                                //延时
    ! c2 t6 M, |$ a9 ^: {1 p8 M! r+ C- z5 n
  259.                 }
    : D8 B& I% Y3 R. X6 b
  260.                 //清除相关的中断标志- e% b  p+ d. z. `, ?, N/ U) U
  261.                 IIC_ClearISR(pHandle, IIC_FLAG_NACKF | IIC_FLAG_STOPF);        //清除NACK,STOP标志( N: i) G/ V! e5 p# L
  262.                 pHandle->I2Cx->CR2 = 0;                                                                                //清除CR2寄存器
    9 x( ?4 n9 x9 z% y& P
  263.                 IIC_SoftReset(pHandle);                                                                        //执行软复位
    % J* B& G  R8 U( [! t8 U. j
  264.                 if(TimeOutUs == 0)                                                //没有超时,就是硬件通讯出错了0 m$ _( c6 y; [; e' t. V: {4 \
  265.                 {
    2 A! L2 V3 u$ ?- ~' g; u
  266.                         DEBUG("IIC发送stop超时\r\n");
    - j7 a* s, ], \1 h' E1 A7 d* F
  267.                         Error = IIC_TIMEOUT;                                //超时
    1 a: \7 t& ~1 n/ ], @
  268.                 }
    / r) f) `; ^% t2 ^# H3 @7 ~3 n4 f& c. n
  269.                 else
    % Z: d: y. D5 C8 ^' \. w
  270.                 {# l' ]$ Q4 d6 i- Y8 D) `: h3 x
  271.                         Error = IIC_HAL_ERROR;                                //底层错误( k2 b8 g/ v9 g  Z8 C6 ?2 ]
  272.                 }' L8 O: K" q- ]
  273.         }
    2 N- ?" a  }  U7 O8 ?
  274.         
    * `! L) X. S( a) p
  275.         return Error;
    ) X0 [; d8 l# U) C/ g
  276. }
    ! w$ Z. u' h% C) K& S9 G

  277. 2 y/ @8 X; a' R8 ?; e# _5 ^7 p

  278. 9 t3 Z% y. R  J* A

  279.   e9 M3 h; Z. N0 E2 ^6 @) x- q" p
  280. /*************************************************************************************************************************
    - I5 K4 g) S; u9 ?' A
  281. * 函数        :                        static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
    ! k0 Z& p3 F: B, n% n' X
  282. * 功能        :                        等待TXIS中断有效(等待 I2C_TXDR 发送寄存器为空)( E- b/ m: n. G7 {9 `( i
  283. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us6 D# Y* N; D4 E( h
  284. * 返回        :                        IIC_ERROR& }+ ^# a& G6 |- b; ~, u/ e+ f
  285. * 依赖        :                        底层宏定义
    % Q5 }7 m& S' {# Q5 H0 I8 g2 x1 E
  286. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ! K. t( \+ h' l  v; Z
  287. * 时间        :                        2020-02-151 f" m- Y$ y/ q- R# P
  288. * 最后修改时间 :         2020-02-15
    4 `. A- c& v, x% E2 ^( n
  289. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的7 _, R! b. ^% j# k* W6 @
  290. *************************************************************************************************************************/  
    7 J5 U* M; m( T: d; I
  291. static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
    . A( E$ i. l' W9 O' ^/ s" ?
  292. {
    6 p( y! T1 j  A- r) f
  293.         //等待TXIS中断有效* i# v5 Y/ J9 r9 l3 `1 r  Y
  294.         while((IIC_GetISR(pHandle) & IIC_FLAG_TXIS) == 0)/ l) W' T& L5 I' A+ E- v
  295.         {
    " i! {- e; @4 d: p$ h9 o
  296.                 //有NACK中断,进行处理! r% m4 B  ?$ j7 U; S( h
  297.                 if(IIC_isCheckNackFlag(pHandle, TimeOutUs) != IIC_OK)        ' f" r5 j2 ~6 [  o! Q
  298.                 {
    4 ?6 h6 t% Y$ U' ~1 `
  299.                         DEBUG("检测到NAK错误\r\n");
    9 B5 y3 [9 v/ J/ _+ a- |2 v6 U
  300.                         return IIC_NACK;. X- G) S& ^: a6 i0 J1 ]- ]
  301.                 }' E" k; w6 f! i, n3 _( w- B& w6 s) n
  302.                
    5 |0 _' `! c/ `3 c  D
  303.                 if(TimeOutUs == 0)                                        //检查是否超时了; |4 G, d; D3 d8 E2 m7 V
  304.                 {! z- K, F" r7 z  m
  305.                         uart_printf("IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);
    0 Z: q8 p1 x* S: D5 G/ g- H# a6 N
  306.                         uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);: l8 G8 \3 t. n3 Z8 j
  307.                         uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));
    4 P( W; i  M/ u2 {5 n& b  ^" d
  308.                         # W+ B8 R3 X" @! a. T8 R8 @
  309.                         IIC_SoftReset(pHandle);                //执行软复位5 F0 t1 X' f2 F8 \+ B
  310.                         return IIC_TIMEOUT;                                //超时  g0 j8 ^5 C( z- D/ W
  311.                 }                        6 k% A  |& R) |1 A+ _4 s- G' E
  312.                 TimeOutUs --;
    9 E0 g; Z% l1 L$ n5 E& g4 \7 e
  313.                 Delay_US(1);                                                //延时2 v6 ]3 C: C& O0 n
  314.         }' l6 G. i- c3 B* u
  315.         4 f1 _6 a1 F/ u, S5 Y" j
  316.         return IIC_OK;
    / Z$ u% I  _& s: t
  317. }$ C, I# c9 \) b) V# \2 |3 j0 T" S1 d$ R

  318. $ V' F8 |( q& h% ^  z
  319. & k" W" b) @' B9 F: u. s4 B
  320. /*************************************************************************************************************************
    % E; o0 d- R6 W, k# f2 [
  321. * 函数        :                        static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)5 ^+ N9 o* v  U5 T5 c0 ?( u; T
  322. * 功能        :                        等待STOP中断有效(等待 发送结束 ); |5 g3 r. M+ d7 h
  323. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us
    : ~9 D, ^; z4 U3 l- Q
  324. * 返回        :                        IIC_ERROR
    * U1 {  C  ^" [$ ]/ Q0 d5 s0 {
  325. * 依赖        :                        底层宏定义
    . w7 f1 g' ?5 I0 A
  326. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    1 P9 O. u4 ^. g( i9 B
  327. * 时间        :                        2020-02-15$ ^7 t) T- d) v% ^  z4 [; t( j
  328. * 最后修改时间 :         2020-02-150 v! A4 \5 C: ]
  329. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的
    ' s0 l% i( N9 O* _
  330. *************************************************************************************************************************/  * \7 x& @! ?& X5 c2 h  F4 ?
  331. static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)3 |' h' t5 M; m/ A8 H# {0 Y, {
  332. {, G' h# H. Y+ @! |! D% B' D
  333.         //等待STOPF中断有效6 f" k' o5 W0 f; _+ f2 W/ u; g; R* ]
  334.         while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
    2 [/ ]  @- \) I% K: Y6 K& `) v/ q
  335.         {) ~/ P4 E- z8 M$ d
  336.                 //有NACK中断,进行处理
    2 B; K9 i3 q  U+ R$ U$ A: q
  337.                 if(IIC_isCheckNackFlag(pHandle, 5) != IIC_OK)        
    & G# U0 Y: u4 X1 w" a
  338.                 {
    3 ~, P! E+ v; W5 [' B1 r
  339.                         return IIC_HAL_ERROR;- e- Y) D3 j0 \& B8 A( R
  340.                 }
    : N/ v( i% p6 Z& O4 d
  341.                
    ; `) A7 ^! x8 y9 _6 S" C# `# C
  342.                 if(TimeOutUs == 0)                                        //检查是否超时了7 s. m4 M& u  F
  343.                 {4 [7 k: g: ]. W5 M
  344.                         IIC_SoftReset(pHandle);                //执行软复位, k8 P7 d% z' @4 B
  345.                         DEBUG("IIC等待结束超时\r\n");
    % Z, |+ ]; ^( T" P5 V
  346.                         return IIC_TIMEOUT;                                //超时
    ; r* r& k  t7 i' h! U: c; l( Y
  347.                 }                        
    , c. B  y* D! ?' }! X  |: Z
  348.                 TimeOutUs --;
    9 D+ c* Q  x) q! z
  349.                 Delay_US(1);                                                //延时6 A+ u) U  d3 p: d
  350.         }1 l/ j% g' \! {; {; K3 `: M' j
  351.         
    0 k' M* d5 {8 d+ [5 }4 |' a
  352.         return IIC_OK;5 n/ [5 A% t0 V- P0 ]
  353. }2 S5 [$ P0 m- r, p9 `
  354. 0 }& b, U- C+ _/ W, E' o! o& H
  355. , q0 u0 G- S6 s5 }1 v+ H/ O. x
  356. /*************************************************************************************************************************3 ?# U& r( N- O9 c  N" Y
  357. * 函数        :                        static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
    3 F% Q9 y! p" ?9 R
  358. * 功能        :                        等待中断有效
    . s) X9 z9 e. ?
  359. * 参数        :                        pHandle:句柄;Flag:需要等待的flag,见IIC_FLAG_xxx;isWaitFlagSet:TRUE:等待标志有效,FALSE:等待标志复位;TimeOutUs:超时时间,单位Us7 Z2 ^3 k& s- W; Z5 w5 a; y% J
  360. * 返回        :                        IIC_ERROR  H) |# S3 t0 m7 d! x; \3 U. e. R
  361. * 依赖        :                        底层宏定义
    ' O$ z$ e# v# z; S% C( p3 Z
  362. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>: ?( `2 F) g. i% L5 @7 G4 I  l' W
  363. * 时间        :                        2020-02-154 f+ Y: B2 T7 {
  364. * 最后修改时间 :         2020-02-15
    $ _# e% n/ s2 B1 T/ D* v: j1 ~; H
  365. * 说明        :                         # M6 V4 v  j. ]4 x7 s% d0 z& {2 h& l
  366. *************************************************************************************************************************/  ' j2 q' {6 \5 _0 D) V5 {( L
  367. static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
    ) M" _5 [! Q! D( V4 p/ ]& z
  368. {- X* x+ b$ |7 ]+ U
  369.         if(isWaitFlagSet)        //需要等待标志有效
    & ]& t8 k9 }/ I( k7 w9 k
  370.         {; x+ b) C7 A7 D4 `8 n+ [/ {# }
  371.                 while((IIC_GetISR(pHandle) & Flag) == 0)+ z7 ^5 y: t* E" N/ C/ q8 h
  372.                 {( \8 `, ~/ X3 f
  373.                         if(TimeOutUs == 0)                                        //检查是否超时了
    9 c2 A3 ]+ F2 ]5 U4 \' z& t
  374.                         {
    * p) q$ b' p* o% G3 W7 _9 [1 M
  375.                                 return IIC_TIMEOUT;                                //超时
      {5 K( u: n' z7 ?- c+ ~0 g: p" q
  376.                         }                        
    ( d0 Z. l" F  W7 y: l" P: i+ R
  377.                         TimeOutUs --;0 j# \% ]9 \7 Z
  378.                         Delay_US(1);                                                //延时6 c8 J4 }; ~& C+ R+ D
  379.                 }
    + x! X1 V. b! p3 G
  380.         }+ W2 ?3 N' v/ ~& J( h3 S
  381.         else                                //需要等待标志复位
    3 ?) T# B) u6 L3 R
  382.         {
    8 W/ p* J  q2 I* R% ^$ Q
  383.                 while((IIC_GetISR(pHandle) & Flag) != 0)7 l, v8 O9 Q0 q. `; p0 |3 W
  384.                 {
    " ~5 ?" t/ `8 s7 A1 Y7 a! m
  385.                         if(TimeOutUs == 0)                                        //检查是否超时了
    ) K' q/ o8 B+ x" }
  386.                         {
    4 ?" y, P9 |) ^0 ?9 M1 q# \
  387.                                 return IIC_TIMEOUT;                                //超时
    7 L9 l1 R' X6 M1 }: V4 f) P6 K0 {
  388.                         }                        * y+ O4 V9 o6 U, E) Q
  389.                         TimeOutUs --;6 S/ g, f$ M/ D1 w  v2 v
  390.                         Delay_US(1);                                                //延时
    1 k0 N3 ?6 h9 h7 B; I' f
  391.                 }& X0 l# ^8 ]+ Q1 o8 n
  392.         }  u' B5 Y6 h4 U$ ^8 A0 |( H
  393. 1 I" a7 \9 g6 q% z( f" t
  394.         return IIC_OK;
    , I8 }4 \( T% ~3 o' e& c  n9 k' _
  395. }
    / t4 @* U8 w. ~2 a# r. T

  396. 7 i# r# t& Z" B4 C+ ?

  397. , m# U7 J9 `- q6 k/ R+ {: L
  398. $ g) M% q) m- K4 b2 {

  399. 6 e" E! a* @  ^1 T
  400. /*************************************************************************************************************************. Z8 N" V& I9 v% L* `
  401. * 函数        :                        static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)) Z( A5 H6 R5 C; j
  402. * 功能        :                        主设备传输配置(配置CR2寄存器)5 c+ O5 G+ n, r& ?! D8 Z" W" |! L
  403. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;TransByteCount:需要传输的数据长度;EndorReload:自动结束还是重载设置,见IIC_RELOAD_END_MODE;StartAndWR:开始读写控制,见StartAndWR
    # V. j2 [  i+ ]
  404. * 返回        :                        无% W! b4 S% Y2 h0 v
  405. * 依赖        :                        底层宏定义
    3 g, M3 d" ~8 Y: P9 |9 c/ j" p
  406. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>1 K$ x' j/ w. T- i! b
  407. * 时间        :                        2020-02-15: W  i+ u7 q* Q) b# r2 v) ^
  408. * 最后修改时间 :         2020-02-16
    . o# \6 X5 m- m; N2 L1 {
  409. * 说明        :                         在往 NBYTE 中设置最后一次传输的字节数前,必须把 RELOAD 位清零便于后续自动发送STOP。2 h9 G0 r9 j! V& {- s
  410.                                         当 RELOAD 位置 1 时,AUTOEND 位将不起作用;
    - W  M; d- X4 J. Z5 v$ o" Y
  411. *************************************************************************************************************************/  
    & A! X0 b4 O- U! [
  412. static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)( T9 I' g& q6 D( n& q( D1 H7 I9 p- t
  413. {
      e- n1 L4 B6 a
  414.         u32 temp = 0;3 z- ^4 p- s) Z9 F8 N
  415.         3 b' f8 f; `1 H, g+ s* [+ a9 H% z# L8 c
  416.         //先读取CR2寄存器的值
    " B# _4 A9 x2 U+ y, F/ D& s8 F4 I
  417.         temp = pHandle->I2Cx->CR2;1 X- @  w1 I3 C$ ?7 _$ |6 c
  418.         //清除掉相关的字节
    ) _+ q1 H$ X5 q6 I3 c
  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));6 {4 G! |  X$ y& X/ [9 q
  420.         //生成配置数据( S4 l8 I  c' l( \* T3 R% N- j
  421.         temp |= (u32)(((u32)SlaveAddr & I2C_CR2_SADD) | (((u32)TransByteCount << 16 ) & I2C_CR2_NBYTES));
    + c# D; C$ V+ x+ A0 Q4 [, b- h
  422.         //重载与自动结束只能二选一. C8 W- C2 n  ~1 s9 A7 h; N2 |
  423.         if(EndorReload == IIC_AUTOEND_MODE)         5 }1 j& J  Q- v' W4 _
  424.         {$ E% Q- N9 F. F9 S7 G+ [# p
  425.                 temp |= I2C_CR2_AUTOEND;        //自动结束模式
    7 w& v* F+ p! Y* e1 K+ U9 N/ b+ |; J
  426.         }
    9 f3 D/ ]! }  a8 M2 L
  427.         else if(EndorReload == IIC_RELOAD_MODE)/ f& @! b! g! h! J% T
  428.         {
    " E! q' Q" D0 P( e: v( }- V( U
  429.                 temp |= I2C_CR2_RELOAD;                //NBYTES 重载模式
    4 |) E+ b2 o1 C
  430.         }
    / S( W! `, S5 ]; K5 I5 ^2 f
  431.         
    % ]- h6 ]8 t4 P1 n: F& M" a) T
  432.         switch(StartAndWR)% _8 ?$ J9 A2 V3 X7 l
  433.         {1 q/ v7 ]; H% H7 N) R  N/ V
  434.                 case IIC_NOSTART_WRITE        :        break;        //没有开始的写-默认就是这样的0 ~. p9 A2 }1 S% `" Z& H
  435.                 case IIC_NOSTART_READ        :                        //没有开始的读-用于后续数据读取; M! M. k, j- e, S' b: B2 ^! k
  436.                 {
    : a4 g& ]: Z" e/ P9 u
  437.                         temp |= I2C_CR2_RD_WRN;                        //读取
    * @- y+ a% Z- n4 }  l  n0 m
  438.                 }break;
    9 t( G8 f9 h0 a
  439.                 case IIC_START_WRITE        :                        //生成开始写; ?- G( t+ z7 `' T  [
  440.                 {
    , {" Q1 c! V+ Q" N9 V4 s3 T, E; u
  441.                         temp |= I2C_CR2_START;                        //启动传输
    ' z1 v) h* K% [+ o+ q9 |9 i" I9 H! P* Q
  442.                 }break;, w9 y7 N5 q, A* u5 D
  443.                 case IIC_START_READ                :                        //生成开始读        . T3 K% Y/ Z0 u6 k7 W
  444.                 {
      }6 v2 c6 K* r. ]
  445.                         temp |= I2C_CR2_RD_WRN;                        //读取( `0 E& L3 O" O5 C4 O0 R" x( f
  446.                         temp |= I2C_CR2_START;                        //启动传输6 J+ \8 e- z8 |& Z
  447.                 }break;) H  J* M( O( n1 f& n
  448.                 default:break;
    ' e/ i1 K8 ]7 ?
  449.         }! S  ?1 d5 W; U, w1 @  Z
  450.         7 L! @+ t* q( O& H* O
  451.         //uart_printf("准备写入CR2=0x%X\t", temp);
    $ v- c+ k& K5 k6 f' Q4 I: I1 Z
  452.         //更新到寄存器
    # o* ~. \! r# |- r3 p" C
  453.         pHandle->I2Cx->CR2 = temp;  //测试
    6 M% \7 @) R% V. S! Q, C! ?
  454.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);: x( ?# L% T! ~% O6 s  Z
  455.         Delay_US(100);* W& V) R2 ?# |+ s& J1 K( i- |
  456. }3 L; ~/ S7 {2 h8 S& f5 j0 M

  457. . ~( I& M- L/ L7 o7 ?- X" ~
  458. 2 \* y8 ]" I% T$ o
  459. /*************************************************************************************************************************
    3 ~% `1 e6 \7 e8 R( e
  460. * 函数        :                        static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)
    . z- C3 P9 u- V0 F- g
  461. * 功能        :                        IIC发送一字节# R" i0 \" J; _
  462. * 参数        :                        pHandle:句柄;data:待发送数据;TimeOutUs:超时时间,单位us% P* S* s4 v9 A+ b; ^: W* [, T
  463. * 返回        :                        IIC_ERROR
    * e  l: L0 O0 {' ?7 s
  464. * 依赖        :                        底层宏定义
    % o! h# c. a5 x1 K0 ^2 L4 }
  465. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    + w; b9 z$ m5 B6 ~; H' m
  466. * 时间        :                        2020-02-15
    7 V/ _! l5 I% O1 B$ N/ ]
  467. * 最后修改时间 :         2020-02-16$ j! z  E0 ]) `' S' M
  468. * 说明        :                         TXIS有效后才会进行数据发送,不会检查数据发送是否完成。9 `, q% X% ^- g1 k  I9 _- l
  469.                                         如果最后一个字节发送完成后不会再触发TXIS中断,只会触发TC中断
    8 s( ^) p3 a" S6 i5 A, V) H( o
  470. *************************************************************************************************************************/  
    % e. `0 e. r& E. ?+ @
  471. static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)
    1 y' Y: U/ {0 {0 n5 [- o" E
  472. {8 I: Q3 Q) W9 z2 J4 x( j, s
  473.         IIC_ERROR Error = IIC_isWaitTXIS(pHandle, TimeOutUs);                                //先等待可以发数据# X: {2 \( W5 @' i+ n4 q
  474.         if(Error != IIC_OK) return Error;
    ) f8 _' ?, y  B9 m0 ?8 p$ p
  475.         pHandle->I2Cx->TXDR = data;                                                                                        //写数据到发送寄存器-不会等待数据发送完成        
    + v- s/ j: Y! n8 t/ c8 e$ K
  476. 2 x# b7 ^  K/ o# m4 O1 w
  477.         return IIC_OK;1 E6 v4 g5 C) N# v
  478. }% G& a! i7 q2 F/ K
  479. 1 k7 n! l! b$ C& l3 J1 F
  480. /*************************************************************************************************************************! z2 u* K- J; J6 c" B/ H5 N
  481. * 函数        :                        static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    : J+ |" M! K* T: b' r
  482.                                                 bool isRead,u32 TimeOutUs)
    ' @; C" S" W! N4 L
  483. * 功能        :                        主设备请求发送从机地址与目标寄存器地址
    4 F% x9 o0 c0 r* W
  484. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;RegAddr:寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,
    5 ^2 W/ i+ `# Q5 [5 z
  485.                                                 FALSE:16bit寄存器地址;isRead:TRUE:这个操作是读取寄存器;否则是写入寄存器;TimeOutUs:超时时间,单位us* l' Q5 Q8 @! f; n" q7 o
  486. * 返回        :                        IIC_ERROR
    2 `* I' }/ |3 Z( d+ k; s* J+ q4 w5 x
  487. * 依赖        :                        底层宏定义
    - p: P, S8 @2 y& U, A  w8 }7 s
  488. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>9 e! S% A$ h6 f, B
  489. * 时间        :                        2020-02-158 c) `2 [7 C" ?
  490. * 最后修改时间 :         2020-02-16: o" B+ @* }. V0 t4 n8 z2 H" ]
  491. * 说明        :                         " o7 X# ~" a- p% z
  492. *************************************************************************************************************************/  
    ) r/ k: \5 t6 a. j+ A" B
  493. static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,bool isRead, u32 TimeOutUs)2 w% S9 z. X, u
  494. {        
    9 ~# |  q( `% ~/ N: l1 _; |# s
  495.         IIC_ERROR Error;
    1 z- v  H- E; _# Y5 j) Q3 `  N
  496.         
    1 N7 H( ?- k/ _6 L4 b
  497.         //uart_printf("WriteAddr1:CR1=0x%X\t", pHandle->I2Cx->CR1);8 l7 }, s, ]8 i* l) `4 O9 W
  498.         //uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    * E/ k% a/ u( m9 S4 N& n4 t+ r
  499.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    / c( R- |& {, ^) v* h* r% G/ e
  500.         //传输配置,并启动传输,发送起始序列,开始IIC传输了
    - Y6 {- R6 x5 N+ p' \6 ?
  501.         //如果是读取则使能软件结束,如果是写则是自动重载4 _3 H' n- R: P8 N% z$ f/ x* R
  502.         IIC_MasterTransConfig(pHandle, SlaveAddr, (is8bitRegAddr==FALSE)?2:1, (isRead)?IIC_SOFTEND_MODE:IIC_RELOAD_MODE, IIC_START_WRITE);        //传输相关配置-写,并启动传输
    & V: I6 V3 w; c; X4 Z
  503.         ( t+ I/ Z" U7 I3 y( s
  504.         //开始发送寄存器地址7 i: o# {9 x# A1 t+ Q8 a+ h2 G' I
  505.         if(is8bitRegAddr==FALSE)                                                                                                //寄存器地址是16位的,IIC通常是MSB高位在前,需要进行高低位对调
    * T0 G6 Z( _' S: j( T
  506.         {  F- a; n8 \& B2 Z
  507.                 Error = IIC_SendByte(pHandle, RegAddr>>8, TimeOutUs);        //先发送MSB-非最后一字节
    , I) w; P. \1 p% T
  508.                 if(Error != IIC_OK)
    9 y5 j, Z2 \- \3 q
  509.                 {
    , L' ^" y$ x, ?" H
  510.                         DEBUG("IIC发送寄存器地址MSB失败\r\n");
    7 N. T7 T1 q1 W
  511.                         return Error;
    3 Q5 j! ]! l8 W/ u( }( N0 F( w" Q% M
  512.                 }        ( b% _0 B+ G: q4 T1 A8 i7 t4 ]6 f
  513.         }" m" F) w& R* E% b3 T  x
  514.         Error = IIC_SendByte(pHandle, RegAddr & 0xFF, TimeOutUs);        //再发送LSB-最后一字节
    * r& v5 a. q( ~9 U) i4 v
  515.         if(Error != IIC_OK). {2 ], R- f1 `
  516.         {
    $ `& b8 d4 Y6 I9 {9 u! E
  517.                 DEBUG("IIC发送寄存器地址LSB失败\r\n");8 B% B' b9 C+ ~
  518.                 return Error;% Q% }3 W5 w$ c0 l
  519.         }# i5 Z6 G: k% M
  520.         //等待全部数据发送完成7 B* Q  ~' b  F9 ], w4 @
  521.         if(isRead)        //读取方向-非重载,等待数据传输完成 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。
    2 U7 O0 m. J! b2 f  l& V
  522.         {
    9 f" E0 c0 P9 o( G
  523.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TC, TRUE, TimeOutUs) != IIC_OK)/ y& h; Z6 B+ a' W4 C/ r# U, y
  524.                 {
    % o; B8 X% R5 L" U0 B7 |0 c( q3 s  V
  525.                         return IIC_TIMEOUT;6 ?. W+ B( p8 S( z- F; [5 w
  526.                 }
    3 [& D/ V8 w& q+ b9 P
  527.         }          o6 H5 c  d) {
  528.         else //写入方向,等待重载
    $ g. v+ L8 n4 N7 p& H
  529.         {
    & ~+ Q0 P$ I5 x7 D+ D
  530.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TCR, TRUE, TimeOutUs) != IIC_OK)
    ' |) k* b1 }3 [' h3 i
  531.                 {3 G; c4 |. d. z' r
  532.                         return IIC_TIMEOUT;, P4 J' s. p+ `. h0 U
  533.                 }
    2 {' [* {) p: L* K6 K, U
  534.         }
    5 h7 V) D. L  ^0 I0 y5 {* ?
  535.         : ]. `7 E* s" q: Q( s8 ~4 E
  536.         return Error;' b6 o  m, @$ S+ O8 ?/ S
  537. }& Z# ^# A8 S8 q1 `
  538. " R; c; K& {$ j. Y

  539.   [4 d) Z; ]$ K  u/ J. W" `# _& w' Y
  540. /*************************************************************************************************************************; [1 y' Y% ?  x% E9 r# U' j. a
  541. * 函数        :                        static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
    1 a+ J! r' y! f* \( [: a7 B
  542. * 功能        :                        等待接收一字节数据, a! \0 b' Y% P/ V% k: `, f: y
  543. * 参数        :                        pHandle:句柄;pData:接收的字节数据缓冲区;TimeOutUs:超时时间,单位ms  w& ?1 u' d1 C- i
  544. * 返回        :                        IIC_ERROR
    & Z  `$ e5 ?' e5 m$ q  T1 h
  545. * 依赖        :                        底层宏定义
    5 m' t- q4 Z. W4 |$ P! y- k
  546. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ( a8 ~% }& i& ~) m. p/ n
  547. * 时间        :                        2020-02-15
    % r; u" i4 X+ k2 x9 M% }: |
  548. * 最后修改时间 :         2020-02-156 T- C1 y( c# z4 ~  z& z) W' A& O
  549. * 说明        :                         当RXNE有效后读取一条数据,否则可能会超时( I" d# }8 Y" h! v5 d5 Z
  550. *************************************************************************************************************************/  
    5 Q' @- S6 B% L8 _2 B  R! i6 x% _
  551. static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
    4 ?2 @3 D' q; n4 u+ o: y& r
  552. {
      s7 M# L$ K; ^( I$ I/ J4 R! u" A
  553.         while((IIC_GetISR(pHandle) & IIC_FLAG_RXNE) == 0)        //等待RXNE有效
    . R2 Y4 X$ l  T, c/ D) F
  554.         {6 Z4 o# `9 g1 M' v2 C. \- S
  555.                 if(TimeOutUs == 0)                                        //检查是否超时了
    * v+ M. s4 C! n4 T4 s0 x7 Z
  556.                 {
    & k4 a$ _4 f2 ]1 T: q
  557.                         DEBUG("IIC等待接收超时\r\n");
    0 \1 y4 n8 t( l7 T2 w1 J  c* w, O
  558.                         return IIC_TIMEOUT;                                //超时3 H* J$ {6 E3 Z
  559.                 }                        
    8 W  [; H! x" a" f1 F: I9 C
  560.                 TimeOutUs --;# ]5 T8 a- G- U0 \8 Y% P4 e
  561.                 Delay_US(1);                                                //延时
    + S9 O6 q8 o+ l* [& ~
  562.         }: ~* C/ D+ r$ c- H0 n3 I
  563.                 ( P2 G2 Q. e' Y: Q  \$ i# {( }9 d
  564.         *pData = pHandle->I2Cx->RXDR;                                                        //读取收到的数据7 r* |; v, }& E
  565.         return IIC_OK;
    6 Y/ A& @( b+ l3 s7 u; v* ?
  566. }
    & w/ b! E: w" Q
  567. 4 ]6 {$ o& g* A3 Q' K
  568. ! U: E* S' ^: H, z3 d
  569. /*************************************************************************************************************************
    9 l& [3 \9 x) T7 i. w2 f
  570. * 函数        :                        IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, 1 d' F, W4 N: n7 B: I  i0 }
  571.                                                 u8 *pDataBuff, u16 ReadByteNum)+ b7 E7 ], v6 V0 R4 N
  572. * 功能        :                        IIC读取寄存器(可以读取1个或者多个寄存器)$ y( Y. K4 g3 w1 @) E% s
  573. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要读取的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;3 z% V/ {, e# S$ d7 [
  574.                                                 pDataBuff:接收的字节数据缓冲区;ReadByteNum:要读取的寄存器数量;
    : g4 |( T  R. l# p# U% W( r; E& l
  575. * 返回        :                        IIC_ERROR
    ; f" X* o+ P8 ]4 z/ p
  576. * 依赖        :                        底层宏定义
    ( j8 I! r/ l3 _5 R; F. @3 r
  577. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    " O0 s/ h; A! ~0 P# @3 c& g
  578. * 时间        :                        2020-02-15
    5 {* L6 n7 D& \+ a3 N- q
  579. * 最后修改时间 :         2020-02-15) s8 n% `) s. \$ z  r; N. w# F9 }' N
  580. * 说明        :                         读取的数据都是小端模式,如果是16bit的寄存器,请读取偶数个数据,并且需要另外进行高低字节对调最后组成16bit数据" C+ N& G  R# l& P. m
  581.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
    $ C3 T; v. D2 Q( N4 w# y' [
  582.                                                 增加信号量
    % u) X4 v# Y- D# C3 v- l
  583.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在# X$ X& h" p+ M
  584.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。! I- K& ]3 n/ f& n
  585. *************************************************************************************************************************/! X: c( d  R: s- Y8 T: v
  586. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum)
    7 ~3 \6 f- s' v8 y$ ?8 X
  587. {
    : A  {9 E0 g& S" D3 u& O$ C
  588.         IIC_ERROR Error = IIC_OK;
    # N9 ^4 N1 G2 r% }$ T! [- L% e
  589.         u16 ReadCount;3 A; i( O+ J' A7 V& ?" C# _
  590.         IIC_HANDLE *pHandle;0 G* i  ^! V- J+ U
  591.         
    # ~1 I3 @" b. I1 D* t0 V9 _
  592.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || ReadByteNum == 0)7 e  Y  r0 Q$ O
  593.         {
    * r, S  V+ i8 I. z
  594.                 DEBUG("IIC错误:无效的参数\r\n");
    8 G; e  e% ~# S- G  v7 \! W
  595.                 return IIC_PARAMETER_ERROR;
    ; T- h- ]; \  X$ l9 I
  596.         }; ?( W, }/ q5 m7 l( K6 I; R
  597.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄# b. B4 K. ]8 F* Z" J: ]
  598.         
    5 [& D/ I' w& E" O
  599.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙8 ]. `5 H- d. {6 |$ b* B( S# O. g
  600.         {. {8 n( ^0 }! U6 H" C, X
  601.                 IIC_SoftReset(pHandle);
    ) U$ b9 S1 u, Y; O9 ~& a
  602.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");3 N# E8 z* `: K) P! e$ K
  603.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙
    4 y! v- y  \! f$ J2 i1 q, N% h* s9 x
  604.                 {. m- H5 w% V7 x' S1 T  f
  605.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");6 F3 Z  `; x" u; z0 Y, I2 K  d
  606.                         Error = IIC_BUSY;; C1 {: a/ f$ J" X
  607.                         goto end_loop;4 C# B! t! i: Q" E
  608.                 }5 T7 E" V1 d: P  o0 R3 c! T" s
  609.         }$ C- S% q: a/ i  C5 C* B. p6 W
  610.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态) o3 @! z( H; ~5 g& i6 O: J9 w
  611.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器$ O8 e" C* R+ ]$ z+ h' s: w
  612.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    0 k/ P) U, W/ X! a8 J7 U
  613.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,TRUE, pHandle->TimeOutUs);
    . q6 k9 _; I3 X- E4 J
  614.         if(Error != IIC_OK)
    ! p5 f6 r# f6 M: V; R( Y& {
  615.         {: H  q& _6 N: ?3 Q. X+ ~7 t: A/ L
  616.                 goto end_loop;
    2 i1 m# o! p5 r
  617.         }
    + I$ ~: G. O! `% L
  618.         //发送后续数据
    ' ^7 v& K, ?. G" a; w  d7 J
  619.         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取-后续还有数据,需要重载
    & X: z  T6 ?; m% n4 O3 m
  620.         {
    6 L8 }6 b% @* W0 E. G+ S
  621.                 ReadCount = 255;        //本次需要读取的数据长度255
    % [, P: p' n- z. B/ j% T' u3 e' {
  622.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输               
      o8 \/ o% M! k+ j
  623.         }
    6 r2 i$ W  l# d0 N; n, i0 j" _
  624.         else
    4 n7 `& ^2 Y0 A5 c+ e# Y
  625.         {
    + _) f. ?  ^3 v, s
  626.                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯后自动结束
    4 Y: p0 }( i  _) T* ~, f' I
  627.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输% G1 {2 Q0 [. X7 I
  628.         }0 u, ]. x. x: m
  629.         
    ' F/ ?( j, h- R$ R7 U. H" a7 Z
  630.         //循环等待接收数据完成: I2 v3 E. i8 f& L+ a( l! x$ @
  631.         do
    9 T2 |0 i( g! e$ a
  632.         {! H7 Y# |. o5 ]( I: Q) E6 D3 h! {
  633.                 //uart_printf("读ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    & S: Y9 z2 _1 [" p7 T+ K8 E
  634.                 Error = IIC_WaitRxOneByte(pHandle, pDataBuff,  pHandle->TimeOutUs);                                        //接收1字节数据' T3 S, v: U: c2 ^
  635.                 if(Error != IIC_OK)
    2 k6 D# }: n4 M# U$ K6 W7 Y6 ~9 l) }
  636.                 {( d/ K' [8 W4 F3 J# c( L# a2 j
  637.                         goto end_loop;
    8 O2 b# i# G3 |* s% R
  638.                 }/ i3 R  j8 I  t. M8 L  T) d" C0 R1 X
  639.         
    7 q" h+ k6 |; D* l/ w
  640.                 pDataBuff ++;: O: [/ ]: R0 e, u9 [$ y) ^8 t
  641.                 ReadCount --;# S8 P; |4 s+ x# @: L
  642.                 ReadByteNum --;! p$ w: ?- f/ @6 j) d4 T0 b% u
  643.                 if((ReadByteNum > 0) && (ReadCount == 0))        //还有数据要读取
    ) ]" s* r4 ^, Q* }! m4 R
  644.                 {1 e0 U  ~0 S' l$ r+ g
  645.                         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取6 ^. _: I/ K+ x. D! R8 U' c
  646.                         {  U$ P/ v: u* k4 w4 ]  U
  647.                                 ReadCount = 255;        //本次需要读取的数据长度255-后续还有数据,需要重载4 K% H. G( [+ q
  648.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        ) ?) `* u& \; ?4 G
  649.                         }) [6 C% {8 h) H- G$ X: S- J: t
  650.                         else
    8 s  q+ [: ]9 F2 u& F* b
  651.                         {
    ) R/ h6 d& \- D
  652.                                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯,自动结束9 Y9 v8 m7 j# l! C! z
  653.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
    9 F+ C6 q$ B& d; p: t8 n
  654.                         }
    ' N( i# G7 }2 c9 V
  655.                 }
    5 E! B7 Z- O/ T* t- s
  656.         }while(ReadByteNum);8 o* f# L, T" }% D) W3 G
  657.         //读取完成了,等待STOP位有效
    & W: h. y0 p& R3 d
  658.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);3 r* ?4 \" K/ @( f& g8 @
  659.         if(Error != IIC_OK)
    0 f/ z7 C9 u  |& R3 {
  660.         {, M1 O' W: X5 W* c, B5 L# q  I
  661.                 Error = IIC_STOP_ERROR;, }# w# O$ l6 q, O: l# o
  662.                 goto end_loop;+ C6 e( @$ w4 T% E3 e! m
  663.         }        
    ( h' z* G/ O# X! Z9 p
  664.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态5 c! \7 W! E8 q5 r. P6 v0 j/ H
  665.         ) C' @( O8 a2 l
  666. end_loop:        * i, O# O5 |1 p$ I9 w9 w) Q
  667.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        
    % w- Q+ k3 ?' F6 ?  e( H4 _
  668.         if(Error != IIC_OK), v3 ]; ]/ d/ f' D7 A
  669.         {
    ) D9 o' \$ Y! S$ a% C3 V5 n
  670.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误
    1 I* b# b7 m* g8 {+ K* F2 m. D+ J
  671.                 DEBUG("[IIC R错误]:%d\r\n", Error);6 r+ t9 S; n) V8 ~
  672.         }
    , Z5 h. \6 C* h( J
  673.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的6 R8 j1 d! ^5 z4 [$ m# r* ~
  674.         {
    3 L1 g9 u. L, I4 n! D4 `
  675.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    2 ^' ]3 m. P8 E8 y
  676.                 DEBUG("IIC R结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);               
    * H) Z2 @$ \" A6 x" n
  677.         }7 {  s: D. ~( ^. l6 S4 ^
  678.         
    " B! p9 u% @9 `( i8 D+ F
  679.         return Error;
    0 I' }# d9 e% H/ x9 i
  680. }
    1 Q9 l, X# c( P1 J* @  T
  681. 2 @7 J( @. \! J3 j0 K; l* K% j
  682. 7 V3 [5 g/ |3 k
  683. /*************************************************************************************************************************. H# g' \+ Y! J- M* K( K% O: \
  684. * 函数        :                        IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, 6 F: X" @/ s3 P
  685.                                                 u8 *pDataBuff, u16 WriteByteNum)
    $ s7 k9 f$ Q( \5 k4 V7 A4 S
  686. * 功能        :                        IIC写寄存器(可以写1个或者多个寄存器)
    $ V& d$ j+ I5 q* D% [$ C& f! C
  687. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要写入的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;$ v/ V8 u" v8 R3 l
  688.                                                 pDataBuff:写入的字节数据缓冲区;WriteByteNum:要写入的寄存器数量;: Q  J) l5 o! K) `( O' n4 j8 a6 ]
  689. * 返回        :                        IIC_ERROR
    ! P6 B& A6 V' \9 n7 I/ v5 p
  690. * 依赖        :                        底层宏定义1 v, j& I& b8 I/ x% v! N2 l) w
  691. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>  M3 n, R5 C: g: }* p
  692. * 时间        :                        2020-02-16
    6 Z6 M, [0 `5 [; }7 O$ x, [- {
  693. * 最后修改时间 :         2020-02-16
    ! D+ C' F1 s: o  a
  694. * 说明        :                         写入的数据都是小端模式,如果是16bit的寄存器,请写入偶数个数据,并且需要提前进行高低字节对调最后组成高字节在前的数据buff7 F) V' N6 V# z* X' k  ]' S0 E& z4 D
  695.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
    . n; D) j, ?- l* ?6 N7 |  c# z. T
  696.                                                 增加信号量  f; B5 H! x3 o  Y% m$ y, G+ w
  697.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在7 A' F; V/ U) p6 j6 J# @
  698.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。
    ; S. q4 ]- G! M! L- \( u$ t
  699. *************************************************************************************************************************/
    + e# X  ?) P# _! _
  700. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum)
    ( G' w8 y5 ?/ G& ~+ y% X, L& i
  701. {  m! t- D; U' ]$ C) a
  702.         IIC_ERROR Error = IIC_OK;
    0 z$ j8 U' }) T2 H' Y
  703.         u16 ReadCount;4 e2 S! r0 q2 w4 B) Y
  704.         IIC_HANDLE *pHandle;9 L$ \7 ~  H8 V, |
  705.         5 {3 w, y# D9 ^- }; Y  i1 o( ~
  706.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || WriteByteNum == 0)
    ( Q  G8 b- z3 u- F" M5 v
  707.         {
    % Z- f3 k4 @  `: r1 E8 B, r' Y- `
  708.                 DEBUG("IIC错误:无效的参数\r\n");" U) V% \$ j& e% x% X  S' h) T, ?
  709.                 return IIC_PARAMETER_ERROR;9 X+ T% q$ G8 {9 \' ~6 Z( H' p/ o" U
  710.         }
    - ~# j1 P1 C* |& b- \
  711.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄* C: `1 y- P6 X  L' x4 N
  712.         
    ! _2 x6 G0 v( u4 B$ V5 v) V
  713.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙
    4 L' X# v5 z2 m" P
  714.         {
    ( T: M7 \$ a! C6 W) S; y
  715.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");0 A' N  k7 A! R% F9 n3 A3 p
  716.                 IIC_SoftReset(pHandle);
    4 M* z3 H1 h' H* b# S
  717.                 / Q# `# a3 r8 N) S' l0 Y
  718.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)        //忙
    $ ~; |$ m7 O" h: |$ _: F1 l
  719.                 {4 c& O+ p4 t1 y& C0 P+ f/ T
  720.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");
    " y- n0 @. W) ^1 ]* [% K* |4 |% B
  721.                         Error = IIC_BUSY;
    " x. u$ k# x0 H+ {# U2 ?2 S. p
  722.                         goto end_loop;$ h1 r6 ?; j8 \3 n% \# H2 M& C
  723.                 }
      s3 k9 C3 [7 {% o
  724.         }
    ' g+ R8 z2 A+ A2 k% a: F- q
  725.         7 G$ H; {( g. ?8 b
  726.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    9 H7 ^$ g3 L! n8 ?" w
  727.         IIC_ClearCR2(pHandle);                                                //复位CR2寄存器& {6 G$ R* U8 b4 L! F4 w8 y
  728.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    - j4 X' f1 ~( A/ Z2 c. K+ d0 B. O
  729.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,FALSE,  pHandle->TimeOutUs);) b# P9 i" {+ c0 F
  730.         if(Error != IIC_OK)
    & l8 s( T3 \7 r! ]
  731.         {1 `+ L& g' M) c' f6 [
  732.                 goto end_loop;8 Z" v1 l3 h$ k  l4 Z
  733.         }0 C$ E/ k7 N2 m5 i3 C  f# o, b% X
  734.         //发送后续数据5 S  f$ [* X' @- k- i( q
  735.         if(WriteByteNum > 255)                        //如果超过255字节,则需要分多次写入-后续还有数据,需要重载& C# T$ }: v5 V- a# v; s8 C+ h
  736.         {! o: Q: k9 ^2 K8 Y' u0 C
  737.                 ReadCount = 255;                        //本次需要写入的数据长度2551 Q  Y" a6 \1 V' v. w
  738.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入                6 N3 {: c" A4 _8 c
  739.         }* K0 p: p: m0 ]3 Z% A" z
  740.         else
    ( K0 B6 O2 i& t/ A
  741.         {
    - N4 G9 k( x" s. g
  742.                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯后自动结束
    % y, r9 Q5 d' H: c, K+ i
  743.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入+ ]; O6 ~: c1 a% N. J# n: o& V1 M
  744.         }
    $ G" Y' C- d+ D& v# o9 A; v8 G2 N
  745. 8 ], p+ C2 [  ~! A% y4 ?+ B3 J! p3 P
  746.         //循环发送数据3 M, ?+ a2 _. Y( r4 c0 M
  747.         do
    1 e1 p: v3 L: \/ S
  748.         {9 Q) H; p! W6 W, l+ p, P( g
  749.                 Error = IIC_SendByte(pHandle, *pDataBuff, pHandle->TimeOutUs);        //发送一字节
    : U4 ?7 D" u% r2 H9 b! ]
  750.                 if(Error != IIC_OK)
    , Z3 M! W" a" ~# b" K& i
  751.                 {4 J- R. v- j8 g% {: P
  752.                         goto end_loop;! n3 T7 Z  T4 s/ K) f; g! w8 |
  753.                 }
    ; x8 s: Y) ~! A4 ~- g
  754. ! _) e) g' C1 J  m* w& h
  755.                 ReadCount --;$ Y) r8 `; k3 o1 X9 A1 o
  756.                 WriteByteNum --;
    / r; x# m+ A, a
  757.                 pDataBuff ++;( ]- z3 i; B; B5 b$ C5 }' o8 l
  758.                 3 G% K& _+ u8 j+ \
  759.                 if((WriteByteNum > 0) && (ReadCount == 0))        //还有数据要读取
    7 u. D$ j/ W$ E) X3 ]( i2 H
  760.                 {
    / k6 H; E+ j  K- M* k, i( O! a
  761.                         if(WriteByteNum > 255)        //如果超过255字节,则需要分多次读取
      B3 _+ }. k, `, l/ f" c
  762.                         {" g3 I; i2 I4 b) I1 g& g$ W
  763.                                 ReadCount = 255;        //本次需要写入的数据长度255-后续还有数据,需要重载* @" |1 d6 H" P1 N6 k7 w; P
  764.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入
    - D$ ~* U- i6 M) @. T- x% R- I' `) f
  765.                         }
    6 a2 }5 |' h+ i3 U6 ^8 q, v
  766.                         else5 }3 [9 Y* M0 N$ |9 a
  767.                         {8 B. |9 C8 t; J* B( _
  768.                                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯,自动结束
    8 D' w* W3 g. h# l& ^! ~: C+ Y# [
  769.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入               
    . h; m0 {6 W6 R  c9 Z9 i
  770.                         }
    ' _) c! }. w# c# ^( K+ V; g1 D
  771.                 }
    % M8 r3 F4 k7 P+ T3 C! X- o9 E
  772.         }while(WriteByteNum);        
    . o8 K" w' M4 d+ v
  773. 4 i9 g5 w% [$ o# S; H
  774.         //写入完成了,等待STOP位有效
    ( t. {" R1 e% c
  775.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);2 M% @. d4 K  |" p# ~1 p
  776.         if(Error != IIC_OK)
    2 L7 m6 o; X2 T" l
  777.         {  N2 A4 x+ c7 H! R( }# t- i* i
  778.                 Error = IIC_STOP_ERROR;# n$ T& ?9 w& t* _( t
  779.                 goto end_loop;1 Q% t: J7 R5 x  C; |5 {6 r: H
  780.         }
    ) C  Z8 `2 v! E+ w5 }- C1 O. V5 \
  781.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态2 ]( x' I: v# Y$ F
  782.         
    & a; b. z) a5 U4 f. `
  783. end_loop:        
      q' V6 ^: d5 D% c/ N" }4 Y
  784.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        
    & r9 J8 \5 L7 i
  785.         if(Error != IIC_OK)
    6 k; G/ c, I. e7 g5 t, q, |$ J
  786.         {. M2 y1 u+ @0 d' [, L- u
  787.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误
      j3 M* e5 L) L; m9 l0 t; }3 \
  788.                 DEBUG("[IIC W错误]:%d\r\n", Error);
      _* {/ J4 z; E5 M: E! Q( m" W% T
  789.         }. }/ O% Z& T, u4 ]2 }2 ^
  790.         
    7 ?( ^" X6 o7 b" h! b# i  X- e
  791.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的3 X/ d; i8 P& \! F& i
  792.         {
    ( Q2 Q3 F3 e2 @' E" r* T0 F
  793.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线9 H; L5 [7 J- J1 B! V( p& H
  794.                 DEBUG("IIC W结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);                * T! I, D4 P* x+ v+ c& t
  795.         }
    3 |! A8 s3 A4 u4 a" g0 X$ ?* N" P
  796.         return Error;5 [  K+ \9 [, b
  797. }5 u0 q- q) R, p0 u, ]+ b1 l/ J" a
  798. & C$ h1 _1 N2 z5 ]; g8 E
  799. ) |& m6 U$ r$ @* }$ B2 V3 H" N
  800. /*************************************************************************************************************************
    # ^1 w+ m9 [) k" V
  801. * 函数                        :        void IIC_SoftReset(IIC_HANDLE *pHandle)
    7 ^$ |, K/ ^7 ^! \* o
  802. * 功能                        :        硬件IIC软复位(会使能IIC)  l; B8 M0 `4 L: l* _/ f! ~
  803. * 参数                        :        ch:IIC通道& Y3 ^  D, G) l: v" w
  804. * 返回                        :        IIC_ERROR$ Q5 d8 |% P) S( v
  805. * 依赖                        :        底层宏定义& K' W! x+ u; l; P' b, N
  806. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    # n7 R# K" F6 E' R7 r) l
  807. * 时间                        :        2020-02-15
    ! q  r0 D  B% C! H, t* C. w
  808. * 最后修改时间         :         2020-02-15
    * N2 I9 I6 @* {7 d+ E& ?  ^# s
  809. * 说明                        :         IIC软复位;必须使 PE 保持低电平持续至少 3 个 APB 时钟周期,才能成功执行软件复位。$ i$ l* n( ~* r* Q/ _3 G4 x2 P
  810. *************************************************************************************************************************/
      ~  ~4 m+ y; s- Q2 r
  811. static void IIC_SoftReset(IIC_HANDLE *pHandle)7 J4 p3 c$ w5 d7 l- O; t0 @
  812. {3 X. r, v- K. U
  813.         pHandle->I2Cx->CR1 &= ~BIT0;                //关闭IIC后执行软复位
    4 ^$ y! _+ ?7 o
  814.         Delay_US(1);        - P# h) z- D. r& P/ {
  815.         if(pHandle->I2Cx->CR1 & BIT0)/ V# d% v9 O5 W9 z
  816.         {4 a) U4 R+ S) ]; ?) B/ t; u
  817.                 DEBUG("IIC软复位失败\r\n");9 R% Z9 x' t$ B) ?" G9 @
  818.         }
    3 q0 i, {8 G) V4 h  T
  819.         pHandle->I2Cx->CR1 |= BIT0;                        //重新启动! j. S" ~# t! ^' I
  820.         Delay_US(1);        
    ) r5 x* y% C, p, Y* {
  821. }3 b7 J+ ]! H) v/ Y+ ~

  822. ( s9 V: P; n' R& w  f

  823. - e) r  }& @3 ~5 \6 ]- I$ p  U, Y% T; G
  824. 0 P' h& r0 ^3 j/ |; @8 n- A" \% ^. x
  825. /*************************************************************************************************************************5 n: f! S% q% I( B4 C
  826. * 函数                        :        static u32 IIC_CalculationTiming(u16 Speed_KHz)" v& w4 G  A$ E: G! [$ z
  827. * 功能                        :        硬件IIC时序计算
    " k  s3 b1 W2 \: X5 v: g& Q
  828. * 参数                        :        ch:IIC通道;Speed_KHz:速度10-1000
    " L" i! [: y3 E' I9 A
  829. * 返回                        :        IIC_ERROR
    3 W) D/ z! W# u0 ?' O" i6 h
  830. * 依赖                        :        底层宏定义" r6 q9 c! v8 C
  831. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>. g& `  P0 Y; j5 n4 _
  832. * 时间                        :        2020-02-15- s& c* X9 y  V4 h
  833. * 最后修改时间         :         2020-02-15& ~2 p7 x$ D& m7 u5 |+ y6 V
  834. * 说明                        :         IIC使用的是APB1时钟,将IIC总线时钟控制在100KHz        7 f/ j0 m( v5 g0 \1 R' U3 }1 E( E
  835.                                         APB1时钟:最大不能超过45MHz        . q/ e8 }4 }1 z$ N7 j5 d3 L
  836.                                         如果速度是100,则按照SMBUS时序5 d& I3 y- i8 u4 x
  837. *************************************************************************************************************************/
    5 |; H5 L& r. z1 X8 N% c
  838. static u32 IIC_CalculationTiming(u16 Speed_KHz)
    - y  Y# M7 ]- k& s7 l
  839. {
    . K7 x% g$ I8 J
  840.         u32 tTime = 0;- `) J, d! s. a/ w
  841.         u32 temp;. b6 ?* ]6 U. r0 q7 e
  842.         u32 time_temp = SYS_GetAPB1ClockSpeed() / 1000000;                //先获取APB1时钟速度
    ! [4 \2 d, G/ a: E* z
  843.         u32 Th = 1000/Speed_KHz/2;                                                                //计算高电平时间(低电平时间一样),单位ns
    ( U9 Z4 m6 S  J
  844.         
    2 t4 y4 v0 \% t
  845.         if(time_temp < 20) time_temp = 20;
    7 n, {, f3 @* I% Z
  846.         time_temp = 1*1000 / time_temp;                                                        //单位ns# B& y1 t& r& k. v: @% H
  847.         uart_printf("IIC时钟计算->APB1周期:%dns\t", time_temp);$ i5 h) y( D3 C* a: b
  848.         if(Speed_KHz == 100)        //如果是100,则按照SMBUS时序+ N6 m, U1 _9 e! j
  849.         {
      ~. d) ~* h3 F6 _! {6 b
  850.                 //主时钟分频系数固定为3
    " l" J5 ?& ?/ ]  |/ A! {! `+ s
  851.                 time_temp *= 3;                        //主时钟周期" A9 s$ b  ^" M* U: {0 [
  852.                 uart_printf("IIC时钟周期:%dns\t", time_temp);" `; o* M" ~, \1 X: k3 z( n
  853.                 tTime |= (3-1) << 28;        //PRESC,时钟预分配- C$ w* d. h2 v* M0 u
  854.                 //计算数据建立时间,要求最小250ns* c. ~! R1 Y: R% a
  855.                 temp = 250 / time_temp;
    . W3 c8 |; ]$ e" ~  D! e
  856.                 if(temp > 15) temp = 15;: |" J" Y5 P* O# ?' N
  857.                 if(temp < 1) temp = 1;2 C' k: N7 `2 R  w" U  j( q
  858.                 tTime |= temp << 20;
    # [+ B% i: R0 m6 i* J
  859.                 //计算数据保持时间,要求至少300ns# i* G- E/ b: A
  860.                 temp = 300 / time_temp;+ R; G3 x; q, _& \' x" x
  861.                 if(temp > 15) temp = 15;
    2 x7 W! C: ^! o* S* M5 Z/ k
  862.                 if(temp < 1) temp = 1;
    * n+ L' I) k4 a. }1 s
  863.                 tTime |= temp << 16;4 k1 P4 \2 @% D4 Y1 o! R8 f( r. w5 x* L
  864.                 //计算高电平周期5us; ^9 K7 @0 [' h4 x( Z* R" j
  865.                 temp = 5*1000 / time_temp;/ H3 {" ~/ X, U" \, _$ v9 `- S% N
  866.                 if(temp > 255) temp = 255;8 k& H; s/ N; p. [- ?+ n7 m
  867.                 if(temp < 1) temp = 1;5 w. z1 O& x1 R7 \: }* y8 y
  868.                 tTime |= temp << 8;2 R! V% ?+ D' r6 {5 i6 a9 |0 w# U, y
  869.                 //计算低电平周期5us
    6 H- ?4 ~& P" a% }
  870.                 temp = 5*1000 / time_temp;: j: K6 D2 N: \; T6 f( I5 D. c7 k
  871.                 if(temp > 255) temp = 255;: I3 s4 Y3 {7 b+ @, ^. X
  872.                 if(temp < 1) temp = 1;
    / I; g3 m& r! e5 [3 V: ?# `
  873.                 tTime |= temp << 0;& c  w. ~+ K' @2 Y: i
  874.         }
    . l  H! t0 e7 Y3 z: K$ d) c2 o( s
  875.         else if(Speed_KHz < 100)
    & r; Y: C4 @6 `" x/ g% K; q
  876.         {+ e  n7 G1 I7 f! ?& G; F  O& ~
  877.                 //主时钟分频系数固定为6
    ) K( ~4 c% ~" x; H* }
  878.                 time_temp *= 6;                        //主时钟周期  C% N, Y$ C/ ~" w( q
  879.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    / m8 V# t! {' v5 W6 d+ A
  880.                 tTime |= (6-1) << 28;        //PRESC,时钟预分配# ]% {& Z5 p. F. K' z( ^3 _+ F
  881.                 //计算数据建立时间,要求最小250ns
    % D7 H8 R' S- u" b: @6 q
  882.                 temp = 250 / time_temp;
    1 h8 n9 r9 N: ^" U; s# u& c$ L
  883.                 if(temp > 15) temp = 15;
    ' h6 l& c6 ^+ Z: p1 m/ Q
  884.                 tTime |= temp << 20;
    & E" }% N4 b: M8 U) u
  885.                 //计算数据保持时间,要求至少300ns
    3 T+ P: M2 j2 R/ f
  886.                 temp = 300 / time_temp;
    7 `5 E3 T. a6 h( D5 ~+ B8 p4 ~
  887.                 if(temp > 15) temp = 15;7 O  G  Q' m$ r" Z2 _
  888.                 tTime |= temp << 16;
    4 G! {( q/ x1 H
  889.                 //计算高电平周期Th us! @* Z  f; f5 K9 ?
  890.                 temp = Th*1000 / time_temp;; z4 k9 Z4 G' A; W3 ]( P5 }
  891.                 if(temp > 255) temp = 255;
    ' A0 c$ b% N, m. ^6 _% r
  892.                 if(temp < 1) temp = 1;
    9 C( V' o$ N' I' l- d" m
  893.                 tTime |= temp << 8;
    8 u7 m& D/ d7 M) {8 u! P
  894.                 //计算低电平周期 Th us" |3 |3 ^& j: M' \3 X7 O: k* G
  895.                 temp = Th*1000 / time_temp;" M: r0 T( ]) B; e  Q" C3 F$ n
  896.                 if(temp > 255) temp = 255;" N- k1 u5 B4 P# \
  897.                 if(temp < 1) temp = 1;/ a( h  L% I) U5 b9 b2 f6 [
  898.                 tTime |= temp << 0;
    + h! o. ?8 I- P
  899.         }
    - d( Q" M& ]0 g( Q
  900.         else //>1005 _( X" G4 H& i0 T, ^; {: b
  901.         {
    - p2 |. n% I( z
  902.                 //主时钟分频系数固定为2" X8 M2 c/ ?( g, ~1 B! w# H+ t
  903.                 time_temp *= 2;                        //主时钟周期
    % ?' }. a1 G+ o) B2 p
  904.                 uart_printf("IIC时钟周期:%dns\t", time_temp);( @+ ?% z, @0 B7 S# y$ @
  905.                 tTime |= (2-1) << 28;        //PRESC,时钟预分配
    $ X! q5 O" ^; V( P9 ?+ O: n
  906.                 //计算数据建立时间,随便给100ns. f1 I1 }7 y- u" \7 v6 R1 O
  907.                 temp = 100 / time_temp;
    3 @( U* O$ m, f/ ]$ Z+ k
  908.                 if(temp > 15) temp = 15;! x- Z* G. _, z8 M' F
  909.                 tTime |= temp << 20;
    9 g& F  n4 D  |* l" _
  910.                 //计算数据保持时间,给100ns& S$ |# b% |7 |1 s* ^; C
  911.                 temp = 100 / time_temp;9 y7 I; K) u( P& r. f3 X
  912.                 if(temp > 15) temp = 15;
    / q; J; @$ ^: [% z& G
  913.                 tTime |= temp << 16;, q' ^5 {8 i8 ~6 V/ Z- |
  914.                 //计算高电平周期Th us* P+ D; P, K2 r2 f; ~) h- p
  915.                 temp = Th*1000 / time_temp;
    & G2 ~0 v# j" q) f' b
  916.                 if(temp > 255) temp = 255;
    9 Q/ K1 X# r5 a" P/ X
  917.                 if(temp < 1) temp = 1;$ ]6 v3 g$ c8 E0 w
  918.                 tTime |= temp << 8;8 ]. u% Y( A' l& L& C! W
  919.                 //计算低电平周期 Th us: c: }: C/ e8 @( t8 |$ l
  920.                 temp = Th*1000 / time_temp;5 Q2 S' O% i3 v& T  ~" L
  921.                 if(temp > 255) temp = 255;
    4 @, B1 |& J) K; _1 P
  922.                 if(temp < 1) temp = 1;0 G1 b- M) q. j" J
  923.                 tTime |= temp << 0;
    % v  P5 Z3 }' g" G6 W
  924.         }/ P. z$ T9 F( f" r5 |# L
  925.         
    - c; L% C5 ]! R% h2 t& x% a
  926.         uart_printf("时序寄存器结果为:0x%X\r\n", tTime);3 j6 [1 I; V- ?7 {; e
  927.         4 ~; W, C: X5 o9 y0 N. Y7 E9 U
  928.         return tTime;
    - }, a- q/ z# B2 H9 x
  929. }
复制代码

% n$ h) [* s1 z' H2 f+ @0 D* q  i! N) m* D
  1. /*************************************************************************************************************
    * i8 c2 y- ?# s% _6 b
  2. * 文件名                :        stm32f7_iic.h3 U$ x( W0 Y" g* S! f
  3. * 功能                        :        STM32F7 IIC接口驱动
    8 r( y0 _( h" w* x; V; O0 m8 u
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    # b! {* Z( v' H$ F8 S7 h
  5. * 创建时间                :        2020-02-09
    7 J, m" {0 B* D1 P9 _/ Y# m
  6. * 最后修改时间        :        2020-02-09# j% E, j8 ~, J% A# q
  7. * 详细:                        
    4 V0 @, v6 K" Z% ]
  8. *************************************************************************************************************/                : @- y* p! ^0 g3 Q$ c& p0 a3 N0 m
  9. #ifndef __STM32F7_IIC_H_: o2 L9 h3 V  ~) V/ y
  10. #define __STM32F7_IIC_H_
    % C" ~4 }/ F+ n7 T1 q, q: i& v2 d
  11. #include "system.h"
    ' T4 f( P; L5 C0 P$ p

  12. , c+ m5 a, a. z
  13. //16位整形数高低对调4 p1 H0 x5 c. O# a( }& o& e
  14. #ifndef SWAP163 x; W$ o! w: O- u/ d' O9 j
  15. #define SWAP16(x)   (((x & 0xff00) >> 8) | ((x & 0xff) << 8))
    * w! o3 C% s/ x& C8 Y9 r. ?
  16. #endif  //SWAP16
    % H6 Q. a* `+ `# `9 m8 M
  17. * s  t# ]/ Z$ i- z
  18. //硬件IO口选择, ]$ @6 o* a, M+ z2 O
  19. //I2C1 IO定义与选择( R) t6 p2 }: t' u( O4 f: K
  20. #define IIC_CH1_PB6_7                                0                                        //PB6,PB72 l2 t8 c. {9 E9 i
  21. #define IIC_CH1_PB8_9                                1                                        //PB8,PB9
      t+ T1 M0 c6 r* S# ^  a0 q4 o
  22. #define IIC_CH1_IO_SELECT                        IIC_CH1_PB6_7                //选择I2C1 的IO        
    6 E3 ]. R7 N( ?3 Z. z" G, ~) j
  23. 2 [9 d, d; r4 G- f
  24. //I2C2 IO定义与选择
    # t' o6 F$ p3 x: Y6 g7 R. z
  25. #define IIC_CH2_PB10_11                                0                                        //PB10,PB11
    + W/ G, E5 U8 v
  26. #define IIC_CH2_PF0_1                                1                                        //PF0,PF1& H: ?2 M3 e4 F% b5 e7 j- m" G( t$ f
  27. #define IIC_CH2_PH4_5                                2                                        //PH4,PH5: z9 u- s( t( E/ E# ]4 l1 s
  28. #define IIC_CH2_IO_SELECT                        IIC_CH2_PB10_11                //选择I2C2 的IO) s. @9 T4 f& E2 p7 S8 Q

  29. ! R% I7 L) M3 S, M& ?
  30. //I2C3 IO定义与选择
    * a0 {7 S; v( g* S: W) ~
  31. #define IIC_CH3_PH7_8                                0                                        //PH7,PH8! w0 `; N, P5 }$ k7 b: w
  32. #define IIC_CH3_PA8_PC9                                1                                        //PA8,PC9, k9 a, e; u% k& _
  33. #define IIC_CH3_IO_SELECT                        IIC_CH3_PH7_8                //选择I2C3 的IO
    5 X1 Q5 B3 f9 y6 V
  34. ( M1 Q/ d! [( j2 s! b4 s
  35. //I2C4 IO定义与选择
    * C& n9 W) f& \! ~9 |) u) r" F, M
  36. #define IIC_CH4_PD12_13                                0                                        //PD12,PD13; x0 ]4 \& A# Z- B
  37. #define IIC_CH4_PF14_15                                1                                        //PF14,PF15: _$ o, u; g' b, Q
  38. #define IIC_CH4_PH11_12                                2                                        //PH11,PH12
    9 L4 R6 B* ]! z
  39. #define IIC_CH4_IO_SELECT                        IIC_CH4_PD12_13                //选择I2C4 的IO
    7 ~+ Y1 ]$ w& |9 |3 ~9 I1 @5 u

  40. 7 w8 T1 I# A) N
  41. //IIC硬件接口选择
    5 v  e/ @0 ~" u' ~( C
  42. typedef enum
    2 ?* Z) Y, B( K% N
  43. {- f7 s; \) ^* I, K
  44.         IIC_CH1        =                0,        //IIC1
    6 T- b& c  w/ ^2 x; B) n3 y: ?
  45.         IIC_CH2        =                1,        //IIC2
    ( s" B' q% Y5 A3 T& y8 `7 W/ R8 `/ ^
  46.         IIC_CH3        =                2,        //IIC3
    - i/ Z4 f& ]  _. N( F1 Z
  47.         IIC_CH4        =                3,        //IIC4
    $ Q7 t+ e9 K# \
  48. }IIC_CH_Type;
    . j9 v6 X8 n* w9 F! R6 `
  49. #define IIC_CH_COUNT        4        //4个IIC# v# o% L9 B% m9 B! O
  50.   I6 b& K' B; n
  51. 4 u; w8 [/ O- s
  52. //中断状态1 h! S, j- t1 r* |1 u9 o
  53. #define IIC_FLAG_TXE                    BIT0        //发送数据寄存器为空(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。
    " a, o# B" X5 s- g3 N
  54. #define IIC_FLAG_TXIS                   BIT1        //发送中断状态(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1,待发送的数据必须写入 I2C_TXDR 寄存器。
    1 Y# r* \3 T/ g; C0 c6 J% f( D
  55. #define IIC_FLAG_RXNE                   BIT2        //接收数据寄存器不为空(接收器); 当接收到的数据已复制到 I2C_RXDR 寄存器且准备就绪可供读取时,该位由硬件置 1。读取I2C_RXDR 时,将清零该位。
    # b1 K9 ^8 q# t0 T, h
  56. #define IIC_FLAG_ADDR                   BIT3        //地址匹配(从模式); 接收到的地址与使能的从设备地址之一匹配时,该位由硬件置 1。该位由软件清零,方法是将ADDRCF 位置 1。
    % g# m: p6 z+ |# y
  57. #define IIC_FLAG_NACKF                  BIT4        //接收到否定应答标志; 传输完字节后接收到 NACK 时,该标志由硬件置 1。该标志由软件清零,方法是将 NACKCF位置 1。5 S) [- j( S" K% d* a6 t
  58. #define IIC_FLAG_STOPF                  BIT5        //停止位检测标志; 当在总线上检测到停止位,且外设也参与本次传输时,该标志由硬件置 1
    5 v" H' Q/ U' Y, R0 \) [
  59. #define IIC_FLAG_TC                     BIT6        //传输完成(主模式); 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 START位或 STOP 位置 1 时,该标志由软件清零。
    9 N6 W% o) j9 Z1 P
  60. #define IIC_FLAG_TCR                    BIT7        //传输完成等待重载; 当 RELOAD=1 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 NBYTES 写入一个非零值时,该标志由软件清零。7 W5 d4 y4 W4 ?1 L! b8 e
  61. #define IIC_FLAG_BERR                   BIT8        //总线错误; 当检测到错位的起始位或停止位,而外设也参与传输时,该标志由硬件置 1。在从模式下的地址阶段,该标志不会置 1。该标志由软件清零,方法是将 BERRCF 位置 1。
    : i' }" r' G2 E4 k, D/ m
  62. #define IIC_FLAG_ARLO                   BIT9        //仲裁丢失; 发生仲裁丢失时,该标志由硬件置 1。该标志由软件清零,方法是将 ARLOCF 位置 1。7 T& W1 ]- j2 O. `+ Y! j9 Y
  63. #define IIC_FLAG_OVR                    BIT10        //上溢/下溢(从模式); 在从模式下且 NOSTRETCH=1 时,如果发生上溢/下溢错误,该标志由硬件置 1。该标志由软件清零,方法是将 OVRCF 位置 1。( ?! _6 y; }! i8 ?1 B5 A* Q
  64. #define IIC_FLAG_PECERR                 BIT11        //接收期间的 PEC 错误; 当接收到的 PEC 与 PEC 寄存器的内容不匹配时,该标志由硬件置 1。接收到错误的 PEC 后,将自动发送 NACK。该标志由软件清零,方法是将 PECCF 位置 1。
    , h# u: W* l  ^* |$ q
  65. #define IIC_FLAG_TIMEOUT                BIT12        //超时或 tLOW 检测标志; 发生超时或延长时钟超时时,该标志由硬件置 1。该位由软件清零,方法是将 TIMEOUTCF 位置 1。
    ( H5 _. E, }) @" S; C
  66. #define IIC_FLAG_ALERT                  BIT13        //SMBus 报警; 当 SMBHEN=1(SMBus 主机配置)、ALERTEN=1 且在 SMBA 引脚上检测到 SMBALERT 事件(下降沿)时,该标志由硬件置 1。该位由软件清零,方法是将 ALERTCF 位置 1。
    ; k  f% v: l; g% l2 N8 a/ m" ]
  67. #define IIC_FLAG_BUSY                   BIT15        //总线繁忙; 该标志用于指示总线上正在进行通信。当检测到起始位时,该位由硬件置 1。当检测到停止位或 PE = 0 时,该位由硬件清零。+ T; g/ V3 N: ~( O
  68. #define IIC_FLAG_DIR                    BIT16        //传输方向(从模式); 该标志在发生地址匹配事件时 (ADDR=1) 更新。;0:写;1:读
    6 D7 J* R' ^, E0 \' j1 {; U
  69. 1 `" L8 f9 @; Q0 ?4 y( K
  70. //通讯错误状态5 n! I+ M; U2 M* n& a
  71. typedef enum
    9 T+ O2 w7 A7 J2 C! e4 Q3 y
  72. {3 h2 }& U. e3 Z. r1 S2 f
  73.         IIC_OK                                        =        0,        //没有错误
    : e9 ?$ H: T- o( a
  74.         IIC_PARAMETER_ERROR                =        1,        //参数错误( D  t% X2 d# W4 M  l1 L  W
  75.         IIC_TIMEOUT                                =        2,        //超时错误,也可能是底层错误
    & N) }& X: m8 ?
  76.         IIC_HAL_ERROR                        =        3,        //底层错误3 S  i! A8 D5 o1 W: ^
  77.         IIC_STOP_ERROR                        =        4,        //等待结束错误) d# y7 r, X- H3 x3 D* E
  78.         IIC_BUSY                                =        5,        //硬件忙
    ' b, ]% f- a8 L  {$ g
  79.         IIC_NACK                                =        6,        //收到NACK了
    3 i9 _" D. W8 U0 m6 B
  80. }IIC_ERROR;& I6 e- t! p# j; O- L# X2 d: l

  81. 5 v' s5 J1 _2 i0 }3 z4 O

  82. 6 y9 @9 G( [' P, G2 [' ?) w
  83. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs);        //硬件IIC初始化
    9 m" w0 G8 p$ ~  b8 Q8 K( W
  84. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum);        //IIC读取寄存器(可以读取1个或者多个寄存器)' a2 Z2 H* }; W' B) B1 m
  85. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum);        //IIC写寄存器(可以写1个或者多个寄存器)) `+ s# z3 [5 d$ ~7 X0 _
  86. ) M% i. O2 E& }# M' L; n

  87. / P9 A5 k+ L- W9 g( C, a; Q
  88. #endif //__STM32F7_IIC_H_
复制代码
" j% G' m3 v* D# X3 _0 _

9 i. l8 [( r. X& [) a8 k//初始化2 H9 B: W, W6 _3 Z3 t+ w0 d* J
" W$ j1 A4 I3 b6 O$ T
  1. IIC_Init(IIC_CH3, 200, 0);        //硬件IIC初始化
复制代码

( ~$ d# `# c- e6 Z
/ S  V, ^) G  U7 l. q//调用: Y, o! G4 p0 I; K. f" P

  1. ; }4 v9 X- L/ a* ?4 f1 J) U4 h
  2. //触摸屏IIC读取寄存器接口* R( N+ B* y$ N7 d& n5 p
  3. bool TP_FT5336_IIC_ReadReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)
    + A' ?* y' Z% _
  4. {+ i; b# g" a! E, D+ ]2 s8 [* S
  5.         if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)- v5 ^3 v7 B  E+ ^9 `
  6.         {
    ) e( ^4 T5 D' m8 t. c
  7.                 return TRUE;
    ' D9 ^1 d- p: I2 }
  8.         }
    + v8 X" [5 F9 q- ]+ k& T& C5 a: I
  9.         else; Y0 r( @" o7 s7 I; d( w( N# M. |
  10.         {
    ( w; _6 B- F( C" E% ]
  11.                 return FALSE;6 t. X, y7 d; t0 J7 u3 a6 i6 e
  12.         }1 z1 b! ^. q% W/ b0 @6 X
  13. }
      d& U! `" V, _) M0 z. D+ k, W3 k

  14. ' L9 W% C  o( X0 m
  15. //触摸屏IIC写寄存器接口
    3 t: O+ d4 e3 s6 t5 Y
  16. bool TP_FT5336_IIC_WriteReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)6 ]5 `$ n& N* `8 @
  17. {/ U  J7 p" `) b3 p! Q0 u
  18.         if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK), d" Q/ A5 y1 m1 x2 c2 @
  19.         {* R& c0 c+ a" k6 ]3 v$ _, M/ ~' b
  20.                 return TRUE;
    ; b7 a0 O. b  S
  21.         }
    - r) K3 \& s$ T/ c, r* z
  22.         else) K8 `+ h2 {1 i% u# X
  23.         {. }* P3 L8 K. d" z
  24.                 return FALSE;
    : n' I1 ^! n; m1 g& ]' V$ Q0 M  B
  25.         }$ U' b( B& E. b( V* e. b
  26. 1 B/ H7 z% y: K0 ~; x( L  v7 b
复制代码

- U* t8 V, [. a5 ?0 D1 A/ [' a
. D, }3 S3 V! T& ~1 F
# k; S7 J3 s' W0 ?1 L* p9 N  }
赞 收藏 评论0 发布时间:2021-12-11 12:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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