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

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

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
目前只实现了主设备模式,一般也只用到主设备模式,IIC如果不能使用硬件方式,读取大量数据的时候效率很大,由于只有1个字节的缓冲区,根本不能使用中断模式(实际使用过程中,IIC会造成100us以内间隔的中断,单片机根本扛不住的),所以建议数据少就直接阻塞,1个字节也就几十us,数据多直接用DMA,将线程阻塞,等待DMA传输完成,而不会阻塞CPU(上传的代码没有实现DMA部分,便于理解)。
, ]. k, _" c! _4 X$ z5 |9 Z* X. _9 x; d; C4 u+ j" Q3 ^) o' m9 H  A0 o- ]
目前已经做了完善的错误处理,读写操作前都会清除中断,遇到错误会软复位,所有位置均做了超时处理,防止程序卡死,目前只测试了几个字节的读写,大量的,长时间的读写均表现稳定,目前手上开发板没有eeprom,无法做大数据的连续读写,如果你在使用过程中遇到问题,欢迎指正。
$ L# J0 t" H$ k: ~6 F# p3 Q7 @( X5 M6 V: _' w4 v
下面是IIC读写的时序例子,可以先熟悉一下,这样比较容易上手,哪一个环节出了问题也要调试。
8 v% @& Q# R+ ?8 h4 F) e9 X% g- Q! s' K: C( f% T$ l( T
20200216194202434.png
- W7 Q0 d, v9 s7 \6 E7 W9 o0 B

/ I3 C3 c( B3 A5 G; I4 L  C' d0 M
20200216194219185.png
# g$ h% |1 J  G( l/ O5 ^/ ~9 `$ s

7 Z8 h0 |: E0 |8 W4 y  H
20200216194234908.png

* t& \; y/ N5 [! n- A$ O5 ~( \5 c6 K2 q& B0 G9 K3 x, M2 O
' {- l9 g, \, |% T- G+ N9 l0 z
下面简要说明一下STM32F7硬件IIC的驱动设计方式(建议先百度学习一下IIC的时序要求):* a! O# X8 {# s8 m4 [
9 h, e$ H0 \  y0 W" b
[基本的初始化]" p7 r6 I' k# `' `9 m1 P

2 M$ c. y% [6 p+ ^2 o1.初始化IIC时钟,IO(IIC IO必须设置为复用开漏输出,这个很重要)。: Y& o. f+ P% G6 f+ }- B6 a0 ^- w
" S2 C8 @8 O7 p5 {9 o
2.CR1先赋值为0,复位IIC.
6 A2 X1 e1 |/ k8 e  T
! r+ C  }1 i" ~+ |5 B+ x! e8 S4 Q- J3.除了TIMINGR寄存器需要自己计算设置好,其余寄存器全部复位为0
5 u( G# X, P0 w1 D! M6 ^# U7 m# M) a4 N: T
4.设置CR1使能IIC。" t/ t9 K% z# A. u& ]7 e! Z

3 B: s' X) U. U& r& l, y8 ^' T注意:上面说到,IIC的IO必须初始化为复用开漏输出,我之前初始化为复用推挽输出,测试很久,只要一启动传输,就会立马收到NACK,然后是STOP中断,数据根本没法发送,弄了好久才发现是这个IO初始化的问题。: E  z. e" B3 ^6 T

& z9 Y( m( @% H& ?/ [) l
- N; I% g1 _0 ?9 y
: n/ E; C* H9 ~9 T6 m' c7 o, j0 q[读取]
. x) y7 I) c# s, t1 k1 g- B2 V4 p( M/ u6 \! M0 o5 P
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。
* P2 w# Z. h& F  a
" j: j: L2 C8 H+ Z" L2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)软件STOP,写模式,启动传输。
0 K: H3 s# ~0 D/ Y: D- m' E$ }- j6 ]  @' v0 A; {# _- {6 W1 f' w* j
3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。- }, \: o- i) i6 E; q

