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

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

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
目前只实现了主设备模式,一般也只用到主设备模式,IIC如果不能使用硬件方式,读取大量数据的时候效率很大,由于只有1个字节的缓冲区,根本不能使用中断模式(实际使用过程中,IIC会造成100us以内间隔的中断,单片机根本扛不住的),所以建议数据少就直接阻塞,1个字节也就几十us,数据多直接用DMA,将线程阻塞,等待DMA传输完成,而不会阻塞CPU(上传的代码没有实现DMA部分,便于理解)。5 Z; }: i/ ~5 ~5 p* p% j' J9 e+ K

+ S! C5 j& w& G2 h. {3 F目前已经做了完善的错误处理,读写操作前都会清除中断,遇到错误会软复位,所有位置均做了超时处理,防止程序卡死,目前只测试了几个字节的读写,大量的,长时间的读写均表现稳定,目前手上开发板没有eeprom,无法做大数据的连续读写,如果你在使用过程中遇到问题,欢迎指正。6 [1 y3 `  j3 h2 p& ^

- T/ ^6 m5 x$ e4 t4 U/ x% H下面是IIC读写的时序例子,可以先熟悉一下,这样比较容易上手,哪一个环节出了问题也要调试。9 W, L  u) {: Q3 n
- \9 s2 ?. }' B- c0 D
20200216194202434.png

0 \/ F5 T( o7 `: A" p2 R4 Z
% S% _9 J# H5 N( l( |' I, X6 K$ a9 X
20200216194219185.png
% ?- `7 N3 h% J* A

' Q0 i) N5 S- |5 ~0 ?4 q! V
20200216194234908.png
+ J" _' x3 Y) }' E* E

6 F1 b. N1 ?% r+ B$ y
) W6 _- X5 l& v1 _6 F1 O( @下面简要说明一下STM32F7硬件IIC的驱动设计方式(建议先百度学习一下IIC的时序要求):, E* c+ N* G4 X' X$ A

; V0 G& }9 D% {- Q* i- L* k[基本的初始化]
& @5 @, f6 g$ B0 }: o" s0 f
, P% {% {/ k( @( p1.初始化IIC时钟,IO(IIC IO必须设置为复用开漏输出,这个很重要)。
! K5 d% t  Z% a- U' ?! j$ j% W
3 P% W+ N+ j! {6 z$ k2 l2.CR1先赋值为0,复位IIC.4 @7 c3 o; N% K! p8 W9 d4 z

3 M4 D/ }  K$ n" m3.除了TIMINGR寄存器需要自己计算设置好,其余寄存器全部复位为0
: @7 x' X0 ^1 \( L( p
0 L- s" Z; J1 X4.设置CR1使能IIC。4 N! m1 y! o; B3 h5 C
5 `, f8 |# ]5 T' {6 \$ U; _
注意:上面说到,IIC的IO必须初始化为复用开漏输出,我之前初始化为复用推挽输出,测试很久,只要一启动传输,就会立马收到NACK,然后是STOP中断,数据根本没法发送,弄了好久才发现是这个IO初始化的问题。6 O  G# G5 p& a' w/ s

: N; }9 M, A) R/ E
  W9 @. A& |! F
) L7 Y/ B  }& @: o, S7 l; I[读取]
- j! }) W* X' h9 u9 G4 h
$ @1 y. H7 z/ d# p1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。
) l+ Q1 v% [" n8 t) Y* z' a0 [7 q- H5 l* [$ x" E: s! D* b4 q7 o" h, I# O
2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)软件STOP,写模式,启动传输。' y3 F9 Z# B1 g