/ I  F6 ^7 i3 C! y7 i  Z& J4.等待TC置位,意味着上面的1-2字节的寄存器地址以及写完成了。& R! }( x4 f2 [, A9 O

. u9 P' _# A" \& W7 K% }* b5.根据要读取的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。
! ~% Z7 g) j9 f- }& X4 n5 r% d$ Z$ H1 U# v9 `! x
6.设置了从机地址,要读取的数据长度,之后设置方向为读取,然后启动START(从写切换到读要重新发送START,这个跟软件模拟是一模一样的)。5 R1 y- p( _* f' Z
7 F" S5 ^! Q( W: A. e  m
7.循环一个字节一个字节的读取数据,字节读取需要等待RXNE有效,只有读取RXDN寄存器,直到所有数据读取完成。
9 I  t/ C. f" \7 B! s: _  c' x" j; f% P# U1 ]+ b: _6 g5 H% a$ l% x6 _
8.读取完成后等待STOP有效,因为前面在最后一包数据读取的时候使能了自动STOP,这个时候检查STOP是否生成。/ E5 J, Y2 d( g! v! W/ s: Q; y

: R6 M6 f. x& o+ U( g( s9 X9.需要注意的是,所有的操作都要给超时,并且是自己可控的,绝对不要有死循环,之所以一直说STM32的IIC死机很大程度上都是由于这个地方没有涉及好,我的程序设计方法是:一旦出现了异常,就复位IIC,如果不复位就会导致下次进去的时候IIC一直忙,因为还处于上一个通讯过程。
+ ~+ V/ e2 \2 u* S/ {& K- z
2 T$ {+ `+ C  T1 ?2 r
5 _9 ?" d( s  b) l/ M  Y" @3 u7 c* b+ M+ B) {. \8 E8 x' X
[写入]
6 K, X# k, P  d' Y  u- I; ^5 k9 {& X" L3 m
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。
9 u! G3 r" H$ U7 P4 N) V' c8 C
! e9 M, m8 `4 P, N4 m9 r2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)自动重载,写模式,启动传输。* O& x; r* `+ n4 o9 X

" Q% J% Z, ?+ j5 G5 w3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。6 Y2 ]' j2 Q5 d) t3 K. S3 f* r

; }% D, w  K. f( F6 [( u5 x4.等待TCR置位,意味着上面的1-2字节的寄存器地址以及写完成了,已经发生重载了,后续可以继续写入数据了。% b8 D+ v0 d$ ~( H' q

! r9 `4 R: s! M4 J7 R! b7 q5.根据要写入的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。8 @2 {6 U" M) _. l; R4 V3 J$ h: A% ]
! w3 {( g$ Q& ?1 h6 j
6.设置了从机地址,要写入的数据长度,之后不用切换方向,不用启动START(都是写,不用重复发送START,这个与读取有区别)。
/ Z  R# H; \. L1 R7 j
& r+ S0 E) o* l7.循环一个字节一个字节的写入,字节写入与步骤3一样,等待TXIS置位,就可以写入数据到TXDR。
- x) ]6 o: D% _. S/ P5 o9 L6 S  S
9 ~* p  ]9 H* e3 l$ F8.等待STOP有效,因为前面在最后一包数据写入的时候使能了自动STOP,这个时候检查STOP是否生成。! P. M8 ]+ s% }8 e  a4 m

) D$ f; V- c8 `/ g9.需要注意的是,所有的操作都要给超时,跟读取一样。
7 Z1 z5 n2 O0 p% _3 Y& w- A* M# M4 k

0 [/ _9 }! E/ p- ^$ Y& G1 ]
  ~# {, m% {# w( s+ u' v& b& a注意:IIC的读取实际很短,超时也不用给很长,以标准的100KHz通讯时钟速度,一个字节大概在90us左右,超时可以给个5-10B时间,也就是450-900us左右。
; G: c. d1 z6 G0 n' `0 O& y; E  l8 s; f8 V2 U

2 z* H6 k7 ]$ O+ p$ v5 i
. K' s' `# j7 P& v好了说了这么多,具体的看代码中的注释,直接上代码(我只测试过I2C3,其余的理论上都是一样的,就是IO初始化部分有区别,别的通道没有硬件进行测试)0 z' [' X4 s) a# y. N! x
3 K- V1 m4 K0 s. C
  1. /*************************************************************************************************************9 X$ g: c6 ~9 B$ ^. ~3 V) T
  2. * 文件名                :        stm32f7_iic.c
    4 {$ `2 x+ m: _( H, C
  3. * 功能                        :        STM32F7 IIC接口驱动" x4 j( {5 n! D9 Q. B$ v3 R8 v( [  O7 @
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>7 k% R3 T+ m1 E2 d. H7 K
  5. * 创建时间                :        2020-02-09' g3 K( ?8 `, m8 j
  6. * 最后修改时间        :        2020-02-09
    1 D9 P0 d4 k# i, f( [  V7 `- J' g2 J
  7. * 详细:                        只支持主机模式,7bit地址,默认APB1为IIC提供时钟
    * v$ i! a! E0 c; x- N
  8.                                         涉及到读写1字节的超时时间是us,其余的是ms
    & G& l1 u4 |, }. C1 }# f
  9.                                         注意:IIC的IO必须初始化为复用开漏输出。
    ! g" A6 W5 g+ U' S, f0 }
  10. *************************************************************************************************************/        
    1 h( U$ s$ H6 u3 F* y8 F# ?
  11. #include "stm32f7_iic.h"
    0 k. T0 Z- }$ u& i0 z  v7 O) M7 g
  12. #include "system.h" ' N5 W8 ?/ @/ y: U1 R2 a" ?' Z$ _
  13. #include "dma.h"- F9 Q4 p1 y; p4 T

  14. & I7 M" [% h/ ?; S( w
  15. #define IIC_FLAG_MASK  ((uint32_t)0x0001FFFF)        //中断标志掩码
    ' \' b6 r5 b5 T$ u

  16. 1 S/ d! q# s) c) ^. N( _2 H
  17. //自动结束或自动重载设置(重载与自动结束只能二选一,或者都不选)
    & O7 h! l. G! w9 n9 a
  18. typedef enum   N( T+ H2 g/ `% j$ p
  19. {
    / `( B  b4 A& g8 e0 g
  20.         IIC_SOFTEND_MODE                =        0,        //手动结束,并不开启重载* k5 k2 u: h, w- j4 Z: @% a
  21.         IIC_AUTOEND_MODE                =        1,        //自动结束,用于最后一次通讯完成后自动发送STOP结束通讯
    1 W& u/ T" k+ f% ?8 Y6 p) r# Y
  22.         IIC_RELOAD_MODE                        =        2,        //后续还有数据,本次通讯后自动重载,重新设置后继续通讯
    8 Q6 n- b5 C" O4 i' ?- g  [  s2 v$ Q
  23. }IIC_RELOAD_END_MODE;
    - Q9 O8 g1 @2 A5 c/ a) M0 I) E

  24. 1 f/ M3 l9 W7 V8 l* r: G
  25. //读写与开始模式控制3 r6 W/ m5 C' v  y) c
  26. typedef enum
    2 z& a- G9 }  w& K5 r& R
  27. {3 ?7 p7 y* ~2 C- `8 [/ t/ c
  28.         IIC_NOSTART_WRITE                =        0,        //没有开始的写-用于后续数据的写入
      o9 n+ c+ |. Y0 C$ a
  29.         IIC_NOSTART_READ                =        1,        //没有开始的读-用于后续数据读取
    2 O! S$ y% ^  x* M  @
  30.         IIC_START_WRITE                        =        2,        //生成开始写-用于通讯开始时,写地址或数据$ q3 Y" P# T& h& c! K5 V0 J
  31.         IIC_START_READ                =        3,        //生成开始读-用于读取数据时切换到读取方向,并读取后续数据
    - e. [8 w, W  \
  32. }IIC_START_WR_MODE;5 h4 U# d# X9 y, P9 Y# G8 R/ M( U( X
  33. / G& N9 Q" Q4 o
  34. //IIC句柄
    1 @7 a3 H$ n0 A8 G
  35. typedef struct4 h6 V5 ?/ X& e/ X5 J
  36. {. Z% ^' I. t& W
  37.         IIC_CH_Type ch;                        //当前通道; S* ?: z7 {3 b' M; Y6 {2 O
  38.         I2C_TypeDef *I2Cx;                //当前通道外设结构体5 L# |7 V+ x. H5 \/ _; ]5 u4 c: z
  39.         u32 TimeOutUs;                        //操作超时,单位us1 {2 o& _- o- @) B0 R* D
  40.         u16 Speed_KHz;                        //通讯速度,单位KHz
    0 H/ @/ a0 q8 Y# Q' h% B
  41.         bool isMasterMode;                //是否为主设备模式-目前只支持主设备模式% [# P/ ?5 z9 N% `7 S. b
  42. }IIC_HANDLE;
    $ R' S% S9 O9 `

  43. 9 Z" D+ @( T  O! J; o7 @
  44. //IIC外设结构指针
    9 U% e1 g3 _( m0 Y4 G3 E0 B5 e& D5 r
  45. static const  I2C_TypeDef * const I2C_TYPE_BUFF[IIC_CH_COUNT] = {I2C1,I2C2,I2C3,I2C4};2 @  |1 U9 N( A$ y& I% `( l3 L7 }% t
  46. //IIC通道句柄定义
    * x: T  m: z% @5 E& d
  47. static IIC_HANDLE sg_IIC_Handle[IIC_CH_COUNT];7 j8 X# I: p% j2 y! U

  48. . Y2 o3 y) _. w( g) t
  49. //发送NAK
    3 O; B# W& i1 y  Q1 p
  50. //static __inline void IIC_SendNAK(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT15;}' I- i: z4 Z: \/ J! C9 `/ Y% h! f
  51. //发送STOP
    # g$ Y% H' ]7 f* H+ _
  52. static __inline void IIC_SendStop(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT14;}
    : d: v$ L9 {$ l9 L3 L# @: v
  53. //发送START, m. V% T2 c  X/ y: u
  54. //static __inline void IIC_SendStart(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= I2C_CR2_START;}
    3 P6 F8 ]3 t0 C8 J+ I' d2 A4 x# T; k
  55. //获取中断状态, F, E7 m; ^; x
  56. static __inline u32 IIC_GetISR(IIC_HANDLE *pHandle) {return pHandle->I2Cx->ISR & IIC_FLAG_MASK;}
    * M" }/ [" [' q
  57. //清除中断状态
    6 x, y  \2 _& G" `0 q  i
  58. static __inline void IIC_ClearISR(IIC_HANDLE *pHandle, u32 IsrFlag) {pHandle->I2Cx->ICR = IsrFlag & IIC_FLAG_MASK;}% [  I" X1 q! s" F7 V# g
  59. //复位CR2寄存器( K; |0 J* U- E
  60. static __inline void IIC_ClearCR2(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 = 0;}9 E: \+ Y+ c6 S) ?
  61. 5 l- K4 u8 f9 @5 f
  62. static void IIC_SoftReset(IIC_HANDLE *pHandle);//硬件IIC软复位(会使能IIC)
    ; \8 o. |  h, T) i2 P
  63. static u32 IIC_CalculationTiming(u16 Speed_KHz);//硬件IIC时序计算4 E% K+ w; S! o! b7 B6 s" O. Q
  64. 4 s$ N, `7 R9 k. C  V2 O

  65. - v. v; V* X3 x) V, x- ?9 Y6 [) C
  66. /*************************************************************************************************************************
    0 b! P* N- v  Q# d; @7 Y( h& `
  67. * 函数        :                        bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs): _! t7 v( [" ~
  68. * 功能        :                        硬件IIC初始化
    ) y! S, a" J5 i* R0 X  D4 l( P8 |
  69. * 参数        :                        ch:IIC通道;Speed_KHz:速度10-1000(如果速度是100,则按照SMBUS时序);TimeOutUs:操作超时us(0:自定计算超时)
    ; Q/ O# Y1 X) U# l, \+ G
  70. * 返回        :                        IIC_ERROR. h; d7 _9 E& o1 ^
  71. * 依赖        :                        底层宏定义
    0 i3 ?1 Z5 G9 C1 B$ }
  72. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ) J! T" ^* D% e0 R
  73. * 时间        :                        2020-02-15
    2 B8 u4 O2 G1 H* X4 i; o
  74. * 最后修改时间 :         2020-02-153 j% ]: p0 e% b5 i/ K
  75. * 说明        :                         速度只是个大概的计算值,设置为100KHz时会严格的按照SMBUS时序,其余的不保证SMBUS兼容,正常情况下只要时钟速度符合要求,
    ! [9 Z, J4 ^8 ^1 a
  76.                                         时钟上升沿到来前数据以及稳定的切换了即可保证通讯稳定性6 v" e/ T1 S0 ^+ X1 Q
  77. *************************************************************************************************************************/  l. W" @, q  W) E8 `/ {
  78. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)$ m7 ?( h8 e* S* u2 ], F1 {7 ^
  79. {
    ) l6 |% F7 v( h+ q9 k3 a. }
  80.         SYS_DEV_CLOCK DevClock;
      d& s8 R* J8 ?6 J) ]# ^* v5 {
  81.         IIC_HANDLE *pHandle;
    3 G4 L7 p6 `: C3 y5 @7 M+ }5 R
  82.         8 l  z/ c9 A- |- d5 Q
  83.         switch(ch)0 o! r( G. l9 F6 X6 f+ z
  84.         {" c6 X/ l$ P$ r) P
  85.                 case IIC_CH1        :        //IIC1
    % A& m+ q4 g2 M
  86.                 {
    0 a  }; F" F$ v# W4 I
  87.                         RCC->DCKCFGR2 &= ~(0x3 << 16);        //清除设置,使用APB1作为时钟源/ x& K& y, U$ _3 B
  88.                         DevClock = DEV_I2C1;
    : e) }9 m! ^6 ~
  89.                         //初始化I2C IO! ]! S# g7 o6 ~8 ~# E+ G$ O' X4 Z
  90. #if(IIC_CH1_IO_SELECT==IIC_CH1_PB6_7)        //I2C1        使用PB6/74 ]+ Q4 x6 ~8 {- c. b, a
  91.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟3 F6 |) v7 ^7 H- ~2 l' `5 }. u3 k
  92.                         SYS_GPIOx_OneInit(GPIOB, 6, AF_OD, SPEED_25M);                //PB6: W4 F! H. Z6 X) P( K
  93.                         SYS_GPIOx_OneInit(GPIOB, 7, AF_OD, SPEED_25M);                //PB7
    7 ~1 l) J/ V) U/ Q$ \, s( f& w
  94.                         SYS_GPIOx_SetAF(GPIOB, 6, AF4_I2C1);                                //AF4! `' S9 b2 [, T) W0 M
  95.                         SYS_GPIOx_SetAF(GPIOB, 7, AF4_I2C1);                                //AF4
    2 G% @. q% \* n; v$ ]; y, P
  96. #elif(IIC_CH1_IO_SELECT==IIC_CH1_PB8_9)        //I2C1        使用PB8/9# H& z& m! m. m1 ?2 C0 H; I+ p5 v
  97.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟' J+ T) S, }5 k1 L$ Z
  98.                         SYS_GPIOx_OneInit(GPIOB, 8, AF_OD, SPEED_25M);                //PB82 ]' V+ E& J3 ]! v
  99.                         SYS_GPIOx_OneInit(GPIOB, 9, AF_OD, SPEED_25M);                //PB9
    5 A* t- f9 U& }5 S: m
  100.                         SYS_GPIOx_SetAF(GPIOB, 8, AF4_I2C1);                                //AF49 i/ M9 T6 M) b0 H* c
  101.                         SYS_GPIOx_SetAF(GPIOB, 9, AF4_I2C1);                                //AF4
    + |$ z, O! [& P" c
  102. #else" S* ~$ k' }! @1 k
  103.                         #error("无效的I2C1 IO选择");0 G; N' r2 ]5 u; H$ N( ~- ?8 }
  104. #endif //IIC_CH1_IO_SELECT8 n* z3 v2 R# A2 J, }- F! A1 D+ {
  105.                 }break;
    ( x' x* ]6 Z! x5 B/ g- ~
  106.                 case IIC_CH2        :        //IIC26 o4 G5 d: p6 m# M7 v7 X
  107.                 {5 X* T1 T6 ^4 ~$ p/ d+ {; U" T
  108.                         RCC->DCKCFGR2 &= ~(0x3 << 18);        //清除设置,使用APB1作为时钟源( ~1 L# d" S2 T9 V- X5 r- |. h
  109.                         DevClock = DEV_I2C2;, F5 \. l  E5 W, W7 h4 C) Q
  110.                         //初始化I2C IO1 q2 V7 R# P7 l: E
  111. #if(IIC_CH2_IO_SELECT==IIC_CH2_PB10_11)        //使用PB10,PB11
    & ]5 g& \# e3 f7 ^) e& _
  112.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟$ c5 u* t; N  x
  113.                         SYS_GPIOx_OneInit(GPIOB, 10, AF_OD, SPEED_25M);                //PB10
    ' ]. Y0 w+ H+ o7 j4 y6 J
  114.                         SYS_GPIOx_OneInit(GPIOB, 11, AF_OD, SPEED_25M);                //PB11
    ) U$ r% X9 e6 S, S
  115.                         SYS_GPIOx_SetAF(GPIOB, 10, AF4_I2C2);                                //AF49 G. A/ ?2 q% v+ H
  116.                         SYS_GPIOx_SetAF(GPIOB, 11, AF4_I2C2);                                //AF4$ W9 C* S0 j% \- l5 l$ J
  117. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PF0_1)        //PF0,PF1
    1 }+ d& w. @4 R/ v, j5 _
  118.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟
    " i9 ]8 Q! Q3 q0 b# U: S# o
  119.                         SYS_GPIOx_OneInit(GPIOF, 0, AF_OD, SPEED_25M);                //PF0
    : U/ ]% G5 n) f" v& ]
  120.                         SYS_GPIOx_OneInit(GPIOF, 1, AF_OD, SPEED_25M);                //PF11 i% w, f/ J( z& J' L
  121.                         SYS_GPIOx_SetAF(GPIOF, 0, AF4_I2C2);                                //AF4
    ' j! ]$ b7 a+ H0 S( D# q
  122.                         SYS_GPIOx_SetAF(GPIOF, 1, AF4_I2C2);                                //AF4
    2 y  R- W) z- O
  123. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PH4_5)        //PH4,PH5( s/ D6 w3 f9 y0 Y
  124.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟0 R, h; U& z& |& P6 X1 i( o/ W" g
  125.                         SYS_GPIOx_OneInit(GPIOH, 4, AF_OD, SPEED_25M);                //PH4
      V  G2 c' W8 T$ C
  126.                         SYS_GPIOx_OneInit(GPIOH, 5, AF_OD, SPEED_25M);                //PH5
    7 u- t+ O4 _- @" |9 K( s
  127.                         SYS_GPIOx_SetAF(GPIOH, 4, AF4_I2C2);                                //AF4$ ?' O! W# b7 v
  128.                         SYS_GPIOx_SetAF(GPIOH, 5, AF4_I2C2);                                //AF4                        
    4 K! T* r& ], C) m$ Q6 ?
  129. #else0 j9 ~1 \  C5 p' I8 B! o
  130.                         #error("无效的I2C2 IO选择");* T/ T0 y/ P& b9 \
  131. #endif //IIC_CH2_IO_SELECT
    " \) w, e3 k* R% w
  132.                 }break;                        ' [7 |6 G% l/ a' s/ V& v
  133.                 case IIC_CH3        :        //IIC3
    & u8 J- v. c% f
  134.                 {
    * c& s: M. _" r* J" H
  135.                         RCC->DCKCFGR2 &= ~(0x3 << 20);        //清除设置,使用APB1作为时钟源
    # }/ C( ]! k! |! }
  136.                         DevClock = DEV_I2C3;8 v8 d* T' R3 ~6 @/ S" B
  137.                         //初始化I2C IO& b' n1 P( B$ R8 T
  138. #if(IIC_CH3_IO_SELECT==IIC_CH3_PH7_8)                //PH7,PH8
    5 R: q4 O7 F6 N* {
  139.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟' g* I* O; D( K% [
  140.                         SYS_GPIOx_OneInit(GPIOH, 7, AF_OD, SPEED_25M);                //PH7
    3 M6 |3 Y1 E" ]1 Z. y
  141.                         SYS_GPIOx_OneInit(GPIOH, 8, AF_OD, SPEED_25M);                //PH8  a/ s7 c! w2 K& p2 U7 m1 \
  142.                         SYS_GPIOx_SetAF(GPIOH, 7, AF4_I2C3);                                //AF4
    , X9 e" t/ L1 @3 i  A( c0 Q
  143.                         SYS_GPIOx_SetAF(GPIOH, 8, AF4_I2C3);                                //AF4
    $ |6 T: h9 T! z3 I2 I
  144. #elif(IIC_CH3_IO_SELECT==IIC_CH3_PA8_PC9)        //PA8,PC93 F7 n4 I4 R+ z0 m. z6 @
  145.                         SYS_DeviceClockEnable(DEV_GPIOA, TRUE);                                //使能GPIOA时钟. a! K: `4 A9 [
  146.                         SYS_DeviceClockEnable(DEV_GPIOC, TRUE);                                //使能GPIOC时钟4 d0 M! v( b# H/ m. q$ ]
  147.                         SYS_GPIOx_OneInit(GPIOA, 8, AF_OD, SPEED_25M);                //PA8* J& b) ^2 S/ M, p; ?* O2 |% i
  148.                         SYS_GPIOx_OneInit(GPIOC, 9, AF_OD, SPEED_25M);                //PC9
    1 Z* A; y! ^, B/ n- |  I- |
  149.                         SYS_GPIOx_SetAF(GPIOA, 8, AF4_I2C3);                                //AF4
    , V( z) d1 [- c8 u
  150.                         SYS_GPIOx_SetAF(GPIOC, 9, AF4_I2C3);                                //AF4                ' g& W) G! l  M4 S/ F
  151. #else
    8 x7 }( e8 F7 b# ^+ w- S# O2 `
  152.                         #error("无效的I2C3 IO选择");
    $ W" k" V0 `8 W$ e* y
  153. #endif //IIC_CH3_IO_SELECT                        : |; x7 h6 q# d" G: k8 d
  154.                 }break;                        
    - \  k4 y" b& W. C) r
  155.                 case IIC_CH4        :        //IIC41 d# X+ G. T; `9 c3 ^
  156.                 {
    * o' w% t* {/ k; G
  157.                         RCC->DCKCFGR2 &= ~(0x3 << 22);        //清除设置,使用APB1作为时钟源' s1 ]0 B% t4 a& Z
  158.                         DevClock = DEV_I2C4;2 W5 X! l- t$ @9 r. @. Z, P9 e' ?
  159.                         //初始化I2C IO
    # u- P3 ^" F% T3 _
  160. #if(IIC_CH4_IO_SELECT==IIC_CH4_PD12_13)                //PD12,PD13* N$ {& C3 N+ R, K! p  U4 n
  161.                         SYS_DeviceClockEnable(DEV_GPIOD, TRUE);                                //使能GPIOD时钟
    , @- V; S! L# ^9 y! m
  162.                         SYS_GPIOx_OneInit(GPIOD, 12, AF_OD, SPEED_25M);                //PD12
    / q( M/ X* u1 g6 r4 j. y: Z: e
  163.                         SYS_GPIOx_OneInit(GPIOD, 13, AF_OD, SPEED_25M);                //PD13- n5 m# n6 M1 B  Y( p
  164.                         SYS_GPIOx_SetAF(GPIOD, 12, AF4_I2C4);                                //AF4
    # {8 M5 G( |8 q8 M, T, j7 c
  165.                         SYS_GPIOx_SetAF(GPIOD, 13, AF4_I2C4);                                //AF40 h) m9 T8 D( N& B
  166. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PF14_15)        //PF14,PF15
    0 T6 U9 y, |/ e. b
  167.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟
    , o8 _7 k) V& X7 J9 ]) w4 [, X* R
  168.                         SYS_GPIOx_OneInit(GPIOF, 14, AF_OD, SPEED_25M);                //PF14
    # E9 e2 M/ C! D5 g& D, [
  169.                         SYS_GPIOx_OneInit(GPIOF, 15, AF_OD, SPEED_25M);                //PF155 f6 ~" Y5 z$ N- N8 M
  170.                         SYS_GPIOx_SetAF(GPIOF, 14, AF4_I2C4);                                //AF4
    1 Y  v7 R9 U, k, B2 @
  171.                         SYS_GPIOx_SetAF(GPIOF, 15, AF4_I2C4);                                //AF4
    2 E7 s1 a  L! Q: Y- \
  172. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PH11_12)        //PH11,PH12
    2 s1 M: j' D& M/ H; ~
  173.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    5 A( l# ~. t5 Y# c' Y
  174.                         SYS_GPIOx_OneInit(GPIOH, 11, AF_OD, SPEED_25M);                //PH11
    . S6 W3 k& V/ {- n6 U8 K
  175.                         SYS_GPIOx_OneInit(GPIOH, 12, AF_OD, SPEED_25M);                //PH12: {+ ?) |' f3 }% X4 o; A
  176.                         SYS_GPIOx_SetAF(GPIOH, 11, AF4_I2C4);                                //AF4
    * A7 y+ b2 \$ A( J, z
  177.                         SYS_GPIOx_SetAF(GPIOH, 12, AF4_I2C4);                                //AF4                        
    8 W6 R+ V* @! h( a
  178. #else, I6 X5 E9 W0 K6 |5 u
  179.                         #error("无效的I2C4 IO选择");# s* l# ^( B! I/ ^" C/ w/ b1 l
  180. #endif //IIC_CH4_IO_SELECT                        ( c5 l5 k2 N# t
  181.                 }break;
    4 ~0 U$ l" s5 d3 S
  182.                 default:
    ( x; A* S1 ]9 _' e& c
  183.                 {' b# \6 U+ q$ d- P- D
  184.                         DEBUG("初始化IIC失败:无效的IIC通道%d\r\n", ch);6 D' ^; W. I# z2 Y$ k
  185.                         return FALSE;
    ) Q- O$ j' ^2 s$ j8 s
  186.                 }& i# }/ q2 ], P+ m7 X% M
  187.         }
    " w% Y1 `6 }4 s3 a" s, q
  188.         pHandle = &sg_IIC_Handle[ch];                                                        //获取相关通道的句柄# y( P8 z" `1 |& f5 `0 t3 O. ]. |
  189.         if(pHandle == NULL)
      u" C5 Z( Y5 W
  190.         {
    ) d/ B' Q$ A: x+ v
  191.                 DEBUG("初始化IIC失败:无效的IIC句柄\r\n");1 q8 M/ _# M3 R; `& J
  192.                 return FALSE;/ M' g" r  c- r7 a' p9 I
  193.         }  t6 D8 H- h( k7 Q) O
  194.         ' V- R) J# l. A
  195.         SYS_DeviceClockEnable(DevClock, TRUE);                                        //使能时钟
    & q" }" R2 Z+ ~2 u1 w
  196.         SYS_DeviceReset(DevClock);                                                                //外设复位, l- X; d  T4 V7 z. y6 |
  197.         pHandle->I2Cx = (I2C_TypeDef *)I2C_TYPE_BUFF[ch];                //外设指针
    ; B, K2 t6 g0 d+ l' d
  198.         pHandle->I2Cx->CR1 = 0;3 z: Y! o! ~9 ~7 f3 B4 s
  199.         Delay_US(1);                                                # U) Z: i/ g. X
  200.         pHandle->I2Cx->CR1 |= 2<<8;                                                                //设置噪声滤波器,关闭所有中断
    ; }  W# q7 D2 I( t9 d& {4 ]7 |
  201.         pHandle->I2Cx->CR2 = 0;
    ) u% r/ v2 d( u0 [5 ?
  202.         pHandle->I2Cx->OAR1 = 0;/ p! E$ L/ j" z3 a/ R. s, q
  203.         pHandle->I2Cx->OAR2 = 0;
    , @# Y3 x- D2 J: {
  204.         if(Speed_KHz > 1000) Speed_KHz = 1000;: x) Z$ Z* ], K# W$ q9 ]
  205.         if(Speed_KHz < 10) Speed_KHz = 10;
    + U% _& Z6 h  s: m) k
  206.         pHandle->Speed_KHz = Speed_KHz;                                                        //记录速度! o9 A$ O+ r& D* t3 |0 N
  207.         if(TimeOutUs == 0)                                                                                //需要自动计算超时时间,时钟周期*10*10
    8 Q+ O' w5 r' k& r7 a/ n% w
  208.         {, e# _3 x. C& O7 ^
  209.                 TimeOutUs = 1000/Speed_KHz;                                                        //时钟周期
    ; R$ U- e8 _* W" y& o: ~
  210.                 TimeOutUs *= 10;                                                                        //字节周期- x4 L9 @  g: {
  211.                 TimeOutUs *= 10;                                                                        //超时时间为10个字节时间
    + d0 \, q% Y3 ^% k3 I& ]  k
  212.         }3 p- _2 T4 g$ {/ H. K: E
  213.         if(TimeOutUs < 3) TimeOutUs = 3;: f3 J$ k$ C2 w) B) D. ]5 q. j
  214.         pHandle->TimeOutUs = TimeOutUs;                                                        //记录通讯超时时间# M) `9 o5 B# |7 ^2 \
  215.         uart_printf("IIC超时时间:%dus\r\n", pHandle->TimeOutUs);
    ; s' Z; A& l; s- w, D) k
  216.         pHandle->I2Cx->TIMINGR = IIC_CalculationTiming(pHandle->Speed_KHz);//0x40912732;                                        //时序5 q" _$ @" x2 {
  217.         pHandle->I2Cx->CR1 |= BIT0;                                                                //使能IIC+ A. q) f- U$ z% F" c2 O
  218.         pHandle->isMasterMode = TRUE;                                                        //主设备模式
    & ], N4 |+ ]0 o; m1 p
  219.         Delay_US(1);  [. }2 E' o8 M4 T" o7 m
  220. % B6 @% F, f; R4 p
  221.         return TRUE;/ }& J" Q" N& j
  222. }
    - @9 s8 ^& o- k# p8 L& b
  223. 1 p( C+ K' U- ?6 E8 r4 F. T/ O

  224. 2 {3 g, d$ u) Q4 }) L2 i% d$ ?! g
  225. /*************************************************************************************************************************
    6 h) G$ s, s$ C! U; J  E
  226. * 函数        :                        static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)- g: I: n; L! J0 j6 U) f: N$ l5 h
  227. * 功能        :                        检查是否有NACK中断状态,如果有则清除掉
    & z- A( d& M0 d! E9 h
  228. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us/ S. }% Y6 E! u* ]( S+ V/ h7 f$ N
  229. * 返回        :                        IIC_ERROR
    # X& c6 W( ^. ^0 G: Z' v
  230. * 依赖        :                        底层宏定义: r; V" z3 k& e6 H. Y; a+ V
  231. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    7 H' R  T0 K: n. j
  232. * 时间        :                        2020-02-158 ?3 V* l" K# ?& A' o! {: [# p. A
  233. * 最后修改时间 :         2020-02-15
    % E3 B' T9 Y0 z9 c' L5 w
  234. * 说明        :                         如果有NACK中断,则先产生停止位,然后清清除掉所有的中断,并复位IIC,然后返回错误) i: G0 e$ n, y8 N! U% h. Z
  235. *************************************************************************************************************************/  " S& z1 G: v1 x; e, S& I
  236. static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)
    2 F4 k0 o3 x( a- v1 c
  237. {0 R5 b  x! Z& H$ r1 `5 P# n* O9 X
  238.         IIC_ERROR Error = IIC_OK;/ h: z9 _$ p$ A
  239.         3 O, O2 m, M  c( e$ k' j0 W1 ^& R! Z
  240.         if(IIC_GetISR(pHandle) & IIC_FLAG_NACKF)        //接收到否定应答标志
    : H1 l6 x, c* p# R
  241.         {- \$ f+ K4 d* {
  242.                 uart_printf("NACK : IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);
    ; I6 ^( b1 I( a! I% n7 ~
  243.                 uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    , o0 M% F& [3 D0 e
  244.                 uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));
    - n4 a8 z$ {$ Z$ |1 Z% ?* _4 p
  245.                 //主设备下,如果没有开启自动产生停止位,则手动产生停止位6 E2 z9 v5 I% P& M
  246.                 if(pHandle->isMasterMode && ((pHandle->I2Cx->CR2 & I2C_CR2_AUTOEND) == 0))
    6 F7 y5 M% a# r' n' P+ C" y
  247.                 {
    " \  ]* K2 @3 U
  248.                         IIC_SendStop(pHandle);                        //send stop
    / G$ S4 h6 S0 J5 H0 Q. L
  249.                 }  t  l% S0 ]: d2 D& [8 n" n) b7 I
  250.                 //等待STOP标志有效+ ?0 p& j6 u: r5 H" x7 {
  251.                 while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)# x  n, N: Y' P( r' ]$ E
  252.                 {; C5 {! p+ Y$ R* }  t5 S: Z8 v
  253.                         if(TimeOutUs == 0)                                //检查是否超时了9 W) ?5 d& l7 H; p6 d
  254.                         {) |& w- R5 g, z, q+ v4 a- F
  255.                                 break;* Z  x2 ]6 _0 I
  256.                         }                        
    " w( S1 j5 f5 r
  257.                         TimeOutUs --;% v* @8 E' E( O$ b
  258.                         Delay_US(1);                                                //延时, R% u# k, X2 D& G& U. Z: ~
  259.                 }
    $ M+ {1 e2 [- c0 X' J' j6 H' ~
  260.                 //清除相关的中断标志* z& F' j7 r3 G! e
  261.                 IIC_ClearISR(pHandle, IIC_FLAG_NACKF | IIC_FLAG_STOPF);        //清除NACK,STOP标志
    % U3 s5 ]8 O+ {2 R
  262.                 pHandle->I2Cx->CR2 = 0;                                                                                //清除CR2寄存器4 ^) \3 h  P+ Y7 [2 x# ]
  263.                 IIC_SoftReset(pHandle);                                                                        //执行软复位
    * P$ c/ C  {& q
  264.                 if(TimeOutUs == 0)                                                //没有超时,就是硬件通讯出错了! Y2 ]" \$ I/ S9 W: ?- \; q
  265.                 {
    + X! F4 j, u/ Z( u& i
  266.                         DEBUG("IIC发送stop超时\r\n");9 C8 [; @, K/ O3 g9 g
  267.                         Error = IIC_TIMEOUT;                                //超时- {: ^; [5 J3 O* q/ X/ f, p' r) t
  268.                 }; m3 C+ D( `* \% p& c
  269.                 else
    , L- r+ k2 Z% e( J7 ^' Q
  270.                 {. H' B* S! _% ]( |5 F
  271.                         Error = IIC_HAL_ERROR;                                //底层错误
    7 |7 v- i; `3 ~
  272.                 }
    ! x& c8 z# F3 d6 Z
  273.         }
    $ `" u( N* v% e* z# V
  274.         + |8 t2 ?; A& r4 L' a1 W
  275.         return Error;; J% X( ?4 @- u. T) Z, o
  276. }
    4 O, O/ g# Y  r) o8 J

  277. ! N( r, H; @* Y8 K. s8 f" H% N
  278. ( J; {* \, k0 V' G5 {; N

  279. ( J; v8 a4 }  P/ y. O: ^  I" ~% d3 X" w
  280. /*************************************************************************************************************************% I/ |' z, w1 M7 l  D
  281. * 函数        :                        static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
    : L* A+ B8 H1 h3 ~9 d2 P
  282. * 功能        :                        等待TXIS中断有效(等待 I2C_TXDR 发送寄存器为空)
    ' ?" s1 F, M6 f  e) \2 B9 f& d
  283. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us) i9 Z/ g9 w4 G% O' b) V# o& q
  284. * 返回        :                        IIC_ERROR+ h& K+ x1 p& }0 Q9 B% }" k) y
  285. * 依赖        :                        底层宏定义
    ' n% j; K" K+ K( C. B. \5 ^
  286. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    6 I7 l( P# f& v3 ~% f) o1 U
  287. * 时间        :                        2020-02-15
    , T- t" N% `7 D8 H& W
  288. * 最后修改时间 :         2020-02-151 X4 M  p5 h4 [1 F( f6 ^
  289. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的) E% n$ a, M" r" E' i
  290. *************************************************************************************************************************/  0 i. B9 p3 @* q8 b$ E
  291. static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)$ q$ r, l% {9 V9 f: P! B
  292. {# W0 R* Z1 R3 c: {& j9 e- h
  293.         //等待TXIS中断有效' z. c0 G% D# S5 ?! C4 k& c0 ]" S5 q+ @! o( v
  294.         while((IIC_GetISR(pHandle) & IIC_FLAG_TXIS) == 0)7 q, T  @, b+ M) `( W6 U
  295.         {
    # L9 y  m: j) J. Q
  296.                 //有NACK中断,进行处理3 h/ y' i3 [8 Z! J6 g7 g! {
  297.                 if(IIC_isCheckNackFlag(pHandle, TimeOutUs) != IIC_OK)        1 }0 |8 [( t# z1 o
  298.                 {
    6 a+ S- Y- s$ ]& O, E
  299.                         DEBUG("检测到NAK错误\r\n");; L9 e1 Q6 S; E
  300.                         return IIC_NACK;
    9 i( x& ~& k4 Q0 y6 s3 y7 U* h  U
  301.                 }6 s* [) M7 H/ F; h- _
  302.                 3 K# O  E4 k" j3 w! R
  303.                 if(TimeOutUs == 0)                                        //检查是否超时了3 v1 l5 B* D# Q
  304.                 {
    ! y# H4 f, I1 R) t. P
  305.                         uart_printf("IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);
    % B8 r2 u4 x. D* P
  306.                         uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);4 x# e4 P) o/ ^( f* @( t9 _
  307.                         uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));; L% T& o+ C$ ~$ k
  308.                         % M; _) `' z6 K1 E! \0 f
  309.                         IIC_SoftReset(pHandle);                //执行软复位& t0 j* P  x! Q1 U& `) Z
  310.                         return IIC_TIMEOUT;                                //超时  d9 G  x8 d& D* M/ `, i5 n
  311.                 }                        7 f6 X% y: [: R" n  J, F( H* n5 n
  312.                 TimeOutUs --;8 z2 O$ T/ V( c9 }* }- Y4 Z
  313.                 Delay_US(1);                                                //延时! x' M' A% l( D! c4 M1 [2 t" {
  314.         }& M9 a! D3 C; a
  315.         - u  B& y; r, I$ c1 P' g. E3 E
  316.         return IIC_OK;$ \; x% G$ }0 u3 j: h7 [
  317. }
    8 ]0 t' D  ^' b/ O" [2 {: y) e6 O
  318. / x* X7 p0 ?- X0 b* b0 X

  319. 5 K) _# ]) A" ]: C, ^
  320. /*************************************************************************************************************************, M1 A% f! s9 `
  321. * 函数        :                        static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)# ]& T' M' [8 M7 S1 l* U
  322. * 功能        :                        等待STOP中断有效(等待 发送结束 )
    9 b4 n9 |9 }* ?9 X- X
  323. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us( P; ^$ F; V; |1 z
  324. * 返回        :                        IIC_ERROR
    2 v0 V3 P" e0 c3 c3 W9 U
  325. * 依赖        :                        底层宏定义
    ' D2 S4 F* @* w  y$ [
  326. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    3 ?; X* F& ^* p
  327. * 时间        :                        2020-02-15# d( x. n' T2 S5 ]. ~( \: b
  328. * 最后修改时间 :         2020-02-15
    ( S2 K% C  S! y. R& U! N
  329. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的
    7 |2 k9 o* W% }* N! \
  330. *************************************************************************************************************************/  # J; N. G( W1 g* T& P+ n: j' g
  331. static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)6 |) Q+ Y2 ^* L% a! V
  332. {
    2 E* d. C+ E* B/ N
  333.         //等待STOPF中断有效5 r, s. u; \9 S# ~: a! @
  334.         while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
      S6 m/ D- i) H1 w+ S% v4 t
  335.         {6 \) k, i% i  o2 A2 X0 z
  336.                 //有NACK中断,进行处理+ s: q* }7 C+ s& I
  337.                 if(IIC_isCheckNackFlag(pHandle, 5) != IIC_OK)        : I, T+ U. W: j& r$ x$ {
  338.                 {( U0 Q- W; f8 n& W( T
  339.                         return IIC_HAL_ERROR;, O; j( ^" r4 A3 q8 U# K2 `
  340.                 }
    ; A& G8 O$ W# w) Y4 ~
  341.                
    0 x  G) ^2 e6 f+ `# Z8 _4 K/ ^
  342.                 if(TimeOutUs == 0)                                        //检查是否超时了
    * j' n! m! z  f; n0 F
  343.                 {
    / o: C/ d/ h: \/ N9 k5 @' `
  344.                         IIC_SoftReset(pHandle);                //执行软复位
    , Q) Q% S3 R3 ~6 n, [/ K
  345.                         DEBUG("IIC等待结束超时\r\n");+ ^% j% A: H5 k) ]$ B. H
  346.                         return IIC_TIMEOUT;                                //超时7 {: |5 R: ^) W1 [) G* x1 k- x9 F
  347.                 }                        0 p' @- L" U7 U5 ]
  348.                 TimeOutUs --;
    ) i% z- X* G) _; d8 j7 Y
  349.                 Delay_US(1);                                                //延时
    + L* t( q: R' P* y5 ^- b3 q
  350.         }
    # u4 N. m) g2 f
  351.         
    - w1 e* I; h  m% \4 z
  352.         return IIC_OK;
    1 O  e+ W% a# ]1 M1 U$ [, E7 f) c
  353. }
    # s- F) J" B* _4 a% D; t4 ^  I
  354. 3 E3 }& u! x% w4 S! n

  355. 7 o6 T- B  c4 w* [( Q
  356. /*************************************************************************************************************************
    ' m% e- L9 @# |7 G! x
  357. * 函数        :                        static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
      ?! U5 U& D# p; Q8 o9 {
  358. * 功能        :                        等待中断有效% }. Q$ v0 q3 g# ~/ X; b' }4 Z% C+ ~
  359. * 参数        :                        pHandle:句柄;Flag:需要等待的flag,见IIC_FLAG_xxx;isWaitFlagSet:TRUE:等待标志有效,FALSE:等待标志复位;TimeOutUs:超时时间,单位Us" p" x& w; g+ A; b% n2 [. S
  360. * 返回        :                        IIC_ERROR# D$ f# D+ ~$ ~2 T
  361. * 依赖        :                        底层宏定义
    ' E# T, V; s) G2 _& _, M% I! @( I
  362. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    , ^" F! C% X/ I% m9 S) P/ z  x
  363. * 时间        :                        2020-02-15' t& B" Y. w+ m. d' j2 }9 @
  364. * 最后修改时间 :         2020-02-15
    ) C4 q5 V4 m" @  _- E3 [9 Y- n
  365. * 说明        :                        
    & n0 V% B  V, ]/ C) U8 |
  366. *************************************************************************************************************************/  8 _: d& i' }* g  o: T
  367. static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)7 v  B- W8 F: m+ n, ]) G
  368. {
    6 v9 C+ @% n8 m$ r- U
  369.         if(isWaitFlagSet)        //需要等待标志有效* J& }% A# `$ q, A  f& L! X
  370.         {9 A' G0 }6 O' ?, }8 ~8 v4 x# {* s
  371.                 while((IIC_GetISR(pHandle) & Flag) == 0)
    $ G+ H1 {, C$ h3 M9 T5 Q# N
  372.                 {
    / Y. j/ `) M/ ]6 ]5 \) w9 R
  373.                         if(TimeOutUs == 0)                                        //检查是否超时了) K* e% n. E: G: Y, O& p3 w% t" R8 \
  374.                         {
      W7 H9 o8 \7 g4 h" z4 z: R( s
  375.                                 return IIC_TIMEOUT;                                //超时
    $ q5 B. O, h) W& P; O
  376.                         }                        
    9 O$ l! u- g, X
  377.                         TimeOutUs --;
    # O, H4 K: x1 a& c0 J
  378.                         Delay_US(1);                                                //延时6 y$ l8 k4 p9 e
  379.                 }$ ^) |1 u4 E8 u' \3 S
  380.         }( `" f! }* f1 {4 K( J% u
  381.         else                                //需要等待标志复位/ Y# X& I6 y0 |9 C4 m
  382.         {* W# A) E1 _8 J1 r0 e1 u
  383.                 while((IIC_GetISR(pHandle) & Flag) != 0)6 B8 r# x* G9 o6 l
  384.                 {4 o2 k) J* w1 ]# O
  385.                         if(TimeOutUs == 0)                                        //检查是否超时了
    " T1 h/ r- C) _5 E% E$ H, {# L
  386.                         {- r$ |- s9 Y% e0 \
  387.                                 return IIC_TIMEOUT;                                //超时( Z+ N6 @# g$ _+ ^- x
  388.                         }                        ! t7 A7 |% c- k9 l
  389.                         TimeOutUs --;: D% B( v, y: e* K
  390.                         Delay_US(1);                                                //延时
    2 H8 j2 t/ [. g  g2 n9 j1 R) c# n
  391.                 }
    & d8 p, Y4 O6 `- L3 o* [
  392.         }" R5 y' x6 J& d2 A  C  ?9 S
  393. - z* B, v7 K5 j
  394.         return IIC_OK;0 d0 h) R% C' E0 X- L
  395. }2 S# U2 C# ?3 Y9 z0 X7 ]! a4 ^

  396. 0 |7 y7 `) [$ \; x

  397. ' \5 y1 f8 ^6 W3 J. ^
  398. % L; Q% S5 j- ], y; L- K1 [/ h

  399. 3 Y8 @) W; M0 s2 b+ O2 k
  400. /*************************************************************************************************************************+ n2 q* A1 I6 `
  401. * 函数        :                        static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)- N; w+ a; @* K/ [6 I8 r
  402. * 功能        :                        主设备传输配置(配置CR2寄存器)
    - Q1 f1 a4 C# U1 Z, }& c* y! f
  403. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;TransByteCount:需要传输的数据长度;EndorReload:自动结束还是重载设置,见IIC_RELOAD_END_MODE;StartAndWR:开始读写控制,见StartAndWR
    7 `( D8 `# q$ ~
  404. * 返回        :                        无3 ~. s" X3 k+ `, o
  405. * 依赖        :                        底层宏定义
    6 f7 C* `1 }# p5 ~/ I# D' B! _
  406. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>1 U) x! |7 F+ t6 }2 f
  407. * 时间        :                        2020-02-15
    ; }' i% d  L& q5 X9 U
  408. * 最后修改时间 :         2020-02-16
    - M9 v: f7 Z) [+ x5 F
  409. * 说明        :                         在往 NBYTE 中设置最后一次传输的字节数前,必须把 RELOAD 位清零便于后续自动发送STOP。
    9 s2 y9 U4 q9 |6 V/ b/ W
  410.                                         当 RELOAD 位置 1 时,AUTOEND 位将不起作用;
    ! k& {& }" D- M1 b  {
  411. *************************************************************************************************************************/  
    7 p1 b- s" N5 Z7 u
  412. static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)
    2 O% k) }4 D+ \. [; L
  413. {
    ( W- R' c9 T9 q, Y7 n
  414.         u32 temp = 0;7 E: Z6 `& R5 ?% V4 G- L
  415.         / s2 ^. i" f& L
  416.         //先读取CR2寄存器的值. e3 Q2 f3 l; D' }6 p- u- v
  417.         temp = pHandle->I2Cx->CR2;
    ( _1 p0 A1 H' ?# c7 Z2 l) ^
  418.         //清除掉相关的字节" P: G0 E1 R6 y7 p' |( e1 Q
  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));
    / o' N7 o3 p! L/ \  `7 q% p% f
  420.         //生成配置数据
    " L% A. x$ Z6 x  i5 E
  421.         temp |= (u32)(((u32)SlaveAddr & I2C_CR2_SADD) | (((u32)TransByteCount << 16 ) & I2C_CR2_NBYTES));
    , S! W3 j. {( n8 z! V' z: c
  422.         //重载与自动结束只能二选一6 e0 a2 |: n& m
  423.         if(EndorReload == IIC_AUTOEND_MODE)         
    - i2 Y1 e  k3 q# h" @* v
  424.         {+ D7 \3 n- ^; D1 ?# L; H
  425.                 temp |= I2C_CR2_AUTOEND;        //自动结束模式" w8 x+ a. U! r
  426.         }
    $ L* ]- Y6 O8 j) I  r! b
  427.         else if(EndorReload == IIC_RELOAD_MODE)
    2 f% S7 \' z0 Y
  428.         {
    ; s# Z% a, X+ P, D7 q6 u! {$ {
  429.                 temp |= I2C_CR2_RELOAD;                //NBYTES 重载模式
    " e8 A$ x9 y% i9 w+ p: B
  430.         }3 b' v8 G1 ?6 C) ^* c
  431.         
    " L, d+ F& V! X1 u7 T; ^
  432.         switch(StartAndWR)
    : g! h3 a) C! r8 a2 N! @1 @; e% L
  433.         {
    0 [8 G. H: Z; v
  434.                 case IIC_NOSTART_WRITE        :        break;        //没有开始的写-默认就是这样的
    ; L- O9 w- B' ]" N: J+ q( n2 b
  435.                 case IIC_NOSTART_READ        :                        //没有开始的读-用于后续数据读取2 ^& {" o; W; _
  436.                 {
    8 S) z$ _! f5 v
  437.                         temp |= I2C_CR2_RD_WRN;                        //读取; ?% G- h9 d# W  r2 X$ _
  438.                 }break;7 |/ ?- {5 @; C9 c# z: W! O6 ?/ }
  439.                 case IIC_START_WRITE        :                        //生成开始写0 J5 f- z: z8 J* G. V+ {: g% N
  440.                 {
    9 `8 n6 I- ~% s' K  J+ e
  441.                         temp |= I2C_CR2_START;                        //启动传输
    7 }6 r. V" @) N. n' F
  442.                 }break;
    6 h" h2 \% O# F% M$ a, K* Y
  443.                 case IIC_START_READ                :                        //生成开始读        3 F4 A% L. e: L8 O1 |" e
  444.                 {
    4 B/ x3 ~0 \7 U- Q
  445.                         temp |= I2C_CR2_RD_WRN;                        //读取
    * \. V9 P& z% _8 ^+ t
  446.                         temp |= I2C_CR2_START;                        //启动传输
    ' g: n& c/ ?$ g# w# u
  447.                 }break;1 W3 J3 X/ w1 T8 u
  448.                 default:break;" C, s8 }, L  U- c$ `# m
  449.         }
    7 o: t3 S% v9 H( x
  450.         " e0 j: J3 K0 P* n$ V. {
  451.         //uart_printf("准备写入CR2=0x%X\t", temp);8 A1 h" Q  R. ]
  452.         //更新到寄存器3 K/ o" G5 ~5 J* X
  453.         pHandle->I2Cx->CR2 = temp;  //测试
    0 G9 ^. d3 j7 S& }+ d
  454.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    " J& {6 V  N/ _% {' m6 H
  455.         Delay_US(100);
    # ~3 p. B' J2 E) a
  456. }0 K( J$ R& C9 M( W: O

  457. 4 {7 V& u  x  U; O( b4 C/ }

  458. 0 S" z: C$ f% l6 b0 G, f) [
  459. /*************************************************************************************************************************
    ( W3 R5 b- ]9 j- g" y
  460. * 函数        :                        static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)( R5 O# ~- @) i# E. v
  461. * 功能        :                        IIC发送一字节
    , Z7 ]2 i8 B! `( J0 C5 A
  462. * 参数        :                        pHandle:句柄;data:待发送数据;TimeOutUs:超时时间,单位us8 i% b3 p$ h. t4 \' t. ^% u4 z
  463. * 返回        :                        IIC_ERROR
    + I( P) Q; W& \5 Y! {
  464. * 依赖        :                        底层宏定义
    % ]- |! @* k  R
  465. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ' S+ U2 S! M0 s
  466. * 时间        :                        2020-02-15% F5 Y" S2 ~* t# n
  467. * 最后修改时间 :         2020-02-16) D# J( K! _5 r) P% \7 c& u
  468. * 说明        :                         TXIS有效后才会进行数据发送,不会检查数据发送是否完成。
    ' d6 c# ]. }: N2 ^  {# u5 T7 c
  469.                                         如果最后一个字节发送完成后不会再触发TXIS中断,只会触发TC中断
    / O+ ?7 z6 N) L" E
  470. *************************************************************************************************************************/  " Y1 U# h, A' Q
  471. static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)
    , k  V; v' b. o7 B0 l
  472. {
    ( g$ w: Y- R1 k8 U4 `9 l& c+ _* @
  473.         IIC_ERROR Error = IIC_isWaitTXIS(pHandle, TimeOutUs);                                //先等待可以发数据
    / M& D1 u' v5 m& s3 I3 F5 ?
  474.         if(Error != IIC_OK) return Error;9 b- R& X  Z6 I
  475.         pHandle->I2Cx->TXDR = data;                                                                                        //写数据到发送寄存器-不会等待数据发送完成        3 x3 F4 L4 d. r: C0 E  A) S

  476. % B& `# P3 Z) D& u5 e
  477.         return IIC_OK;0 G3 S) N% A8 |' @; s3 C8 I
  478. }
    8 N; }- b1 R5 e$ q

  479. + z% P" f2 Q/ N4 _9 j, ^$ j
  480. /*************************************************************************************************************************
    - V$ C$ \$ M& H4 b, {
  481. * 函数        :                        static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    & S7 W6 s7 n% A4 D9 z6 n) O
  482.                                                 bool isRead,u32 TimeOutUs)
    ! b1 t4 }4 p3 r$ Q8 Q
  483. * 功能        :                        主设备请求发送从机地址与目标寄存器地址1 X$ f5 Y, E# v' v4 i
  484. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;RegAddr:寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,
    3 o) F# o! p% L1 g7 g4 i7 B# L" b9 R
  485.                                                 FALSE:16bit寄存器地址;isRead:TRUE:这个操作是读取寄存器;否则是写入寄存器;TimeOutUs:超时时间,单位us
    * l% m" j+ s# i  Z  ^1 S  I* J
  486. * 返回        :                        IIC_ERROR
    " H' Y$ V  O1 P2 y9 n. l
  487. * 依赖        :                        底层宏定义
    ! `! u+ m9 |3 Y" h: K4 R
  488. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    + H) c4 T  k; k
  489. * 时间        :                        2020-02-15
    1 W: `1 g) \: j% x4 s
  490. * 最后修改时间 :         2020-02-16
    + P8 |6 \0 Z$ a
  491. * 说明        :                         6 X% y3 U0 r' y
  492. *************************************************************************************************************************/  
    2 k5 x; F8 u, z; `
  493. static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,bool isRead, u32 TimeOutUs)
    * r1 C& Z* Z5 I5 T1 A# ^
  494. {        , ?- @5 T) p% J- {+ \0 y$ \
  495.         IIC_ERROR Error;7 q5 s) Z6 _" H
  496.         1 o5 \4 ~& j0 Q" i
  497.         //uart_printf("WriteAddr1:CR1=0x%X\t", pHandle->I2Cx->CR1);, ^5 ], b3 ]9 \: @8 k! T/ d& E
  498.         //uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);% k7 a( l2 n; K! O* ~- m
  499.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);) @9 I* y) j- n/ i1 M. m( [' N  k
  500.         //传输配置,并启动传输,发送起始序列,开始IIC传输了
    1 Q8 q1 O1 g: z6 C5 O9 \/ M
  501.         //如果是读取则使能软件结束,如果是写则是自动重载5 N$ W( S- L8 J- V; I3 [
  502.         IIC_MasterTransConfig(pHandle, SlaveAddr, (is8bitRegAddr==FALSE)?2:1, (isRead)?IIC_SOFTEND_MODE:IIC_RELOAD_MODE, IIC_START_WRITE);        //传输相关配置-写,并启动传输" B' k% X8 d% j3 l6 @( h' O
  503.         : ~- S7 L# u) _4 k9 R: i
  504.         //开始发送寄存器地址
    . K9 [4 s  m: K
  505.         if(is8bitRegAddr==FALSE)                                                                                                //寄存器地址是16位的,IIC通常是MSB高位在前,需要进行高低位对调9 b% X: O3 T: a, `. |
  506.         {
    7 [( Y" _( _, Q" V2 ^9 w
  507.                 Error = IIC_SendByte(pHandle, RegAddr>>8, TimeOutUs);        //先发送MSB-非最后一字节
    1 t* \, c! K6 u' P; M" w
  508.                 if(Error != IIC_OK)! M( R) G, c4 Z* N0 B0 o
  509.                 {- M' Z/ J. s$ O6 z" K+ L
  510.                         DEBUG("IIC发送寄存器地址MSB失败\r\n");
    : x$ [# h: g6 [. ]! M
  511.                         return Error;6 R; ?0 ^4 q- Z, X1 o
  512.                 }        " b1 u" A; t1 r' S- ]% h6 B- N
  513.         }+ b0 \9 v2 c- \% ^4 N9 J) _
  514.         Error = IIC_SendByte(pHandle, RegAddr & 0xFF, TimeOutUs);        //再发送LSB-最后一字节
    7 _5 u% N& r  D
  515.         if(Error != IIC_OK)$ y* k$ {, A6 Q/ _" P+ V: M
  516.         {' K! w; T" I# [/ u% k5 v0 A- _
  517.                 DEBUG("IIC发送寄存器地址LSB失败\r\n");. t* h1 @  |9 m: \
  518.                 return Error;
    ! \/ w6 S! F6 o3 T
  519.         }
    7 g$ s  E% S( ]/ U
  520.         //等待全部数据发送完成
    5 {# s0 Q7 {- J& C! b- ]
  521.         if(isRead)        //读取方向-非重载,等待数据传输完成 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。( ]) b. {. {/ U- K4 Y7 g1 i
  522.         {- U; g+ e* K1 E9 B& Y; C) J
  523.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TC, TRUE, TimeOutUs) != IIC_OK)& m# k: p; n) U! c( o/ x0 G
  524.                 {9 y  k; O. |5 M
  525.                         return IIC_TIMEOUT;. _( a8 p6 N  v) J0 s- E5 S
  526.                 }- j) n- P. F% d" `# Q
  527.         }        
    * |9 ~  L% x& @3 q. Q$ o5 _, ~/ D
  528.         else //写入方向,等待重载
    ) x$ E4 p- P& c
  529.         {/ d; C) D% u, p2 b6 g# V
  530.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TCR, TRUE, TimeOutUs) != IIC_OK)( w2 y2 C8 l# s9 x1 b( k+ a2 {" p
  531.                 {1 v" p' n0 |0 c5 k  b  x, Y! K
  532.                         return IIC_TIMEOUT;
    2 K1 o+ y9 P. u' c3 M& D
  533.                 }
    ( `3 e" s0 @5 [) [" @3 \3 V
  534.         }
    4 r9 D( H$ o4 Y) l
  535.         
    % U: ^9 A6 v9 j' V. {- _! v
  536.         return Error;5 z, r  O7 m+ q2 P( i" I0 Q
  537. }( T* N+ f) E8 {  ?2 f$ l, [# S  L

  538. $ @7 b6 A7 \& L: I" H
  539. 5 q- |" P! H" ~. ^. ]9 g' A" t4 ]' K7 z$ {
  540. /*************************************************************************************************************************
    , W& ~( Q8 k5 {) V+ l
  541. * 函数        :                        static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
    & R0 k7 b" M; g( _+ S
  542. * 功能        :                        等待接收一字节数据
    ! W* |" n6 |- \/ d3 x1 h  N# D% Q
  543. * 参数        :                        pHandle:句柄;pData:接收的字节数据缓冲区;TimeOutUs:超时时间,单位ms' s; r& F% r7 W
  544. * 返回        :                        IIC_ERROR
    5 H" x) L8 d8 U7 Z' h' \0 q& o
  545. * 依赖        :                        底层宏定义
    ) P  B) M9 P; c* a7 M
  546. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    7 ]8 X$ G' G# {9 t
  547. * 时间        :                        2020-02-15- S# y+ p+ m$ \" f
  548. * 最后修改时间 :         2020-02-15: q6 I- ^' z7 H' Z  O& y
  549. * 说明        :                         当RXNE有效后读取一条数据,否则可能会超时
    ( f7 [! ~  k5 Z, D' ?: N  U6 o
  550. *************************************************************************************************************************/  
    & A: a8 e, q% N' l# s8 w
  551. static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
    5 `) Z9 K8 M9 n9 p, {% A1 H: ~- Y
  552. {: d5 I+ e9 ~9 ]5 S2 X, w
  553.         while((IIC_GetISR(pHandle) & IIC_FLAG_RXNE) == 0)        //等待RXNE有效3 i. W4 D3 w$ F& Z4 v" O, Y
  554.         {
    4 }% p$ z5 Y. h! Y2 G
  555.                 if(TimeOutUs == 0)                                        //检查是否超时了, `) Z% q5 x# S) L% o+ B# L' a
  556.                 {4 r: J5 J0 U3 h. J
  557.                         DEBUG("IIC等待接收超时\r\n");1 T6 n: u$ r6 N3 C4 d' _" ^) x* l
  558.                         return IIC_TIMEOUT;                                //超时
    2 ], k  A, I) F( b, N; G
  559.                 }                        , D9 y) `, g7 [- k) L5 ^5 _
  560.                 TimeOutUs --;7 s6 |- i9 g- A8 Q( H7 |0 \
  561.                 Delay_US(1);                                                //延时. z8 S" g" _4 D
  562.         }) J# S7 K  E) A2 u
  563.                 : B1 Q1 V. u, A$ Z
  564.         *pData = pHandle->I2Cx->RXDR;                                                        //读取收到的数据
    5 F. b+ g7 a6 U
  565.         return IIC_OK;
    : q4 R' Z& n; q% D) b
  566. }
    - Y! {: K/ \/ I! b# X5 o) j8 c
  567. + N1 G. v: n, [4 z: n. B, P) F  t+ u5 a+ S
  568. 3 b' l  t) S3 k' H
  569. /*************************************************************************************************************************8 R( m: f* B# W( u. p* T. q
  570. * 函数        :                        IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, # M& X% G9 X/ M
  571.                                                 u8 *pDataBuff, u16 ReadByteNum)8 o) d1 \! u6 X0 {+ N
  572. * 功能        :                        IIC读取寄存器(可以读取1个或者多个寄存器)3 J' b) I, q# j" c0 I. h
  573. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要读取的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;
    1 I0 R7 _' H" w2 k- W
  574.                                                 pDataBuff:接收的字节数据缓冲区;ReadByteNum:要读取的寄存器数量;, C2 Z( P4 z+ O, O7 K/ l
  575. * 返回        :                        IIC_ERROR- a; `  s8 H, N3 h# e
  576. * 依赖        :                        底层宏定义7 ]4 V1 B2 P0 T- {$ Y
  577. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    / L, u! O8 s, {% Z
  578. * 时间        :                        2020-02-15
    3 N5 R/ x, b$ }5 l
  579. * 最后修改时间 :         2020-02-15
    8 q$ b0 j. q7 A' [9 i2 f& w
  580. * 说明        :                         读取的数据都是小端模式,如果是16bit的寄存器,请读取偶数个数据,并且需要另外进行高低字节对调最后组成16bit数据
    2 I5 T: d. B5 y4 S+ ]5 T8 G
  581.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
    ( T# M9 g8 L  w3 B1 w( a- X
  582.                                                 增加信号量4 F9 N: p/ v! A/ _- Q; P8 b! d
  583.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在
    : I9 l" q. q" n% v% U' H% f$ l
  584.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。+ W3 j) v  _3 R/ V
  585. *************************************************************************************************************************/
    - D! c  p: V- Z2 G" t* H
  586. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum)* e, D+ Q: B( L4 x
  587. {
    2 }" \& b$ L, [( j
  588.         IIC_ERROR Error = IIC_OK;6 C" M7 C' A( J3 j( }: ?
  589.         u16 ReadCount;: i. z! P5 f; f. w) p6 K
  590.         IIC_HANDLE *pHandle;
    ( I* Q: a  n# b! d3 u$ w# Q& V
  591.         7 g( l  r4 U- N0 Q" t# w" e+ `
  592.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || ReadByteNum == 0)/ B* ~) r. b/ b% q
  593.         {
    6 n& b: \0 b2 P) K  H8 O4 L- v0 W
  594.                 DEBUG("IIC错误:无效的参数\r\n");
    - e1 f  \9 D9 ?- h
  595.                 return IIC_PARAMETER_ERROR;
    & F+ A/ L) C1 d6 b  M- y1 u. }
  596.         }
    % U) e* s2 z/ ^  _- P3 V$ s
  597.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄( Z( c! j" ?$ E6 q; g  @! E% e: G4 w$ [
  598.         
    # m3 I/ W6 Y5 K/ r! D% s
  599.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙+ N, O' M. L& B8 E. S# ?
  600.         {# n0 ]1 O0 Z0 J- H4 x, ^
  601.                 IIC_SoftReset(pHandle);
    5 U" w1 Z) o; o4 u5 A
  602.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");1 d3 ?' X! I& b, U/ k
  603.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙$ r# j5 V4 }! E
  604.                 {3 Z9 Q' o7 z2 `# q# Q4 S1 \: L
  605.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");
      P$ j/ F' u% e  ^" x
  606.                         Error = IIC_BUSY;
      k/ t% n$ K( ~3 V  _  v& Y1 ^
  607.                         goto end_loop;
    ( w3 Q0 ^& {/ x5 S' y% q1 C
  608.                 }8 h2 E6 V, j+ l( N) C& e! v
  609.         }
    " {( ?9 f' S3 D( i* r/ y
  610.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态* K! J* o/ E0 D/ W3 v( l2 w- F/ @
  611.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器/ T5 j; L$ X) b# `0 Y8 M
  612.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    ' w4 v# l9 ^4 @8 c5 E/ D: ]
  613.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,TRUE, pHandle->TimeOutUs);" Z, g4 F- i1 k; s, M4 y# Z. E, C- m. g
  614.         if(Error != IIC_OK)
    7 P2 W, P; C" ?
  615.         {/ e" u% ~; F. U) p
  616.                 goto end_loop;
    " `% h) b: w7 m; N0 y1 ~
  617.         }
    ' c2 D2 J: Q2 i) a# C9 m6 {
  618.         //发送后续数据
    6 [3 N* Y1 E6 X7 Y1 Z% C, ~% A
  619.         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取-后续还有数据,需要重载
    8 c" w; c; E9 S
  620.         {* x0 ]7 q. Z( t/ ^6 h
  621.                 ReadCount = 255;        //本次需要读取的数据长度255
    ) \8 ^6 F- _4 e- M4 i
  622.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输                7 r" R3 l* F- j: E& W. I+ V+ I" |* N5 l7 T
  623.         }5 l8 ~3 G6 A+ L! c5 @% }& V
  624.         else8 V. d1 \' y2 E3 l
  625.         {" G- y, p: A0 J" a2 Z7 q* P- J" i
  626.                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯后自动结束
    ; \! D; Q# V# G
  627.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输; y" ^7 z# b# T9 p' j+ t7 l
  628.         }# T. |; V5 V9 F2 |, v% z+ r3 G5 o
  629.         
      }$ a( q5 Q" D9 H6 y3 K9 ?
  630.         //循环等待接收数据完成* L6 c, [: d7 f  U
  631.         do
    % C3 `2 k+ `: j# F3 `# S
  632.         {! F0 Y( x+ O: R+ R
  633.                 //uart_printf("读ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    ; ^0 p+ r: w( F
  634.                 Error = IIC_WaitRxOneByte(pHandle, pDataBuff,  pHandle->TimeOutUs);                                        //接收1字节数据% f- I5 @: q  a1 v3 Y
  635.                 if(Error != IIC_OK)6 |7 x+ H8 ]# a
  636.                 {
    9 j' s+ }% s% N' i
  637.                         goto end_loop;% g' r+ \2 |4 L, ~9 |9 v
  638.                 }
    " r1 J# W9 x, v9 }8 A* b6 z; K
  639.         
    . E# j7 l" }0 R& T9 q% ?
  640.                 pDataBuff ++;& F$ p9 r" `( U6 I
  641.                 ReadCount --;- ^3 w8 S- p  f5 J1 d* J! b$ J4 f
  642.                 ReadByteNum --;+ O9 l8 H+ Q. j2 {% @4 w
  643.                 if((ReadByteNum > 0) && (ReadCount == 0))        //还有数据要读取
    , G- f4 O# S7 J- i( a7 {- q1 P
  644.                 {8 ]% p; Y8 @9 P: K5 }0 j9 g) Z
  645.                         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取
    4 H  i$ p+ ^# u1 q% l5 o6 g) C
  646.                         {- |4 y+ _- Y& X+ J6 Y# X' q7 y
  647.                                 ReadCount = 255;        //本次需要读取的数据长度255-后续还有数据,需要重载
    , a/ ]* R9 K3 r" W! X% `
  648.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
    7 J: J7 t' H6 q& W2 X6 {
  649.                         }  U/ {4 N/ h2 ]' n4 k( `0 u  m
  650.                         else
    , L' O( r" ^. \) f
  651.                         {" k  ?* p" [2 n$ Y4 G" n9 Q1 T3 S
  652.                                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯,自动结束* }$ L( T4 E* [: c
  653.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
    ; e3 e' d3 R: g" P- e9 V+ E2 D
  654.                         }
    $ M6 Q/ p1 G8 S
  655.                 }
    8 H1 C* o0 h; s( J7 @& l; U" s3 y
  656.         }while(ReadByteNum);
    3 m6 d& v  X3 n. H6 l9 ?: A
  657.         //读取完成了,等待STOP位有效% Z7 _9 i. m% E( P
  658.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);
    ( ]# H! `5 ]% o9 w3 O
  659.         if(Error != IIC_OK)
    / s& Y- Y. z* G! Q% R
  660.         {
    ( p* f! J% R- \9 i% L: K
  661.                 Error = IIC_STOP_ERROR;
    ! Y8 W% e" Y! d
  662.                 goto end_loop;
    8 ^& b: j6 w6 E2 R
  663.         }        & a! N( S2 w% e5 @
  664.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态4 ]- K9 [( o8 Z0 `# J# I
  665.         
    : A6 t2 {( v9 R8 p
  666. end_loop:        
    5 Q9 |  L' V( S$ ?2 y% c
  667.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        
    - g/ @& m/ i! T4 D! _
  668.         if(Error != IIC_OK)
    . [, L6 l+ L; @5 \
  669.         {1 y" c8 }, L- j9 w
  670.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误2 \* m! n4 R' F" ~- w  }9 d
  671.                 DEBUG("[IIC R错误]:%d\r\n", Error);
    . }! O& u! h$ k1 S- R& f8 N$ k
  672.         }' b1 X" \+ h, o# T9 N; p/ c
  673.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的6 M1 e; P2 L8 y/ j! [, y, Y
  674.         {
    / v, V9 [- g* g5 o5 C
  675.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线3 a5 D! \- ~3 g# `
  676.                 DEBUG("IIC R结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);               
    4 X- ~8 X# W+ `5 `5 m
  677.         }
    / K  \8 V. o3 k: u& A9 e2 V  D
  678.         
    ( f7 @4 u+ @* t/ _% @+ L" d
  679.         return Error;
    % X! {& e. v: V8 N& z1 ^
  680. }
    0 L# H/ p3 T8 M% p' Z! p' _" B
  681. 6 p: @* J; S6 H0 B% h4 l7 |2 f

  682. ; `+ J2 E9 ?9 ]2 [9 d' v
  683. /*************************************************************************************************************************: b* ]/ O  p' S( R6 v
  684. * 函数        :                        IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    , i  |! Q$ R. h, u2 Q
  685.                                                 u8 *pDataBuff, u16 WriteByteNum)% g+ E" e; j4 S2 [
  686. * 功能        :                        IIC写寄存器(可以写1个或者多个寄存器)
    . G0 }  W2 v1 I# x. j6 j2 G3 C9 j1 K
  687. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要写入的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;
    ) n. n4 E' {' f3 L3 C3 p5 B5 K8 u
  688.                                                 pDataBuff:写入的字节数据缓冲区;WriteByteNum:要写入的寄存器数量;
    8 G( `8 Y) [% X- k% `9 V
  689. * 返回        :                        IIC_ERROR! o5 D/ O- q7 t. l2 v
  690. * 依赖        :                        底层宏定义/ o- c; A- c6 T/ z
  691. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>, n3 F: J! [8 N" {# D$ b
  692. * 时间        :                        2020-02-16
    , |' R8 s% h- R
  693. * 最后修改时间 :         2020-02-16
    " m1 @9 ^( p' N' ?7 _+ T4 Z; h0 X8 \
  694. * 说明        :                         写入的数据都是小端模式,如果是16bit的寄存器,请写入偶数个数据,并且需要提前进行高低字节对调最后组成高字节在前的数据buff  c6 @! q$ J5 N6 k* ]  B( m( \
  695.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如) ?# z7 |; H- K8 k: @9 k
  696.                                                 增加信号量
    * p, W9 h" z7 h5 l
  697.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在
    6 I+ F2 o6 e) ^, m% u& T3 j7 d
  698.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。; W* h" [" x. k9 e0 |; V
  699. *************************************************************************************************************************/
    ; C- B/ u/ |0 C* \0 H" v  B
  700. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum)
    8 x+ E9 ~: P3 \# ~. W1 G  v5 o- ?
  701. {
    4 t5 A* r! a9 B+ l* |
  702.         IIC_ERROR Error = IIC_OK;
    % A4 r$ I  m2 z; u- ?2 G
  703.         u16 ReadCount;' z" N2 O$ }! Y% R" Y
  704.         IIC_HANDLE *pHandle;
    ) s' w2 x3 u/ P! i3 p
  705.         / b! a# H6 g( @! y- e! E  n7 \5 B
  706.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || WriteByteNum == 0)! m* C8 u9 G; E3 i2 d0 {4 g1 F% d
  707.         {
    % u" Q, P. i8 ^, F, x; D
  708.                 DEBUG("IIC错误:无效的参数\r\n");' H% Z& M. {. [' R
  709.                 return IIC_PARAMETER_ERROR;
    - p0 A% F+ S% A5 c7 x- ~
  710.         }  w* @8 B6 _' A. C( p
  711.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄
    ! _- T3 ?+ {8 Q% i% `
  712.         
    ' j1 B+ i! P" L
  713.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙
    $ ]8 I. F3 H: y# e) Y
  714.         {
    5 Z  a% p/ T3 b8 t6 r8 R
  715.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");
    5 x6 y: g# }# R) a
  716.                 IIC_SoftReset(pHandle);6 _1 d- e9 \6 g2 _) T* X; r- L0 o
  717.                 - C- ^9 a! i" }9 ^- M) x
  718.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)        //忙. Q; w7 _% Y) l5 H/ n5 X& A
  719.                 {. j1 @7 c: x' J/ V1 R
  720.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");% [; E/ D2 F- ^0 Q5 h
  721.                         Error = IIC_BUSY;$ d  Y! i+ ~2 s# }" a; Z5 Q8 l
  722.                         goto end_loop;7 g( N/ M1 d  _' E0 D3 x! C
  723.                 }! D2 j2 B5 O0 [, Y( D
  724.         }
    : T; K+ e, h+ h; j2 D; c* X) X
  725.         
    6 a" D$ a3 }) P6 T* p4 \  Y8 l
  726.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
      I+ U  s( W( w- `# Y! b
  727.         IIC_ClearCR2(pHandle);                                                //复位CR2寄存器
    ( h! Z8 z9 ]! A# n  w% P  s" s) O; c
  728.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    * l/ C/ O7 i% A' c, ^8 H
  729.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,FALSE,  pHandle->TimeOutUs);
    ) D/ h& j* c1 N  {
  730.         if(Error != IIC_OK)
    / ^: J! n  A2 M; w. Z; @4 F
  731.         {
    3 I# B& t  B# v
  732.                 goto end_loop;, |/ [+ a$ G* S2 I0 p1 X2 ^& T
  733.         }
    4 p! u1 ~, m) l3 w1 @! g
  734.         //发送后续数据" C: ~# _& H3 t+ n0 F- c  ?
  735.         if(WriteByteNum > 255)                        //如果超过255字节,则需要分多次写入-后续还有数据,需要重载  W9 m3 r- X$ r: t2 g
  736.         {
      B; F8 F. D$ q
  737.                 ReadCount = 255;                        //本次需要写入的数据长度255
    ! d5 G0 j( [1 v0 `5 _7 R& }8 C
  738.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入                8 ^* |/ a/ c( w. I
  739.         }2 ?3 ^2 N' p4 G2 q  f. l
  740.         else
    8 g& f3 F7 ]6 N/ h* s5 G- ^9 ?; l, K
  741.         {
      w/ H% E# Q1 |- u( |3 z4 b
  742.                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯后自动结束
    + I0 C  Y6 N6 l  F, a
  743.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入" ^7 ~6 X2 U2 ?. k- e
  744.         }/ O) x! }: u  L4 H' v; d' f# w
  745. 1 e: n5 A/ z4 i
  746.         //循环发送数据" V! _( E; C1 \; b. a( b" |' ^
  747.         do6 i' [7 ]0 S* z: G9 W
  748.         {
    0 o, a/ f: T* G: R( r9 a
  749.                 Error = IIC_SendByte(pHandle, *pDataBuff, pHandle->TimeOutUs);        //发送一字节 ! f; r" `" Z9 N. M
  750.                 if(Error != IIC_OK)
    6 B7 n1 Q2 f$ ?
  751.                 {. p' i4 H9 f/ u4 g! J( }
  752.                         goto end_loop;2 f. Z: B, S8 `* E7 e, f5 y, ~$ B8 @
  753.                 }; h( L; O" b# j' \6 b

  754. 4 T$ v) N; e+ D4 i, x
  755.                 ReadCount --;
    + V) z) \( z/ q/ v  m3 t
  756.                 WriteByteNum --;
    3 b$ u# |7 B6 D: Y# ?- k6 U
  757.                 pDataBuff ++;
    1 T  I: |0 {9 t' ^: F$ E
  758.                
    3 m  T$ B3 ^& [/ S. N! r4 ?. Y
  759.                 if((WriteByteNum > 0) && (ReadCount == 0))        //还有数据要读取& f, J/ S+ h; g& B
  760.                 {
    / j0 n+ b& y4 a
  761.                         if(WriteByteNum > 255)        //如果超过255字节,则需要分多次读取
    # d& p" g, v6 }4 D2 y* B
  762.                         {; |9 U; D3 X' y# K3 a* ^1 w- Y4 ?
  763.                                 ReadCount = 255;        //本次需要写入的数据长度255-后续还有数据,需要重载" f' y7 j+ y. U5 [2 n4 W# ?9 n5 ^
  764.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入
    - Q+ |: \: G, d% Z! G! w
  765.                         }4 a+ H0 ?; [0 w: Q3 D6 g' Y: W
  766.                         else
    7 ~/ L9 o- E9 J; T
  767.                         {
    ! o; a- u9 m0 R5 V
  768.                                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯,自动结束* }5 t' i% P2 d$ C$ X0 U
  769.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入                7 |) K& K; h0 a6 `# S1 d' S% V
  770.                         }- G7 }! I) E& m
  771.                 }3 q; P  U% S" p' L" G
  772.         }while(WriteByteNum);        ) w" J! c+ d- i% C, Z% c
  773. . o, @9 f7 w( T% Z) v
  774.         //写入完成了,等待STOP位有效
    ' v) D# M, S3 N* l8 W
  775.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);* W0 R$ P# |4 C! F  }
  776.         if(Error != IIC_OK) ) N8 q7 f  J9 A2 |
  777.         {
    6 B# X; F3 o: ]7 m+ r
  778.                 Error = IIC_STOP_ERROR;( m: R' _/ V8 t. ^- J9 Y9 `6 Z( a
  779.                 goto end_loop;
    % c/ ?4 Q: o) S2 u
  780.         }: c1 Y- J6 d9 o! `. `6 E
  781.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态8 [2 v4 n$ e2 W; ~' v8 o! s/ ^
  782.         
    & H. [9 P3 W! \( A9 |
  783. end_loop:        
    3 R  |5 n: p& q: `' Z6 e/ _
  784.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        & @6 l  b, z0 m, F4 q9 z9 \, i8 P
  785.         if(Error != IIC_OK)
    4 a) z" B0 i5 x! l# G' @
  786.         {
    ) s7 z  _5 |0 }5 }
  787.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误/ @! O6 R( Y; n1 G- B0 O: y
  788.                 DEBUG("[IIC W错误]:%d\r\n", Error);. X; m6 F+ r, k, e5 F0 Q& i/ _
  789.         }1 e: [5 K0 u! U
  790.           U9 t6 C3 Y% b
  791.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的1 L$ O" [. ^3 F+ K) ~  w8 T7 ~
  792.         {, m( ]4 N, M( R. K5 Z# t/ K8 \9 O
  793.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    ! I2 k- @% h6 q: V- E% f  C3 d
  794.                 DEBUG("IIC W结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);               
    3 Q  @: E1 L$ x
  795.         }/ f9 S+ f5 S$ \6 {1 g0 a
  796.         return Error;
    " Y/ b0 S% Q6 L* I- ?
  797. }0 K, m0 z9 I1 w4 q3 L
  798. - G0 _* m+ H" e9 |6 V1 W4 f
  799. 4 T; u- X7 S( R3 t% t
  800. /*************************************************************************************************************************( Z/ `& l+ M& {) h
  801. * 函数                        :        void IIC_SoftReset(IIC_HANDLE *pHandle)
    3 l2 Y& k7 o$ Y$ G( K- e8 D! E
  802. * 功能                        :        硬件IIC软复位(会使能IIC)3 ~5 s, o  P, b+ x
  803. * 参数                        :        ch:IIC通道
    / Z- K# p" C2 m5 G2 a; u
  804. * 返回                        :        IIC_ERROR
    ; D2 `5 P2 ?% |
  805. * 依赖                        :        底层宏定义
    4 M: o4 ^- q4 r( J" u, W
  806. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    # F5 D  @+ D1 o! h9 m
  807. * 时间                        :        2020-02-15+ N$ W" u) s$ B: b/ ?# D" c
  808. * 最后修改时间         :         2020-02-152 U, E* y* r6 _$ |5 L
  809. * 说明                        :         IIC软复位;必须使 PE 保持低电平持续至少 3 个 APB 时钟周期,才能成功执行软件复位。9 j7 k; S, E8 V% \) p% h
  810. *************************************************************************************************************************/
    * r" D) z5 v  {- O% m2 [% y
  811. static void IIC_SoftReset(IIC_HANDLE *pHandle)% d4 N: ^, c8 U* w
  812. {
    $ o; n+ D; D0 H/ }
  813.         pHandle->I2Cx->CR1 &= ~BIT0;                //关闭IIC后执行软复位
    ) @4 d( q# S3 _1 }0 S
  814.         Delay_US(1);        + k. Y+ \7 Z+ K) b' S" P
  815.         if(pHandle->I2Cx->CR1 & BIT0)
    " j' {0 J% L; W" E
  816.         {
    + _7 h- u, S; A0 P+ {( r& A# W
  817.                 DEBUG("IIC软复位失败\r\n");
    8 |6 b" S  o; i/ L3 Z4 ]
  818.         }
    2 \& V2 A& ~8 o, h5 o+ S# X
  819.         pHandle->I2Cx->CR1 |= BIT0;                        //重新启动( w: D$ I: j1 Z" p  `5 ]
  820.         Delay_US(1);        + H; N. G: l1 `& y  o. C7 P& L3 {
  821. }0 Z' Z& I# I7 j0 j
  822. & O9 T" k4 r- O
  823. ( r7 l9 i0 Q5 r% c, j2 Z2 [; J, h) F

  824. 5 ?$ L! l: U; F, N
  825. /*************************************************************************************************************************
    % F3 ]( C. D1 y
  826. * 函数                        :        static u32 IIC_CalculationTiming(u16 Speed_KHz)( W# A: v, q" B, `# ?
  827. * 功能                        :        硬件IIC时序计算! p7 s4 B6 z0 R2 \9 J: t
  828. * 参数                        :        ch:IIC通道;Speed_KHz:速度10-1000" c) @  h9 y! k* ?& a& D
  829. * 返回                        :        IIC_ERROR9 K# e- v/ B& \' G: N2 s' w
  830. * 依赖                        :        底层宏定义" g& j. K& h3 C2 }6 C9 |
  831. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    3 r) k! P  J3 |- U- c
  832. * 时间                        :        2020-02-15$ B- v5 f2 Y, w8 A5 a" [
  833. * 最后修改时间         :         2020-02-15
    0 e& \5 P1 ^' _, ~5 Z, u+ F1 n, Z0 e
  834. * 说明                        :         IIC使用的是APB1时钟,将IIC总线时钟控制在100KHz        & t4 V- p% L3 g* S" M
  835.                                         APB1时钟:最大不能超过45MHz        
    ; s* i. z% g5 B2 Q( B
  836.                                         如果速度是100,则按照SMBUS时序1 I8 L  A+ L( E* G" q) P" z6 v! T+ A
  837. *************************************************************************************************************************/2 l8 J# L3 E5 \  n
  838. static u32 IIC_CalculationTiming(u16 Speed_KHz)
      n% G3 C: ~* E5 H5 n0 q1 k( I
  839. {0 s* ~' r7 P/ u, K
  840.         u32 tTime = 0;5 B3 o) a; z7 _/ j( w9 P
  841.         u32 temp;1 C& x4 C* n  E: R, W, j7 h& u
  842.         u32 time_temp = SYS_GetAPB1ClockSpeed() / 1000000;                //先获取APB1时钟速度
    % c* `3 d. D. o+ O8 V7 Q
  843.         u32 Th = 1000/Speed_KHz/2;                                                                //计算高电平时间(低电平时间一样),单位ns2 y0 R5 J5 N1 @, m: W, j. @
  844.         5 y& H! Y+ l. O8 |: ?! a
  845.         if(time_temp < 20) time_temp = 20;* f$ d) x7 ?* n5 N
  846.         time_temp = 1*1000 / time_temp;                                                        //单位ns' D# f+ C3 ~# q5 J% p/ D# e/ J5 C
  847.         uart_printf("IIC时钟计算->APB1周期:%dns\t", time_temp);
    % c0 T. Y' S7 V$ S; u
  848.         if(Speed_KHz == 100)        //如果是100,则按照SMBUS时序8 Q* i) M% M- `3 q
  849.         {
    % h9 `8 P% F$ g$ A3 ~( h
  850.                 //主时钟分频系数固定为3
    4 t( S" P* k2 s0 Q8 D  y  c
  851.                 time_temp *= 3;                        //主时钟周期
    5 G/ r4 ~( a1 B4 v$ `; x* E
  852.                 uart_printf("IIC时钟周期:%dns\t", time_temp);- m4 B4 y1 [) G. a& k( ?5 U
  853.                 tTime |= (3-1) << 28;        //PRESC,时钟预分配
    3 h& ]: T% o3 N" V
  854.                 //计算数据建立时间,要求最小250ns
    7 }4 }3 w7 i7 [9 Q9 l
  855.                 temp = 250 / time_temp;7 x$ G. }8 N  r  M6 x5 v: [$ t
  856.                 if(temp > 15) temp = 15;
    / u: ^6 ^# L- `/ U7 V% u
  857.                 if(temp < 1) temp = 1;6 c  }: V: c0 ~2 q0 O# M" I* f
  858.                 tTime |= temp << 20;$ Y2 G. Q9 D( ^: [
  859.                 //计算数据保持时间,要求至少300ns
    1 t7 q0 \. f5 l* T7 U) S& v2 G
  860.                 temp = 300 / time_temp;
    ' q% m+ U3 P4 K+ e
  861.                 if(temp > 15) temp = 15;9 F; z. A, z- C* W
  862.                 if(temp < 1) temp = 1;( A9 f- B7 G" x' y
  863.                 tTime |= temp << 16;
    : d  i: O: l4 ]4 I
  864.                 //计算高电平周期5us: {7 y% b2 ?" O3 }& f5 \
  865.                 temp = 5*1000 / time_temp;9 N3 A4 M: U. n- K
  866.                 if(temp > 255) temp = 255;/ _$ w9 P! R6 y; Q6 u2 p3 a( j- h% N
  867.                 if(temp < 1) temp = 1;
    % ^2 e/ v; q( w# i
  868.                 tTime |= temp << 8;2 w/ P8 r! H" L/ p! @
  869.                 //计算低电平周期5us$ C0 M& O! B6 H
  870.                 temp = 5*1000 / time_temp;
    6 |0 P) V0 l0 }
  871.                 if(temp > 255) temp = 255;- b3 z3 Y/ L" c
  872.                 if(temp < 1) temp = 1;8 S$ _5 |- @5 G6 ?
  873.                 tTime |= temp << 0;; G$ `9 G( ]. _% Y1 X% C$ G
  874.         }. x0 ]& g1 j& y. O+ k9 d3 i4 t2 X
  875.         else if(Speed_KHz < 100)3 n/ @, d' P, W. I) Z
  876.         {
    - b- {$ L/ O/ }5 w& p$ W- D
  877.                 //主时钟分频系数固定为6
    , k+ V& {3 c5 M  }% d. g/ {
  878.                 time_temp *= 6;                        //主时钟周期- i& O, Q8 W$ h
  879.                 uart_printf("IIC时钟周期:%dns\t", time_temp);* a0 h) M: s0 s$ s
  880.                 tTime |= (6-1) << 28;        //PRESC,时钟预分配
    , w: S% H4 Z% J  F7 F9 p0 a
  881.                 //计算数据建立时间,要求最小250ns
    , Y; h& P9 }+ d3 u- d/ X0 j
  882.                 temp = 250 / time_temp;9 y1 R5 h. K4 o# y
  883.                 if(temp > 15) temp = 15;' P2 J% q! a& R" l
  884.                 tTime |= temp << 20;
    $ }- ]' |( i# k$ Z
  885.                 //计算数据保持时间,要求至少300ns5 y$ `6 Z* i8 l4 ~
  886.                 temp = 300 / time_temp;. ?2 @( W- ~" Y, b8 s  @. l3 l
  887.                 if(temp > 15) temp = 15;
    ! N" Q- V6 m& a/ X
  888.                 tTime |= temp << 16;
    4 n; x9 V5 D; {
  889.                 //计算高电平周期Th us
    ) \/ Q, T4 ~% c& Z: h2 c! V: i4 {
  890.                 temp = Th*1000 / time_temp;
    " w. n, E7 @: y& K$ s; b
  891.                 if(temp > 255) temp = 255;3 b1 q( ~4 G8 P4 [
  892.                 if(temp < 1) temp = 1;
    7 T5 l3 `& H3 U- K" s4 M$ Q* E& W! I
  893.                 tTime |= temp << 8;
    3 y4 q. h% y8 p# h3 ^# e
  894.                 //计算低电平周期 Th us
    3 @9 }* {, w& ~2 A$ ^5 S2 p
  895.                 temp = Th*1000 / time_temp;
    5 X9 X& }0 L) W  s- V& W' x
  896.                 if(temp > 255) temp = 255;& b; i& _' f5 j% A% m# A
  897.                 if(temp < 1) temp = 1;
    4 o, D4 W# a5 B4 {: j" }$ ^6 q
  898.                 tTime |= temp << 0;% u9 D: }# u* U+ O8 B9 Z5 E
  899.         }
    7 ^- z" Z7 D0 y7 }
  900.         else //>1001 w7 |. K. K4 @% W* j0 p* R
  901.         {
    3 `! u) A  ?- |  l/ [
  902.                 //主时钟分频系数固定为2( G- `: t  `" y8 o* {5 {4 P
  903.                 time_temp *= 2;                        //主时钟周期
    + ~* d' L; c6 e8 C6 c
  904.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    3 b; ~/ r9 V. U2 D; B$ J! i  ]
  905.                 tTime |= (2-1) << 28;        //PRESC,时钟预分配
    & x& |! c# }( p8 s+ [: \4 ~' G
  906.                 //计算数据建立时间,随便给100ns: ], w2 o! z# b2 k
  907.                 temp = 100 / time_temp;" Q' l  h  ]: q5 ~. L* P6 n
  908.                 if(temp > 15) temp = 15;
    * P+ o4 h; l; t! p6 M
  909.                 tTime |= temp << 20;
    ) o. ?! t: y0 w
  910.                 //计算数据保持时间,给100ns
    * ~, ]: k) H) C! U& I9 |5 N
  911.                 temp = 100 / time_temp;9 G3 O$ z1 D8 A: f2 @
  912.                 if(temp > 15) temp = 15;$ ^! \; P0 {, s: ]
  913.                 tTime |= temp << 16;
    * Z1 v6 N" e; b1 }$ ~5 k
  914.                 //计算高电平周期Th us
    % Y5 s& m* H$ @1 j  K- N% j
  915.                 temp = Th*1000 / time_temp;( ~- i3 c; w; d- j3 \0 @
  916.                 if(temp > 255) temp = 255;- ?# X5 V- ?+ {* ^& e
  917.                 if(temp < 1) temp = 1;
    , q2 k. Q9 F, S5 ^# m- E5 f% ^
  918.                 tTime |= temp << 8;7 G* p) e4 i! F: ]6 ]! |
  919.                 //计算低电平周期 Th us" G% d4 N, J. D3 c! f
  920.                 temp = Th*1000 / time_temp;
    # u1 @( R- E4 h) w. c+ I9 h
  921.                 if(temp > 255) temp = 255;
    & |; e" s% Y2 u% t) f, ^: w
  922.                 if(temp < 1) temp = 1;
    . D: c! i6 i) I# [# q! U8 S
  923.                 tTime |= temp << 0;
    6 K* P3 i6 K* N8 ^8 {
  924.         }
    & |' k, B: }: C9 T8 j; O* Y$ z
  925.         
    ( ?9 J7 U2 q' x$ o' c: N/ j1 t
  926.         uart_printf("时序寄存器结果为:0x%X\r\n", tTime);
    % ?4 z3 i* i8 y9 Y% B9 N
  927.         2 u; p+ g! b* y1 j" M. ^
  928.         return tTime;
    ; p/ u2 z) X* E5 s1 q) w
  929. }
复制代码

" ^' w- G. R" ]+ v* I) E6 o" i# @: }- K) W6 }& z5 V# E( p
  1. /*************************************************************************************************************
      w1 a$ L" o2 `* v3 p
  2. * 文件名                :        stm32f7_iic.h& n" u4 e8 T; G4 Y' |6 @; _6 ^
  3. * 功能                        :        STM32F7 IIC接口驱动
    $ d' R/ u: A3 J2 `
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    * I2 L; t- P$ t* l
  5. * 创建时间                :        2020-02-09
      y$ @+ ]! K/ h% Q6 }4 x
  6. * 最后修改时间        :        2020-02-09
    # {$ ?- U7 h( U! n$ S1 e
  7. * 详细:                        
    # u$ @3 K5 _! R% W5 H: }/ H
  8. *************************************************************************************************************/                1 ?$ l7 A- q; U" m9 Z) O
  9. #ifndef __STM32F7_IIC_H_
    $ ]# H* n( T+ A' }5 {1 S0 ~) ^
  10. #define __STM32F7_IIC_H_* _, U1 s# ~- @6 e' h& I- f
  11. #include "system.h"
    + ]/ [# J* d/ C: c$ Q  Y
  12. ' X; o! s# C+ U3 {8 u) b2 E
  13. //16位整形数高低对调
    $ B8 \( T" B/ k# A" u$ L# Q* z
  14. #ifndef SWAP16
    ) p7 N5 V8 g0 V( N  I/ F
  15. #define SWAP16(x)   (((x & 0xff00) >> 8) | ((x & 0xff) << 8)). B' j; Q: F, D  g* ^/ k" E7 X0 Y
  16. #endif  //SWAP165 b/ J' ?; F0 H6 M
  17. 5 P* S' y- [) B9 Q3 b
  18. //硬件IO口选择8 S/ |/ v. J/ B, W) {2 }- C
  19. //I2C1 IO定义与选择
    4 R$ u! e4 ]9 K5 G
  20. #define IIC_CH1_PB6_7                                0                                        //PB6,PB70 w; R3 E6 `. r7 i& O3 q: r/ j
  21. #define IIC_CH1_PB8_9                                1                                        //PB8,PB90 U" w* A3 k$ {5 n5 U" m
  22. #define IIC_CH1_IO_SELECT                        IIC_CH1_PB6_7                //选择I2C1 的IO        * B4 w0 m4 }* s- N2 H' S# @" ?

  23. + a; @( \$ I* j% W! H# h5 f& k4 m
  24. //I2C2 IO定义与选择
    $ g+ C  W, C1 Z4 R: H! N* N! o. m, b
  25. #define IIC_CH2_PB10_11                                0                                        //PB10,PB11$ ~& c; K6 U$ `. z
  26. #define IIC_CH2_PF0_1                                1                                        //PF0,PF1
    8 ?8 E4 B# Q, z: i- Q8 A" q% e
  27. #define IIC_CH2_PH4_5                                2                                        //PH4,PH5
    , ~- D7 W3 H' J& G! _0 L1 V
  28. #define IIC_CH2_IO_SELECT                        IIC_CH2_PB10_11                //选择I2C2 的IO$ `( o2 f% c3 A9 o) S% ]# w- N% F

  29. " g( s! d, b; P2 U/ R1 i' Q
  30. //I2C3 IO定义与选择: c: C/ h: Z: w% [
  31. #define IIC_CH3_PH7_8                                0                                        //PH7,PH8
    , d- j/ }) ^- a* u  w: a+ V2 ?; E
  32. #define IIC_CH3_PA8_PC9                                1                                        //PA8,PC9$ Y* Z! q2 f. y. y
  33. #define IIC_CH3_IO_SELECT                        IIC_CH3_PH7_8                //选择I2C3 的IO' W( k& R5 F4 c- h
  34. 1 Y; g; Q9 C! M7 _0 p
  35. //I2C4 IO定义与选择( U1 W, w, o) B# ]* }
  36. #define IIC_CH4_PD12_13                                0                                        //PD12,PD13( u0 i0 d( T9 H& M
  37. #define IIC_CH4_PF14_15                                1                                        //PF14,PF15
    5 h! N$ H8 U* n# T2 W5 Q+ ^4 ^/ T/ I
  38. #define IIC_CH4_PH11_12                                2                                        //PH11,PH12
    ( ^/ ^4 ]) e) Y, ^
  39. #define IIC_CH4_IO_SELECT                        IIC_CH4_PD12_13                //选择I2C4 的IO+ _, I  d/ s* ^6 x/ L+ p, V
  40. : ~+ D/ U: i/ O7 ?! T6 E
  41. //IIC硬件接口选择/ b  s6 ]% E1 _8 m( \
  42. typedef enum
    + E/ X  y: _2 R: g: R4 \. r; T2 S
  43. {
    . P% Q3 W6 q' p; y4 y# N& Y
  44.         IIC_CH1        =                0,        //IIC1
    4 w9 ^4 b' K2 L4 W
  45.         IIC_CH2        =                1,        //IIC2- m9 g, a1 G" K( |& i
  46.         IIC_CH3        =                2,        //IIC3
    8 U+ g! T: o- M+ Z; h8 S7 X  ~
  47.         IIC_CH4        =                3,        //IIC4. F. x& ^" F, W% D1 V* [
  48. }IIC_CH_Type;
    , b1 v- w8 o! g8 D4 o2 j
  49. #define IIC_CH_COUNT        4        //4个IIC6 e4 Y/ N% s/ E- |$ E

  50. : r9 i: T  q, X: d' B0 `
  51. 4 |1 U: l) _4 }! n! a
  52. //中断状态9 ~- o& @, u- N: u/ @
  53. #define IIC_FLAG_TXE                    BIT0        //发送数据寄存器为空(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。( H% ^: A5 |6 o6 |. n
  54. #define IIC_FLAG_TXIS                   BIT1        //发送中断状态(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1,待发送的数据必须写入 I2C_TXDR 寄存器。
    . ^% m9 `3 I6 k/ A& H
  55. #define IIC_FLAG_RXNE                   BIT2        //接收数据寄存器不为空(接收器); 当接收到的数据已复制到 I2C_RXDR 寄存器且准备就绪可供读取时,该位由硬件置 1。读取I2C_RXDR 时,将清零该位。
    / M) z! g  B2 {$ m0 [. T1 f
  56. #define IIC_FLAG_ADDR                   BIT3        //地址匹配(从模式); 接收到的地址与使能的从设备地址之一匹配时,该位由硬件置 1。该位由软件清零,方法是将ADDRCF 位置 1。
    + R$ `, d" i' }. l
  57. #define IIC_FLAG_NACKF                  BIT4        //接收到否定应答标志; 传输完字节后接收到 NACK 时,该标志由硬件置 1。该标志由软件清零,方法是将 NACKCF位置 1。; _# B( h  {+ F4 ^9 k
  58. #define IIC_FLAG_STOPF                  BIT5        //停止位检测标志; 当在总线上检测到停止位,且外设也参与本次传输时,该标志由硬件置 1( x" [& H6 r( }
  59. #define IIC_FLAG_TC                     BIT6        //传输完成(主模式); 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 START位或 STOP 位置 1 时,该标志由软件清零。
    # {1 r9 l- x( a0 U
  60. #define IIC_FLAG_TCR                    BIT7        //传输完成等待重载; 当 RELOAD=1 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 NBYTES 写入一个非零值时,该标志由软件清零。. n/ k0 I, V( [9 z& ^8 l+ k1 z
  61. #define IIC_FLAG_BERR                   BIT8        //总线错误; 当检测到错位的起始位或停止位,而外设也参与传输时,该标志由硬件置 1。在从模式下的地址阶段,该标志不会置 1。该标志由软件清零,方法是将 BERRCF 位置 1。4 K' n; X7 _' n+ t, C
  62. #define IIC_FLAG_ARLO                   BIT9        //仲裁丢失; 发生仲裁丢失时,该标志由硬件置 1。该标志由软件清零,方法是将 ARLOCF 位置 1。
    3 f7 E" O' R7 j- ]
  63. #define IIC_FLAG_OVR                    BIT10        //上溢/下溢(从模式); 在从模式下且 NOSTRETCH=1 时,如果发生上溢/下溢错误,该标志由硬件置 1。该标志由软件清零,方法是将 OVRCF 位置 1。
    ! o! n8 I$ J' q0 e" e* X% X) Y
  64. #define IIC_FLAG_PECERR                 BIT11        //接收期间的 PEC 错误; 当接收到的 PEC 与 PEC 寄存器的内容不匹配时,该标志由硬件置 1。接收到错误的 PEC 后,将自动发送 NACK。该标志由软件清零,方法是将 PECCF 位置 1。' n9 _' s( z. |# H5 }6 G$ ^" H  Q3 \
  65. #define IIC_FLAG_TIMEOUT                BIT12        //超时或 tLOW 检测标志; 发生超时或延长时钟超时时,该标志由硬件置 1。该位由软件清零,方法是将 TIMEOUTCF 位置 1。7 u2 x) |& n8 J$ k
  66. #define IIC_FLAG_ALERT                  BIT13        //SMBus 报警; 当 SMBHEN=1(SMBus 主机配置)、ALERTEN=1 且在 SMBA 引脚上检测到 SMBALERT 事件(下降沿)时,该标志由硬件置 1。该位由软件清零,方法是将 ALERTCF 位置 1。$ o  v1 W$ Q$ c7 Z: P& o, ]* _. R
  67. #define IIC_FLAG_BUSY                   BIT15        //总线繁忙; 该标志用于指示总线上正在进行通信。当检测到起始位时,该位由硬件置 1。当检测到停止位或 PE = 0 时,该位由硬件清零。& {* {8 H6 E' W3 v* F
  68. #define IIC_FLAG_DIR                    BIT16        //传输方向(从模式); 该标志在发生地址匹配事件时 (ADDR=1) 更新。;0:写;1:读- O4 ?3 b; G8 w9 O
  69. / z, S1 x: {9 h  }) Z
  70. //通讯错误状态
    + _3 W5 R' k% h4 c$ K/ I5 }; Y
  71. typedef enum! R% s1 k3 L" j
  72. {2 H6 O; r- b+ M4 _( |) G9 }
  73.         IIC_OK                                        =        0,        //没有错误- B  O' b1 [% w& z' c$ ^; J/ a
  74.         IIC_PARAMETER_ERROR                =        1,        //参数错误( n: q; D% J" w- s8 s; ]$ I
  75.         IIC_TIMEOUT                                =        2,        //超时错误,也可能是底层错误+ d9 A: ?, ~9 {' d
  76.         IIC_HAL_ERROR                        =        3,        //底层错误0 L& i) u  P$ o* Z4 k2 D- l# `% [' g
  77.         IIC_STOP_ERROR                        =        4,        //等待结束错误7 N, Q2 P8 _, ?
  78.         IIC_BUSY                                =        5,        //硬件忙5 Z- B1 N8 J5 n3 ]
  79.         IIC_NACK                                =        6,        //收到NACK了9 U: d  q9 d- |8 U* x* G5 @. B
  80. }IIC_ERROR;
    ; f6 x4 C1 z/ K! B
  81. ( [: B# Q2 g; {+ \- H/ G

  82. 0 v8 G# H. I1 ?2 E5 |6 ]3 m# p3 `1 ^: U
  83. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs);        //硬件IIC初始化
    % O. l+ w8 W% h7 ]5 _# u8 k
  84. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum);        //IIC读取寄存器(可以读取1个或者多个寄存器)8 u  \" F0 u( z
  85. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum);        //IIC写寄存器(可以写1个或者多个寄存器)8 \; [  a. W# k* a% G% B3 i
  86. 2 g+ R1 X/ `( K$ q
  87. & X( t: l. Z6 M) h' U! f
  88. #endif //__STM32F7_IIC_H_
复制代码
! H/ z+ `$ M1 C2 d& ]& ~' Y  _
% l3 P+ b+ H0 j: O$ L. S7 c
//初始化4 f# b  d, `( G5 _
* D+ g+ h1 y: F4 r  O/ r4 ?* E
  1. IIC_Init(IIC_CH3, 200, 0);        //硬件IIC初始化