$ y2 V- {$ H0 y; O% q- q+ L8 I3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
  k6 s4 i' h/ ^! @% ?! U# }: y- P3 m2 u& A6 S3 b& [3 T6 [
4.等待TC置位,意味着上面的1-2字节的寄存器地址以及写完成了。
+ `' G2 a- [0 n) W8 m1 ?3 F, r$ n; |. w: U
5.根据要读取的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。
, Y2 Q* N: p: N8 a6 N. f5 ]! e! l
1 P( _3 O( }& b6.设置了从机地址,要读取的数据长度,之后设置方向为读取,然后启动START(从写切换到读要重新发送START,这个跟软件模拟是一模一样的)。
5 t" Y% E8 y& N+ V! f- q+ E; E. ]- P. ~
7.循环一个字节一个字节的读取数据,字节读取需要等待RXNE有效,只有读取RXDN寄存器,直到所有数据读取完成。
0 Z5 _* V! ?% v, s1 ^0 q1 b  k9 }" o6 x6 c
8.读取完成后等待STOP有效,因为前面在最后一包数据读取的时候使能了自动STOP,这个时候检查STOP是否生成。4 w) B5 C$ t1 t9 {7 v; ?0 [
6 ?( e4 V0 x' J/ L
9.需要注意的是,所有的操作都要给超时,并且是自己可控的,绝对不要有死循环,之所以一直说STM32的IIC死机很大程度上都是由于这个地方没有涉及好,我的程序设计方法是:一旦出现了异常,就复位IIC,如果不复位就会导致下次进去的时候IIC一直忙,因为还处于上一个通讯过程。/ {% D% ~- a2 M' {6 u- i: a
7 i- I( @0 s+ n

" ^0 C$ P+ p6 ?8 C- E1 U
( N3 l7 |- c9 a! b1 c1 P3 A+ X7 c[写入]5 \! {! G4 e* D- Z

# {+ k% ?1 ~4 t/ N% M- Q1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。$ \: I) ]2 W5 z1 [- k* ]9 y

% D" A. h- F. g- b2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)自动重载,写模式,启动传输。7 Z/ h4 M, A, \2 R% L

, U! W2 n9 y8 `" I' c: {3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
# q- q2 P  u' B. V7 ^. S1 Y- O) p/ V3 r# o
4.等待TCR置位,意味着上面的1-2字节的寄存器地址以及写完成了,已经发生重载了,后续可以继续写入数据了。
$ u' b( o9 k( e& @! X' [  H& w# E6 q  i9 ^# D9 b
5.根据要写入的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。
" t0 T9 b7 Q" w7 s6 a5 G) E, y) t/ c6 c0 m, J, U
6.设置了从机地址,要写入的数据长度,之后不用切换方向,不用启动START(都是写,不用重复发送START,这个与读取有区别)。
9 ]6 r4 d. y' m2 o8 Z6 n& y" ^+ k7 c
7.循环一个字节一个字节的写入,字节写入与步骤3一样,等待TXIS置位,就可以写入数据到TXDR。
9 V4 p2 p& p+ Y2 x, a+ E  L3 [- r3 P& ~9 q9 x0 E
8.等待STOP有效,因为前面在最后一包数据写入的时候使能了自动STOP,这个时候检查STOP是否生成。4 a. F* ~, B$ [  z" r  `: B  z

+ T3 G' M" b; b1 U" K. K9.需要注意的是,所有的操作都要给超时,跟读取一样。
, G, m1 Z5 F) D$ S, V
( r+ ?- ?3 p  i% C4 w. K$ c/ I- y$ X' n- I6 K& ?8 t/ \

) Y% p+ V7 y: v# `注意:IIC的读取实际很短,超时也不用给很长,以标准的100KHz通讯时钟速度,一个字节大概在90us左右,超时可以给个5-10B时间,也就是450-900us左右。
' m' W* K7 S+ D9 G7 L2 ]/ D) s
, F. _4 R* w+ D. h4 [8 h( D# H# ?% g. ], J
, W7 c- b9 ~( f, T$ S0 U. ^
好了说了这么多,具体的看代码中的注释,直接上代码(我只测试过I2C3,其余的理论上都是一样的,就是IO初始化部分有区别,别的通道没有硬件进行测试)5 n! o5 J9 S1 U( r3 ~/ R" q3 A

7 p5 h: E" ]) l* U8 Z5 {
  1. /*************************************************************************************************************; O2 ?) q; T+ o. C# @" M
  2. * 文件名                :        stm32f7_iic.c
    ! z# O! \' P7 I, X( j
  3. * 功能                        :        STM32F7 IIC接口驱动7 v* J8 @9 e+ Q( h
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    8 D* _' j7 J% L/ j
  5. * 创建时间                :        2020-02-09( A* j+ }$ Y: @( |, K5 ?2 w* s
  6. * 最后修改时间        :        2020-02-09% I# z4 ]/ @+ Z( I( B& n
  7. * 详细:                        只支持主机模式,7bit地址,默认APB1为IIC提供时钟
    " W/ Q8 K$ [2 R! n: B8 s) b
  8.                                         涉及到读写1字节的超时时间是us,其余的是ms
    1 i/ g- Y8 I/ o8 u
  9.                                         注意:IIC的IO必须初始化为复用开漏输出。
    % D- S5 V! a: H' \1 H! j9 r! q+ H2 ]
  10. *************************************************************************************************************/        
    ! w. v- R* o6 a" t
  11. #include "stm32f7_iic.h"
    7 F: w1 X5 ]0 I' ?" f. U! ?, c; X1 M
  12. #include "system.h"
    5 x2 G* w7 U5 U
  13. #include "dma.h"$ m2 k- B! h$ Y. W5 V% p2 R% D

  14. # l5 x2 X% J' r
  15. #define IIC_FLAG_MASK  ((uint32_t)0x0001FFFF)        //中断标志掩码3 s' P8 Z' K+ j" F9 y) C$ Y: S

  16. , ^) f% ^8 [# d; V! W5 ~
  17. //自动结束或自动重载设置(重载与自动结束只能二选一,或者都不选)
    2 W7 w9 Q% R7 r: I7 B, }" X4 f
  18. typedef enum
    : g! r  l" X3 e4 v) Z/ ^
  19. {# g* D/ H  V- w5 z% ?1 B% w% _
  20.         IIC_SOFTEND_MODE                =        0,        //手动结束,并不开启重载; n1 m+ m( R% C; A! W
  21.         IIC_AUTOEND_MODE                =        1,        //自动结束,用于最后一次通讯完成后自动发送STOP结束通讯" d, b2 O! h. g" o1 S# N  q3 ?, Q
  22.         IIC_RELOAD_MODE                        =        2,        //后续还有数据,本次通讯后自动重载,重新设置后继续通讯
      }9 {; q0 M9 Y. H
  23. }IIC_RELOAD_END_MODE;' C' ?; m3 ~5 f+ `

  24. ! E7 l, h% z, F4 \9 X: Q7 z
  25. //读写与开始模式控制
    - B: B0 t$ d8 x% J) i
  26. typedef enum
    ' z* k2 G& V/ g! o9 L
  27. {* n0 s! r0 w# D/ C8 y
  28.         IIC_NOSTART_WRITE                =        0,        //没有开始的写-用于后续数据的写入) |+ {* S3 H# ?1 l0 p! ~: F2 j) r
  29.         IIC_NOSTART_READ                =        1,        //没有开始的读-用于后续数据读取4 j4 k: O. M" _  d9 Y, N9 H
  30.         IIC_START_WRITE                        =        2,        //生成开始写-用于通讯开始时,写地址或数据
    / ], {( W1 I; W  F( t# w
  31.         IIC_START_READ                =        3,        //生成开始读-用于读取数据时切换到读取方向,并读取后续数据6 t$ V5 F8 h* g1 b/ T
  32. }IIC_START_WR_MODE;5 z7 w( B( g% u* T- T/ v7 J4 ~2 n
  33. 2 ]' `+ |2 k3 q4 M8 X4 m
  34. //IIC句柄
    0 U/ q* O; i/ M0 t
  35. typedef struct
    ; u( M0 A5 [, S6 F
  36. {# I0 w; e7 ]! I5 i+ L" F
  37.         IIC_CH_Type ch;                        //当前通道: x- l$ f$ Z& ~' O+ g  s- V& T5 c
  38.         I2C_TypeDef *I2Cx;                //当前通道外设结构体
    ) ^" I( ?: x9 ~! W
  39.         u32 TimeOutUs;                        //操作超时,单位us/ |' b8 O7 R) i$ j5 H3 @
  40.         u16 Speed_KHz;                        //通讯速度,单位KHz6 C" c- [( P5 p8 Z/ l' |9 f
  41.         bool isMasterMode;                //是否为主设备模式-目前只支持主设备模式
      ~- J( Z+ Y0 [+ s  X$ g
  42. }IIC_HANDLE;
    ; b8 E% D& o# @0 @# t, N

  43. $ K+ Q/ O' S! t0 g
  44. //IIC外设结构指针1 Y' r, k7 s7 h: d" u7 |
  45. static const  I2C_TypeDef * const I2C_TYPE_BUFF[IIC_CH_COUNT] = {I2C1,I2C2,I2C3,I2C4};+ b1 x* m8 ?3 N6 |7 i/ t3 ^" C
  46. //IIC通道句柄定义
    7 h$ {! {" D% n' K; A( G
  47. static IIC_HANDLE sg_IIC_Handle[IIC_CH_COUNT];
    0 g1 p# z& Y5 F$ ]

  48. & l6 C  R# @2 @- t# c7 S/ `
  49. //发送NAK
    & e0 C" w$ p" `! d- s: \8 h$ ^
  50. //static __inline void IIC_SendNAK(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT15;}# R8 _# `2 v& g7 `8 i( G' O2 g
  51. //发送STOP" T, r- E/ X/ k, c/ b0 s3 {+ G  k& ]
  52. static __inline void IIC_SendStop(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT14;}  t8 ?6 w, X2 q# f6 E2 Y
  53. //发送START
    7 w- k) r0 ~% f, Y& ?+ D
  54. //static __inline void IIC_SendStart(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= I2C_CR2_START;}8 c5 A9 {( r- Y# ?& }* p
  55. //获取中断状态  A# H7 r- I* S3 |. H6 F0 Q
  56. static __inline u32 IIC_GetISR(IIC_HANDLE *pHandle) {return pHandle->I2Cx->ISR & IIC_FLAG_MASK;}( {* f3 C3 I, V8 x2 K' l
  57. //清除中断状态) Q1 d9 F( m2 ~& |5 h. t
  58. static __inline void IIC_ClearISR(IIC_HANDLE *pHandle, u32 IsrFlag) {pHandle->I2Cx->ICR = IsrFlag & IIC_FLAG_MASK;}2 Z" n7 L: z- Q! D8 _6 g% g
  59. //复位CR2寄存器
    9 ^3 K4 b. P9 c% x1 E
  60. static __inline void IIC_ClearCR2(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 = 0;}
    4 T9 A+ m% x4 S3 W5 D
  61. " o+ @6 ^! J& J' d  ?: C
  62. static void IIC_SoftReset(IIC_HANDLE *pHandle);//硬件IIC软复位(会使能IIC)
    4 Y& Z3 G2 }6 F" |
  63. static u32 IIC_CalculationTiming(u16 Speed_KHz);//硬件IIC时序计算1 n) |& d: K8 G# o3 c

  64. 1 g$ x! O, |7 `6 q/ f' e$ W. k' i

  65.   t5 Z' F# V, T) i
  66. /*************************************************************************************************************************
    + n3 r% Q5 k  @
  67. * 函数        :                        bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)/ Z1 c9 z; J% O' \0 ]
  68. * 功能        :                        硬件IIC初始化. i( U8 `+ w. w  A: v* r3 {- A
  69. * 参数        :                        ch:IIC通道;Speed_KHz:速度10-1000(如果速度是100,则按照SMBUS时序);TimeOutUs:操作超时us(0:自定计算超时)" t. m) X6 g9 d+ E- q9 \; g" g8 ~
  70. * 返回        :                        IIC_ERROR
    . }! z/ Y/ C1 ]  j  i
  71. * 依赖        :                        底层宏定义3 w) X4 C5 Q- o$ ?1 B5 |! c
  72. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    3 n4 f6 F: f/ U( }. X0 X, r" {) |
  73. * 时间        :                        2020-02-15
    3 B: o! T; E! N0 M- J
  74. * 最后修改时间 :         2020-02-15
    8 p- X6 H. z8 J$ p& W. K
  75. * 说明        :                         速度只是个大概的计算值,设置为100KHz时会严格的按照SMBUS时序,其余的不保证SMBUS兼容,正常情况下只要时钟速度符合要求,
    , N- S% a& c' [: H$ E
  76.                                         时钟上升沿到来前数据以及稳定的切换了即可保证通讯稳定性
    $ G) x# f2 ], x, @2 j/ `- r+ k' G' ]
  77. *************************************************************************************************************************/. N  V; o1 ^/ F4 `, \: ?: x
  78. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs); G: C5 L9 d, Y. x& O8 b
  79. {
    ! d( D2 t6 C1 p) d$ J
  80.         SYS_DEV_CLOCK DevClock;% F  o( I$ v0 ]
  81.         IIC_HANDLE *pHandle;
    5 d! u( B3 b9 [' O5 `
  82.         3 h* q3 W( z+ G2 l* u% p- ?
  83.         switch(ch)
    ) j) g% o  ^/ p% L8 ^6 |
  84.         {
    4 ~0 R- J# q% D) X+ G' O" R7 P
  85.                 case IIC_CH1        :        //IIC1
    5 z, g, S! c" K3 n  F; f
  86.                 {0 H& |- T6 ]' M; @0 b
  87.                         RCC->DCKCFGR2 &= ~(0x3 << 16);        //清除设置,使用APB1作为时钟源
    # m1 R& M" A' `: ~4 T5 C
  88.                         DevClock = DEV_I2C1;
    8 X1 _7 v3 N' U: f
  89.                         //初始化I2C IO
    " {6 R7 L8 X& y% U
  90. #if(IIC_CH1_IO_SELECT==IIC_CH1_PB6_7)        //I2C1        使用PB6/7- ^& I( O: t; b) ]  P+ T  g
  91.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟' y% v8 j$ s" s8 U( T
  92.                         SYS_GPIOx_OneInit(GPIOB, 6, AF_OD, SPEED_25M);                //PB6
    " I, r6 f. g9 s6 J, U9 ?& i
  93.                         SYS_GPIOx_OneInit(GPIOB, 7, AF_OD, SPEED_25M);                //PB7
    " \5 K5 Y0 o$ L
  94.                         SYS_GPIOx_SetAF(GPIOB, 6, AF4_I2C1);                                //AF41 Q, K3 ?- W& r+ X6 L
  95.                         SYS_GPIOx_SetAF(GPIOB, 7, AF4_I2C1);                                //AF4
    % q; s8 n5 H& ?- a
  96. #elif(IIC_CH1_IO_SELECT==IIC_CH1_PB8_9)        //I2C1        使用PB8/9
    9 x7 X) C' I" b7 p
  97.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟: R9 [5 v! b& a
  98.                         SYS_GPIOx_OneInit(GPIOB, 8, AF_OD, SPEED_25M);                //PB8
      T# @3 B# {# Q" k" ?1 c
  99.                         SYS_GPIOx_OneInit(GPIOB, 9, AF_OD, SPEED_25M);                //PB9
    - u0 @3 F& k* [
  100.                         SYS_GPIOx_SetAF(GPIOB, 8, AF4_I2C1);                                //AF4; p$ p+ B4 U6 q/ v2 y
  101.                         SYS_GPIOx_SetAF(GPIOB, 9, AF4_I2C1);                                //AF4
    " r6 F( v& x8 p7 x6 d$ F
  102. #else& I, ^# O" |* ~( A, \# D+ J
  103.                         #error("无效的I2C1 IO选择");
    & e. w% [% T- y
  104. #endif //IIC_CH1_IO_SELECT
    1 D( `. p$ y2 ^5 G, |9 S
  105.                 }break;
    : R+ _9 e4 S( R2 z+ f% |
  106.                 case IIC_CH2        :        //IIC2
    ! o& W) K$ U8 H7 D# L& b6 `2 ?; ?' I
  107.                 {
    5 t/ P; h: p- Z1 w9 c8 T* }
  108.                         RCC->DCKCFGR2 &= ~(0x3 << 18);        //清除设置,使用APB1作为时钟源
    . m/ e! D3 |1 P  w8 {' I" T/ p
  109.                         DevClock = DEV_I2C2;4 u9 A) G  x. P% ~3 z
  110.                         //初始化I2C IO% x% o3 V  j5 Y- o6 ^  A
  111. #if(IIC_CH2_IO_SELECT==IIC_CH2_PB10_11)        //使用PB10,PB114 S; o1 b6 y4 {; {: a# g5 O
  112.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟- }+ y% `3 L+ \! t3 r$ H
  113.                         SYS_GPIOx_OneInit(GPIOB, 10, AF_OD, SPEED_25M);                //PB10* I4 H* }2 t* X; @- B' X5 p
  114.                         SYS_GPIOx_OneInit(GPIOB, 11, AF_OD, SPEED_25M);                //PB11
    ) ?# I/ F5 \7 \) w
  115.                         SYS_GPIOx_SetAF(GPIOB, 10, AF4_I2C2);                                //AF4
    ) t# \8 Q: O; X3 L
  116.                         SYS_GPIOx_SetAF(GPIOB, 11, AF4_I2C2);                                //AF4
    " G9 q% G) W" I3 m0 m, W+ u
  117. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PF0_1)        //PF0,PF19 g; b, |# D/ [$ J' W
  118.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟
    7 _9 n  V6 ~# @: L4 G
  119.                         SYS_GPIOx_OneInit(GPIOF, 0, AF_OD, SPEED_25M);                //PF0- @' P0 c+ `6 w1 b
  120.                         SYS_GPIOx_OneInit(GPIOF, 1, AF_OD, SPEED_25M);                //PF1  k. h4 [6 [. D* G
  121.                         SYS_GPIOx_SetAF(GPIOF, 0, AF4_I2C2);                                //AF4, l& f3 I& G3 c5 ?  O$ n
  122.                         SYS_GPIOx_SetAF(GPIOF, 1, AF4_I2C2);                                //AF40 N9 w- l3 X3 s- `
  123. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PH4_5)        //PH4,PH5
    # L0 f: V* H  J: ^' i3 s
  124.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    : ?+ ^. A: h2 W1 a% Y
  125.                         SYS_GPIOx_OneInit(GPIOH, 4, AF_OD, SPEED_25M);                //PH4+ X; B5 v; }* N, F
  126.                         SYS_GPIOx_OneInit(GPIOH, 5, AF_OD, SPEED_25M);                //PH57 I, a' g& k0 ^9 l
  127.                         SYS_GPIOx_SetAF(GPIOH, 4, AF4_I2C2);                                //AF4
    $ W' f+ V% Y7 a) H% Y& N
  128.                         SYS_GPIOx_SetAF(GPIOH, 5, AF4_I2C2);                                //AF4                        . J; L% U0 Y2 `+ o
  129. #else
    ( i# b8 I! }2 A' L$ @, D; \/ b
  130.                         #error("无效的I2C2 IO选择");+ E9 o' v1 j) _* s, Q
  131. #endif //IIC_CH2_IO_SELECT
    * e) x8 T- \: P2 y
  132.                 }break;                        
    8 @+ i$ G8 x$ d* z) X9 {7 M
  133.                 case IIC_CH3        :        //IIC39 z. D  c5 n2 z7 {% p. \0 i
  134.                 {! e( M8 r4 @- M* A
  135.                         RCC->DCKCFGR2 &= ~(0x3 << 20);        //清除设置,使用APB1作为时钟源3 Y  Y; Y% f+ H2 i  X
  136.                         DevClock = DEV_I2C3;5 d# n1 J4 ?1 j$ \/ O( L% R) d: c  t
  137.                         //初始化I2C IO% L" g' j  c& B$ N7 f4 K4 h$ _
  138. #if(IIC_CH3_IO_SELECT==IIC_CH3_PH7_8)                //PH7,PH8
    / F, C7 ]  U$ n2 |
  139.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟4 D1 a& h8 m5 `! D2 L2 L5 i9 Z7 S' b
  140.                         SYS_GPIOx_OneInit(GPIOH, 7, AF_OD, SPEED_25M);                //PH7
    : g6 R1 o( X  t3 R% A
  141.                         SYS_GPIOx_OneInit(GPIOH, 8, AF_OD, SPEED_25M);                //PH8
    8 ^) {. Z0 O' O. m
  142.                         SYS_GPIOx_SetAF(GPIOH, 7, AF4_I2C3);                                //AF4
    8 u& b$ j3 B4 L# u1 t) n0 z
  143.                         SYS_GPIOx_SetAF(GPIOH, 8, AF4_I2C3);                                //AF4: ?: P! U6 ]4 s. I$ a& j) S
  144. #elif(IIC_CH3_IO_SELECT==IIC_CH3_PA8_PC9)        //PA8,PC9
    0 V4 w5 I# Y. S. D% E
  145.                         SYS_DeviceClockEnable(DEV_GPIOA, TRUE);                                //使能GPIOA时钟* h" l3 O; }: \+ h
  146.                         SYS_DeviceClockEnable(DEV_GPIOC, TRUE);                                //使能GPIOC时钟
    + Q* R6 @4 i8 O, W) ~
  147.                         SYS_GPIOx_OneInit(GPIOA, 8, AF_OD, SPEED_25M);                //PA8
    0 I5 N) p1 i. E8 J. z9 S/ @
  148.                         SYS_GPIOx_OneInit(GPIOC, 9, AF_OD, SPEED_25M);                //PC9
    - d$ X5 ^1 f0 M; l6 E
  149.                         SYS_GPIOx_SetAF(GPIOA, 8, AF4_I2C3);                                //AF4
    % M; Z& L! P9 C1 B6 `, j
  150.                         SYS_GPIOx_SetAF(GPIOC, 9, AF4_I2C3);                                //AF4               
    7 b  G/ k! W# m( q
  151. #else
    $ D# `  e  {9 T( j
  152.                         #error("无效的I2C3 IO选择");$ g0 e8 v! s9 }; x2 n
  153. #endif //IIC_CH3_IO_SELECT                        & B0 n/ J' o: f
  154.                 }break;                        
    4 Q8 ]1 L- {: \) x' O2 ^7 J
  155.                 case IIC_CH4        :        //IIC4; l+ O+ ^7 L- z" C
  156.                 {
    1 X  T+ ]7 c$ D" s6 V( S
  157.                         RCC->DCKCFGR2 &= ~(0x3 << 22);        //清除设置,使用APB1作为时钟源
    1 N- q( Y$ A: z8 \( n# r! V
  158.                         DevClock = DEV_I2C4;' j. V& q7 T" R! U
  159.                         //初始化I2C IO
    3 o) }3 ^/ d5 {
  160. #if(IIC_CH4_IO_SELECT==IIC_CH4_PD12_13)                //PD12,PD13
    ! Q- P  J6 R  f- C9 X2 G' k8 T
  161.                         SYS_DeviceClockEnable(DEV_GPIOD, TRUE);                                //使能GPIOD时钟
    4 P. G8 f4 {, i9 \  S5 |0 }# m& K
  162.                         SYS_GPIOx_OneInit(GPIOD, 12, AF_OD, SPEED_25M);                //PD12* j( ^9 n: z9 u' @0 Y
  163.                         SYS_GPIOx_OneInit(GPIOD, 13, AF_OD, SPEED_25M);                //PD134 I) t5 L8 d; i' ~6 `# f
  164.                         SYS_GPIOx_SetAF(GPIOD, 12, AF4_I2C4);                                //AF4
    + M7 o2 L* u0 H( ~% J4 U8 n$ L
  165.                         SYS_GPIOx_SetAF(GPIOD, 13, AF4_I2C4);                                //AF4- A& n# X5 n3 _1 h7 A; Y; S$ J
  166. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PF14_15)        //PF14,PF15
    1 M6 S+ N0 R! _1 W1 j
  167.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟4 o* ~' b4 B7 X. w" Q; P$ P
  168.                         SYS_GPIOx_OneInit(GPIOF, 14, AF_OD, SPEED_25M);                //PF14' m  U4 f( T5 z
  169.                         SYS_GPIOx_OneInit(GPIOF, 15, AF_OD, SPEED_25M);                //PF15
    ' [; u/ H# Y( N
  170.                         SYS_GPIOx_SetAF(GPIOF, 14, AF4_I2C4);                                //AF4
    2 Q! |  |3 y9 j+ J
  171.                         SYS_GPIOx_SetAF(GPIOF, 15, AF4_I2C4);                                //AF4' m* E* y" r% i$ P
  172. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PH11_12)        //PH11,PH12
    + J" a! F, ^" a9 Q4 h
  173.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    . i  v* r$ M& l- }/ ?+ F
  174.                         SYS_GPIOx_OneInit(GPIOH, 11, AF_OD, SPEED_25M);                //PH111 f; U! k' Y1 A
  175.                         SYS_GPIOx_OneInit(GPIOH, 12, AF_OD, SPEED_25M);                //PH12. [) a7 N- Y8 D$ X' C& p9 L8 ~
  176.                         SYS_GPIOx_SetAF(GPIOH, 11, AF4_I2C4);                                //AF4; F% s- {& [- d6 N5 M3 o3 M
  177.                         SYS_GPIOx_SetAF(GPIOH, 12, AF4_I2C4);                                //AF4                        
    0 I6 V; a2 i# q
  178. #else) P. O0 r* T% k5 }) i+ Z' g* S, L
  179.                         #error("无效的I2C4 IO选择");, x, R  F' n$ [" A
  180. #endif //IIC_CH4_IO_SELECT                        & a/ B8 Z! D- x2 F' i
  181.                 }break;
    * c& d7 Y2 ~! t
  182.                 default:) e7 J0 m  @* F- g
  183.                 {/ u1 @: c: V% B0 m4 e2 u7 |
  184.                         DEBUG("初始化IIC失败:无效的IIC通道%d\r\n", ch);
    / u+ X) B) G. X  w7 y
  185.                         return FALSE;
    * z* ~. r# V9 f4 p
  186.                 }
    / q% ?2 n' l5 b. k
  187.         }
    . M  L  r) W  U6 u% s6 Y% J
  188.         pHandle = &sg_IIC_Handle[ch];                                                        //获取相关通道的句柄5 f9 h3 |; B$ f! A
  189.         if(pHandle == NULL)( e% Y( ]6 I3 x: P
  190.         {; T3 Q# ]0 S/ G' Z, a+ E
  191.                 DEBUG("初始化IIC失败:无效的IIC句柄\r\n");
    ' F6 W6 t1 \/ y( T. }/ {! j/ n
  192.                 return FALSE;
    ( g. R% f2 Q& `; T8 ?
  193.         }7 u" d. _: G+ x' P* _- Z
  194.         
    5 k9 W1 b9 D9 k* H
  195.         SYS_DeviceClockEnable(DevClock, TRUE);                                        //使能时钟
    - L7 V8 o( y2 N  `& d" q
  196.         SYS_DeviceReset(DevClock);                                                                //外设复位
    0 b3 a, {8 [& |5 q6 @; d
  197.         pHandle->I2Cx = (I2C_TypeDef *)I2C_TYPE_BUFF[ch];                //外设指针( H" T. [- C8 v' @9 ?
  198.         pHandle->I2Cx->CR1 = 0;
    ) |3 Q; F$ N* h4 L% a
  199.         Delay_US(1);                                                . D3 }4 P+ c! A+ C" k9 t
  200.         pHandle->I2Cx->CR1 |= 2<<8;                                                                //设置噪声滤波器,关闭所有中断
    6 f1 q1 S; x0 ~& I
  201.         pHandle->I2Cx->CR2 = 0;- d: o5 m$ T  N* b: _4 V' F
  202.         pHandle->I2Cx->OAR1 = 0;* P9 R% Y! ^& m; X
  203.         pHandle->I2Cx->OAR2 = 0;  Y  G( K; ?/ Y  q
  204.         if(Speed_KHz > 1000) Speed_KHz = 1000;6 B+ c" M. m* k! [: @5 W6 O
  205.         if(Speed_KHz < 10) Speed_KHz = 10;/ @' E3 r: \9 S- j6 V% r
  206.         pHandle->Speed_KHz = Speed_KHz;                                                        //记录速度
    ; I! W/ X0 k; t6 {
  207.         if(TimeOutUs == 0)                                                                                //需要自动计算超时时间,时钟周期*10*10
    ' _. N8 p5 z% o8 N; f9 i7 X
  208.         {
    ( H$ ^  q; k  K& o( e" a
  209.                 TimeOutUs = 1000/Speed_KHz;                                                        //时钟周期7 t8 _3 Q7 c, P" V6 \
  210.                 TimeOutUs *= 10;                                                                        //字节周期
    1 E/ [% _! a" }. H' _( v
  211.                 TimeOutUs *= 10;                                                                        //超时时间为10个字节时间
    9 e1 y. a7 [1 Z; \, X
  212.         }
    ; x: E- r, S2 r, j" q' ^4 n! J
  213.         if(TimeOutUs < 3) TimeOutUs = 3;
    : ~- N$ v* _- \* c7 k" M5 R
  214.         pHandle->TimeOutUs = TimeOutUs;                                                        //记录通讯超时时间
    . b1 v& U8 x* k5 T7 M
  215.         uart_printf("IIC超时时间:%dus\r\n", pHandle->TimeOutUs);
    2 J# u! p/ F6 [# L. Q. ^' [
  216.         pHandle->I2Cx->TIMINGR = IIC_CalculationTiming(pHandle->Speed_KHz);//0x40912732;                                        //时序5 ]) o" C! n( K7 G4 P$ G3 }
  217.         pHandle->I2Cx->CR1 |= BIT0;                                                                //使能IIC1 P) P" |2 ~! o$ _
  218.         pHandle->isMasterMode = TRUE;                                                        //主设备模式
    0 O; k. C5 C# d/ {6 Y7 |) F
  219.         Delay_US(1);7 c6 l. n" ^" P( ?+ X

  220. ' K* z( @) O2 Y+ `# s
  221.         return TRUE;* l7 U5 ?( E7 u7 s
  222. }7 b3 w5 z! g1 K( N. q, S3 _

  223. ( ^3 ^3 F$ c4 u  C

  224. % Q4 F( I1 P4 E( t. S  A) y2 ?3 M$ `9 h
  225. /*************************************************************************************************************************
    / r" B3 {6 L& v, b
  226. * 函数        :                        static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs). g: h5 [* d" D- T, b: W+ l
  227. * 功能        :                        检查是否有NACK中断状态,如果有则清除掉" e% e' c* ^: L5 L
  228. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us
    ' l3 x; {4 n& s& S) c
  229. * 返回        :                        IIC_ERROR, z* D5 L. |& }1 P: q8 z, P4 `
  230. * 依赖        :                        底层宏定义
    ( n, k4 k+ p+ j3 ]4 s$ x
  231. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a># ~% x) i2 r! O3 M+ Q6 _- C
  232. * 时间        :                        2020-02-15- g0 }  D$ a' z0 V3 G
  233. * 最后修改时间 :         2020-02-15* b) U7 v( ~) @/ a
  234. * 说明        :                         如果有NACK中断,则先产生停止位,然后清清除掉所有的中断,并复位IIC,然后返回错误7 h2 `' i9 l& r6 c" m
  235. *************************************************************************************************************************/  , y- W: N5 D) \3 f
  236. static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)
    " A2 F" c8 g8 B1 y+ k; k4 C* ?% @- X9 A
  237. {
    . n/ C: k2 d+ T
  238.         IIC_ERROR Error = IIC_OK;6 ?4 D/ ]1 _, t- Q1 F  ~
  239.         7 q/ i9 D1 G) Y
  240.         if(IIC_GetISR(pHandle) & IIC_FLAG_NACKF)        //接收到否定应答标志+ T' [: q7 x" h7 P( A
  241.         {
    ! d' R' T; Z8 n# `0 H9 Q
  242.                 uart_printf("NACK : IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);
    2 l, {( U6 L- e) p% ?1 H
  243.                 uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    4 ^! g+ i% G4 [" N- C0 o
  244.                 uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));
    * ~, r) [, S6 ]  D2 Y
  245.                 //主设备下,如果没有开启自动产生停止位,则手动产生停止位
    ) p- n! g( ~" i( [6 }" ^" H3 r6 O
  246.                 if(pHandle->isMasterMode && ((pHandle->I2Cx->CR2 & I2C_CR2_AUTOEND) == 0))! [$ V7 w. Q3 Z% I& e8 a
  247.                 {. b. {3 a# d* `* s% r
  248.                         IIC_SendStop(pHandle);                        //send stop
    0 T- p& T9 X9 S; Z" q  d& d
  249.                 }
    * d$ O1 \, c+ D: i( ?
  250.                 //等待STOP标志有效
    # p9 u6 E0 x4 n- c
  251.                 while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
    : P1 p' \$ @8 V0 `4 i: J
  252.                 {) z6 C4 Z; s2 ~; f
  253.                         if(TimeOutUs == 0)                                //检查是否超时了# u/ K  W% X( o' e1 b. \
  254.                         {
    ! u' m- L% R! t+ _
  255.                                 break;
    4 p, x- d8 b2 c! l  d
  256.                         }                        9 ~( B7 V8 n; t* M) r% [: m" O
  257.                         TimeOutUs --;( F# \( U) D  X) o# J: J4 e1 Y
  258.                         Delay_US(1);                                                //延时) ?: |4 d+ k0 Z
  259.                 }7 Q# F! H7 z' q2 B
  260.                 //清除相关的中断标志
    1 s) V: f# G. Q3 z
  261.                 IIC_ClearISR(pHandle, IIC_FLAG_NACKF | IIC_FLAG_STOPF);        //清除NACK,STOP标志
    4 F& D' y# J- }* m1 S* s
  262.                 pHandle->I2Cx->CR2 = 0;                                                                                //清除CR2寄存器
    " j+ ~9 W3 e: V( I% k* w9 o
  263.                 IIC_SoftReset(pHandle);                                                                        //执行软复位, M* l+ B, Z; |/ f& c9 Q
  264.                 if(TimeOutUs == 0)                                                //没有超时,就是硬件通讯出错了5 G7 X3 q& n9 ~2 `5 N. s+ c9 {
  265.                 {
    & x/ u/ ~! I* I
  266.                         DEBUG("IIC发送stop超时\r\n");- p) p0 S% Y8 e. H
  267.                         Error = IIC_TIMEOUT;                                //超时
    ( A6 l# ^. D  X  u1 p0 ]& m
  268.                 }
    # D  T  P6 a3 d% S: d, Q
  269.                 else
    1 F2 Q) }3 `2 m9 C3 H1 g4 |' W( D
  270.                 {2 G$ Z1 J0 k% Z6 I  D
  271.                         Error = IIC_HAL_ERROR;                                //底层错误/ |! p$ R: G) e/ ]* j
  272.                 }
    6 a% `* @2 z) q8 X4 o. O3 c* b( w
  273.         }0 V$ V1 s6 p1 t; ], r* m  Z
  274.         & n5 ~$ v% g3 A' T; S
  275.         return Error;
    " {3 X9 A) g, e2 p8 U
  276. }1 y4 k0 f4 c0 q' n( B

  277. ) J  [! t$ R2 N6 k2 X) Z

  278. 9 a4 c" r: {& a4 P

  279. ( t, k  x9 Q% x) V8 \+ A; ]% f4 b$ s' v
  280. /*************************************************************************************************************************
    2 k  I- h0 p2 s( l# w
  281. * 函数        :                        static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
    ; J" {! W/ p8 c# P
  282. * 功能        :                        等待TXIS中断有效(等待 I2C_TXDR 发送寄存器为空)
    ' }7 Y. h* Q/ `- \, F# ~7 P. ~: B8 `0 \
  283. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us3 F0 p8 ~! W2 p5 L
  284. * 返回        :                        IIC_ERROR3 ?" l$ J+ A( e4 ~+ }) Z
  285. * 依赖        :                        底层宏定义
    ( P4 N9 P, B) M
  286. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>, x* Y" a* @+ ]. X  Z
  287. * 时间        :                        2020-02-15
      {! i; D/ F+ R9 Q( J
  288. * 最后修改时间 :         2020-02-15
    ; l4 e2 D2 {( A5 z. }6 O
  289. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的
    2 I/ N8 f( r5 M
  290. *************************************************************************************************************************/    O+ N" C- ~: t4 q- b( B7 ?* }. y0 z
  291. static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
    6 o+ q" w$ s$ @3 x8 y
  292. {! F5 x- `! ~4 C5 F& Z3 j
  293.         //等待TXIS中断有效
    : u3 [" U! i  s4 t* t5 T8 l$ N% `
  294.         while((IIC_GetISR(pHandle) & IIC_FLAG_TXIS) == 0)1 g4 M3 l  [, v4 J# M1 Y3 B; _. X4 F
  295.         {3 ^5 \+ B) P: }( f, H8 `' F
  296.                 //有NACK中断,进行处理& z" G1 n# |7 T/ M
  297.                 if(IIC_isCheckNackFlag(pHandle, TimeOutUs) != IIC_OK)        
    % X3 q) K( c6 c0 B
  298.                 {* L2 u0 R' u, ]# z
  299.                         DEBUG("检测到NAK错误\r\n");
    7 ^5 P& V( T1 X
  300.                         return IIC_NACK;
    / W9 d0 c' G- I
  301.                 }
    " Q. }& G3 Z6 I5 g  I
  302.                 ( }6 |. B5 a$ E! ?7 C
  303.                 if(TimeOutUs == 0)                                        //检查是否超时了
    ; M0 N. v+ }: b3 k9 I
  304.                 {
    8 q) v2 ^1 A+ S
  305.                         uart_printf("IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);- [6 P' \; e' H! O0 H( W
  306.                         uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);0 E( ?3 C* N0 B4 U
  307.                         uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));
    0 y; Y$ K! _- d
  308.                         
      X5 c6 R8 p" ]' j
  309.                         IIC_SoftReset(pHandle);                //执行软复位
    ; P( q; w! A2 @8 _" i# h
  310.                         return IIC_TIMEOUT;                                //超时7 l# Y0 f. V2 V8 W* A" |; ~1 H$ t
  311.                 }                        
    % U- V$ K, ?4 M5 W( K8 o
  312.                 TimeOutUs --;2 y! }5 _" j" k1 W! @, s. ]
  313.                 Delay_US(1);                                                //延时; k* ~1 Q, p" c
  314.         }6 k, j' u" p; }2 N; O+ ?- s
  315.         
    0 z, A5 P% l' q7 N5 l3 _
  316.         return IIC_OK;
    & X' o4 L" F  ]4 M9 P
  317. }) I; q6 l$ d/ d4 c5 h+ P* c
  318. : {* \4 G! m" Y1 I. x% f

  319. " M. e" c  C# ^6 F' E. p: L
  320. /*************************************************************************************************************************
    3 L8 G9 c) j! ]2 v  n* Y
  321. * 函数        :                        static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)# O# Z: c+ v. j. ~( [
  322. * 功能        :                        等待STOP中断有效(等待 发送结束 )' M3 }# k  ]/ f: [9 j2 e7 u5 r
  323. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us$ p1 g4 w2 s0 x0 k$ W$ ~( S! A
  324. * 返回        :                        IIC_ERROR
    0 r) v8 K8 k" }: s8 `
  325. * 依赖        :                        底层宏定义
    + n0 O* x  j2 f4 P9 q
  326. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>4 u. T# g; h, \- _2 d! e! s
  327. * 时间        :                        2020-02-15. i- Y1 M1 i5 }' B+ k+ d
  328. * 最后修改时间 :         2020-02-15
    % C3 v: Y# w4 d; f" |! ]1 H5 b
  329. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的
    : c* Y: E" g- Y6 e8 U
  330. *************************************************************************************************************************/  ( h! T( o5 Z, [
  331. static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)
    * H/ M2 {* v: R& _
  332. {
    ( @* a* @+ F6 Z4 N( }& l4 L
  333.         //等待STOPF中断有效5 Y5 B3 v1 @: e+ I% y6 V1 P) I
  334.         while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
    ) G6 [/ y6 P) C6 ~, c) a. K- h
  335.         {4 {, _! O. f. ^2 n' P- {( p
  336.                 //有NACK中断,进行处理4 u, V' j( A' S) @4 J$ a) _2 V
  337.                 if(IIC_isCheckNackFlag(pHandle, 5) != IIC_OK)          Y6 ~4 c# ]3 e' t! o7 X  S1 W
  338.                 {0 u/ j( ^& |# S- j0 P  [3 E
  339.                         return IIC_HAL_ERROR;
      R6 s2 n9 U% Z9 F% g& N
  340.                 }
    ! o, x1 ~! ~4 ~7 m
  341.                 % E0 G4 T. T1 `3 K& p' y9 G
  342.                 if(TimeOutUs == 0)                                        //检查是否超时了
    . a% |7 W, X4 y; T! g
  343.                 {! @+ C& C0 B+ e% L! s" W
  344.                         IIC_SoftReset(pHandle);                //执行软复位; ^) s1 ~8 m( Q% s0 f" v* T
  345.                         DEBUG("IIC等待结束超时\r\n");1 y$ K' p& f: R" _3 t  G6 s: t
  346.                         return IIC_TIMEOUT;                                //超时
    3 t8 t+ ~- U- E& M' E
  347.                 }                        ! C! W' q. c' r
  348.                 TimeOutUs --;8 E0 U$ p, S  X5 n! }. D
  349.                 Delay_US(1);                                                //延时
    ( G" q! i" }4 e1 o# R
  350.         }
    5 a# o$ Y! l* K  Q
  351.         
    ! \1 K' |! n( ^$ y/ T" y5 U! A/ }4 P
  352.         return IIC_OK;( T# s6 U: a$ H1 _: D+ v
  353. }
    ! c2 P  L, n6 f' o9 o
  354. 5 I% \% u% Y- y, m+ {9 @

  355. ; Y/ w+ n9 A# r, ?# o" F
  356. /*************************************************************************************************************************) M# i' n! {) z8 E2 A
  357. * 函数        :                        static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
    . N! C. V. y  I7 N' q
  358. * 功能        :                        等待中断有效9 P1 ]6 L' D8 {0 ^- `
  359. * 参数        :                        pHandle:句柄;Flag:需要等待的flag,见IIC_FLAG_xxx;isWaitFlagSet:TRUE:等待标志有效,FALSE:等待标志复位;TimeOutUs:超时时间,单位Us9 J$ F% O0 N* ~* h8 S
  360. * 返回        :                        IIC_ERROR/ @9 o  q# t9 N# E$ u* C1 e( X& g
  361. * 依赖        :                        底层宏定义
    ( T* [9 L# [* g
  362. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    7 D* x) W) z8 x7 Q: Y
  363. * 时间        :                        2020-02-15
    : r' G) A3 x. n% b+ \
  364. * 最后修改时间 :         2020-02-15
    9 Q- y) ^6 L! [: g% }' y8 v& I& ^
  365. * 说明        :                        
    7 k# e5 R4 L9 D+ n2 z
  366. *************************************************************************************************************************/  3 l7 v  z0 W, e, s, p3 @$ s: D+ i8 M
  367. static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
    0 f+ J# f7 ~1 A/ M4 F
  368. {3 m/ a0 ^3 Y8 o
  369.         if(isWaitFlagSet)        //需要等待标志有效
    * c1 O, R; [' M+ R5 }( _
  370.         {  i. M9 L" [! s( R1 J4 \
  371.                 while((IIC_GetISR(pHandle) & Flag) == 0)
    1 A; u/ G2 V- Q6 D/ b8 Q
  372.                 {8 a9 ?. X/ w+ ~3 R/ {
  373.                         if(TimeOutUs == 0)                                        //检查是否超时了2 m. B$ l5 `7 h! K) k# o
  374.                         {
    # y" l% U" h2 Z1 [) l4 U8 M
  375.                                 return IIC_TIMEOUT;                                //超时
    2 S$ y$ G  T+ e6 r, b
  376.                         }                        
    1 n$ Y  ^0 i# H6 @- B/ [% e
  377.                         TimeOutUs --;
    5 ?3 p0 Y3 A/ E# O7 D$ ~
  378.                         Delay_US(1);                                                //延时3 L% k6 g4 N1 J4 _+ L* c
  379.                 }
    + L( f2 v7 t3 U7 Q1 N" x9 G
  380.         }
    ; V6 G$ B0 ~4 I% A2 X9 E8 x( G
  381.         else                                //需要等待标志复位
    7 Z) W' A) t/ @9 R: b4 V0 z5 s/ }
  382.         {  s2 h2 R4 |- o/ D+ V
  383.                 while((IIC_GetISR(pHandle) & Flag) != 0)
      T" X' M" w( P' M/ }
  384.                 {
    : v! ~( V9 [5 a
  385.                         if(TimeOutUs == 0)                                        //检查是否超时了0 D' d$ I) w/ b+ C$ g9 s
  386.                         {6 n% ~% k& V" ]2 {( d
  387.                                 return IIC_TIMEOUT;                                //超时
    . L5 A' F1 W! j# _
  388.                         }                        
    ' f7 @; y/ w7 V" F
  389.                         TimeOutUs --;3 w7 G6 L- P% G0 K/ t4 y8 g% T
  390.                         Delay_US(1);                                                //延时* p3 S: j9 g1 H/ v- P4 C; H
  391.                 }
    % ~9 y( P+ M/ C# O' I
  392.         }
    7 ?2 M5 ~3 u; W1 G$ ^& e

  393. ; N& _. E) Z, W$ R8 K
  394.         return IIC_OK;
    ) C% H; n4 p) `+ V% y' i* R' F
  395. }5 b/ Z% c" S% d8 J$ p0 i+ D

  396. 6 |5 A7 y: ?: r( V6 G1 p

  397. # O" V% E" a: t. Z- Z+ Z$ G9 q

  398. 2 _' g' v* P) U9 |" ]: ^+ ]0 T0 {
  399. 6 O& G6 L3 X; e; T; S% o
  400. /*************************************************************************************************************************
    + A) \3 n8 f9 v+ Q" a
  401. * 函数        :                        static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR). [7 d+ B( _/ b* ]
  402. * 功能        :                        主设备传输配置(配置CR2寄存器)5 N7 L5 y. p2 `# L
  403. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;TransByteCount:需要传输的数据长度;EndorReload:自动结束还是重载设置,见IIC_RELOAD_END_MODE;StartAndWR:开始读写控制,见StartAndWR
    / V/ ~; E. h4 \  ~! i* H$ a0 i3 r
  404. * 返回        :                        无* }. E- t' b8 r0 I! U3 j
  405. * 依赖        :                        底层宏定义
    6 y  w6 y6 a; Q5 n" H
  406. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    " G* I8 Q" k1 A# J9 q% ^! W
  407. * 时间        :                        2020-02-15
    4 R8 ?/ f, }8 s2 Z
  408. * 最后修改时间 :         2020-02-166 B7 O) _+ P9 h# ~7 H
  409. * 说明        :                         在往 NBYTE 中设置最后一次传输的字节数前,必须把 RELOAD 位清零便于后续自动发送STOP。/ T; ^3 ]; G' D8 ^' a+ R
  410.                                         当 RELOAD 位置 1 时,AUTOEND 位将不起作用;
    , c9 s% \( F! U9 F' z
  411. *************************************************************************************************************************/  * @7 Q* f9 P6 S9 ?! c1 k
  412. static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)4 P1 A  P, j. J
  413. {" ?. m7 S! ?; m$ |5 H- I
  414.         u32 temp = 0;" l' l- k4 _: Z; ]# x9 e
  415.         
    * Y: t9 d5 w* R: A4 j! t
  416.         //先读取CR2寄存器的值  L5 u) x5 i, i' i8 W- z
  417.         temp = pHandle->I2Cx->CR2;& }. r; z# T7 b( i" ^
  418.         //清除掉相关的字节
    # L( `. \/ G" g! T# N7 P% n
  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));5 B4 a6 A9 C( s: i, P& C6 U
  420.         //生成配置数据* h8 j& O" c1 F5 l7 ]- d6 E& W
  421.         temp |= (u32)(((u32)SlaveAddr & I2C_CR2_SADD) | (((u32)TransByteCount << 16 ) & I2C_CR2_NBYTES));
    * N' j2 [% R4 f! V) I6 ]* ]) e
  422.         //重载与自动结束只能二选一
    - L. Q& o6 N( O
  423.         if(EndorReload == IIC_AUTOEND_MODE)         # }3 S' P% k* p9 n7 j
  424.         {
    $ X2 }9 d' m- R
  425.                 temp |= I2C_CR2_AUTOEND;        //自动结束模式$ d; g2 x1 `, @* e$ @$ F& O) b
  426.         }
    0 C& j/ J# w/ F* u% Y6 R2 H, s: r
  427.         else if(EndorReload == IIC_RELOAD_MODE)  t4 @' ?4 B$ y2 V
  428.         {
    # `; V9 C+ A, c: K! k6 }' C; `
  429.                 temp |= I2C_CR2_RELOAD;                //NBYTES 重载模式: s9 f0 l2 y, p+ g7 T
  430.         }. b+ ]& M! f- t0 J. X3 S
  431.           F! N; p6 m9 u* Q1 G* |
  432.         switch(StartAndWR)
    & @3 K, X2 o( P. x9 F' |; O
  433.         {3 h) H1 H) F8 J0 v8 I: f/ @" p+ `
  434.                 case IIC_NOSTART_WRITE        :        break;        //没有开始的写-默认就是这样的  t! o3 \( i% a* M9 w
  435.                 case IIC_NOSTART_READ        :                        //没有开始的读-用于后续数据读取
    : @8 T! F7 z: Y$ H4 l
  436.                 {. \/ w- c/ y, x- M  R+ n
  437.                         temp |= I2C_CR2_RD_WRN;                        //读取
    : \1 s6 Z; x8 K
  438.                 }break;" F3 B, J1 s; ?7 k- V. A  }. i* W
  439.                 case IIC_START_WRITE        :                        //生成开始写
    " n# Z4 x9 x- n1 A3 |' C' w2 v! w
  440.                 {
    5 H+ E$ T9 E3 }9 X7 H' T1 w
  441.                         temp |= I2C_CR2_START;                        //启动传输
    " V: P/ c" f# A- [# Y' o8 m; m- M% W
  442.                 }break;' g9 c; z& @& I( F
  443.                 case IIC_START_READ                :                        //生成开始读        
    0 ]% h- ]2 N( U/ L, c. f* }% T
  444.                 {
    / T# G% ^2 ~' v  _& O; m5 {! I
  445.                         temp |= I2C_CR2_RD_WRN;                        //读取+ J0 o, R! \" l6 S% f0 V
  446.                         temp |= I2C_CR2_START;                        //启动传输
    1 q4 O5 v: k$ u% h1 y* `* x& g6 D0 e
  447.                 }break;! y8 Q' `! ]2 f6 t* e/ L* j
  448.                 default:break;
    , R5 ]5 M. Q8 h% E! v; _* l& x
  449.         }
    1 J: D$ M% T1 _7 i; a9 o7 |
  450.         5 D$ n% O! {! V9 ~' E; o, ]
  451.         //uart_printf("准备写入CR2=0x%X\t", temp);
    6 b* G6 k3 j+ u  S1 a
  452.         //更新到寄存器7 w; e4 ?, [- s) ?
  453.         pHandle->I2Cx->CR2 = temp;  //测试
    2 @3 y6 J) B! b+ f. @' l
  454.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);! J  x1 p. ~; `& H1 G: l
  455.         Delay_US(100);8 }: u/ f% P* B: I% g# L1 T
  456. }
    * s3 y/ i3 X: x

  457. . @- N7 ~4 U# o
  458. 7 K) d; _% Y; r, g
  459. /*************************************************************************************************************************9 E( B* h/ n; ?( X
  460. * 函数        :                        static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)! j" U/ e: W- D6 H5 `: u
  461. * 功能        :                        IIC发送一字节
    2 Z# k5 A! X# P- i
  462. * 参数        :                        pHandle:句柄;data:待发送数据;TimeOutUs:超时时间,单位us8 d9 Y. h4 ^7 |4 D
  463. * 返回        :                        IIC_ERROR
    6 W, r; c: w5 R" \1 [# R2 n
  464. * 依赖        :                        底层宏定义; X) I  X" i, c5 w! H; e) w
  465. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>$ T3 c5 V9 ]1 b8 B5 U- T
  466. * 时间        :                        2020-02-15+ z4 {+ p  W8 ~- T/ U; c) S3 {
  467. * 最后修改时间 :         2020-02-16
    # |) k7 B! q( z1 H7 R
  468. * 说明        :                         TXIS有效后才会进行数据发送,不会检查数据发送是否完成。
    ! a4 G4 e9 O4 p* a0 {% _
  469.                                         如果最后一个字节发送完成后不会再触发TXIS中断,只会触发TC中断
    7 O( [; ^* u) r9 v! P; Y6 g
  470. *************************************************************************************************************************/  
    , K) S6 h6 _' W$ n) t% e
  471. static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)' d! S* I$ T+ J# G: |; F
  472. {) A/ ^+ S$ P2 `0 y  ]2 w4 U
  473.         IIC_ERROR Error = IIC_isWaitTXIS(pHandle, TimeOutUs);                                //先等待可以发数据
    " E9 u9 }# R' D7 d$ ~9 G
  474.         if(Error != IIC_OK) return Error;& U* {$ X. [# D; t' E/ E( b: s$ m) ~
  475.         pHandle->I2Cx->TXDR = data;                                                                                        //写数据到发送寄存器-不会等待数据发送完成        
    , a, Q( ?: t6 m/ `
  476. 1 y  A  q% I2 H* ~
  477.         return IIC_OK;
    " O  J1 `9 A# `' T
  478. }
    # ^; N  O0 e  r& _1 J
  479. ; |6 _* r  c3 f3 F
  480. /*************************************************************************************************************************2 H# y3 ^% g# L
  481. * 函数        :                        static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,   K/ h8 K8 A; E6 v, C1 y4 R& i
  482.                                                 bool isRead,u32 TimeOutUs)0 f& M* r  R, n
  483. * 功能        :                        主设备请求发送从机地址与目标寄存器地址
    9 g, j5 r% n/ r
  484. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;RegAddr:寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,
    3 @  L( S/ H/ V
  485.                                                 FALSE:16bit寄存器地址;isRead:TRUE:这个操作是读取寄存器;否则是写入寄存器;TimeOutUs:超时时间,单位us
      k8 l+ m! X1 C% R- u6 t
  486. * 返回        :                        IIC_ERROR
    ) i  k$ `/ {! y4 _9 A+ w5 z  y& e
  487. * 依赖        :                        底层宏定义
    , o9 U# D$ G4 u  ]5 y/ W  O. k
  488. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    2 l$ R- O0 O5 X% Z2 }
  489. * 时间        :                        2020-02-156 {, r- B, [0 W& P3 q0 ]" z$ t' j
  490. * 最后修改时间 :         2020-02-16
    ; M& b+ M( ?3 t5 k6 q# d7 z! m
  491. * 说明        :                        
    1 ^$ ?, |$ O! I1 r
  492. *************************************************************************************************************************/  
    + m& A9 t/ N- P6 l# j8 O0 A# v& e9 A
  493. static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,bool isRead, u32 TimeOutUs)6 a! [& _6 y" u- `( A1 y8 O# C8 c
  494. {        9 E# \/ {0 F! v7 [. [
  495.         IIC_ERROR Error;+ j; @& v& x$ U; |9 ^+ I# d+ D/ [
  496.         
    6 g) M% \' m4 c$ t1 B2 v) s
  497.         //uart_printf("WriteAddr1:CR1=0x%X\t", pHandle->I2Cx->CR1);
    4 I& p/ t1 S0 ]) U! v  V0 V
  498.         //uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    & H% M; z" D( ^
  499.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);+ w, [" t1 B% W8 A8 M/ l2 {4 m9 P
  500.         //传输配置,并启动传输,发送起始序列,开始IIC传输了
    ) r, h! w% `; k* l6 p
  501.         //如果是读取则使能软件结束,如果是写则是自动重载
    ) F9 r9 n2 ?5 S
  502.         IIC_MasterTransConfig(pHandle, SlaveAddr, (is8bitRegAddr==FALSE)?2:1, (isRead)?IIC_SOFTEND_MODE:IIC_RELOAD_MODE, IIC_START_WRITE);        //传输相关配置-写,并启动传输
    ! B  p5 e6 P2 ?5 p3 U2 X1 X; h7 z
  503.         4 c% c" B/ k2 d. T' Y* q. z
  504.         //开始发送寄存器地址
    ! w* g& Z8 d8 y% j3 ?
  505.         if(is8bitRegAddr==FALSE)                                                                                                //寄存器地址是16位的,IIC通常是MSB高位在前,需要进行高低位对调% e, r6 ^* }0 t( k& j
  506.         {
    ; q. I! q9 k) w, h9 {: @' ]
  507.                 Error = IIC_SendByte(pHandle, RegAddr>>8, TimeOutUs);        //先发送MSB-非最后一字节* W& I3 o: _- e/ H5 ~! J! s: H% H
  508.                 if(Error != IIC_OK)% K6 X; z3 W9 E
  509.                 {
    3 }0 i8 d: l  C9 ~" o
  510.                         DEBUG("IIC发送寄存器地址MSB失败\r\n");
    ! |3 j9 e. _" g
  511.                         return Error;6 y3 h$ p6 s1 ?# b: L$ r2 K2 W; E
  512.                 }        
    & l5 f$ ?; v# c+ Q0 Z  j9 |* H
  513.         }, O( M( i% @/ T, o) A+ ~
  514.         Error = IIC_SendByte(pHandle, RegAddr & 0xFF, TimeOutUs);        //再发送LSB-最后一字节, S+ e3 N  u' F' W; {
  515.         if(Error != IIC_OK)
    " L9 ^( V& l. R0 S" B) _& M
  516.         {
    , N3 X5 R! s0 `
  517.                 DEBUG("IIC发送寄存器地址LSB失败\r\n");$ g+ H# K3 A" b+ N
  518.                 return Error;
    ' M' _; m6 |, ~+ |
  519.         }
    / [  B7 ?" |8 |, k, ~& Z7 Q$ c8 k$ g
  520.         //等待全部数据发送完成
    ) v' Z& ^7 r1 @/ T
  521.         if(isRead)        //读取方向-非重载,等待数据传输完成 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。+ {2 g" X+ q" C- e8 R" R
  522.         {& y$ `- V- M2 O2 m
  523.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TC, TRUE, TimeOutUs) != IIC_OK)* t# c* P# J" K8 L! t1 e
  524.                 {
    , N' {8 \4 o/ M4 `% q' |; _
  525.                         return IIC_TIMEOUT;3 R0 ^; n: E# t0 M0 l
  526.                 }0 n* U. L2 j: x
  527.         }        : N4 E: t$ f+ n- e; H+ C
  528.         else //写入方向,等待重载
    4 R6 a  O, l" W* _' r
  529.         {
      z- Q. x" C5 u. D8 u
  530.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TCR, TRUE, TimeOutUs) != IIC_OK)' S$ C6 ?6 f' A! G& x9 a6 ^0 ]
  531.                 {
    2 z2 u9 n8 x+ B* @7 \: Y" z
  532.                         return IIC_TIMEOUT;
    ! H( y4 c% {6 O  ^0 F% ~# t# `
  533.                 }
    " P" y" F* r( R  p# ]8 {
  534.         }0 C9 g) {# T7 v
  535.         
    / H: Y+ o" R8 r9 s2 J/ G
  536.         return Error;
    $ r$ I# s' @: ^/ F
  537. }$ h  w9 T/ p) j" O- W6 m) }$ }
  538. - D/ `5 T1 p, x) s3 e2 U! T
  539. ; O% R: \4 S& ^3 z/ o3 g
  540. /*************************************************************************************************************************% ?& Z% `0 R7 v6 a! Y
  541. * 函数        :                        static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs). T6 ]# O9 s) U# G: a+ y
  542. * 功能        :                        等待接收一字节数据
    , i4 V" `- k9 X  J) F3 N
  543. * 参数        :                        pHandle:句柄;pData:接收的字节数据缓冲区;TimeOutUs:超时时间,单位ms# L) S$ a- o; d0 F( T
  544. * 返回        :                        IIC_ERROR0 c+ o  c0 S6 E' V: Y5 e% T  S- `
  545. * 依赖        :                        底层宏定义
    ' }  L9 |' u1 }
  546. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    7 D: u4 b+ g) x' O
  547. * 时间        :                        2020-02-15# [  Y, q% C( t0 e
  548. * 最后修改时间 :         2020-02-15
    . O. i' y) P' Q* h$ T
  549. * 说明        :                         当RXNE有效后读取一条数据,否则可能会超时
    ! Y" k7 j# T5 B
  550. *************************************************************************************************************************/  
    . l$ y% O: k9 Q" _
  551. static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
    6 `$ F) E: y/ P4 {
  552. {
    ( W4 ^; o- D) b4 N! ~9 e+ C
  553.         while((IIC_GetISR(pHandle) & IIC_FLAG_RXNE) == 0)        //等待RXNE有效
    ' r1 x6 `% ?  _$ p
  554.         {6 q  F% a* m9 N9 M
  555.                 if(TimeOutUs == 0)                                        //检查是否超时了
    " R" q' z7 t. Y7 n. `
  556.                 {# \& T: x0 N2 s7 ?' U1 p- p& V
  557.                         DEBUG("IIC等待接收超时\r\n");
    $ X, l/ v: l9 A
  558.                         return IIC_TIMEOUT;                                //超时
    % Z" V7 a8 v- G- {
  559.                 }                        
    5 X& M; ^+ v  V+ W! X$ ~0 O/ V
  560.                 TimeOutUs --;
    6 ?7 y. O7 s7 r  s/ U1 ]
  561.                 Delay_US(1);                                                //延时
    4 f1 w! `# _; \1 k
  562.         }
    8 ^4 d8 h; v' x" @
  563.                
    ! p: p% ]! y1 J' B" ]
  564.         *pData = pHandle->I2Cx->RXDR;                                                        //读取收到的数据4 ?2 I$ Z$ ?1 y3 g* V
  565.         return IIC_OK;
    8 g6 t2 K, P+ B6 y9 Y, \8 w( B
  566. }
    5 V- y4 D" ~6 k3 l0 a9 i4 E

  567. ' P& o, ?5 j- s4 I' n

  568. 2 Y5 E! P" j$ q. k5 r& J
  569. /*************************************************************************************************************************
    8 w! C5 v0 F# X$ J5 j" ^0 `
  570. * 函数        :                        IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, / U: n  M5 C  J- U$ Y
  571.                                                 u8 *pDataBuff, u16 ReadByteNum)5 D7 e* q' @4 ^; v2 ^7 @* ~
  572. * 功能        :                        IIC读取寄存器(可以读取1个或者多个寄存器)+ M& }! f& j9 W/ ~4 n
  573. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要读取的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;
    1 |( j* ?3 Z. J
  574.                                                 pDataBuff:接收的字节数据缓冲区;ReadByteNum:要读取的寄存器数量;  q; z0 G: {# S% W
  575. * 返回        :                        IIC_ERROR
    / p- e  w0 z% v! }' l3 q+ X
  576. * 依赖        :                        底层宏定义
    7 u7 M! P) f: B/ i/ O' `( Y5 G
  577. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>& I) V: f( P! s8 S: k9 J! h
  578. * 时间        :                        2020-02-15# o3 V+ c1 x2 x* d+ l  ], r
  579. * 最后修改时间 :         2020-02-15
    3 G# o2 v' \& U1 Y  M/ N" U/ R
  580. * 说明        :                         读取的数据都是小端模式,如果是16bit的寄存器,请读取偶数个数据,并且需要另外进行高低字节对调最后组成16bit数据0 Q3 v  G$ G( S$ F( m8 B/ B
  581.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如& ]- ~. _4 p" e* D3 e5 @$ w
  582.                                                 增加信号量0 v4 t$ C1 d% I, o% k! o0 W( Z# M& B
  583.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在. l7 d( d- C/ ^+ c: S5 F3 @! [3 _
  584.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。
    , J# w* [% u9 i* A0 J! y8 p
  585. *************************************************************************************************************************/
    + ]1 Y: Y7 Z' s# I- q3 ^, }
  586. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum)
    ; R1 F. \  @& F3 e' }) U
  587. {  x! D% w# ^# n6 w$ x
  588.         IIC_ERROR Error = IIC_OK;
      c# _5 t" ~' }
  589.         u16 ReadCount;
    6 E( u4 Y& S$ ]4 ^: `
  590.         IIC_HANDLE *pHandle;9 w  Z2 O% j4 ^  }8 K
  591.         
    $ r: x( Y, B, i( p+ L
  592.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || ReadByteNum == 0)  P' v4 N$ `. r; W: Y  d
  593.         {
      Q. U! F4 y& l! y* E) z; e2 e
  594.                 DEBUG("IIC错误:无效的参数\r\n");
    * G8 l. l- m0 H7 C0 i; N. f
  595.                 return IIC_PARAMETER_ERROR;; Z7 ]8 G  S; e; u0 `: g
  596.         }
      v0 j  Q& w. O, X* C3 e
  597.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄# u0 C+ N% ]$ j; l( b
  598.         6 P7 T* _% i* E2 H+ w; C( K8 J
  599.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙: m2 b9 ~% |7 }: a3 h6 q* A
  600.         {5 @5 r- g( o& U
  601.                 IIC_SoftReset(pHandle);/ B3 u2 g3 K8 G4 w, r
  602.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");5 _& }8 ~- Q$ L0 @; P
  603.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙
    $ f/ B6 l" o4 X! C1 F& @
  604.                 {
    ' f8 Z) w" O# q4 l/ o" C# |
  605.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");
    2 w* l# i6 f$ Q2 c4 g/ q
  606.                         Error = IIC_BUSY;
    $ d" ]. C: P* ^" D; {
  607.                         goto end_loop;+ g  i) H6 ]! c! X% C* a
  608.                 }
    ) \0 B6 l$ p; W' M
  609.         }9 m. K7 m) B, ?7 G2 ~
  610.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    7 [6 m' R- F! V+ m; ?
  611.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器# r  G2 s8 U# |- r5 ~$ [
  612.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    . B# m+ d3 F$ {* N& r# V
  613.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,TRUE, pHandle->TimeOutUs);
    4 B( c9 @2 r3 W  ^5 |9 P% F  ]
  614.         if(Error != IIC_OK)
    1 F. t; G* O, w! s+ T
  615.         {
    % M+ b# l' U# U
  616.                 goto end_loop;
    ) R. y; d! c7 G) [" Y6 h* w
  617.         }' O; i; y" O* F6 K8 x6 V. y
  618.         //发送后续数据% T+ u9 q; K- _1 e7 l/ t: e
  619.         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取-后续还有数据,需要重载
    % `" y3 f2 {- i( `6 i1 B$ d, I
  620.         {
    # h* ?9 p# ^& D9 D
  621.                 ReadCount = 255;        //本次需要读取的数据长度255; q) s& ?: u+ }3 y+ v6 M
  622.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输                1 b2 p1 _* }; y$ d. J
  623.         }5 a, f, _, k0 T  @; z7 N' Q& G
  624.         else
    & P! ~9 p# b+ [4 F- w
  625.         {
    " R6 t( Z3 c/ B; C1 H) n
  626.                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯后自动结束
    2 A+ l4 h& X1 I( D. R
  627.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输
    & [, e0 ^) O/ c. H( [$ z
  628.         }8 f: p# E: K+ [6 J
  629.         # `9 G- u3 @' Y; ~% d- T
  630.         //循环等待接收数据完成
    - J. B3 t' ~9 z8 Z
  631.         do; ^3 Q# q6 b4 Q, f
  632.         {
    3 W  z. k4 l+ Z, w2 F+ W
  633.                 //uart_printf("读ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    + Q1 j2 }, H3 h- C/ K1 Q% N
  634.                 Error = IIC_WaitRxOneByte(pHandle, pDataBuff,  pHandle->TimeOutUs);                                        //接收1字节数据
    + a" |4 {, d7 i" R8 o
  635.                 if(Error != IIC_OK)
    ' i  {/ q+ X  `6 c( }# m! S
  636.                 {
    % m  w/ n8 r: `: _& `( o0 |2 e
  637.                         goto end_loop;; P& H6 B1 C5 k! u' \+ Z
  638.                 }
    $ b8 E8 n# ?+ K# a4 }, n) ]* ^' t1 Z5 n
  639.         
    6 G3 v# U! z) `: @5 m! s, C7 X
  640.                 pDataBuff ++;
    $ C7 X( i6 X8 k4 i# I( X; T9 |
  641.                 ReadCount --;7 U" |, T7 O$ ?  C
  642.                 ReadByteNum --;; y) j, }' @; n4 `$ b% a
  643.                 if((ReadByteNum > 0) && (ReadCount == 0))        //还有数据要读取* G0 y1 j6 w0 O( H" j' L2 S
  644.                 {
    # s9 R9 Q- Z  D! h; S% O" `; g
  645.                         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取
    / p0 }% n1 `' C( R
  646.                         {
    / M: f% w0 g8 F7 T" ^1 N
  647.                                 ReadCount = 255;        //本次需要读取的数据长度255-后续还有数据,需要重载
    ! z7 H1 Z; K* O7 z0 \0 d+ I
  648.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
    0 y7 b- e2 c. m7 l7 R( {
  649.                         }
    6 o2 S: O9 L3 W% _, g: S' x
  650.                         else
    3 @0 q% m& h( N7 o8 a0 X7 P
  651.                         {$ A* r8 n8 V( v5 y! Q
  652.                                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯,自动结束
    ' Z6 P. h' a! w
  653.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
      N9 O. Q4 [/ p  z
  654.                         }% o( i/ l% ~) F
  655.                 }' R" f" C6 \. [* W  v
  656.         }while(ReadByteNum);
    $ j6 d4 w2 k9 P* a9 U/ ?
  657.         //读取完成了,等待STOP位有效
    - Y6 C8 V; J; c( s4 x
  658.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);7 o3 Y! K& n& A9 t8 ~* |; M% g
  659.         if(Error != IIC_OK)
    " K( k: Q9 l/ Z1 _( l
  660.         {5 ~; v6 H9 z% L) f4 q( P; R  k6 M
  661.                 Error = IIC_STOP_ERROR;
    ' B4 N, M* C$ `/ P1 ]
  662.                 goto end_loop;% c2 t; v6 c4 I
  663.         }        1 e* O" [# X& Z* }8 p: ]+ A
  664.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态; M3 ^6 }9 T) w8 y: j( a$ M
  665.         9 C# b* N+ N, N) n
  666. end_loop:        
    4 Y! z2 s$ ?7 B# t$ N  q
  667.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        + I( k- B; ^# \+ V
  668.         if(Error != IIC_OK)
    * I! d3 H6 U' ~
  669.         {
    . n9 f; C( m# f; X7 g( y
  670.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误
    9 y" D) F2 E+ ]* ]
  671.                 DEBUG("[IIC R错误]:%d\r\n", Error);! v3 I/ U  x% V, h+ x
  672.         }/ I+ ^. D6 K5 G' ~( A% ~: A- {
  673.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的
    - ]3 o2 J( ?: Q& K. J4 ?: r, h
  674.         {
    & Z7 [1 ^) \4 l8 ~4 H0 t* m
  675.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    % I/ k1 [5 _8 d5 K0 {+ W7 z0 z
  676.                 DEBUG("IIC R结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);                / \# m: e' g1 {6 U7 d
  677.         }6 G  m  B# {- H9 l- E
  678.         
    1 x/ X+ H7 L, s$ r
  679.         return Error;
    ( p1 F( i, ^! X2 \& u
  680. }9 P, {, L2 d! I/ L4 a0 ?

  681. , x0 H6 s3 U, K# M

  682. + B# i/ G: i4 o4 A
  683. /*************************************************************************************************************************! C6 L- `6 l$ ]* c
  684. * 函数        :                        IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    ! x1 ^( ^- M. o3 t. m6 P1 N$ d
  685.                                                 u8 *pDataBuff, u16 WriteByteNum)
    : k5 ]7 Z1 J# \, y
  686. * 功能        :                        IIC写寄存器(可以写1个或者多个寄存器)
    8 W( A* S5 z3 W, a" U: z2 @9 _! Y
  687. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要写入的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;+ u/ [! ]! o( W' x
  688.                                                 pDataBuff:写入的字节数据缓冲区;WriteByteNum:要写入的寄存器数量;5 W2 C7 m/ J8 D6 b7 }
  689. * 返回        :                        IIC_ERROR
    1 Y) p% Y8 k  F$ U0 X  I
  690. * 依赖        :                        底层宏定义
    2 i! `* ~% i0 {, B% d& c- D: c- K
  691. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>. E: }) Q/ O, o/ l/ n  w
  692. * 时间        :                        2020-02-16
    ' a$ P, _+ n' z6 S
  693. * 最后修改时间 :         2020-02-16+ A, o( z1 I# p+ r: R# h) e& k
  694. * 说明        :                         写入的数据都是小端模式,如果是16bit的寄存器,请写入偶数个数据,并且需要提前进行高低字节对调最后组成高字节在前的数据buff% Q2 F( J6 @9 s0 t0 Q
  695.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
    3 \: Q7 o& P1 \" P6 t1 R' W
  696.                                                 增加信号量
    # K' J5 b2 F( h' S7 V: T# ~
  697.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在: P6 v+ z9 V5 M7 u- {, O4 M
  698.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。  ~: R# S- h8 o! `5 [* H
  699. *************************************************************************************************************************/
    # k0 n/ U7 [: R: l: L$ U% X% c
  700. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum)
      a) v& H2 i" P  m
  701. {
    + D3 e8 |, `3 P" Y6 }  B( R
  702.         IIC_ERROR Error = IIC_OK;. a1 h* D/ h/ [
  703.         u16 ReadCount;; E+ U) \8 E/ ^# M$ v" V
  704.         IIC_HANDLE *pHandle;
    . Y  D) j: \' p" G
  705.         ) n  ^3 F' y1 }" A5 t7 K& ~
  706.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || WriteByteNum == 0)
      \0 i& |. O: v& q8 c0 J
  707.         {
    + C2 F2 `0 z* n) m' Y! n
  708.                 DEBUG("IIC错误:无效的参数\r\n");/ |* w- Z% y/ j2 |
  709.                 return IIC_PARAMETER_ERROR;
    " o" T. E/ g8 u. }, `
  710.         }
    0 D5 E% Z/ _! v2 N# r
  711.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄6 O! D; J1 L6 B3 P+ ?' Q6 T
  712.         
    2 V# v4 c: F' U% G" s
  713.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙$ c0 c: O; J+ N$ P
  714.         {3 Q% G" `0 h5 r3 S/ w9 ~( ?$ o
  715.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");1 i$ q. ?4 _) C& M1 j- `( ^0 P- A
  716.                 IIC_SoftReset(pHandle);) x2 E9 h, [/ W# h
  717.                
    ! E  d1 K2 {! |, K
  718.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)        //忙" y; [: X9 z5 w) h3 K* r  k- U4 |$ O
  719.                 {3 L. {/ d0 J4 f) i8 m
  720.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");1 v' D4 r; q/ R# U( u
  721.                         Error = IIC_BUSY;3 d) d. c' Z3 P! B- P2 ^
  722.                         goto end_loop;
    0 X) M9 p3 Z% R# V3 w+ F8 K0 @7 E
  723.                 }6 `8 k8 s' ?5 T) [$ Q& ~3 v( |
  724.         }
    ( l7 {* s, {* R+ r
  725.         
    4 k3 @6 p. \' Y! _
  726.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态% N8 {# A" ]' C  ?
  727.         IIC_ClearCR2(pHandle);                                                //复位CR2寄存器
    2 M, q! \0 X) t: y7 r: I
  728.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    ; N  e; d5 x! r7 m2 w
  729.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,FALSE,  pHandle->TimeOutUs);
    , z! {3 N; N( f- x
  730.         if(Error != IIC_OK)
    . l" r  @5 [6 w/ ]
  731.         {
    6 k5 x4 Y/ G; a+ f: o1 L
  732.                 goto end_loop;
    % k# k, R, U% ~: [- Z
  733.         }
    * N( y- |6 ]+ V7 h1 F
  734.         //发送后续数据
    + N% m& n& l* F/ o4 H* e
  735.         if(WriteByteNum > 255)                        //如果超过255字节,则需要分多次写入-后续还有数据,需要重载
    $ b5 g, |; P9 t( J
  736.         {' D6 K, y4 [9 Q
  737.                 ReadCount = 255;                        //本次需要写入的数据长度255: f% I7 b* h0 w8 n
  738.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入                - b( \1 A' t8 Y0 N
  739.         }
    7 a7 D2 x$ V3 E
  740.         else0 \( _! K# J' w; ]* ~
  741.         {
    0 ]% l2 F* K1 ~  E% U
  742.                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯后自动结束
    3 F8 S/ ~' C0 L5 X: E" c; j$ v
  743.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入
    2 t; j0 x, i4 E/ L9 c# C% }) H3 f
  744.         }
    6 W" V9 o& y. K% M$ i9 h9 w: U2 I
  745. % e: d! S9 S, X( l- Q3 R( }2 j% a
  746.         //循环发送数据& M- C& C1 B( `, o3 g
  747.         do, x0 X1 N7 {* h5 L/ g) `
  748.         {7 I( A( l$ @. s" j" @  \
  749.                 Error = IIC_SendByte(pHandle, *pDataBuff, pHandle->TimeOutUs);        //发送一字节 $ I  W. j, H9 }3 q6 X# d0 Y% i
  750.                 if(Error != IIC_OK)   h9 ]% ^5 e% B) \
  751.                 {+ X( u3 C9 j9 A
  752.                         goto end_loop;9 V: N% h8 a; [$ J! D0 ~
  753.                 }) H4 f" Z" t+ X$ v1 ]: b

  754. & \* ]% {) z* C! r  Z- x$ S
  755.                 ReadCount --;
    8 H+ e# Z% \+ W- [6 R
  756.                 WriteByteNum --;
    & z1 C! k) E5 o$ J
  757.                 pDataBuff ++;& l* P, T: }% a1 d0 Z
  758.                 0 Q: T' |0 l8 _/ w! t
  759.                 if((WriteByteNum > 0) && (ReadCount == 0))        //还有数据要读取7 e: `" V3 G2 I  W) a% m* w
  760.                 {
    2 c+ U) j, H, J! n+ R
  761.                         if(WriteByteNum > 255)        //如果超过255字节,则需要分多次读取) O, k  q7 [4 d8 W+ I& ]& K- i4 K/ A
  762.                         {
    8 c" y1 s. @9 a
  763.                                 ReadCount = 255;        //本次需要写入的数据长度255-后续还有数据,需要重载) j3 G% P* i- |) M5 Z% I2 w
  764.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入
    + x* f( p" X& I! [0 a' D
  765.                         }
    . @" N6 t( r6 Q3 G  d( A* r! x
  766.                         else2 d! G; E8 J2 c. V, H' R
  767.                         {( |( a- |) ~, W3 C5 d$ M
  768.                                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯,自动结束
    ! t  \, u1 V1 m1 p; i. E' u
  769.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入               
    2 |6 m* D* y/ w" I7 w
  770.                         }, ?' |$ x1 J5 c" x4 l5 I
  771.                 }+ \1 ], R8 M# @5 J  S
  772.         }while(WriteByteNum);        
    - C( Z, n; S) n5 Y0 y
  773. ; ~+ B/ T/ ?7 ~2 K3 \9 o6 ~$ s, Y
  774.         //写入完成了,等待STOP位有效
    * N9 |1 Q9 @3 a
  775.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);
    / {3 k: ?7 @8 B5 X
  776.         if(Error != IIC_OK)
    $ F, y5 E" j% J/ x2 f
  777.         {( J5 O' c7 E! q3 a) ]
  778.                 Error = IIC_STOP_ERROR;4 |$ z9 G% M  ]
  779.                 goto end_loop;2 ?) N9 V$ |5 C% v
  780.         }
    9 D; g. N* B  v! O& z# h! [
  781.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    . `) s+ F7 E2 c/ l, {, b* j
  782.         8 q# S( f+ Y1 }, Y; Y: k9 x. c
  783. end_loop:        ) ~7 E! r3 I6 z8 H
  784.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        
    ' A7 T- _, F, K$ R' E
  785.         if(Error != IIC_OK)
    ; a+ }$ s1 q/ T( c( F
  786.         {
    ' ~( Z) {! r0 R3 U
  787.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误
    " M( J& c3 `' V5 V. i! N
  788.                 DEBUG("[IIC W错误]:%d\r\n", Error);
    ' h0 e0 o, ?+ d) ?
  789.         }
    ) H3 Z7 m0 ?7 b3 t1 C3 H
  790.         
    * L) K+ [8 p/ ~3 l7 e% q1 q
  791.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的
    . V9 M( Q8 ?8 ~. \
  792.         {2 W7 y$ s" S0 e1 g- I! z
  793.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线& N7 B; ?0 n  a; ~4 n/ |) N
  794.                 DEBUG("IIC W结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);                , m8 k7 S7 N3 E2 i
  795.         }- L- l: g1 m. h$ k1 |
  796.         return Error;. ~( w1 U4 L! \! i3 b9 I1 h" i! K
  797. }
    ; f2 t5 F4 Z! B, b! a) m6 r
  798. % w# ?7 m* p; K! e! ~) S" V$ |* C5 M

  799. 2 H5 g' [" ?2 j9 o. _- K
  800. /*************************************************************************************************************************3 l6 i  n0 O" r8 p3 t6 v  S2 ^
  801. * 函数                        :        void IIC_SoftReset(IIC_HANDLE *pHandle)/ Z& q  S4 q5 w
  802. * 功能                        :        硬件IIC软复位(会使能IIC)& p( @5 j( X0 s2 @6 D" Q
  803. * 参数                        :        ch:IIC通道
    - f2 Q, |7 M( q" x2 P) z
  804. * 返回                        :        IIC_ERROR
    " U- ?% d! k1 j( [$ I$ M1 y
  805. * 依赖                        :        底层宏定义
    5 A/ H% h3 A3 B0 t0 R- |# e9 c5 x
  806. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ! u& }3 H& ^- y! [; u
  807. * 时间                        :        2020-02-157 e" _, s; r1 U0 _0 N9 C
  808. * 最后修改时间         :         2020-02-15
    7 ]5 i+ `) c; c2 _2 ?' i
  809. * 说明                        :         IIC软复位;必须使 PE 保持低电平持续至少 3 个 APB 时钟周期,才能成功执行软件复位。
    5 \! S4 P! g: p( R
  810. *************************************************************************************************************************/" `) o1 H$ g. L! l* ?* Z  M5 \
  811. static void IIC_SoftReset(IIC_HANDLE *pHandle): e1 W# y. ^4 p" C" S! U8 g, ^* t% O
  812. {
    , f) i7 i6 A, d- ]  D
  813.         pHandle->I2Cx->CR1 &= ~BIT0;                //关闭IIC后执行软复位
    + ~+ b) m% z/ c  T5 I" L* L
  814.         Delay_US(1);        
    3 m  R) g0 i5 }# x- F' n1 m
  815.         if(pHandle->I2Cx->CR1 & BIT0)$ d% I6 U, ^7 v$ L
  816.         {
    : J" c# C$ ?% P0 X
  817.                 DEBUG("IIC软复位失败\r\n");1 K' O# B- Q: z, R# s- ?
  818.         }
    ! k) {; H. a  H0 l+ X
  819.         pHandle->I2Cx->CR1 |= BIT0;                        //重新启动& f, A3 n& ?7 C' x
  820.         Delay_US(1);        1 X: Y9 N2 B; z& c8 L# _
  821. }
    ; P& H( v3 S! d. k/ y

  822. & P- A3 x. v; c4 e
  823. ! L! \3 @9 C5 E& I
  824. " u( q( u4 B1 @0 t8 Q
  825. /*************************************************************************************************************************2 b; H3 X1 \3 B- e. O
  826. * 函数                        :        static u32 IIC_CalculationTiming(u16 Speed_KHz)7 m# a/ ^' }" H6 X9 l6 W
  827. * 功能                        :        硬件IIC时序计算( I1 t: A8 T0 D2 `
  828. * 参数                        :        ch:IIC通道;Speed_KHz:速度10-1000
      w5 Z! v- b- H3 z
  829. * 返回                        :        IIC_ERROR. }' {% `$ l/ R9 e& `4 P2 t
  830. * 依赖                        :        底层宏定义9 i* H/ _( M2 v6 l
  831. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    % q" J! G) T2 K; J+ [/ D% d& s' J1 j
  832. * 时间                        :        2020-02-153 y# u; Z; d, ]/ ?6 p" ~
  833. * 最后修改时间         :         2020-02-15
    ) K: E; a( Q/ s" a/ C
  834. * 说明                        :         IIC使用的是APB1时钟,将IIC总线时钟控制在100KHz        
    7 F4 m- D- @9 q* K1 Y$ x
  835.                                         APB1时钟:最大不能超过45MHz        4 [3 G  @2 n; R9 q' p* ~* [" U1 Z0 a; x
  836.                                         如果速度是100,则按照SMBUS时序
    ; e1 R- ]* W# h0 s8 c
  837. *************************************************************************************************************************/
    $ t+ s9 O+ K, u6 S
  838. static u32 IIC_CalculationTiming(u16 Speed_KHz)
    3 H1 [5 R) i+ A( p# F' {
  839. {  f/ B  B8 Y. ?' s4 w. M+ y
  840.         u32 tTime = 0;* |; d1 e1 g, f$ [" U' s
  841.         u32 temp;
    6 R% q3 q' l- C
  842.         u32 time_temp = SYS_GetAPB1ClockSpeed() / 1000000;                //先获取APB1时钟速度1 V/ M6 q: F8 L6 C5 f
  843.         u32 Th = 1000/Speed_KHz/2;                                                                //计算高电平时间(低电平时间一样),单位ns' X: F- O5 z* [# A/ I
  844.         
    : |2 E6 H  q0 U3 ~
  845.         if(time_temp < 20) time_temp = 20;
    ' Q' J. [$ F/ b* U% q2 K
  846.         time_temp = 1*1000 / time_temp;                                                        //单位ns
    ! b9 P% f; B. Y& O
  847.         uart_printf("IIC时钟计算->APB1周期:%dns\t", time_temp);
    " ~1 r7 `. k' q, ~8 e  F( Z
  848.         if(Speed_KHz == 100)        //如果是100,则按照SMBUS时序
    0 T: X" e2 r# W' ~9 t# v6 g
  849.         {" O; f1 P! [/ g6 ~  B+ l1 L
  850.                 //主时钟分频系数固定为39 U6 v  o! k8 O# |3 _' D( P
  851.                 time_temp *= 3;                        //主时钟周期
    ! r/ e/ a; s# B) p8 ^
  852.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    & b: ?4 }+ ~5 ~0 U  m. u. \7 m. B7 L
  853.                 tTime |= (3-1) << 28;        //PRESC,时钟预分配$ b+ t( B, e- k; R, s
  854.                 //计算数据建立时间,要求最小250ns
    $ H! l7 M5 V+ [7 J
  855.                 temp = 250 / time_temp;
    ' D- Q8 R' U4 ]- j
  856.                 if(temp > 15) temp = 15;
    & \# f6 w1 F0 l. }- @. F% t
  857.                 if(temp < 1) temp = 1;; d. ^* U8 i" d( z: ]+ L" X
  858.                 tTime |= temp << 20;
    , t' {4 Z$ O0 D2 H: B
  859.                 //计算数据保持时间,要求至少300ns3 ~. w7 y9 ^& ?, S/ Z
  860.                 temp = 300 / time_temp;6 y& O& m. D& n5 W5 u
  861.                 if(temp > 15) temp = 15;
    - H. w7 S  [* ]# p
  862.                 if(temp < 1) temp = 1;( Y1 i9 k+ z2 C& Z. q* x) H
  863.                 tTime |= temp << 16;
    $ n' C7 j1 p& ]7 F
  864.                 //计算高电平周期5us
    # {) P; p+ ]) ^
  865.                 temp = 5*1000 / time_temp;$ l! Z: i9 L1 i( U" d0 ]9 x- M
  866.                 if(temp > 255) temp = 255;" D. U. h* u0 j( @5 |8 k! k' n- o
  867.                 if(temp < 1) temp = 1;
    : `; z: x* y- p1 P( l0 z. x
  868.                 tTime |= temp << 8;
    4 n+ z% ^" g3 g6 G
  869.                 //计算低电平周期5us' K* x+ \) K! N' b3 G
  870.                 temp = 5*1000 / time_temp;
    7 Z% I. S: V1 P
  871.                 if(temp > 255) temp = 255;
    ! x1 f9 _6 }. a3 o* B2 M
  872.                 if(temp < 1) temp = 1;# ]. O  B; I. t- x* J9 [
  873.                 tTime |= temp << 0;
    6 @5 X( p# O1 Q% b9 i
  874.         }% k' I; O0 D2 z9 d* U2 x% F
  875.         else if(Speed_KHz < 100)
    - ?, ?- e8 h! J# o
  876.         {" O5 v* [2 Q0 i% ~
  877.                 //主时钟分频系数固定为6' {' K* c% X5 J
  878.                 time_temp *= 6;                        //主时钟周期" l+ E" I1 ?- X! t- k
  879.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    ' R* h+ P" Q# F: r. @' Y
  880.                 tTime |= (6-1) << 28;        //PRESC,时钟预分配
    - B) O7 x6 \* ?5 L9 c
  881.                 //计算数据建立时间,要求最小250ns; S9 }+ n* T* K( z3 n$ Z+ |* P
  882.                 temp = 250 / time_temp;
    " e5 E! N0 \2 \3 v+ r" ]
  883.                 if(temp > 15) temp = 15;
    / l9 s  g8 `; d
  884.                 tTime |= temp << 20;
    $ V" \2 L7 |" o8 Y
  885.                 //计算数据保持时间,要求至少300ns
    $ @8 D- E1 Q+ U" I$ F
  886.                 temp = 300 / time_temp;+ s2 l8 @4 g; R# `( x
  887.                 if(temp > 15) temp = 15;* ~3 x) H4 N1 e# L
  888.                 tTime |= temp << 16;
    : y% c( v# E' O: W. n: @
  889.                 //计算高电平周期Th us
    8 Y0 V7 k8 `* @1 G# {, E9 c
  890.                 temp = Th*1000 / time_temp;/ O5 [0 i4 X1 {. x! Q
  891.                 if(temp > 255) temp = 255;# q! c% V* I; u5 r; X
  892.                 if(temp < 1) temp = 1;6 @( {* |/ @! O6 o& Y# R3 @
  893.                 tTime |= temp << 8;
    6 k1 Y4 F, k- d& L) W3 _6 o
  894.                 //计算低电平周期 Th us' w# @4 f: O4 {/ ?5 U3 t
  895.                 temp = Th*1000 / time_temp;  O8 d' X3 Y8 `$ z& p
  896.                 if(temp > 255) temp = 255;
    6 M. K, B# ^' ^' u4 J4 g- ^* z2 _
  897.                 if(temp < 1) temp = 1;$ s( o- P5 @; o( y; B4 }' _
  898.                 tTime |= temp << 0;7 ^8 Q9 I# {1 O" ?9 l
  899.         }
    4 P; v2 {9 p6 T3 S1 F+ w1 [/ _
  900.         else //>1007 @: y- d* _1 A# k( [" t
  901.         {* R; \, ]  t1 p2 p
  902.                 //主时钟分频系数固定为20 ]- u; _5 u) U, n# }; t- m
  903.                 time_temp *= 2;                        //主时钟周期5 y9 T) J# q  y0 {, M. B
  904.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    1 K! ]& l/ N' |! F" Q  I
  905.                 tTime |= (2-1) << 28;        //PRESC,时钟预分配
    ; i0 s; |6 B: U+ ?2 X3 o* V0 D
  906.                 //计算数据建立时间,随便给100ns; L: Y, @5 [% X) N& e& ?( X( t/ @
  907.                 temp = 100 / time_temp;
    1 S! Q+ O' P) w7 ^4 U
  908.                 if(temp > 15) temp = 15;
    4 K( }$ r; _/ `# U4 W7 A
  909.                 tTime |= temp << 20;
    % n7 }9 o4 ?7 L# }" b
  910.                 //计算数据保持时间,给100ns
    6 o8 N9 J4 d$ Y8 g
  911.                 temp = 100 / time_temp;
    1 ^/ t. N8 Q+ ]# ?
  912.                 if(temp > 15) temp = 15;( o) `) e& p+ W
  913.                 tTime |= temp << 16;
    % D( t4 O4 X* F+ h' e9 }2 t" @
  914.                 //计算高电平周期Th us
    ! M  u1 _- d6 [
  915.                 temp = Th*1000 / time_temp;
    ) h# `5 v8 i$ Z% L/ W& z" N
  916.                 if(temp > 255) temp = 255;7 ^; Y1 M8 M: ~2 `
  917.                 if(temp < 1) temp = 1;
      u7 ^) j, R5 J, I) @
  918.                 tTime |= temp << 8;
    ; A5 i; a: H# w
  919.                 //计算低电平周期 Th us
    ' W/ q! @5 t/ u" v) n; D
  920.                 temp = Th*1000 / time_temp;
    # f6 t& A0 ^; \, w, ?
  921.                 if(temp > 255) temp = 255;( A' ~% {  F& M( e, G2 o
  922.                 if(temp < 1) temp = 1;
    0 \' I8 z# I7 a  \5 q7 t1 U: H
  923.                 tTime |= temp << 0;( v, T& r6 l3 }# J" B% C
  924.         }
    / q7 }* J1 K" w3 [
  925.         
    3 t9 i# `, P' Q5 B6 P; C3 ~2 F2 X2 J2 k
  926.         uart_printf("时序寄存器结果为:0x%X\r\n", tTime);5 B6 T! ~, \  O6 S+ C
  927.         6 \8 y, }8 ~* Y) F7 S8 G: W3 X
  928.         return tTime;& ?* V6 f2 s. I/ y% l1 y0 b
  929. }
复制代码

9 j$ E( |1 q2 O  d- P
. X7 u0 q: q4 {" v( _
  1. /*************************************************************************************************************8 B+ n2 w1 U& k$ r" ]
  2. * 文件名                :        stm32f7_iic.h
    2 k9 ?( j& P/ Z" F9 o
  3. * 功能                        :        STM32F7 IIC接口驱动
    . o5 @$ `9 S3 z- F0 L
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>' T! T( G: n: u6 z
  5. * 创建时间                :        2020-02-09; e5 p( n8 n4 y
  6. * 最后修改时间        :        2020-02-09, `0 N/ Q3 p5 c/ V/ W
  7. * 详细:                        " F! d) l. J: P# y
  8. *************************************************************************************************************/                5 P7 w6 u2 @; E4 K/ r
  9. #ifndef __STM32F7_IIC_H_
    " w9 T/ B+ Y+ }) W  v" V; e
  10. #define __STM32F7_IIC_H_# e- s- w9 `' x) b
  11. #include "system.h"
    6 r7 E! u5 @! I' N* T
  12. 6 a& P& O' }9 X$ i* d; h9 A6 [
  13. //16位整形数高低对调) b0 B5 S: p+ @/ H8 t$ q
  14. #ifndef SWAP160 Y0 F, i. r$ C0 c1 H: o
  15. #define SWAP16(x)   (((x & 0xff00) >> 8) | ((x & 0xff) << 8))  Q" {4 N& m: J3 ~% z8 x) T
  16. #endif  //SWAP16$ S+ {* y3 c- q- L8 R0 |# h9 O. u

  17. % I8 u3 u+ k5 R5 ]$ l% T( N* {0 v6 f
  18. //硬件IO口选择8 B" u4 t, E( Y" f0 S
  19. //I2C1 IO定义与选择
    9 [8 @) f/ D$ D; r
  20. #define IIC_CH1_PB6_7                                0                                        //PB6,PB7, k" n& K8 Q3 A
  21. #define IIC_CH1_PB8_9                                1                                        //PB8,PB9
    , i4 ]: l1 M$ E" L8 D: s
  22. #define IIC_CH1_IO_SELECT                        IIC_CH1_PB6_7                //选择I2C1 的IO        
    # g% _* q4 q. j1 ^* q$ }  z
  23. 5 c/ n4 X4 }- R
  24. //I2C2 IO定义与选择
    & c6 r6 X0 \7 G# W4 v* E: ^
  25. #define IIC_CH2_PB10_11                                0                                        //PB10,PB11
    ; z) f: F: y: r# [) n# I; z- j7 J
  26. #define IIC_CH2_PF0_1                                1                                        //PF0,PF1! n( \, l, {1 @9 Y# l0 g: _
  27. #define IIC_CH2_PH4_5                                2                                        //PH4,PH54 h* r1 C. |2 P
  28. #define IIC_CH2_IO_SELECT                        IIC_CH2_PB10_11                //选择I2C2 的IO
    ! R" n/ w% v: Q' `6 ~
  29. ) U+ H) h: E; M/ [* N& b
  30. //I2C3 IO定义与选择) \! U0 A' W9 d% _
  31. #define IIC_CH3_PH7_8                                0                                        //PH7,PH8' A5 E2 l/ R( i
  32. #define IIC_CH3_PA8_PC9                                1                                        //PA8,PC9
    2 _: G; r  H8 Q" I/ B8 A6 [
  33. #define IIC_CH3_IO_SELECT                        IIC_CH3_PH7_8                //选择I2C3 的IO! n9 S: F3 q1 a; |1 f3 k
  34. 4 Z; t2 N1 _+ e
  35. //I2C4 IO定义与选择. p9 H$ @8 i6 h! |
  36. #define IIC_CH4_PD12_13                                0                                        //PD12,PD13
      g, D; F% b; M2 [7 D4 c0 [# k
  37. #define IIC_CH4_PF14_15                                1                                        //PF14,PF15
    0 {- U0 {9 O6 l
  38. #define IIC_CH4_PH11_12                                2                                        //PH11,PH12, e( m( J6 a, {: G% J3 l
  39. #define IIC_CH4_IO_SELECT                        IIC_CH4_PD12_13                //选择I2C4 的IO
    ( `/ I9 ^' z6 {9 I! j2 R$ W; s

  40. & n$ d4 t3 g* n. ^7 T6 u5 V
  41. //IIC硬件接口选择
    ; I$ F; W: N. K7 P2 [
  42. typedef enum6 y$ ^% n/ V; u
  43. {' `0 C" ?! J5 P) H
  44.         IIC_CH1        =                0,        //IIC1/ Q' v" ^5 q: O1 i+ _
  45.         IIC_CH2        =                1,        //IIC20 }: \* a& j! _4 h2 L2 R  v
  46.         IIC_CH3        =                2,        //IIC3
    ) K! F# g4 p, h! d
  47.         IIC_CH4        =                3,        //IIC4
    # i0 f# w: [+ T. ?# W7 ]2 Y
  48. }IIC_CH_Type;* G/ e( B7 d" M% @2 v; q1 k4 j
  49. #define IIC_CH_COUNT        4        //4个IIC# O5 u% t3 y2 \
  50. 7 |+ a9 ?. I" {5 Z: z
  51. : H/ B+ F# X; W. m5 u
  52. //中断状态
    " Q) e2 o7 n% s" n. \
  53. #define IIC_FLAG_TXE                    BIT0        //发送数据寄存器为空(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。
    % T6 p2 O0 X1 g
  54. #define IIC_FLAG_TXIS                   BIT1        //发送中断状态(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1,待发送的数据必须写入 I2C_TXDR 寄存器。
    ; z+ t9 C: l0 {3 q( @# p$ R
  55. #define IIC_FLAG_RXNE                   BIT2        //接收数据寄存器不为空(接收器); 当接收到的数据已复制到 I2C_RXDR 寄存器且准备就绪可供读取时,该位由硬件置 1。读取I2C_RXDR 时,将清零该位。
    + `$ \; \' A' A$ s. i
  56. #define IIC_FLAG_ADDR                   BIT3        //地址匹配(从模式); 接收到的地址与使能的从设备地址之一匹配时,该位由硬件置 1。该位由软件清零,方法是将ADDRCF 位置 1。$ M2 Q0 k2 p& p* L  J
  57. #define IIC_FLAG_NACKF                  BIT4        //接收到否定应答标志; 传输完字节后接收到 NACK 时,该标志由硬件置 1。该标志由软件清零,方法是将 NACKCF位置 1。
    # H" H4 Y" I7 P3 ?; G! M
  58. #define IIC_FLAG_STOPF                  BIT5        //停止位检测标志; 当在总线上检测到停止位,且外设也参与本次传输时,该标志由硬件置 1$ d# E% m; B; S7 h. _
  59. #define IIC_FLAG_TC                     BIT6        //传输完成(主模式); 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 START位或 STOP 位置 1 时,该标志由软件清零。; S. H- C. E4 Y% z
  60. #define IIC_FLAG_TCR                    BIT7        //传输完成等待重载; 当 RELOAD=1 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 NBYTES 写入一个非零值时,该标志由软件清零。0 W6 h9 v7 d0 G
  61. #define IIC_FLAG_BERR                   BIT8        //总线错误; 当检测到错位的起始位或停止位,而外设也参与传输时,该标志由硬件置 1。在从模式下的地址阶段,该标志不会置 1。该标志由软件清零,方法是将 BERRCF 位置 1。
    * Q9 R! {+ B) o
  62. #define IIC_FLAG_ARLO                   BIT9        //仲裁丢失; 发生仲裁丢失时,该标志由硬件置 1。该标志由软件清零,方法是将 ARLOCF 位置 1。
    ; v& n; b9 I4 E9 A& k
  63. #define IIC_FLAG_OVR                    BIT10        //上溢/下溢(从模式); 在从模式下且 NOSTRETCH=1 时,如果发生上溢/下溢错误,该标志由硬件置 1。该标志由软件清零,方法是将 OVRCF 位置 1。/ h# t7 n& `, O0 R# Q5 T) ?( e& X
  64. #define IIC_FLAG_PECERR                 BIT11        //接收期间的 PEC 错误; 当接收到的 PEC 与 PEC 寄存器的内容不匹配时,该标志由硬件置 1。接收到错误的 PEC 后,将自动发送 NACK。该标志由软件清零,方法是将 PECCF 位置 1。0 [  Z2 ^7 S: a0 V0 \  ^" j
  65. #define IIC_FLAG_TIMEOUT                BIT12        //超时或 tLOW 检测标志; 发生超时或延长时钟超时时,该标志由硬件置 1。该位由软件清零,方法是将 TIMEOUTCF 位置 1。
    4 X5 i+ c2 M$ K6 V: {  C- `3 P
  66. #define IIC_FLAG_ALERT                  BIT13        //SMBus 报警; 当 SMBHEN=1(SMBus 主机配置)、ALERTEN=1 且在 SMBA 引脚上检测到 SMBALERT 事件(下降沿)时,该标志由硬件置 1。该位由软件清零,方法是将 ALERTCF 位置 1。
    / E' f8 Y# m; G+ Y
  67. #define IIC_FLAG_BUSY                   BIT15        //总线繁忙; 该标志用于指示总线上正在进行通信。当检测到起始位时,该位由硬件置 1。当检测到停止位或 PE = 0 时,该位由硬件清零。
    ; [8 v, U# D1 X+ K; C3 r: `
  68. #define IIC_FLAG_DIR                    BIT16        //传输方向(从模式); 该标志在发生地址匹配事件时 (ADDR=1) 更新。;0:写;1:读- l( U# C1 g& }( A. o7 q

  69. 3 ]' ^9 H0 G9 q+ v( m/ M- ?% i0 N7 L
  70. //通讯错误状态
    $ y: h$ W) _7 Y' f6 r! g/ z
  71. typedef enum
    / ^8 T8 ~: w& I5 v: h
  72. {
    9 M0 J: K7 f, J' n+ Q* A  H/ s
  73.         IIC_OK                                        =        0,        //没有错误
    $ S/ x9 T. d7 y" _1 c  D
  74.         IIC_PARAMETER_ERROR                =        1,        //参数错误
    * C3 N! }7 p, J4 }7 d
  75.         IIC_TIMEOUT                                =        2,        //超时错误,也可能是底层错误9 ~; f6 X2 |) b, Z8 g
  76.         IIC_HAL_ERROR                        =        3,        //底层错误
    ( g2 L. R% D6 U
  77.         IIC_STOP_ERROR                        =        4,        //等待结束错误% k+ i/ J9 f$ y% w) ]8 y
  78.         IIC_BUSY                                =        5,        //硬件忙
    . V, @3 J+ g% W6 v0 P+ |8 n
  79.         IIC_NACK                                =        6,        //收到NACK了
    $ u; P& V: \/ w/ t$ F  Z
  80. }IIC_ERROR;: f' p, ?6 `5 V/ R' H( W/ _& i* O; I( S

  81. 9 M9 H* e+ C  r

  82. 7 |8 ?8 L/ K2 a- k
  83. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs);        //硬件IIC初始化, A+ L$ l  o3 v; W" @9 e  ^' b
  84. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum);        //IIC读取寄存器(可以读取1个或者多个寄存器)
    ) t7 n4 I9 E$ {5 O
  85. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum);        //IIC写寄存器(可以写1个或者多个寄存器)
    - |( O8 r$ R# [! e

  86. / p: N1 f' @+ r; A% |+ B

  87. 9 U' H3 b- a/ O1 U
  88. #endif //__STM32F7_IIC_H_
复制代码

. g2 s# |8 F# e4 k' F# F
: |$ m  ]! r5 G" ?% L1 {5 z" n//初始化
7 W3 y/ p' t8 ^! z2 l
4 @- U. k! b2 }* |
  1. IIC_Init(IIC_CH3, 200, 0);        //硬件IIC初始化
复制代码

! X4 Y9 u/ u, l# t" w; ^* A- y  V3 A( O& D( ^5 A7 K2 S
//调用# R7 |) l; y* ~* i4 a
  1. 7 H6 `- b% ^2 }
  2. //触摸屏IIC读取寄存器接口
    + S) b. a# E* C2 h' m6 [' b
  3. bool TP_FT5336_IIC_ReadReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum), m5 N, A( w& d. k- a
  4. {
    ) m* O3 K, G9 Z1 Q$ {' _$ ~( s
  5.         if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)
    6 i$ i- N9 i$ R0 [4 [* U
  6.         {
      a& c. _3 c& }- D( N4 J
  7.                 return TRUE;# x5 d9 x$ M; m! ]! V
  8.         }( P+ c) j; e5 d6 {7 E" A1 R
  9.         else2 m% P3 L5 A" [% }; m
  10.         {
    7 ?/ w) z' c  W  d; F
  11.                 return FALSE;
    # W1 ]: |9 w5 Q+ f
  12.         }1 n! P3 K, r0 _  {) R" h3 R" T' R
  13. }
    % g( ?' ?. r" y  E

  14. 6 r" b1 r5 [& F8 C5 n; U$ ~
  15. //触摸屏IIC写寄存器接口
    3 _3 B% b) k1 o! w5 V
  16. bool TP_FT5336_IIC_WriteReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)/ q- P  S3 k4 s3 N
  17. {) h' ?1 M' m9 ]7 M  T3 [
  18.         if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)" L* n1 t2 X) n
  19.         {) e: j& }/ b- ]( [- @, v
  20.                 return TRUE;
    & t+ K# d: B1 {' J8 L" {0 H
  21.         }
    " W* K  r8 X* d% Y
  22.         else6 k9 y* L3 G7 s0 C* v0 Y* ^
  23.         {
    ; t: J) R1 `$ Q$ M* k+ a
  24.                 return FALSE;5 L$ ?6 H/ r/ ?
  25.         }
    6 F0 p/ O! @( a0 ]
  26. 9 v( o( m4 Y$ Y3 M
复制代码
, I, b- R" _9 Q  {6 ~

* q6 x4 R: |4 w- l8 n. h! x% i4 n6 K% R; s( p, o
收藏 评论0 发布时间:2021-12-11 12:00

举报

0个回答

所属标签

相似技术帖

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