复制代码

' r$ K  ]" D* I6 W1 p. R5 t. I$ Y, e- F$ b$ t9 z( ?. l: T1 |# f; L
//调用; Q3 D4 j$ t3 D4 s0 Y# @* W/ s. n

  1. 7 g9 R0 \7 \( Y6 V- X" P% e, C
  2. //触摸屏IIC读取寄存器接口
    ; [' G6 |$ x" S, ^/ x
  3. bool TP_FT5336_IIC_ReadReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)
    . |9 S1 Q0 h9 h$ y
  4. {4 }- @1 d, T1 X' r
  5.         if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)
    1 J) u* C1 |# e7 a# H6 {9 w
  6.         {! y0 c1 H& w/ E" F" U1 C
  7.                 return TRUE;
    : H8 w5 e+ c4 `1 Q; N
  8.         }2 }9 g9 p7 s4 A7 s1 D# c4 r
  9.         else1 Q( O' T, a/ d9 H& p. }
  10.         {
    / G  f3 z6 _; f
  11.                 return FALSE;
    ! _0 C7 o, [7 h- q( G& [4 M6 f) K5 M/ \
  12.         }
    - `1 ]: c; @" F" v3 O; E: J
  13. }
    5 D" z' N$ h: o+ b! a2 z1 D6 R6 a* A

  14. . H! N% }$ j- @& P; e
  15. //触摸屏IIC写寄存器接口
    $ E# x, `' D5 A" H1 w
  16. bool TP_FT5336_IIC_WriteReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)9 d* a! _7 I! X+ U
  17. {
    ' \& P0 U* H) N5 C6 F  y9 e- f
  18.         if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)
    % e' t  i7 [3 l) M5 d6 x
  19.         {6 `* c/ x, N$ C; p& T/ z' H
  20.                 return TRUE;. g0 Q* z& z% i% p6 \: V$ p6 P. D
  21.         }: E# Y) U/ N$ q" ^4 h
  22.         else
    ) C+ g, A# G% u2 n( V7 y3 [/ G
  23.         {! v* ^- ^; `$ E5 m$ f3 b
  24.                 return FALSE;
    4 j8 g4 U/ B, U
  25.         }
    4 r9 X8 t0 X9 B0 N: N  h" c- i+ S! ?

  26. . F1 w- E+ ]. C. p8 [9 I' L  b
复制代码
7 r" k7 K' G8 Q1 l* W% Y
' z( R% H9 {9 G% s2 z2 N3 P

1 I* J5 g0 }: }8 {! {! _" [8 N
赞 收藏 评论0 发布时间:2021-12-11 12:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

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