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

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

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

1 p  S' R( E" X: J9 _  p4 E目前已经做了完善的错误处理,读写操作前都会清除中断,遇到错误会软复位,所有位置均做了超时处理,防止程序卡死,目前只测试了几个字节的读写,大量的,长时间的读写均表现稳定,目前手上开发板没有eeprom,无法做大数据的连续读写,如果你在使用过程中遇到问题,欢迎指正。
0 y. D$ x4 @5 k, ~. m3 w* L  l: o
/ }5 ]" L) @- ^: b) `* x  R下面是IIC读写的时序例子,可以先熟悉一下,这样比较容易上手,哪一个环节出了问题也要调试。7 d+ q) R8 z( q0 M

1 p7 T, a  `9 r
20200216194202434.png
4 _( i+ a+ r. k+ a' A
4 U3 f& a7 ]  h% H7 ~% ]7 {% r
20200216194219185.png

% v& [" `7 F) F- k& ~, O3 l  d. `- V. }% d5 H! c  A
20200216194234908.png

' g+ L) }7 n5 V7 L
  ]/ p. {, b* `1 Q3 i2 R) }9 B* W5 [$ ~7 V) i
下面简要说明一下STM32F7硬件IIC的驱动设计方式(建议先百度学习一下IIC的时序要求):) l' `* A2 X( D5 x! b1 P8 K" O. e
' C3 Z- P9 T7 ?+ r1 D9 _
[基本的初始化]
# r8 G* j, s# x- ?5 y
9 ^! e; f# X2 g* h$ X+ E5 e1.初始化IIC时钟,IO(IIC IO必须设置为复用开漏输出,这个很重要)。
; T# R9 w9 i5 P4 Y2 o' H& T9 \8 X
+ b7 a% q/ R( O' c  V6 K2.CR1先赋值为0,复位IIC.
2 j9 z0 f- j/ T# @- b5 R# e5 m* p; _: D( L  M5 J
3.除了TIMINGR寄存器需要自己计算设置好,其余寄存器全部复位为0/ Z$ {2 M4 ]3 W
7 p7 P/ ~2 W6 @/ ^7 C; i& t. e
4.设置CR1使能IIC。
) I+ k& z' q* V. c7 [) M  ]
- \) B! S* P4 i& j# p" b. `3 D注意:上面说到,IIC的IO必须初始化为复用开漏输出,我之前初始化为复用推挽输出,测试很久,只要一启动传输,就会立马收到NACK,然后是STOP中断,数据根本没法发送,弄了好久才发现是这个IO初始化的问题。
9 D9 l9 z7 ~6 j( _( W* b8 U4 x( J
$ N- x; h; @" g4 c& \5 x7 _- Y
/ m% h0 w9 U, Q1 o7 t, j
# b6 e; z8 x: x4 x: i6 o[读取]9 c4 _9 u1 {4 z6 V- R5 ]$ \( x

# k; Y' i) Z9 l  b) z1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。) b" {. z1 {2 r4 a' ~4 o1 o

5 _) y. Y! G- V2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)软件STOP,写模式,启动传输。! u9 l( x; a, `- I1 ]" R

* W8 g" B3 S) C8 V* C3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
0 O/ `- `! I* p! v
. B' }* s% @* L; u! A: Z) ]" _5 k% S4.等待TC置位,意味着上面的1-2字节的寄存器地址以及写完成了。& T  E+ X1 P6 o, p% S0 @% }2 L; k+ j% a
4 H' K1 u/ N& Y( q
5.根据要读取的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。5 k; U, ?& ^0 W/ ~
- Q# x4 o: s2 I2 R& n
6.设置了从机地址,要读取的数据长度,之后设置方向为读取,然后启动START(从写切换到读要重新发送START,这个跟软件模拟是一模一样的)。4 f# C# f3 b' i# h! A8 K9 g

  u9 R/ X) [8 e* l! P6 u7.循环一个字节一个字节的读取数据,字节读取需要等待RXNE有效,只有读取RXDN寄存器,直到所有数据读取完成。
* H# }+ s! s+ y& Y3 W# o* }! w) D# }- s7 a9 e! I/ b
8.读取完成后等待STOP有效,因为前面在最后一包数据读取的时候使能了自动STOP,这个时候检查STOP是否生成。9 ~' v8 s% R* X
! a0 K8 e! o! P9 D% Z, y8 ~
9.需要注意的是,所有的操作都要给超时,并且是自己可控的,绝对不要有死循环,之所以一直说STM32的IIC死机很大程度上都是由于这个地方没有涉及好,我的程序设计方法是:一旦出现了异常,就复位IIC,如果不复位就会导致下次进去的时候IIC一直忙,因为还处于上一个通讯过程。2 L3 d1 h# K  B$ I; ~9 M# o) g+ _- E
8 N6 R: f- I# J  [' a" ?5 n8 Q% `1 S

( \% j, S3 q) L8 e5 Y# b! T. h  A3 W0 F  i9 y/ h
[写入]+ b- @( ^6 a# T& j6 I

( m8 ?! E0 Z1 C: e4 Q1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。0 L( c$ |7 ?; y: s! {) c1 g6 H& H
. H/ W! |! u! _3 o
2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)自动重载,写模式,启动传输。
3 |5 D9 `1 H2 z9 U1 L
- W* b; ~3 X1 L7 B3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
5 }+ W  m$ Q1 ~
3 e! I* i. j0 K7 `: v4.等待TCR置位,意味着上面的1-2字节的寄存器地址以及写完成了,已经发生重载了,后续可以继续写入数据了。* R$ }3 a  N3 j& f

# n! R7 \' Z# _5.根据要写入的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。) q7 t* y1 }- |
- O* x+ o# Q4 U. |: X$ W8 K0 d
6.设置了从机地址,要写入的数据长度,之后不用切换方向,不用启动START(都是写,不用重复发送START,这个与读取有区别)。/ m1 C# O6 }2 D  y% u. n
: ~+ |- d7 W5 J5 n& S
7.循环一个字节一个字节的写入,字节写入与步骤3一样,等待TXIS置位,就可以写入数据到TXDR。' {: h8 {' W9 h6 n/ h, L

5 D5 \) q! y7 i6 g0 m8.等待STOP有效,因为前面在最后一包数据写入的时候使能了自动STOP,这个时候检查STOP是否生成。
/ D( e5 L% p, e- x7 @. N% C1 {, n6 h. p* k/ ]* h. O! ^
9.需要注意的是,所有的操作都要给超时,跟读取一样。! R" o% N/ u5 V! a" R; ~

( P# t# D  O$ c3 x7 o
$ h$ i, Y( }5 p. c+ W, f
5 R6 O# i$ O: r: F' f. T  Y注意:IIC的读取实际很短,超时也不用给很长,以标准的100KHz通讯时钟速度,一个字节大概在90us左右,超时可以给个5-10B时间,也就是450-900us左右。
2 ?' ?/ M6 _  B" _* X2 j! _) F- l! L6 P- j1 e, m

6 p4 @5 R$ X  W" W% A& d
  y9 c/ q3 F; p, f% r好了说了这么多,具体的看代码中的注释,直接上代码(我只测试过I2C3,其余的理论上都是一样的,就是IO初始化部分有区别,别的通道没有硬件进行测试)2 Q/ X, i4 [" f0 h5 q

7 c( ]7 `7 O, s# e  j
  1. /*************************************************************************************************************
    4 O8 n' C. x3 w1 s; B( y4 `
  2. * 文件名                :        stm32f7_iic.c5 |1 ]. O" M# L
  3. * 功能                        :        STM32F7 IIC接口驱动
    4 M0 H0 s3 m4 E" Y3 H' Z- F* z& ^
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>" _! D; E& ~9 [. Z! k
  5. * 创建时间                :        2020-02-09. e8 V: \5 a6 @
  6. * 最后修改时间        :        2020-02-09
    ! v& b8 h! O! S3 C( F4 C
  7. * 详细:                        只支持主机模式,7bit地址,默认APB1为IIC提供时钟
    2 i! S+ O& w, |0 [$ v9 L
  8.                                         涉及到读写1字节的超时时间是us,其余的是ms
    4 ?$ D( y$ f5 Z
  9.                                         注意:IIC的IO必须初始化为复用开漏输出。
    1 e1 U  q0 o( ?+ j$ M
  10. *************************************************************************************************************/        6 T9 W4 }3 o0 t5 X, n- O
  11. #include "stm32f7_iic.h"7 v0 L3 |% ], s3 Z  s
  12. #include "system.h"
    ' t/ k7 B; W" M2 f6 a9 ]* x* H% J
  13. #include "dma.h"
    6 @' }# _$ M# k% k
  14. ! x% n  J3 C. O  L9 x( q! V0 F1 w
  15. #define IIC_FLAG_MASK  ((uint32_t)0x0001FFFF)        //中断标志掩码  L& j6 L# X/ g, u6 L
  16. ! F1 m$ |' `! [9 n0 b( X4 w1 v
  17. //自动结束或自动重载设置(重载与自动结束只能二选一,或者都不选)
    % C2 K- J, t! ^( d9 }6 }0 {
  18. typedef enum & E+ E3 J9 v& ^- R$ p& I+ w
  19. {4 C5 ^. ^: i* i3 t1 P
  20.         IIC_SOFTEND_MODE                =        0,        //手动结束,并不开启重载8 |) L. b& `7 N8 D$ s6 D
  21.         IIC_AUTOEND_MODE                =        1,        //自动结束,用于最后一次通讯完成后自动发送STOP结束通讯
    " o8 f/ c8 o8 K
  22.         IIC_RELOAD_MODE                        =        2,        //后续还有数据,本次通讯后自动重载,重新设置后继续通讯
    ! @  r' [/ o4 A) w3 b# p7 D3 W
  23. }IIC_RELOAD_END_MODE;$ ?* ~" Y) x* C" I; \$ k
  24. 6 ^+ t: \6 L4 n9 y; D
  25. //读写与开始模式控制
    $ a9 C# m8 R% U
  26. typedef enum
    7 ~; c4 A+ i9 L! n! G, q2 A
  27. {
    . ~; Y7 J6 @* X  a/ e5 m1 }
  28.         IIC_NOSTART_WRITE                =        0,        //没有开始的写-用于后续数据的写入8 f9 g$ H9 J2 s$ o% ]5 l" K
  29.         IIC_NOSTART_READ                =        1,        //没有开始的读-用于后续数据读取; |0 \, m' Q( j& Q/ K/ y
  30.         IIC_START_WRITE                        =        2,        //生成开始写-用于通讯开始时,写地址或数据
    * g, T( C/ t( k. M
  31.         IIC_START_READ                =        3,        //生成开始读-用于读取数据时切换到读取方向,并读取后续数据) j# n0 v. }6 r0 p# j% |
  32. }IIC_START_WR_MODE;
    5 w* _9 ^. B3 ?7 Y& O

  33. ( Z$ O6 ]$ ]0 h' U/ T
  34. //IIC句柄
    # c# C# @$ p: H% x/ `0 Q8 z+ u% ^
  35. typedef struct5 h+ P0 }( v' D3 j
  36. {
    + B* U$ M% C$ W1 S
  37.         IIC_CH_Type ch;                        //当前通道& n+ [1 R5 C7 |$ w% J
  38.         I2C_TypeDef *I2Cx;                //当前通道外设结构体* C/ l7 f% C1 t9 Q5 c
  39.         u32 TimeOutUs;                        //操作超时,单位us9 j$ L; C; {6 x
  40.         u16 Speed_KHz;                        //通讯速度,单位KHz6 `6 h. j$ E& T8 V, A8 P
  41.         bool isMasterMode;                //是否为主设备模式-目前只支持主设备模式
    , @: R9 ^* C8 A! \7 @
  42. }IIC_HANDLE;- c6 T$ [, m# V
  43. 4 M& P: [% M# J0 M) f* w/ H7 Q+ z$ w
  44. //IIC外设结构指针
    . W* v2 V- `, V, b
  45. static const  I2C_TypeDef * const I2C_TYPE_BUFF[IIC_CH_COUNT] = {I2C1,I2C2,I2C3,I2C4};+ Q/ w' o; b+ p/ d
  46. //IIC通道句柄定义
    " |% v3 b/ u7 |' R# ^
  47. static IIC_HANDLE sg_IIC_Handle[IIC_CH_COUNT];
    2 y; E$ U5 ^/ C' w  a9 ~5 z
  48. 7 E' K0 M1 n3 |4 t$ c  v
  49. //发送NAK8 t+ u+ C! T/ q' |+ w0 g/ h, t. Y8 J
  50. //static __inline void IIC_SendNAK(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT15;}
    ( w+ h8 }& L1 D. O' n4 K- |
  51. //发送STOP* D0 i$ g" B' U  M1 t2 Y: y
  52. static __inline void IIC_SendStop(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT14;}, Z/ I% E% ~6 W
  53. //发送START% j8 |( V3 C. a1 R: W8 A
  54. //static __inline void IIC_SendStart(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= I2C_CR2_START;}  m. V2 f9 b$ D: `# N# F* F9 |
  55. //获取中断状态. W8 O# r) I; N9 }5 H. r9 }
  56. static __inline u32 IIC_GetISR(IIC_HANDLE *pHandle) {return pHandle->I2Cx->ISR & IIC_FLAG_MASK;}
    + c4 u3 t3 p( }% t
  57. //清除中断状态
    9 e: b- o( t: z: l- }3 n
  58. static __inline void IIC_ClearISR(IIC_HANDLE *pHandle, u32 IsrFlag) {pHandle->I2Cx->ICR = IsrFlag & IIC_FLAG_MASK;}: _$ U/ B  L& n: m
  59. //复位CR2寄存器
    9 L) E7 S& s) k
  60. static __inline void IIC_ClearCR2(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 = 0;}
    3 x- [. e' R$ _" _9 V, _

  61. 6 o8 ]) z# d0 o: c0 `  p# s
  62. static void IIC_SoftReset(IIC_HANDLE *pHandle);//硬件IIC软复位(会使能IIC)2 e3 ^8 \& O+ |) @
  63. static u32 IIC_CalculationTiming(u16 Speed_KHz);//硬件IIC时序计算! l$ W/ n: \* E1 w$ V

  64. - b) v/ d6 e* a# p* L

  65. % v5 w9 i" q: `1 b5 |  p
  66. /*************************************************************************************************************************
    : ], |) A- z6 H& l6 P1 `/ G% k
  67. * 函数        :                        bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)3 Y, S6 K3 T* ^) h( w+ G  v
  68. * 功能        :                        硬件IIC初始化
    " \! u( ?+ p/ }1 ^+ n: A. D
  69. * 参数        :                        ch:IIC通道;Speed_KHz:速度10-1000(如果速度是100,则按照SMBUS时序);TimeOutUs:操作超时us(0:自定计算超时)
    1 L$ E' _, L. F/ `# ?
  70. * 返回        :                        IIC_ERROR# A  c1 x# t0 O0 n
  71. * 依赖        :                        底层宏定义. q4 V3 k9 k  K0 [, x0 G
  72. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>5 C/ o9 _  V2 q+ Z
  73. * 时间        :                        2020-02-15/ E6 B1 c2 \0 G
  74. * 最后修改时间 :         2020-02-15
    ) O! C' Z, F0 u+ S" E4 c& N8 ^
  75. * 说明        :                         速度只是个大概的计算值,设置为100KHz时会严格的按照SMBUS时序,其余的不保证SMBUS兼容,正常情况下只要时钟速度符合要求,
    & ~: ?% M+ U; x
  76.                                         时钟上升沿到来前数据以及稳定的切换了即可保证通讯稳定性" t2 i% a( ?# X6 i; j% X
  77. *************************************************************************************************************************/* J( c2 N: p; x
  78. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)/ E2 _8 }- }* n3 j, ^6 g" a$ \! m8 ^
  79. {
    7 |+ R2 r$ D/ C: y+ L9 p9 Z& K
  80.         SYS_DEV_CLOCK DevClock;/ Y  Y: [% |& o4 {( D
  81.         IIC_HANDLE *pHandle;) A2 \9 n$ F+ u2 S6 L1 i
  82.         
    9 M+ y  _; R/ B6 v
  83.         switch(ch)
      w& Q% w& Z/ F0 Z; o. S# i% @
  84.         {
    3 }; M, a, S$ z- V
  85.                 case IIC_CH1        :        //IIC1  t4 }( x7 m, S' h: B& g$ E
  86.                 {7 u4 H* S3 }% J
  87.                         RCC->DCKCFGR2 &= ~(0x3 << 16);        //清除设置,使用APB1作为时钟源* W0 _0 B2 ~. y2 w
  88.                         DevClock = DEV_I2C1;
    9 a2 v1 J" L+ E$ m; A
  89.                         //初始化I2C IO, o8 V5 i& v' l
  90. #if(IIC_CH1_IO_SELECT==IIC_CH1_PB6_7)        //I2C1        使用PB6/7) ?* W1 {* Z4 C. }) r4 Y0 n+ c
  91.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟, {% Z& H8 d4 ?8 t! U* @$ G
  92.                         SYS_GPIOx_OneInit(GPIOB, 6, AF_OD, SPEED_25M);                //PB6
    2 U6 a2 R+ ~) ]9 }
  93.                         SYS_GPIOx_OneInit(GPIOB, 7, AF_OD, SPEED_25M);                //PB7* a& O6 e9 ]% P2 H
  94.                         SYS_GPIOx_SetAF(GPIOB, 6, AF4_I2C1);                                //AF4+ l8 t, [( c( I3 R; b
  95.                         SYS_GPIOx_SetAF(GPIOB, 7, AF4_I2C1);                                //AF4/ G7 ~) i( F; f6 l7 I  ?# n' X% j; U7 s
  96. #elif(IIC_CH1_IO_SELECT==IIC_CH1_PB8_9)        //I2C1        使用PB8/9
    ( ?& s/ f7 j, x; Q  ^" t" Z
  97.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟# p) `- x4 M) v, k; [& v# j
  98.                         SYS_GPIOx_OneInit(GPIOB, 8, AF_OD, SPEED_25M);                //PB8
    " Z; I, w6 b8 W- s5 K: Q" m6 F$ T
  99.                         SYS_GPIOx_OneInit(GPIOB, 9, AF_OD, SPEED_25M);                //PB90 }2 h7 p) l+ O: L
  100.                         SYS_GPIOx_SetAF(GPIOB, 8, AF4_I2C1);                                //AF4
    5 Y' h2 K# _9 {, N3 d* p) c
  101.                         SYS_GPIOx_SetAF(GPIOB, 9, AF4_I2C1);                                //AF4
    - u* e$ ]% T% x* D  l
  102. #else
    % O7 h8 }6 B7 L* A- I
  103.                         #error("无效的I2C1 IO选择");% M: B4 J' d: O! k/ P" v
  104. #endif //IIC_CH1_IO_SELECT
    $ Z3 H/ }$ q/ c- u5 j
  105.                 }break;' B: g9 ^: M# _5 t
  106.                 case IIC_CH2        :        //IIC2
    : U3 p' d$ Q- Q
  107.                 {
    * Y" q6 `+ r% z1 a! D# U
  108.                         RCC->DCKCFGR2 &= ~(0x3 << 18);        //清除设置,使用APB1作为时钟源) ~* R0 T1 H8 ~5 F& s/ K8 E' n
  109.                         DevClock = DEV_I2C2;
    - i. n9 f  j* m: J; k$ O
  110.                         //初始化I2C IO
    3 j; L! x4 C  g6 j3 P
  111. #if(IIC_CH2_IO_SELECT==IIC_CH2_PB10_11)        //使用PB10,PB11
    / C* |; H  c: C* X& G8 M  K( _7 c3 F
  112.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟3 Q0 n' `! L4 f0 y2 K2 Z
  113.                         SYS_GPIOx_OneInit(GPIOB, 10, AF_OD, SPEED_25M);                //PB10
    / M* b" ^! u* [/ {
  114.                         SYS_GPIOx_OneInit(GPIOB, 11, AF_OD, SPEED_25M);                //PB112 S; ]3 g5 d! ?4 h) _
  115.                         SYS_GPIOx_SetAF(GPIOB, 10, AF4_I2C2);                                //AF4, y8 Z, u5 n8 O& h- r
  116.                         SYS_GPIOx_SetAF(GPIOB, 11, AF4_I2C2);                                //AF4
    $ ~5 {( T' x% x% M4 g- c
  117. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PF0_1)        //PF0,PF1$ n/ R4 k/ X, B
  118.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟
    " N) g3 u5 O( b
  119.                         SYS_GPIOx_OneInit(GPIOF, 0, AF_OD, SPEED_25M);                //PF00 U5 D  }: w- K, }  E: b4 C
  120.                         SYS_GPIOx_OneInit(GPIOF, 1, AF_OD, SPEED_25M);                //PF16 U, t; ]2 K: e/ T& e/ C
  121.                         SYS_GPIOx_SetAF(GPIOF, 0, AF4_I2C2);                                //AF4( |0 P: ^1 B+ f5 O, M, V. P
  122.                         SYS_GPIOx_SetAF(GPIOF, 1, AF4_I2C2);                                //AF4+ W/ m9 C" Q' f" j3 O2 u3 W3 J$ m
  123. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PH4_5)        //PH4,PH5
    , q9 r% `4 w7 ^
  124.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    + f  m. U, r! i; b! P, Y
  125.                         SYS_GPIOx_OneInit(GPIOH, 4, AF_OD, SPEED_25M);                //PH4% @% l9 s$ z. X3 l- Y; t
  126.                         SYS_GPIOx_OneInit(GPIOH, 5, AF_OD, SPEED_25M);                //PH5% ^6 l* U8 B4 o, e. J
  127.                         SYS_GPIOx_SetAF(GPIOH, 4, AF4_I2C2);                                //AF4. ~9 `& V5 F6 T" T0 H
  128.                         SYS_GPIOx_SetAF(GPIOH, 5, AF4_I2C2);                                //AF4                        3 S( c5 b% h  l
  129. #else! J* B% o: @) ], m& l3 k
  130.                         #error("无效的I2C2 IO选择");
    + r, `, z- n+ |6 l
  131. #endif //IIC_CH2_IO_SELECT
    + w5 i( z) \& O+ y7 {; z1 K$ N
  132.                 }break;                        
    0 G7 c( n3 q* F6 k
  133.                 case IIC_CH3        :        //IIC3& z/ U' M5 ?+ y
  134.                 {2 Y# j( u! A1 u# Z. Y
  135.                         RCC->DCKCFGR2 &= ~(0x3 << 20);        //清除设置,使用APB1作为时钟源* P  L, \3 X1 {1 `& U" R
  136.                         DevClock = DEV_I2C3;
    # a8 \+ l% k) l2 O: i
  137.                         //初始化I2C IO
      Y* H. g$ I3 `0 V% \/ }1 p" z: w& V
  138. #if(IIC_CH3_IO_SELECT==IIC_CH3_PH7_8)                //PH7,PH8
    6 s- S8 V5 H& |/ [1 `
  139.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    & V2 F/ i- @( t. d, ?' k, a
  140.                         SYS_GPIOx_OneInit(GPIOH, 7, AF_OD, SPEED_25M);                //PH7- m* X% X( y9 }+ D9 J5 |, d6 y, o
  141.                         SYS_GPIOx_OneInit(GPIOH, 8, AF_OD, SPEED_25M);                //PH83 P, z' z; {5 {* F. Z' v
  142.                         SYS_GPIOx_SetAF(GPIOH, 7, AF4_I2C3);                                //AF4! ?: o/ h* D$ M1 ?% D
  143.                         SYS_GPIOx_SetAF(GPIOH, 8, AF4_I2C3);                                //AF4
    9 D" ]  N6 x1 X  q
  144. #elif(IIC_CH3_IO_SELECT==IIC_CH3_PA8_PC9)        //PA8,PC9
    , J5 a$ O/ ]+ N# p
  145.                         SYS_DeviceClockEnable(DEV_GPIOA, TRUE);                                //使能GPIOA时钟5 o4 q- N: k. R2 H# I2 J
  146.                         SYS_DeviceClockEnable(DEV_GPIOC, TRUE);                                //使能GPIOC时钟
    % {; ]. f, |8 u* T* R  w
  147.                         SYS_GPIOx_OneInit(GPIOA, 8, AF_OD, SPEED_25M);                //PA8; |# f, y. v2 h" D# F
  148.                         SYS_GPIOx_OneInit(GPIOC, 9, AF_OD, SPEED_25M);                //PC9
    1 J/ G+ ?$ B# B* v' |4 i
  149.                         SYS_GPIOx_SetAF(GPIOA, 8, AF4_I2C3);                                //AF49 S. Q' h- [6 {$ J0 w
  150.                         SYS_GPIOx_SetAF(GPIOC, 9, AF4_I2C3);                                //AF4               
    ) E+ C: Y( e. }
  151. #else. F/ M, {2 N+ V- B% Z+ a* w# O6 n
  152.                         #error("无效的I2C3 IO选择");
    + ~, |7 T6 [0 `5 I
  153. #endif //IIC_CH3_IO_SELECT                        2 p6 o; b, I# s/ k
  154.                 }break;                        7 h* ^- q* P* j5 @
  155.                 case IIC_CH4        :        //IIC4
    " N9 Z, s* M% j7 u' ]6 T
  156.                 {  ]! ]% |4 M. i$ ^1 ]8 \  t
  157.                         RCC->DCKCFGR2 &= ~(0x3 << 22);        //清除设置,使用APB1作为时钟源
    : Z+ Q$ g* r* i4 J3 ]+ H
  158.                         DevClock = DEV_I2C4;, {4 y$ s  f' V2 p! n
  159.                         //初始化I2C IO
    2 J4 ]5 @( K  W& p2 ]
  160. #if(IIC_CH4_IO_SELECT==IIC_CH4_PD12_13)                //PD12,PD13
    ( |: M, ^% S- P* T) F
  161.                         SYS_DeviceClockEnable(DEV_GPIOD, TRUE);                                //使能GPIOD时钟
      \  p, h- S7 n* B4 u
  162.                         SYS_GPIOx_OneInit(GPIOD, 12, AF_OD, SPEED_25M);                //PD12) N- a; w+ _' o* x+ p" Z' N
  163.                         SYS_GPIOx_OneInit(GPIOD, 13, AF_OD, SPEED_25M);                //PD13
    1 x" c- u8 ?# l: e! @4 I+ l  V
  164.                         SYS_GPIOx_SetAF(GPIOD, 12, AF4_I2C4);                                //AF4& P- D/ V0 l* K. {
  165.                         SYS_GPIOx_SetAF(GPIOD, 13, AF4_I2C4);                                //AF4
    - t0 `9 L& s9 I+ s
  166. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PF14_15)        //PF14,PF15  ^+ ~7 q# _/ |$ m1 ]7 h. ?
  167.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟
    ( b) b" J' j) Q7 q8 f4 u5 _" w
  168.                         SYS_GPIOx_OneInit(GPIOF, 14, AF_OD, SPEED_25M);                //PF144 P* A! h2 @( a6 G" W2 |+ U) m2 J
  169.                         SYS_GPIOx_OneInit(GPIOF, 15, AF_OD, SPEED_25M);                //PF15
    $ M: V  S/ Y3 z; }
  170.                         SYS_GPIOx_SetAF(GPIOF, 14, AF4_I2C4);                                //AF4
      |( y* E/ p; y, ?9 ?" _: T
  171.                         SYS_GPIOx_SetAF(GPIOF, 15, AF4_I2C4);                                //AF4( N1 H0 S1 p5 {4 d- z
  172. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PH11_12)        //PH11,PH12
    6 v  t1 @+ k, [  C! u
  173.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    " `& }  G- J$ G3 j* v3 E; x6 {
  174.                         SYS_GPIOx_OneInit(GPIOH, 11, AF_OD, SPEED_25M);                //PH11
      g0 z' G: O  r4 F2 |
  175.                         SYS_GPIOx_OneInit(GPIOH, 12, AF_OD, SPEED_25M);                //PH12
    * I& R9 [) q4 r$ `# ~# |' H! ]1 P6 Y
  176.                         SYS_GPIOx_SetAF(GPIOH, 11, AF4_I2C4);                                //AF43 _: l- R! r* ~5 P
  177.                         SYS_GPIOx_SetAF(GPIOH, 12, AF4_I2C4);                                //AF4                        
    3 E! k8 s  w( t  @) l
  178. #else
    8 e7 {5 T& A- p1 U; Z
  179.                         #error("无效的I2C4 IO选择");8 e& X  x  T5 [! N/ O
  180. #endif //IIC_CH4_IO_SELECT                        
    3 q/ M) ?8 e- c6 ^7 u
  181.                 }break;
    2 y& G4 N. h6 e5 [9 C7 C& E* b+ u
  182.                 default:
    $ q5 ^6 {9 A8 u! K
  183.                 {* t7 P' a! [1 }  w$ `$ Z
  184.                         DEBUG("初始化IIC失败:无效的IIC通道%d\r\n", ch);
    9 z  I/ W7 W4 |5 m
  185.                         return FALSE;+ _3 F0 [: \9 |- p8 o
  186.                 }) M. o6 X( n% q) t2 f+ n; E
  187.         }
    & J0 F4 [% S" i3 X4 v& n& n
  188.         pHandle = &sg_IIC_Handle[ch];                                                        //获取相关通道的句柄( i# a7 ~/ K/ ~
  189.         if(pHandle == NULL)& X( P+ g8 s1 ?9 M
  190.         {
    : _! Q. a+ G( J( W/ n! Z5 S+ R
  191.                 DEBUG("初始化IIC失败:无效的IIC句柄\r\n");
    ' X8 m) B0 }2 j+ `
  192.                 return FALSE;
    0 \5 m9 F  R$ N5 p3 X
  193.         }
    4 d" v' V/ s3 X$ }* l$ i6 G
  194.         
    3 \; Y# C; \" B+ T9 Y: g
  195.         SYS_DeviceClockEnable(DevClock, TRUE);                                        //使能时钟
    0 x: \$ M+ G" B5 L9 X+ O$ c9 c
  196.         SYS_DeviceReset(DevClock);                                                                //外设复位
    0 f4 \. r3 K2 A4 E: d
  197.         pHandle->I2Cx = (I2C_TypeDef *)I2C_TYPE_BUFF[ch];                //外设指针
    + G1 M5 F* A5 w+ J5 Y
  198.         pHandle->I2Cx->CR1 = 0;
    ' Z0 |3 }  n& g+ }- F  i* t
  199.         Delay_US(1);                                                - A% ~2 M, d1 {, {8 ]5 T9 K! C' w5 y  N1 S
  200.         pHandle->I2Cx->CR1 |= 2<<8;                                                                //设置噪声滤波器,关闭所有中断
    8 @* f/ F( q1 L- Q4 z% s
  201.         pHandle->I2Cx->CR2 = 0;
    ! \6 p) K1 D, F. E/ {
  202.         pHandle->I2Cx->OAR1 = 0;
    , X, [8 G. F9 K0 b# |, ^. P& x1 x$ Y
  203.         pHandle->I2Cx->OAR2 = 0;
    ( @% @; |  ?& b" h+ G
  204.         if(Speed_KHz > 1000) Speed_KHz = 1000;: l, ]9 C* G2 q0 F) K
  205.         if(Speed_KHz < 10) Speed_KHz = 10;, P  u+ `3 W0 G3 X
  206.         pHandle->Speed_KHz = Speed_KHz;                                                        //记录速度
    ' x3 y4 H4 C1 D) s0 {( R
  207.         if(TimeOutUs == 0)                                                                                //需要自动计算超时时间,时钟周期*10*10 + d2 y% M; `# v9 U! x# |
  208.         {
    / Z$ r! F, \& a( ?/ v, U
  209.                 TimeOutUs = 1000/Speed_KHz;                                                        //时钟周期4 k# ?8 r. J3 E4 C1 H
  210.                 TimeOutUs *= 10;                                                                        //字节周期
    % r1 T$ v% m4 @8 N
  211.                 TimeOutUs *= 10;                                                                        //超时时间为10个字节时间) s; T; ?5 Q  r' ~$ r% q" q( U
  212.         }
    ; _3 H$ T4 P. I" x$ C
  213.         if(TimeOutUs < 3) TimeOutUs = 3;
    ) {$ k3 H5 K* A, [1 G
  214.         pHandle->TimeOutUs = TimeOutUs;                                                        //记录通讯超时时间
    4 K) V, ^+ Q2 W' c! ~7 G1 q
  215.         uart_printf("IIC超时时间:%dus\r\n", pHandle->TimeOutUs);
    % t! A7 X1 f: h* E
  216.         pHandle->I2Cx->TIMINGR = IIC_CalculationTiming(pHandle->Speed_KHz);//0x40912732;                                        //时序3 f/ H$ m4 {% ~" c; c
  217.         pHandle->I2Cx->CR1 |= BIT0;                                                                //使能IIC
    8 V$ f: K% A1 Z; c) k0 F& @
  218.         pHandle->isMasterMode = TRUE;                                                        //主设备模式+ q6 D0 q2 A! K! \( ^' g
  219.         Delay_US(1);
    ' x/ B, z' w& r, g; J# z/ O
  220. * J* z' U# S- E9 U0 {$ e: P7 ^
  221.         return TRUE;8 H# g+ ]. c4 g" c( E& l1 @& [
  222. }5 m2 A+ Y8 l+ y9 a

  223. ) q% V' B% r7 `- `
  224. * w0 W2 I$ w8 M7 C
  225. /*************************************************************************************************************************
    1 I% z3 O8 D, N& k! G% b  |
  226. * 函数        :                        static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)3 s: a, r* s3 r
  227. * 功能        :                        检查是否有NACK中断状态,如果有则清除掉
    , [" ?5 n9 H7 X" L/ K
  228. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us
    2 F) G# |5 m  M/ W; F6 p
  229. * 返回        :                        IIC_ERROR+ T% s1 \# U, O& [- d. ]
  230. * 依赖        :                        底层宏定义$ z! I" z$ Z6 ^  w+ Q" l1 P: ?
  231. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>8 w4 |1 z) ^- S/ V  d6 H
  232. * 时间        :                        2020-02-15
      i5 l9 l" x; c3 C0 |9 F& H4 U7 z/ O
  233. * 最后修改时间 :         2020-02-151 A; O4 _$ ?8 f% B
  234. * 说明        :                         如果有NACK中断,则先产生停止位,然后清清除掉所有的中断,并复位IIC,然后返回错误
    ( _+ f& X( U" t* E; U/ ^
  235. *************************************************************************************************************************/  + p) @! T" c" F3 Y8 \! j- V. T: F9 E0 [
  236. static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)
    / m( t6 U; H2 \9 t
  237. {1 S& x) Z  y! F' b+ Z
  238.         IIC_ERROR Error = IIC_OK;; |. p! @% A  ], H  m* n1 x
  239.         
    - V8 g% m% u. D& L9 U7 n. e
  240.         if(IIC_GetISR(pHandle) & IIC_FLAG_NACKF)        //接收到否定应答标志( r2 K3 ~% O/ d& o' Q) Q
  241.         {
    ! W* O0 T& \/ }! J4 }$ E0 l
  242.                 uart_printf("NACK : IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);0 g/ w- j1 g" c9 g2 `& v" @" ], T. N
  243.                 uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);: S( T% O  y$ M8 n: m
  244.                 uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));/ q2 p$ l, W: k6 Z
  245.                 //主设备下,如果没有开启自动产生停止位,则手动产生停止位
    , T; Z$ z' G* D& t2 k
  246.                 if(pHandle->isMasterMode && ((pHandle->I2Cx->CR2 & I2C_CR2_AUTOEND) == 0))* b7 c. |; z* y9 J# T+ }- j7 V
  247.                 {) \3 W3 c8 }3 y
  248.                         IIC_SendStop(pHandle);                        //send stop
    % {# ~' L  ~7 w1 s3 {  ^  W
  249.                 }
    / I. ]9 z; Y: D
  250.                 //等待STOP标志有效
    ! `5 Z0 I- l6 y  t
  251.                 while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)! k. a& }" k; v) N; ?$ `' C& w
  252.                 {8 d7 U  S0 g( V2 R! J2 e6 h: ^
  253.                         if(TimeOutUs == 0)                                //检查是否超时了* C3 N, H5 {! q9 F: z5 ~
  254.                         {
    # [$ l5 H$ O& C% u- L; }
  255.                                 break;
    : K/ H+ D0 u/ V/ s! ]  L  E! K
  256.                         }                        . f8 H7 R: o* C- W* r% ~4 {
  257.                         TimeOutUs --;( m' d+ C9 X! Y; T2 K& l
  258.                         Delay_US(1);                                                //延时
    ( M8 u( u$ `2 o- a2 F
  259.                 }
    8 Z1 s, P# ~8 \+ e  g  Y( z
  260.                 //清除相关的中断标志
    $ \8 s8 V! v# K0 G9 y, y$ D  i2 y
  261.                 IIC_ClearISR(pHandle, IIC_FLAG_NACKF | IIC_FLAG_STOPF);        //清除NACK,STOP标志, j, K5 X$ K8 A
  262.                 pHandle->I2Cx->CR2 = 0;                                                                                //清除CR2寄存器
    ; u3 F& u* T) m: I8 d
  263.                 IIC_SoftReset(pHandle);                                                                        //执行软复位  b3 X* ]; z2 I7 F5 q' f6 Z+ H
  264.                 if(TimeOutUs == 0)                                                //没有超时,就是硬件通讯出错了8 I8 S3 C6 c" Q7 i  n5 t
  265.                 {
    4 j4 B0 Y! n- D4 W
  266.                         DEBUG("IIC发送stop超时\r\n");6 A3 K# p2 G$ w
  267.                         Error = IIC_TIMEOUT;                                //超时
      e8 I- z; `4 _
  268.                 }
    # N, o" b' ?  B1 u4 s- s
  269.                 else5 u' X/ M6 X- w3 p
  270.                 {
    , M6 I! n% w( q5 d  o1 l2 @
  271.                         Error = IIC_HAL_ERROR;                                //底层错误
    7 P. g( e/ J5 F3 }
  272.                 }/ y  N7 k8 p1 `$ L
  273.         }
    , V9 Y9 z6 D/ w
  274.         
    ' W* f- m. w2 z) `! C0 h
  275.         return Error;! w2 A* Z8 e  h
  276. }
    & O3 e' e) ^( q/ I3 a4 A' k

  277. * m) z/ C: a  c' h4 D' T' B

  278. ( B0 E! l" @, n- Q2 t  C0 W
  279. + a# R& V* w1 o. O* @1 q
  280. /*************************************************************************************************************************) K# R2 B# E! f( z4 l2 g5 P0 T
  281. * 函数        :                        static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)& m1 u1 n. a- U  r% u. H
  282. * 功能        :                        等待TXIS中断有效(等待 I2C_TXDR 发送寄存器为空)
    5 Z/ x( h" j! _
  283. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us
    * i- N2 |  C+ k7 Z  z; _
  284. * 返回        :                        IIC_ERROR
    / c3 o. p7 m- a2 t6 Y2 B
  285. * 依赖        :                        底层宏定义) B$ }7 _7 A7 x6 z6 [
  286. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>4 S$ ?6 T4 G+ m
  287. * 时间        :                        2020-02-15
    - U. m; _9 D# Z
  288. * 最后修改时间 :         2020-02-157 m, u. s5 R+ l- ^, Y
  289. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的* G. z) |* J( i; d6 }" f4 @# c
  290. *************************************************************************************************************************/  $ ?& N1 h0 w: k
  291. static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
    " j. x2 t) I6 F+ Z& Y  N9 O
  292. {
    " `6 t+ S' h. X% e2 j
  293.         //等待TXIS中断有效
    9 b( ~; Y* Q$ F0 G
  294.         while((IIC_GetISR(pHandle) & IIC_FLAG_TXIS) == 0)
    9 N' F; R( r" i% S; D& b) q' r) N
  295.         {
    + B( V( n% |& P) x" A6 v
  296.                 //有NACK中断,进行处理- m, g" I9 i9 d
  297.                 if(IIC_isCheckNackFlag(pHandle, TimeOutUs) != IIC_OK)        
    5 D2 F! k* T* p/ }. f% W' D
  298.                 {
    7 u. v, c+ K. u, `
  299.                         DEBUG("检测到NAK错误\r\n");# r. a5 Z& x" M
  300.                         return IIC_NACK;+ d9 A8 b- A4 s/ l1 Y
  301.                 }
    # {5 J: J9 t% c6 h
  302.                 9 g. |% m( e2 ?0 Y9 t
  303.                 if(TimeOutUs == 0)                                        //检查是否超时了
    ' d- Z& z6 x( [) O
  304.                 {
    5 c% d9 c+ X: H: U, k
  305.                         uart_printf("IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);7 l& Y4 z" }" z- m
  306.                         uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);! y3 ?$ o. e& G% W9 R* {
  307.                         uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));
    8 T1 y+ ~: R- h' I
  308.                         6 @# j2 v! {7 B+ c
  309.                         IIC_SoftReset(pHandle);                //执行软复位4 v0 s9 t+ d2 n& D4 Z6 {0 M' y
  310.                         return IIC_TIMEOUT;                                //超时
    $ ~$ C0 {/ p0 i& |7 J0 T' r) ~& z
  311.                 }                          T# Q" |& @8 B
  312.                 TimeOutUs --;4 k% a9 S  }8 C) P) |9 V
  313.                 Delay_US(1);                                                //延时9 e+ g0 n# a3 {% K$ ?* g
  314.         }7 g3 Q/ }- S- S. S6 B! c
  315.         ; u8 H: e3 M5 z
  316.         return IIC_OK;
    ( ~, s8 a/ M$ g7 w6 g5 o2 S
  317. }
    ) t2 m& x6 ]$ W0 i- f+ v& e( E

  318. # F& M$ r/ }' S! {
  319.   n" @* d, Z1 K- R, F
  320. /*************************************************************************************************************************( z8 O6 n. c- w7 s' V4 I
  321. * 函数        :                        static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)9 c( `. q4 ^) g# C/ t! y% Z
  322. * 功能        :                        等待STOP中断有效(等待 发送结束 )
    ! y9 {/ z2 }' Q9 a: E- I% |
  323. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us# Z  T$ {: J- m' o- Z6 H% X! I
  324. * 返回        :                        IIC_ERROR/ ^/ g8 ]2 i9 b2 R( O7 I
  325. * 依赖        :                        底层宏定义
    ( B6 E- X# f+ W1 C! W9 ~( O
  326. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    3 q/ y; }* b/ v' L  z, ]9 R  k' }1 Z
  327. * 时间        :                        2020-02-15- [) [% Q* Q6 \: ?8 G
  328. * 最后修改时间 :         2020-02-15# G* S, l1 T8 T
  329. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的
    * n, M# z  s' Z7 R- F
  330. *************************************************************************************************************************/  : n& [% Z- G* O
  331. static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)
    ! d) }5 S0 d4 r' d- A5 b6 I
  332. {4 _: t* a6 q" i3 H
  333.         //等待STOPF中断有效0 y: A/ K# l& ^5 w, W
  334.         while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
    1 I0 g( N2 ?2 V3 r
  335.         {1 ?& X- p4 w+ i# m) X
  336.                 //有NACK中断,进行处理4 \# [' c9 L+ A& m
  337.                 if(IIC_isCheckNackFlag(pHandle, 5) != IIC_OK)        . w+ t: U% H/ F9 M
  338.                 {; T: o& [( ]1 V/ x, e
  339.                         return IIC_HAL_ERROR;
    : c/ f+ ~: s5 |1 ?+ K: S& P" }
  340.                 }5 y2 b  c& N6 h) Q% G
  341.                
    " [( |5 I' c6 s6 @6 h/ H& p7 ^8 t9 B1 t. H
  342.                 if(TimeOutUs == 0)                                        //检查是否超时了9 R# Y0 ~5 b1 P2 v1 _% M
  343.                 {5 L7 {+ H- D# `2 H' ~; G
  344.                         IIC_SoftReset(pHandle);                //执行软复位2 A) Y6 F+ m: X" ^: z5 C2 n
  345.                         DEBUG("IIC等待结束超时\r\n");; l' ]3 t/ @2 a: x
  346.                         return IIC_TIMEOUT;                                //超时
    % T0 L: O* F$ o; m; ^9 p
  347.                 }                        : i- v% Y% F3 p: @$ g9 d
  348.                 TimeOutUs --;1 m- X* l; z3 o: H  m0 p0 v
  349.                 Delay_US(1);                                                //延时4 B- U% e+ t6 _" V7 |0 k
  350.         }* x- \! i! v; ]; J4 Y3 v3 a
  351.         3 S, ^# m+ ^# e7 b( F9 s" O
  352.         return IIC_OK;
    # l4 f. D5 z% e) g% E0 c
  353. }
    5 ^7 v7 c$ S. ~" U- A7 P
  354. 9 d1 `. k5 P. Z1 m+ }

  355. 3 e3 Q) x- c5 g" J# a4 n
  356. /*************************************************************************************************************************( w2 N0 ^' Z* S+ n
  357. * 函数        :                        static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
    3 Q1 C- e/ M1 N( q5 j
  358. * 功能        :                        等待中断有效
    ! j: M+ ^4 y: e! k# D/ p/ f
  359. * 参数        :                        pHandle:句柄;Flag:需要等待的flag,见IIC_FLAG_xxx;isWaitFlagSet:TRUE:等待标志有效,FALSE:等待标志复位;TimeOutUs:超时时间,单位Us/ Y! k  W6 J' F$ I4 _1 |
  360. * 返回        :                        IIC_ERROR
    ! o$ Y7 O' T/ P& f' E
  361. * 依赖        :                        底层宏定义
    2 h7 J+ E) ?0 ]3 _! X
  362. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>7 O; N6 O2 E* W/ }
  363. * 时间        :                        2020-02-15
    + ]3 l  [! y% r7 ?$ e& f
  364. * 最后修改时间 :         2020-02-15) X9 v. V; @  y5 ~
  365. * 说明        :                        
    0 x% v  v: K7 F, ]
  366. *************************************************************************************************************************/  " R' Q( b+ p' Y$ B/ y2 C
  367. static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)* m9 R5 [7 q; }, T* h) r
  368. {
    & I/ K3 @. `7 Y+ U8 r! O: A3 }
  369.         if(isWaitFlagSet)        //需要等待标志有效1 Q# E- C. r) k; j3 T
  370.         {$ I" e" `+ N4 \% X# ]& I+ }
  371.                 while((IIC_GetISR(pHandle) & Flag) == 0)
    5 {3 M, ~# O5 U  Y
  372.                 {
    & b8 u$ \  D3 l0 d' Y/ W# v
  373.                         if(TimeOutUs == 0)                                        //检查是否超时了
    ! v# @: i( ?! }0 z- H
  374.                         {0 l) l1 W# e3 V5 f, Y; ~
  375.                                 return IIC_TIMEOUT;                                //超时
    / L* P  Y) d* d& e9 J; i9 [) W
  376.                         }                        3 {* ?6 o8 u& p- y5 ~& R" F
  377.                         TimeOutUs --;+ N: Z4 a& G( }
  378.                         Delay_US(1);                                                //延时. q; v6 m- V5 {, y" u
  379.                 }
      ?6 U9 N! a5 q8 \
  380.         }
    $ L, Q, E& q" }; N) F  ?4 w4 r
  381.         else                                //需要等待标志复位" ?4 c" O& x- b3 s, ~3 k
  382.         {' w% }2 G, V) w3 q  a$ t( a+ q
  383.                 while((IIC_GetISR(pHandle) & Flag) != 0)
    2 f. ~% e- h* c
  384.                 {
    $ N9 G9 x2 Q& S! A$ k  X' \* ~
  385.                         if(TimeOutUs == 0)                                        //检查是否超时了& ~/ ~4 |, G3 |8 V* a+ F& u
  386.                         {
    / E9 l/ x+ ~1 D( Y  B& }
  387.                                 return IIC_TIMEOUT;                                //超时6 A9 v* W9 d1 ]. x7 @& t4 j" P
  388.                         }                        
    ! F) @% C& s& ~( A# f
  389.                         TimeOutUs --;7 r( w! |5 S! k7 b1 b6 j3 \
  390.                         Delay_US(1);                                                //延时1 R( I7 z9 Q+ f% z& C) ~7 j
  391.                 }( x8 G* M0 |5 }( S" l
  392.         }
    " F5 \" \" H! X% J, v
  393. 9 Z9 V8 g3 N5 q# u
  394.         return IIC_OK;
    ( Z% H# ]( f& b  e
  395. }
    . H: z4 H* V7 `4 t: `
  396. 6 Q2 P* B9 N6 N! k- v
  397. 3 v- N9 `: l% T$ ^- \: u  l- h$ N
  398. , a; z' l$ a- B" o. V

  399. + N7 [1 N/ d) r  ?
  400. /*************************************************************************************************************************/ D- W! P- ]8 e  @# D+ P
  401. * 函数        :                        static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)8 o: o/ O9 N" ^3 J* \/ R7 B
  402. * 功能        :                        主设备传输配置(配置CR2寄存器)
    4 K* [" b0 t( x6 t* B& o
  403. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;TransByteCount:需要传输的数据长度;EndorReload:自动结束还是重载设置,见IIC_RELOAD_END_MODE;StartAndWR:开始读写控制,见StartAndWR
    - p+ ~3 v5 h! L  _
  404. * 返回        :                        无5 L/ @5 V, Q: ^5 j
  405. * 依赖        :                        底层宏定义$ Y5 g$ x) W8 t
  406. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>0 O$ w# C% o, H- d% M& }
  407. * 时间        :                        2020-02-15% X9 S- \/ m0 b8 \' S7 c+ B* V
  408. * 最后修改时间 :         2020-02-16
    1 }) G! v1 |$ d, P. r& E
  409. * 说明        :                         在往 NBYTE 中设置最后一次传输的字节数前,必须把 RELOAD 位清零便于后续自动发送STOP。
    - ^) k+ D" p0 L0 t
  410.                                         当 RELOAD 位置 1 时,AUTOEND 位将不起作用;! e* p+ i/ p2 ?. F( G1 }: I
  411. *************************************************************************************************************************/  
    3 B# f1 _0 M- n6 N8 q8 P2 s
  412. static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)2 _' I& V: c& z
  413. {
    6 L5 R  P' G* I: F8 T% P# o) b  x
  414.         u32 temp = 0;
    ! n( ]6 F/ K; e; f% D
  415.         8 p  J7 l% m4 d. A1 O- y  d
  416.         //先读取CR2寄存器的值0 Q& E' t2 ^' u0 m
  417.         temp = pHandle->I2Cx->CR2;
    ) R, J3 W# D8 Z0 d, w% T
  418.         //清除掉相关的字节0 }' D: R$ ~: r9 y2 c6 F( |
  419.         temp &= (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND |I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP));  N) B; w- q. x
  420.         //生成配置数据( w9 m: ]& X( N. R
  421.         temp |= (u32)(((u32)SlaveAddr & I2C_CR2_SADD) | (((u32)TransByteCount << 16 ) & I2C_CR2_NBYTES));
    + z1 b$ Y# r, F$ W  M1 c4 j4 Z
  422.         //重载与自动结束只能二选一+ a, _  F& m# H! J8 {9 {6 ~4 j
  423.         if(EndorReload == IIC_AUTOEND_MODE)         . N( p% S5 n2 H5 T" ?' ?
  424.         {
    ) x8 ?& W5 h  ~, u' W
  425.                 temp |= I2C_CR2_AUTOEND;        //自动结束模式/ }% o& x. \* v: n) t
  426.         }9 T6 p) h3 r' n+ |. l: y+ y  V
  427.         else if(EndorReload == IIC_RELOAD_MODE)2 E! ]3 V$ N0 P( o# ?8 G+ i  ~
  428.         {
    $ k: w9 E3 L2 B
  429.                 temp |= I2C_CR2_RELOAD;                //NBYTES 重载模式
    ( `1 a7 f! _- T6 A3 |" e6 x
  430.         }
    , c2 p) ~; d- Z$ h3 i: A7 U2 p9 r6 F, t
  431.         , M: e* v' {( g+ u$ H
  432.         switch(StartAndWR)4 A1 h8 Y9 T6 d* {! Z+ B
  433.         {$ ?0 f; C; C! b4 s# O7 j/ A
  434.                 case IIC_NOSTART_WRITE        :        break;        //没有开始的写-默认就是这样的
    3 ~) e, Y. ~, q' j2 e
  435.                 case IIC_NOSTART_READ        :                        //没有开始的读-用于后续数据读取$ c) }: _5 ?# Z% k
  436.                 {
    * |- N2 k# s8 l* k* B- x" q
  437.                         temp |= I2C_CR2_RD_WRN;                        //读取
    # @( R1 m1 W6 y' e; U2 c
  438.                 }break;
    ' {1 {( G: |3 f6 Y- R
  439.                 case IIC_START_WRITE        :                        //生成开始写
    ! H7 |6 e7 q* W( `3 I
  440.                 {
    7 J+ b8 J5 j" H. A  I; G# d1 j
  441.                         temp |= I2C_CR2_START;                        //启动传输- W5 i5 U% {; A% M( M/ f3 z
  442.                 }break;
    1 j6 y& w6 K5 \1 ~& ?7 t
  443.                 case IIC_START_READ                :                        //生成开始读        4 G( P& S( a' t/ S9 ?3 F& B
  444.                 {: \' M+ M6 n3 b5 \8 @. e# X8 g0 g
  445.                         temp |= I2C_CR2_RD_WRN;                        //读取
    ) U' D* X; N- f
  446.                         temp |= I2C_CR2_START;                        //启动传输
    " f9 _4 G. h' n, B6 ?
  447.                 }break;
    / D# n% c. Z  }. v8 }/ j7 m
  448.                 default:break;
    $ b/ Q* L  B% `& M
  449.         }5 F9 Z3 y- P/ @4 X
  450.         
    * G" g- P$ ?6 ^
  451.         //uart_printf("准备写入CR2=0x%X\t", temp);  G/ s1 q2 t8 ^. I; B0 l
  452.         //更新到寄存器
    % c' K. U% ]; N- w$ m5 P
  453.         pHandle->I2Cx->CR2 = temp;  //测试" A9 g! K8 Y2 w
  454.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    " U% z+ Q* N$ |3 j8 S; ?
  455.         Delay_US(100);
    . w7 J( M: o7 q  ~% R7 M
  456. }
    : ^  i- h5 i6 x* Y, g( ]
  457. - b: `( ?& }" N5 X" F$ O* t

  458. 6 n; V4 j" l" P" X8 Z& R* K
  459. /*************************************************************************************************************************
    + Y' F) w8 u" ]% F
  460. * 函数        :                        static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)6 k' b+ _0 q: U6 u8 }
  461. * 功能        :                        IIC发送一字节
    ) i2 i9 x+ `. v7 J
  462. * 参数        :                        pHandle:句柄;data:待发送数据;TimeOutUs:超时时间,单位us4 c& M5 R! E* |; y! ^% W
  463. * 返回        :                        IIC_ERROR
    0 V6 @# Y" @! T* M/ e7 Y+ d- u
  464. * 依赖        :                        底层宏定义# `: [( \) D$ [8 t7 q
  465. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    - N( k# d6 L! l2 A0 Y
  466. * 时间        :                        2020-02-15- f! {% q0 ?- X+ q# R
  467. * 最后修改时间 :         2020-02-16
    6 K  w! S( G2 {
  468. * 说明        :                         TXIS有效后才会进行数据发送,不会检查数据发送是否完成。
    & _! H  i3 o3 m! n
  469.                                         如果最后一个字节发送完成后不会再触发TXIS中断,只会触发TC中断# B! F( A! M+ i  N, c
  470. *************************************************************************************************************************/  
    ' _) e( l% N, n- \$ M: {
  471. static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)+ U! D( U% `, D9 m; G) A
  472. {
    ! y* l+ c7 Y  K) w% C; v
  473.         IIC_ERROR Error = IIC_isWaitTXIS(pHandle, TimeOutUs);                                //先等待可以发数据8 Q9 B3 \, c" i) e' d+ _4 g; Z: F; Y
  474.         if(Error != IIC_OK) return Error;
    : J* n# k% V. P2 X& q) J& K% S* L
  475.         pHandle->I2Cx->TXDR = data;                                                                                        //写数据到发送寄存器-不会等待数据发送完成        : @! ?$ i  y& Z+ Y) i

  476. % y: D8 `9 C5 }0 F
  477.         return IIC_OK;% i! [2 `" A9 n5 _/ R" _
  478. }. W/ r* a3 l* u
  479. 4 J9 L6 y, d# N8 }6 s  z
  480. /*************************************************************************************************************************
    . ~5 W3 k( {4 H3 i% A& K* N
  481. * 函数        :                        static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    & `! r- H& Q+ g8 ~+ F
  482.                                                 bool isRead,u32 TimeOutUs)
    9 n- t! b+ K' r4 \1 w+ C. R' s
  483. * 功能        :                        主设备请求发送从机地址与目标寄存器地址4 O8 A+ u2 O8 s/ ?/ ~7 s* m
  484. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;RegAddr:寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,/ i0 G9 D8 H) C6 \5 ?4 K: b6 G
  485.                                                 FALSE:16bit寄存器地址;isRead:TRUE:这个操作是读取寄存器;否则是写入寄存器;TimeOutUs:超时时间,单位us6 T, C  o( w& y$ G  A5 \. |8 @
  486. * 返回        :                        IIC_ERROR
    ' a3 v1 R( T9 T/ R2 w
  487. * 依赖        :                        底层宏定义! J" V8 a/ s2 D. Z$ A2 i; }
  488. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ! g( c( N& D. J7 K* Y# `
  489. * 时间        :                        2020-02-158 o9 Y5 M( D' d) K$ L4 y
  490. * 最后修改时间 :         2020-02-16) e* b, q0 L$ d: K) N
  491. * 说明        :                        
    ' N8 O' s4 m: L
  492. *************************************************************************************************************************/  
    4 J: t9 x* ^; N7 Q7 D/ V4 p. C& b
  493. static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,bool isRead, u32 TimeOutUs)/ n- `, o9 q% ^/ [% {6 n% A, ^! f! y' {
  494. {        
    8 n8 x1 c& E7 I+ _
  495.         IIC_ERROR Error;
    8 ]7 f  `& G  p
  496.         7 Z6 Z; q8 k6 t4 A  n
  497.         //uart_printf("WriteAddr1:CR1=0x%X\t", pHandle->I2Cx->CR1);
    - l% @/ r1 {5 q+ e3 E
  498.         //uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    8 k2 q% L/ @8 s- ]( N
  499.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);4 p1 ]5 y# ^3 |  p! A0 `+ G! V
  500.         //传输配置,并启动传输,发送起始序列,开始IIC传输了
      j& V- z) F# s9 t& s
  501.         //如果是读取则使能软件结束,如果是写则是自动重载
    7 D2 k. ]2 ]- p* T: s. r' J/ ?( a
  502.         IIC_MasterTransConfig(pHandle, SlaveAddr, (is8bitRegAddr==FALSE)?2:1, (isRead)?IIC_SOFTEND_MODE:IIC_RELOAD_MODE, IIC_START_WRITE);        //传输相关配置-写,并启动传输
    ) J4 X% D9 n+ n9 k5 f' k* E- i
  503.         
    8 }2 A7 ]* Z- ~9 n+ @5 Y
  504.         //开始发送寄存器地址
      w# I4 q6 v7 ^# J1 B8 Z# U
  505.         if(is8bitRegAddr==FALSE)                                                                                                //寄存器地址是16位的,IIC通常是MSB高位在前,需要进行高低位对调
    $ C5 k9 o! C0 h. q) ]3 p
  506.         {2 u5 J& q: j* P
  507.                 Error = IIC_SendByte(pHandle, RegAddr>>8, TimeOutUs);        //先发送MSB-非最后一字节; Z7 t+ g7 ^% ]) m+ H# q
  508.                 if(Error != IIC_OK): f8 K/ W9 G' t
  509.                 {
    ( i7 e$ Q& U; p+ A! @- M- A. v9 V' V) X
  510.                         DEBUG("IIC发送寄存器地址MSB失败\r\n");
    ; t. [  B  Y: Q; B  I
  511.                         return Error;
    & ?4 G# U) \' V2 W; b1 [
  512.                 }        
    ! ~; V) u$ ^" }
  513.         }1 P" Z0 o/ T( s6 d2 W( s) a3 X- [
  514.         Error = IIC_SendByte(pHandle, RegAddr & 0xFF, TimeOutUs);        //再发送LSB-最后一字节- j! n0 w  G$ B& j8 e! ?5 s
  515.         if(Error != IIC_OK)
    5 f/ P# r6 m# y
  516.         {6 e# y! A6 ~. S' ?/ E7 a3 Z4 ?
  517.                 DEBUG("IIC发送寄存器地址LSB失败\r\n");* N6 O9 ?( r" I4 H: M) f
  518.                 return Error;, o! O) K! |, m8 N: M% r
  519.         }
      H) p& j( c4 a) c2 D5 T
  520.         //等待全部数据发送完成8 A" V# M% P; }
  521.         if(isRead)        //读取方向-非重载,等待数据传输完成 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。
    * P/ }2 ~; c8 F6 P" |
  522.         {  C# F. Q0 }2 _/ F
  523.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TC, TRUE, TimeOutUs) != IIC_OK)+ B4 ~1 f  `' u
  524.                 {4 y6 t6 S" |/ [# J
  525.                         return IIC_TIMEOUT;* @7 {9 [$ \- P. w5 d1 I& V) c# W
  526.                 }9 C0 E. P3 [/ ^: N2 s$ ]
  527.         }        9 p' a/ {' f# C" u* K
  528.         else //写入方向,等待重载
    + @- W/ R6 A( R$ i" P6 b
  529.         {
    0 {0 `8 [! z) H, ^- _# n
  530.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TCR, TRUE, TimeOutUs) != IIC_OK)
    ) |8 O) i5 k3 p- p# b: s- Q
  531.                 {
    - ^! `/ q. T8 l" H0 u
  532.                         return IIC_TIMEOUT;2 _3 ?1 f# |5 T6 w- O* x0 V
  533.                 }
    ; C1 N/ V! J3 H
  534.         }
    & X- v* `& F, U8 j6 d5 [( M* _! n5 x
  535.         
    : m. B5 P, t. r! ^8 b5 |  N; }
  536.         return Error;
    ; ^6 A! h, x, G! \: Z* t
  537. }
    - B- X) I& N$ C5 |( b

  538. 1 |# o4 H: n( n6 e) |; {$ g

  539. ) w  K1 u4 e: b7 f
  540. /*************************************************************************************************************************7 m" c! F( f3 m' e, k0 A
  541. * 函数        :                        static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)5 r4 V6 V/ l7 N4 z' ?
  542. * 功能        :                        等待接收一字节数据% j2 K, N$ [. T" M2 W/ A
  543. * 参数        :                        pHandle:句柄;pData:接收的字节数据缓冲区;TimeOutUs:超时时间,单位ms
    # Z" S7 n; `8 k, a* w9 I
  544. * 返回        :                        IIC_ERROR
    6 s& r7 M* s/ s  {  [0 _4 N9 c4 t: ]
  545. * 依赖        :                        底层宏定义3 d! H$ ~1 w. g8 s; A; q
  546. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>8 Y% L1 z( ~( e( H! V6 v/ u
  547. * 时间        :                        2020-02-15! m, ]- ~) [/ O+ I
  548. * 最后修改时间 :         2020-02-15
    ' r: f( d4 d; }* h3 T/ E" u
  549. * 说明        :                         当RXNE有效后读取一条数据,否则可能会超时9 y" g/ c7 }/ Y  N
  550. *************************************************************************************************************************/  9 c. C# N+ d+ w  e
  551. static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
    5 `+ F4 X& [4 C. c4 V0 t5 W
  552. {4 v& n" s$ v8 S
  553.         while((IIC_GetISR(pHandle) & IIC_FLAG_RXNE) == 0)        //等待RXNE有效
    ; s% U/ K  s# [" _; C0 F
  554.         {
    1 c1 N( n) t7 n& V
  555.                 if(TimeOutUs == 0)                                        //检查是否超时了
    3 c% Z+ d* C) q$ u
  556.                 {2 L- v$ ]# H" e9 t0 a4 \
  557.                         DEBUG("IIC等待接收超时\r\n");  e0 Z, [5 N+ D1 \# c3 {, |
  558.                         return IIC_TIMEOUT;                                //超时
    " J! }+ R% w4 x. `
  559.                 }                        1 b# |; b, E, Q; T1 f" O
  560.                 TimeOutUs --;
    7 \2 R/ F9 Q' r% N: H; `) z  L( s! Q
  561.                 Delay_US(1);                                                //延时
    ; p: F' A2 ]; }
  562.         }
    + B) N* B& g: l: x3 Y
  563.                 # X" _: O* m/ f$ n
  564.         *pData = pHandle->I2Cx->RXDR;                                                        //读取收到的数据4 m+ N  a4 \8 O8 I4 I' A4 K% c) O- k
  565.         return IIC_OK;% u9 K9 E- \7 a/ t2 A
  566. }! R7 o; |  }/ @  Z
  567. 3 V( O4 q/ H0 u6 f! z

  568. # R" [6 d! N6 s
  569. /*************************************************************************************************************************
      S( c! J0 Q  i$ K& a
  570. * 函数        :                        IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, 4 R. p- d' ^$ q  D9 e: P$ B
  571.                                                 u8 *pDataBuff, u16 ReadByteNum)' D: k8 C* H5 ^9 f7 ]6 A1 E5 e
  572. * 功能        :                        IIC读取寄存器(可以读取1个或者多个寄存器)% n8 P- G' J" }7 V
  573. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要读取的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;
    ! S$ y% f; M1 c; I& @, D
  574.                                                 pDataBuff:接收的字节数据缓冲区;ReadByteNum:要读取的寄存器数量;
    1 Q5 a9 G7 g: j/ a' y- e3 \0 d0 T
  575. * 返回        :                        IIC_ERROR
    7 x+ i: J8 ?$ ]. `
  576. * 依赖        :                        底层宏定义7 q: |) J3 k6 s5 }2 p/ z+ S- u* r
  577. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    , w' J9 M* X5 S1 ^7 @2 O3 A
  578. * 时间        :                        2020-02-15& r0 ~8 F% \+ O+ h3 H/ k
  579. * 最后修改时间 :         2020-02-15
    - @$ P9 Z0 I8 u% l2 V7 D* m9 {% P2 t" k' Z
  580. * 说明        :                         读取的数据都是小端模式,如果是16bit的寄存器,请读取偶数个数据,并且需要另外进行高低字节对调最后组成16bit数据
    3 d" U. u( x, ]2 r  F/ [' n
  581.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
    6 y. j' ]$ y0 s4 X6 R4 a1 @* p
  582.                                                 增加信号量
    9 g. |3 A& v- Z3 w4 q
  583.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在' U. e6 E) {4 Y  A$ R: I* D# b- Z
  584.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。2 _6 P+ H# w. H$ a
  585. *************************************************************************************************************************/
      l8 r+ o) x3 R5 i5 ?% i& C
  586. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum)- q9 P2 S1 B$ L8 y! f
  587. {
    ) H" r% C/ B  Z6 o6 ]: E, \
  588.         IIC_ERROR Error = IIC_OK;/ Y9 V5 J! ^$ M5 X
  589.         u16 ReadCount;
    ( q+ U: G) h$ R8 ]' g* J( I
  590.         IIC_HANDLE *pHandle;( `0 b1 N3 J, G. H/ t1 [/ e
  591.         $ f$ c1 K- {5 ]; `
  592.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || ReadByteNum == 0)/ ?1 g' S' K- B; d: S
  593.         {
    / p+ A) ^! P; O5 R- m8 Y+ v
  594.                 DEBUG("IIC错误:无效的参数\r\n");
    ! f( @: t+ K3 q
  595.                 return IIC_PARAMETER_ERROR;
    ' Q2 B7 e% f. h
  596.         }3 z" u9 F8 l& k9 g) ^. Z
  597.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄- U1 k, q; W" o8 J  C( \
  598.         ! k; e, j" }) U4 w/ U
  599.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙+ X& ?: d' C  A2 p: \
  600.         {
    4 M: z- N9 l' R
  601.                 IIC_SoftReset(pHandle);
    4 {# {2 j$ d; i0 D  ]3 k9 R
  602.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");
    ; b: S" W& r, n$ k! q: E4 |
  603.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙
    , b4 O0 p6 ?# L; h9 D0 N) a* R2 h- o
  604.                 {
    * k5 {, `: C' T  ?! p
  605.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");8 h& H( _8 p  z9 f; @
  606.                         Error = IIC_BUSY;+ a* ^: F. E8 T$ H" m, k+ Z) i
  607.                         goto end_loop;
    : ]+ ~7 H& X5 ?7 \! X& _
  608.                 }1 ~  j; {7 G$ N8 P: @
  609.         }
    ' m. t7 ]5 l, y( R% C
  610.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态' b' c# ~) a( o5 k2 g! o
  611.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器
    # N( _+ O2 Q. J" x3 @. o
  612.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    % C" _5 X% N7 O
  613.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,TRUE, pHandle->TimeOutUs);  u4 V& Y9 D4 u+ q) X! K
  614.         if(Error != IIC_OK)" X) T- z* i$ r) h8 A' D
  615.         {
    + c. R: C2 A; [% z: |
  616.                 goto end_loop;7 P7 V! q, G4 d( k2 m9 t! ?: d7 X
  617.         }
    " O  q+ W0 P  i% \" Q2 r: q" _  s
  618.         //发送后续数据+ o7 ~- I% J1 T" p4 m7 U  [1 g
  619.         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取-后续还有数据,需要重载
    + r3 M. g7 ]! t  Q% S, j2 ]
  620.         {
    ( v0 q2 }' V$ y4 J5 J
  621.                 ReadCount = 255;        //本次需要读取的数据长度255* s' D, E: j' R- c9 g: n
  622.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输                ( c4 u' p) C* m% o% n" U
  623.         }
    2 Z# z% [' a/ ]+ Y3 f+ e
  624.         else0 x) {2 N; G  n6 g4 ~# v6 N
  625.         {9 N5 B- J" x! _* }' \
  626.                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯后自动结束
    # w/ a1 ]4 O& E) Y; D- d4 P
  627.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输
    % Z; O9 h6 ~; ?0 |0 {8 R' y: q, Z
  628.         }
    ; K# L/ c0 s+ o  x& A
  629.         ! A' D1 d- O: W7 D( g3 y, y
  630.         //循环等待接收数据完成
    3 D. u, i) Q) B4 @3 t
  631.         do
    2 X- T2 I( G! l5 m% A
  632.         {" Z+ F+ o) _2 V, J. r3 M" m
  633.                 //uart_printf("读ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    0 M7 f9 J4 E% d$ e2 p
  634.                 Error = IIC_WaitRxOneByte(pHandle, pDataBuff,  pHandle->TimeOutUs);                                        //接收1字节数据4 c% s3 T' h9 N1 V8 ?" G
  635.                 if(Error != IIC_OK)
    , T& d" W3 b" r0 c0 |7 ~% _8 y
  636.                 {
    8 N# l1 O$ p( `  X
  637.                         goto end_loop;
    ' f( P$ P# K, b+ B
  638.                 }
    - v- `. ?* G% X7 K5 V! b- f) {  ?7 g
  639.         7 O$ k  o+ F6 i9 k; T
  640.                 pDataBuff ++;
    + {- q  {. \: m1 W  ?. `/ h
  641.                 ReadCount --;, D$ F/ ]1 I$ i4 S4 D
  642.                 ReadByteNum --;* d( |' u4 l) P0 {) K: L3 N! b
  643.                 if((ReadByteNum > 0) && (ReadCount == 0))        //还有数据要读取; P3 {* J4 [: J* r) E0 ~  i
  644.                 {
    $ J- l+ }8 @& g1 L2 `
  645.                         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取
    , C7 x9 h6 M1 u" R% G' o
  646.                         {9 ~! i: K  H. p' G2 s$ y3 U
  647.                                 ReadCount = 255;        //本次需要读取的数据长度255-后续还有数据,需要重载% D8 j: z/ b# j" b% M) q" s
  648.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
    $ L% s! ^/ s9 o2 L% H
  649.                         }! l1 s3 o$ d" }
  650.                         else" g- L1 `+ N$ H% x1 u( h; R. M
  651.                         {* W- g9 Q, s; |8 X" p; Q
  652.                                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯,自动结束
    ) m% @; f# {/ f/ W# Z" N
  653.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
    - {7 \# U/ f/ J- o9 i+ N
  654.                         }) M, i, i; f- z5 O2 f; r
  655.                 }
    : g8 x) i$ r$ k( k) h. c5 F
  656.         }while(ReadByteNum);) i, `1 X: S, k% {6 }/ R' {5 w5 T2 c
  657.         //读取完成了,等待STOP位有效' u" f; c* N/ k; o# j5 D/ Y
  658.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);
    1 v% Q3 C' f; p8 E
  659.         if(Error != IIC_OK) ) ~! c+ P& `. L% i: i, m
  660.         {
    2 ]# ~) Z" \( L( o  V1 s' V6 }
  661.                 Error = IIC_STOP_ERROR;
    & a6 o- L- E  n( g. p/ X- |; o  ^
  662.                 goto end_loop;& o9 @7 N. x) S7 L, ?
  663.         }        , y" ~/ b0 O0 J' T
  664.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态( \" T4 }, j6 r/ O% ]$ _6 U5 {% L+ L
  665.         
    " h( t3 U/ Z. ]; C8 b3 l% ?
  666. end_loop:        
      ]) L; s: Q0 n) F* _1 \
  667.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        3 g) o, S0 ~' p2 i* k
  668.         if(Error != IIC_OK)
    5 l; \" K5 @* F
  669.         {. l+ L9 s, n+ _
  670.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误0 a/ \' J6 Q& s' ^/ R
  671.                 DEBUG("[IIC R错误]:%d\r\n", Error);" r" M0 J' }9 `+ j
  672.         }
    6 v0 h" \# U, R, @4 ^: p
  673.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的# P! {: B$ w6 x3 n8 \  J" u( e
  674.         {
    - p+ r6 w5 H# f* k7 E2 k2 {
  675.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    0 ?; l5 X/ V- f  R
  676.                 DEBUG("IIC R结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);                : C/ W" H0 @0 J2 F6 a
  677.         }- x# V' }% I! f1 r: P4 F3 }
  678.         
    2 ]8 X1 u9 \5 S2 E: ?/ H
  679.         return Error;# `7 E% n3 o6 o% R- z% P
  680. }
    ' `& H: K" X* R2 _% O. c9 g9 p' o
  681. 7 u4 }: C- N- Y% I  e, ^5 a# k, ?

  682. % t/ [! h* i: H% G
  683. /*************************************************************************************************************************
    5 G4 ^) |/ X1 G) j. x, |9 v7 t
  684. * 函数        :                        IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    + {: |0 x+ E% w# ]/ A" |! Y, n
  685.                                                 u8 *pDataBuff, u16 WriteByteNum): C6 U' a( Q1 v! f3 n4 A( |, m
  686. * 功能        :                        IIC写寄存器(可以写1个或者多个寄存器)
    7 C' Y5 O  R8 B
  687. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要写入的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;- H; q2 Q/ j5 }7 i/ w. k& K& v
  688.                                                 pDataBuff:写入的字节数据缓冲区;WriteByteNum:要写入的寄存器数量;! u7 u$ |+ H% N6 w7 n8 X# _
  689. * 返回        :                        IIC_ERROR7 ^/ y" ~0 l2 U3 J/ i6 G6 @! A! g
  690. * 依赖        :                        底层宏定义
    - \5 y( Z( g* C# ]% r
  691. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>0 g+ C5 }; c& ?  V" ?" |+ q
  692. * 时间        :                        2020-02-16( ~8 ^6 f; F$ W, @0 |6 J1 k7 J2 M
  693. * 最后修改时间 :         2020-02-16
    , o4 F% Z. ]( [
  694. * 说明        :                         写入的数据都是小端模式,如果是16bit的寄存器,请写入偶数个数据,并且需要提前进行高低字节对调最后组成高字节在前的数据buff" b) Y& G- s2 |! w2 r; l
  695.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
    : U- S4 \. q& q# r3 j
  696.                                                 增加信号量! R8 b, h8 |1 y  R- f2 j8 R
  697.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在. B9 O: _. u9 G7 H4 {. D
  698.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。
    ( [; _2 ~, E; O8 n% W5 \- s0 k
  699. *************************************************************************************************************************/# B- A4 t" ~( V) l! n+ X3 [
  700. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum)5 _- M! z+ {3 K- R4 u
  701. {
      x+ u/ q' ?7 i, A7 z$ @' w4 a
  702.         IIC_ERROR Error = IIC_OK;6 r4 d7 U/ @2 y. Q- ^
  703.         u16 ReadCount;# o& K7 w3 U( y) v# K6 j; J4 s) g
  704.         IIC_HANDLE *pHandle;, I" T! J! r' c% y. T9 C7 r, s, p
  705.         1 b- x9 h7 G3 m6 v. b6 B
  706.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || WriteByteNum == 0)
    * [: i  n9 ~4 U# p
  707.         {
    5 ?1 M4 O) {1 H- }2 y" L' _% W! a
  708.                 DEBUG("IIC错误:无效的参数\r\n");1 g+ r" H3 D( @" ~" _
  709.                 return IIC_PARAMETER_ERROR;) l2 U- L! e2 K
  710.         }
    4 N1 a' [) E4 o, ]
  711.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄
    : a3 u4 y% E% n1 Q
  712.         * B( I$ Q/ @  c# k
  713.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙$ J  e$ s- B, c. w, y6 h
  714.         {0 z! g% \9 R: [$ K5 o9 r( i
  715.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");
    3 z+ [& F; V+ `
  716.                 IIC_SoftReset(pHandle);0 {( n8 r. m3 B* A
  717.                 9 w4 S# Q- [6 R* U4 ^3 {: z
  718.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)        //忙
    : ~2 G" T2 c! h% H" ^0 ^+ k
  719.                 {) a/ }8 o7 N) |- L' ?
  720.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");
    % _" U7 w' Y3 o. V6 v& s
  721.                         Error = IIC_BUSY;) H# \3 e  \: J1 s+ V' q
  722.                         goto end_loop;
    8 @2 m3 k" l  x+ Y
  723.                 }7 t1 \4 N2 x6 }9 q
  724.         }
    . S) n: E/ Y3 Y3 Q- m
  725.         
    2 E+ b% z" C% B- i( ~. U: |  Z
  726.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态0 ?9 R( {' u( }) t+ y, i5 D
  727.         IIC_ClearCR2(pHandle);                                                //复位CR2寄存器
    $ c" s& g0 C% R0 u
  728.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    0 |8 j3 M7 U! f: \
  729.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,FALSE,  pHandle->TimeOutUs);) I. l# T% k) q1 z# C
  730.         if(Error != IIC_OK)
    * U& d$ |0 g: L9 R2 b
  731.         {. B; w' t/ i9 V5 \- d5 X
  732.                 goto end_loop;0 \4 @: \7 s. R! b8 v
  733.         }
    . W5 x3 g! S8 s  J0 l2 m% M6 O1 l
  734.         //发送后续数据$ _. W7 R% e5 z1 i% j% O/ l
  735.         if(WriteByteNum > 255)                        //如果超过255字节,则需要分多次写入-后续还有数据,需要重载
    / B0 M9 [+ Q7 I5 j4 c
  736.         {
    ; M) I: U& D  A4 J; }
  737.                 ReadCount = 255;                        //本次需要写入的数据长度255
    + o9 P9 }$ G) M# S
  738.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入               
    5 M; r1 ?6 l2 |7 ]) d
  739.         }. s& J# h9 [0 l# e, H5 @3 T$ G: J& e
  740.         else
    8 ?* C( P( I2 i. o( K
  741.         {
    ' s$ P2 {; \: \3 G0 a
  742.                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯后自动结束
    0 \; t' S4 e4 `) ^. G( v& R2 [
  743.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入8 v7 e' Y; G( j3 D
  744.         }
    ! O; l6 T  O% }1 H

  745. $ e2 K5 F& g, o3 @
  746.         //循环发送数据7 L& C/ z8 t" P) U3 ?" [
  747.         do
    $ \/ g2 V9 Z) S. P' j' `
  748.         {8 y1 @" B6 O. X: h& e
  749.                 Error = IIC_SendByte(pHandle, *pDataBuff, pHandle->TimeOutUs);        //发送一字节 ' G* t2 Z( T' T2 K5 c3 N
  750.                 if(Error != IIC_OK) 1 _& s5 z7 o, x! U4 ?1 m- ?% `
  751.                 {7 L' I. b: N- x7 [
  752.                         goto end_loop;
    0 z# E  f, K2 h) ]
  753.                 }+ s0 k. a* ~$ {* g. g( o

  754. ! c8 d! N# n1 J  L
  755.                 ReadCount --;& E" t' ^& L1 O5 f0 S0 L/ ]
  756.                 WriteByteNum --;7 N( Z4 J6 p; R+ N% |: ?( r2 c8 E
  757.                 pDataBuff ++;
    ' y) h5 {/ m$ B4 J  w4 }2 x
  758.                 5 d# p/ K2 {- j/ H. [: P
  759.                 if((WriteByteNum > 0) && (ReadCount == 0))        //还有数据要读取
    % q5 v+ C) J* C3 Z7 K8 ^
  760.                 {& V1 c8 p. j  v/ }- ^5 T3 ?1 Z
  761.                         if(WriteByteNum > 255)        //如果超过255字节,则需要分多次读取5 K" F* Y, w" m
  762.                         {" w, ]9 d, ^; e
  763.                                 ReadCount = 255;        //本次需要写入的数据长度255-后续还有数据,需要重载1 `, |- U( J: D6 y/ \
  764.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入
    . c  u, x; e. Y2 K# W
  765.                         }
    : @+ ~5 y& A3 k2 \
  766.                         else
    6 c4 t' G, J# P: R/ q, e  [3 t9 D$ l
  767.                         {
    - }, c1 W% |! _( {3 P( T. F
  768.                                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯,自动结束
    5 H1 O9 C* x8 E: L0 P5 @
  769.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入               
    1 B4 p7 N, N- d9 A; [- s- m- |4 ]
  770.                         }
    * f5 O! d. g8 }4 V
  771.                 }
    2 H, c/ ~$ R* ]+ |+ a! d8 c' ?
  772.         }while(WriteByteNum);        
    ' ]6 M5 {1 h- E, l* [* y! c
  773. & f8 p/ @+ }9 O1 I( K
  774.         //写入完成了,等待STOP位有效
    ( n/ q3 T9 D4 T8 R4 S3 k; M
  775.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);9 |& C4 L) g, V" d1 w( \
  776.         if(Error != IIC_OK) 0 h7 j2 E0 s1 P/ o
  777.         {
    7 I( f& e; }- U5 D3 g
  778.                 Error = IIC_STOP_ERROR;
    - e) m( f5 v3 _2 S7 N) ~& i
  779.                 goto end_loop;$ T. j: V" X, f, T( g) @6 h, p9 o, @
  780.         }
    1 N* r  Z  Y. H2 H+ W
  781.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    - `3 L# X! R- }
  782.         / v0 v* t7 Y) q7 U9 ^
  783. end_loop:        
    % p; r/ M' n( t# l1 U0 b
  784.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        4 n+ W3 X& x- N
  785.         if(Error != IIC_OK); s( d; b% N# O* e  M/ n+ A$ h  z
  786.         {2 Y8 n2 W) Q( ^' F
  787.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误6 K( A1 K( L& n# E
  788.                 DEBUG("[IIC W错误]:%d\r\n", Error);! K" j9 o7 Q( z3 \6 c
  789.         }
    0 [, V* p& A1 O+ t. |% b# F1 v
  790.         
    " o  T% J+ U. g& n8 E
  791.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的+ E# \6 d2 D$ b. Y6 \' Z; a8 I
  792.         {
    ' \! A, U- N0 b4 G) P
  793.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    # o: s  F( s: @: _! g: r4 h% w$ |9 e
  794.                 DEBUG("IIC W结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);               
    . D6 v% t  C! v* X
  795.         }* q; w( Q- A4 |( O( o" W; z
  796.         return Error;$ D& \4 d: F: G2 B# L6 @
  797. }
    0 R( H$ E- I& ?
  798. % H! _* o- L7 M- r) c# ?5 P( p
  799. , \0 f7 c! k. b' i6 k0 V
  800. /*************************************************************************************************************************# E$ k9 B3 i6 C5 ]* u  [- d+ }
  801. * 函数                        :        void IIC_SoftReset(IIC_HANDLE *pHandle)
    4 l% G& N$ `0 W, j; t: P
  802. * 功能                        :        硬件IIC软复位(会使能IIC)
      ]. H$ \, j  U( D% B" n
  803. * 参数                        :        ch:IIC通道
    9 Z* N1 {* W" I5 l  g# }
  804. * 返回                        :        IIC_ERROR
    / M" w7 t4 ^% f* w1 H
  805. * 依赖                        :        底层宏定义
    ; b6 ?  u) E$ y5 P' R, ]" b
  806. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>2 x( ^$ c2 n& l  F, B' j9 T3 ~
  807. * 时间                        :        2020-02-15
    9 n- K5 R/ n& {% K( [6 B
  808. * 最后修改时间         :         2020-02-159 p3 w8 m2 K4 A) ]& p' t
  809. * 说明                        :         IIC软复位;必须使 PE 保持低电平持续至少 3 个 APB 时钟周期,才能成功执行软件复位。/ q5 a9 C: e4 M$ M. b, O
  810. *************************************************************************************************************************/
    . L5 v, `4 U8 R3 m" \8 j
  811. static void IIC_SoftReset(IIC_HANDLE *pHandle)
    " B+ z6 A' B' C) w& W
  812. {' l9 [' l* R2 F( r
  813.         pHandle->I2Cx->CR1 &= ~BIT0;                //关闭IIC后执行软复位
    5 K. ^6 }; m7 P" s; t7 t1 @2 z
  814.         Delay_US(1);        
    - t+ {3 d# Y3 {+ I( A
  815.         if(pHandle->I2Cx->CR1 & BIT0)
    - B, F& V& Y% M1 k- e- b; P9 O, K
  816.         {- [1 j1 b. B3 [1 ^5 c5 L) j& R/ R
  817.                 DEBUG("IIC软复位失败\r\n");
    " ?8 M& T" v3 [) p, v# o3 O
  818.         }
    9 @+ r- ~/ V3 B7 [/ N) f" G7 g1 `! h) N
  819.         pHandle->I2Cx->CR1 |= BIT0;                        //重新启动  J4 k, W! y. D8 G6 Z
  820.         Delay_US(1);        
    6 b+ t3 l: b+ v- D8 P6 l1 ~
  821. }/ ^4 J; n1 }- M  T1 A: Q4 O6 |
  822. 6 W* Y6 d6 ]$ P# r8 z& x
  823. ' ?" _( F2 `" O7 F* X
  824. 2 N$ _% h" o0 @7 u/ ]' M
  825. /*************************************************************************************************************************
    5 G  Z9 K! b3 p8 B' v( U/ `
  826. * 函数                        :        static u32 IIC_CalculationTiming(u16 Speed_KHz)
    " w, ~% \0 S" n1 s& L
  827. * 功能                        :        硬件IIC时序计算6 C/ K5 D3 p+ @/ f' y5 c
  828. * 参数                        :        ch:IIC通道;Speed_KHz:速度10-1000
    / X3 l' N0 K2 }# O
  829. * 返回                        :        IIC_ERROR; m8 F1 h% c2 u& J
  830. * 依赖                        :        底层宏定义
    : C" a2 ~9 e/ _9 a; I5 F% Q7 \
  831. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>/ G- h2 ]7 ~. u2 ?
  832. * 时间                        :        2020-02-15
    . `7 G- g" u$ r, \
  833. * 最后修改时间         :         2020-02-15) K* w7 s7 s6 \3 w6 S% F$ D
  834. * 说明                        :         IIC使用的是APB1时钟,将IIC总线时钟控制在100KHz        
    ) x4 I8 o- u( @' F( B
  835.                                         APB1时钟:最大不能超过45MHz        
    6 g( W. O' A' {6 D0 n9 Q
  836.                                         如果速度是100,则按照SMBUS时序
    ; @: f8 Z1 q! \5 ]. m
  837. *************************************************************************************************************************/
    6 ^. Y& x0 M$ i) E6 f
  838. static u32 IIC_CalculationTiming(u16 Speed_KHz)
    # H2 c, Q6 O/ l7 p( T1 U% m
  839. {
    5 ^0 g0 b* ]- W2 u& U! [' J9 @
  840.         u32 tTime = 0;4 u0 e8 n; e5 l+ u% r2 P, p
  841.         u32 temp;0 z% z5 X0 y8 \0 x+ c, r
  842.         u32 time_temp = SYS_GetAPB1ClockSpeed() / 1000000;                //先获取APB1时钟速度
    - r( ?* d! x/ u6 H1 ~. y
  843.         u32 Th = 1000/Speed_KHz/2;                                                                //计算高电平时间(低电平时间一样),单位ns
    8 Y# e( b2 [  V6 s
  844.         
      E% u3 j- m7 F  n/ e
  845.         if(time_temp < 20) time_temp = 20;
    . V5 }, o# T; A6 A9 b3 q
  846.         time_temp = 1*1000 / time_temp;                                                        //单位ns( W8 f, s$ \8 x6 x6 @- L
  847.         uart_printf("IIC时钟计算->APB1周期:%dns\t", time_temp);- H$ @. h, K6 l' g
  848.         if(Speed_KHz == 100)        //如果是100,则按照SMBUS时序3 B, C' h  @: M, e- C
  849.         {1 q% ]: L5 l8 A  [$ ?; |
  850.                 //主时钟分频系数固定为3
    ! v/ x! B$ B+ t& v% Q
  851.                 time_temp *= 3;                        //主时钟周期& C% W, f6 C" Z2 q: ~$ h" s
  852.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    $ I0 }8 y; S5 ?7 `2 k1 {
  853.                 tTime |= (3-1) << 28;        //PRESC,时钟预分配
    3 }8 z! ~4 H/ D/ v  L
  854.                 //计算数据建立时间,要求最小250ns1 b) o0 T5 k3 U
  855.                 temp = 250 / time_temp;6 ]; h; N9 V) u' L/ M) o
  856.                 if(temp > 15) temp = 15;7 Q5 D, M! c& {; I# ^% h9 ~
  857.                 if(temp < 1) temp = 1;
    : R: i. n  k% A" D8 U- g
  858.                 tTime |= temp << 20;& |- \+ z, `& }
  859.                 //计算数据保持时间,要求至少300ns
    6 `( _+ U& i  n7 E1 o" c2 e
  860.                 temp = 300 / time_temp;! d3 j2 i/ x% H+ Q0 H
  861.                 if(temp > 15) temp = 15;
    6 E, c+ r8 |+ @6 U+ c; k# l
  862.                 if(temp < 1) temp = 1;
    / ?; p/ Z) T* }0 s, a6 q1 N
  863.                 tTime |= temp << 16;
    + f( O* ~" t# a" P( N
  864.                 //计算高电平周期5us
    + f# i8 Y* H. `! g0 t( S5 ~4 T% T
  865.                 temp = 5*1000 / time_temp;7 Z3 I: |# D% A: O6 G" H
  866.                 if(temp > 255) temp = 255;
    - t, o. [- M& c" q5 l" `! x) Z& J% ?& J
  867.                 if(temp < 1) temp = 1;
    4 R. q" v; |" j1 h" [
  868.                 tTime |= temp << 8;2 G( }9 l( }/ O+ V1 m
  869.                 //计算低电平周期5us7 N: N* n: X2 I  Q" }
  870.                 temp = 5*1000 / time_temp;5 h: F6 T# L7 B9 i* k* ]- F7 t
  871.                 if(temp > 255) temp = 255;0 {. v0 W( L2 c' ]$ q
  872.                 if(temp < 1) temp = 1;  \" e2 K3 B  q* B, z0 ~
  873.                 tTime |= temp << 0;" n8 d/ ?9 K; E1 Q% h9 ^
  874.         }
    8 D4 S) v4 u2 ~- U. r7 u3 I# y0 x
  875.         else if(Speed_KHz < 100)
    $ ]4 ~8 m5 u; [+ b" a
  876.         {
    # t( |; b! i2 a2 Y# X) s
  877.                 //主时钟分频系数固定为6# ?9 U2 r, w+ P8 z
  878.                 time_temp *= 6;                        //主时钟周期! {: a. N( E9 v$ ]' a) G& [* S
  879.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    $ u( D! l& N, R  Y$ \( G
  880.                 tTime |= (6-1) << 28;        //PRESC,时钟预分配
      a2 c$ H" O3 D6 d
  881.                 //计算数据建立时间,要求最小250ns* b6 `$ C  O* ^9 ~
  882.                 temp = 250 / time_temp;
    0 G7 G; v- `: m! O$ E; C# {7 J( p$ u
  883.                 if(temp > 15) temp = 15;
    3 }( ?1 Q) C" R0 d5 T( P
  884.                 tTime |= temp << 20;
    2 ~6 J9 A8 Z* x9 E+ O  D' ]* P
  885.                 //计算数据保持时间,要求至少300ns9 D5 j& B' t6 e3 q
  886.                 temp = 300 / time_temp;/ L3 j" r- I8 E  ?* A7 q, E& z1 H: E" s
  887.                 if(temp > 15) temp = 15;
    , H, t0 W, Z5 a  G' k& K
  888.                 tTime |= temp << 16;
    ( I5 b1 a9 ^$ t4 q0 ~* W  i( m& D
  889.                 //计算高电平周期Th us
    9 }  k5 [$ w$ k6 r6 m4 ^2 f6 z
  890.                 temp = Th*1000 / time_temp;/ |( A5 ^. J) z+ I* @
  891.                 if(temp > 255) temp = 255;
    ( ?# v, `- n% d' ~9 i- k
  892.                 if(temp < 1) temp = 1;, B- P: y, t' M  K( i
  893.                 tTime |= temp << 8;
    6 q- ?9 A7 k) Q* w0 e+ t# W
  894.                 //计算低电平周期 Th us" A) g! ^& d9 m3 s4 w
  895.                 temp = Th*1000 / time_temp;
    5 h6 f- Y6 e: o9 _" f/ k6 ]% A
  896.                 if(temp > 255) temp = 255;
    : I3 |, F' Q. z4 F3 U
  897.                 if(temp < 1) temp = 1;1 r/ q; Y4 B% ~
  898.                 tTime |= temp << 0;  c. W* ]0 W$ _- G, T- C4 t) a
  899.         }
    $ R  I; s7 p) V
  900.         else //>100
    1 E3 S  N+ D' k: _7 Z
  901.         {& Z: k+ l. R. ^. l- M8 E% G
  902.                 //主时钟分频系数固定为2; V4 I" B- q, U- f
  903.                 time_temp *= 2;                        //主时钟周期
    , M0 V' p( v/ v$ s
  904.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    , W' p$ C" l+ `3 F# @
  905.                 tTime |= (2-1) << 28;        //PRESC,时钟预分配' h0 j! g3 y2 B8 c
  906.                 //计算数据建立时间,随便给100ns
    ; M" f1 p6 V8 X' h
  907.                 temp = 100 / time_temp;( K( a3 m7 |& o. p
  908.                 if(temp > 15) temp = 15;
    & c# F/ y6 u7 l2 N
  909.                 tTime |= temp << 20;
    & c) p' k3 ]2 k' g) o
  910.                 //计算数据保持时间,给100ns
    1 w1 s  Q9 J6 i- |$ J5 R+ j. Q0 |) }% y
  911.                 temp = 100 / time_temp;% }% B4 B. {# f* Q( g
  912.                 if(temp > 15) temp = 15;
    9 O9 A7 z$ r9 y
  913.                 tTime |= temp << 16;
      J, i+ m! G( x7 A+ k- l
  914.                 //计算高电平周期Th us
    , h' _$ G' W5 P2 n% A4 B, ~" I
  915.                 temp = Th*1000 / time_temp;2 V; Z% P& b) I- k6 A5 r
  916.                 if(temp > 255) temp = 255;- D: s! z; T) {" [# G, j. E
  917.                 if(temp < 1) temp = 1;
    " Y. [5 n9 \  P$ u9 v
  918.                 tTime |= temp << 8;
    : r+ h  }0 C; _
  919.                 //计算低电平周期 Th us9 z0 N0 l% V5 x4 X- c* p9 |* v
  920.                 temp = Th*1000 / time_temp;/ f; a, d: d: q4 q* V: R! y* M9 z
  921.                 if(temp > 255) temp = 255;
    6 _& r. _. }7 i: g- b# X
  922.                 if(temp < 1) temp = 1;
    9 m: s- i8 F7 h0 o, q
  923.                 tTime |= temp << 0;& G# X; y& f- O4 T  i2 q3 F2 z
  924.         }2 c1 o% t& c( O0 t
  925.         
    % W5 P- B  {" D2 {% O1 y3 j* a: v
  926.         uart_printf("时序寄存器结果为:0x%X\r\n", tTime);
    ) o' F3 O- `) j8 q" B
  927.         
    & O+ x: P5 a; x9 s
  928.         return tTime;
    - x9 O  r4 y, E# C* I& A2 j: m
  929. }
复制代码

& C# u( c* ?+ C8 V# x3 b" g
( U3 S0 E0 @3 \  [
  1. /*************************************************************************************************************
    * f2 m8 K* a& p1 R! i
  2. * 文件名                :        stm32f7_iic.h! t+ x, ?8 n  \$ p/ l* o5 [. V
  3. * 功能                        :        STM32F7 IIC接口驱动6 |* u3 K; `- g3 ^. j. ]
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    4 J  z: x0 T6 Z$ G
  5. * 创建时间                :        2020-02-09; Y; [, ~7 ]( u% I* b9 j
  6. * 最后修改时间        :        2020-02-09
    8 s! q3 ]2 q1 @1 q; O  m6 _
  7. * 详细:                        
    0 T9 ]& t% V, ]/ {# I+ v6 z
  8. *************************************************************************************************************/                ; b& N* [# H+ ]
  9. #ifndef __STM32F7_IIC_H_4 C& ^; H4 e: k) K( e# i# I# e
  10. #define __STM32F7_IIC_H_1 ]5 R! \. \# e8 r$ E9 ?8 k& F
  11. #include "system.h" " Y6 Z1 c, u- C: o

  12. ! Y2 _4 s4 Z" R% m6 O  ^
  13. //16位整形数高低对调
    4 u# ~# E7 }, Q8 W
  14. #ifndef SWAP16! Q/ @6 e, G9 M, K3 h2 V7 p
  15. #define SWAP16(x)   (((x & 0xff00) >> 8) | ((x & 0xff) << 8))
    7 E( G9 d1 d5 A, x
  16. #endif  //SWAP16% L% v; l  }# h# r

  17. ! Q# p% ^2 p( U
  18. //硬件IO口选择; g3 N. B" F! V* `7 s" D$ R; Z/ k
  19. //I2C1 IO定义与选择8 N# j/ P6 C5 y# h# M6 F& z
  20. #define IIC_CH1_PB6_7                                0                                        //PB6,PB75 `" h$ E+ I7 e# V
  21. #define IIC_CH1_PB8_9                                1                                        //PB8,PB9
    6 l& |3 s1 E( S: J
  22. #define IIC_CH1_IO_SELECT                        IIC_CH1_PB6_7                //选择I2C1 的IO        
    1 u3 X- ]) m3 N, {5 [0 c- _
  23. 6 H6 S. K8 r3 N; I& K
  24. //I2C2 IO定义与选择
    5 O+ T/ w% e7 c+ [: ?6 e$ H. N
  25. #define IIC_CH2_PB10_11                                0                                        //PB10,PB11; v( x7 J, a2 I7 L  p
  26. #define IIC_CH2_PF0_1                                1                                        //PF0,PF1
    . r% k% ]! w3 D2 q! r) J# M. B: @
  27. #define IIC_CH2_PH4_5                                2                                        //PH4,PH54 q4 A7 v) j; r
  28. #define IIC_CH2_IO_SELECT                        IIC_CH2_PB10_11                //选择I2C2 的IO
    6 X6 E( K+ {# R4 i: p7 ]. l
  29. 7 d: U! d: c; N8 P
  30. //I2C3 IO定义与选择3 r: S/ Q9 F0 X2 p
  31. #define IIC_CH3_PH7_8                                0                                        //PH7,PH8- k' D) u2 x" Q3 w$ ^
  32. #define IIC_CH3_PA8_PC9                                1                                        //PA8,PC9
    * ~" k3 W* N. |, s
  33. #define IIC_CH3_IO_SELECT                        IIC_CH3_PH7_8                //选择I2C3 的IO
    6 L0 ?* G2 l% [) c

  34. 3 l( m$ ^$ T+ ~  o" H3 {
  35. //I2C4 IO定义与选择
    * D, N* |2 z7 k* I
  36. #define IIC_CH4_PD12_13                                0                                        //PD12,PD13
    ! G3 L/ W. e1 z* s- o3 L
  37. #define IIC_CH4_PF14_15                                1                                        //PF14,PF15  {1 ?$ ?/ f. S0 C
  38. #define IIC_CH4_PH11_12                                2                                        //PH11,PH12/ b" ~, Q! X% k% I2 T/ d
  39. #define IIC_CH4_IO_SELECT                        IIC_CH4_PD12_13                //选择I2C4 的IO
    : E) e9 y: `2 t8 ~& H" L- k" E

  40. # B) B4 f- B# D/ _) j- _7 P( f
  41. //IIC硬件接口选择7 E7 h0 ^4 q, ?, s: T& t% t" h
  42. typedef enum% C; H$ l' }: u  d8 H
  43. {
    % N9 ^; \; @' f
  44.         IIC_CH1        =                0,        //IIC1+ H! u0 T! i- Y  [
  45.         IIC_CH2        =                1,        //IIC28 G- c0 Y5 C# Q( y! S
  46.         IIC_CH3        =                2,        //IIC3* d( N; G/ l* \% g+ i+ F, z% h
  47.         IIC_CH4        =                3,        //IIC4
    ' C6 I; B  h" j# i% I" P' r
  48. }IIC_CH_Type;
    # C/ V8 \8 J/ g9 a
  49. #define IIC_CH_COUNT        4        //4个IIC# G+ m. [1 W  x1 `" s
  50. ! f2 z: M" f% U4 C! G7 B) g; b, A/ \
  51. ) w; W% Z4 l) P0 ~
  52. //中断状态% u; Z" M: M( v# J% E& O9 `
  53. #define IIC_FLAG_TXE                    BIT0        //发送数据寄存器为空(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。* l6 r8 T' X& k" k2 Z
  54. #define IIC_FLAG_TXIS                   BIT1        //发送中断状态(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1,待发送的数据必须写入 I2C_TXDR 寄存器。+ A$ I7 s: i" k7 j
  55. #define IIC_FLAG_RXNE                   BIT2        //接收数据寄存器不为空(接收器); 当接收到的数据已复制到 I2C_RXDR 寄存器且准备就绪可供读取时,该位由硬件置 1。读取I2C_RXDR 时,将清零该位。$ W$ x  h7 v6 ?! r) c' w% j+ l" [& t
  56. #define IIC_FLAG_ADDR                   BIT3        //地址匹配(从模式); 接收到的地址与使能的从设备地址之一匹配时,该位由硬件置 1。该位由软件清零,方法是将ADDRCF 位置 1。8 m* J. g' d6 f3 z) B$ C
  57. #define IIC_FLAG_NACKF                  BIT4        //接收到否定应答标志; 传输完字节后接收到 NACK 时,该标志由硬件置 1。该标志由软件清零,方法是将 NACKCF位置 1。
    ' e  N+ h9 @4 f- L
  58. #define IIC_FLAG_STOPF                  BIT5        //停止位检测标志; 当在总线上检测到停止位,且外设也参与本次传输时,该标志由硬件置 1* U( p; r* q( f: C) p9 }9 L4 q
  59. #define IIC_FLAG_TC                     BIT6        //传输完成(主模式); 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 START位或 STOP 位置 1 时,该标志由软件清零。2 m" [$ g2 F5 F1 S# |) [* L) \) w# Y
  60. #define IIC_FLAG_TCR                    BIT7        //传输完成等待重载; 当 RELOAD=1 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 NBYTES 写入一个非零值时,该标志由软件清零。
    . \% _3 }4 [( R7 ?3 N! ?7 t" m" M7 d
  61. #define IIC_FLAG_BERR                   BIT8        //总线错误; 当检测到错位的起始位或停止位,而外设也参与传输时,该标志由硬件置 1。在从模式下的地址阶段,该标志不会置 1。该标志由软件清零,方法是将 BERRCF 位置 1。
    # r3 ?" U9 O0 [/ i& i) L
  62. #define IIC_FLAG_ARLO                   BIT9        //仲裁丢失; 发生仲裁丢失时,该标志由硬件置 1。该标志由软件清零,方法是将 ARLOCF 位置 1。
    3 l  ^. T/ S/ w5 P+ H$ y. q, w
  63. #define IIC_FLAG_OVR                    BIT10        //上溢/下溢(从模式); 在从模式下且 NOSTRETCH=1 时,如果发生上溢/下溢错误,该标志由硬件置 1。该标志由软件清零,方法是将 OVRCF 位置 1。  u. |" r* u, \, I5 v
  64. #define IIC_FLAG_PECERR                 BIT11        //接收期间的 PEC 错误; 当接收到的 PEC 与 PEC 寄存器的内容不匹配时,该标志由硬件置 1。接收到错误的 PEC 后,将自动发送 NACK。该标志由软件清零,方法是将 PECCF 位置 1。. S$ q' t" ^, J! E7 \, d) R* d
  65. #define IIC_FLAG_TIMEOUT                BIT12        //超时或 tLOW 检测标志; 发生超时或延长时钟超时时,该标志由硬件置 1。该位由软件清零,方法是将 TIMEOUTCF 位置 1。! j/ ~3 W; y- v. @
  66. #define IIC_FLAG_ALERT                  BIT13        //SMBus 报警; 当 SMBHEN=1(SMBus 主机配置)、ALERTEN=1 且在 SMBA 引脚上检测到 SMBALERT 事件(下降沿)时,该标志由硬件置 1。该位由软件清零,方法是将 ALERTCF 位置 1。( _# s! e4 k# q4 [: H7 D* @) X0 n
  67. #define IIC_FLAG_BUSY                   BIT15        //总线繁忙; 该标志用于指示总线上正在进行通信。当检测到起始位时,该位由硬件置 1。当检测到停止位或 PE = 0 时,该位由硬件清零。
    ; N5 \" t* u; S3 [* {7 Q$ k; z
  68. #define IIC_FLAG_DIR                    BIT16        //传输方向(从模式); 该标志在发生地址匹配事件时 (ADDR=1) 更新。;0:写;1:读
    2 u+ n8 r: V& ]# a6 n1 z2 C

  69. * c- {$ ^+ c. S& C# a* o2 ^/ h
  70. //通讯错误状态
    3 K, x$ ^# |  @. _* y, q
  71. typedef enum2 V% }" ?& l8 s& C
  72. {) _6 @- W- L) J# V
  73.         IIC_OK                                        =        0,        //没有错误
      N/ W& H2 W% I$ q+ u  q
  74.         IIC_PARAMETER_ERROR                =        1,        //参数错误; W) X/ F( i6 b; b4 g5 O
  75.         IIC_TIMEOUT                                =        2,        //超时错误,也可能是底层错误' `, g& [' G0 ~( |+ J6 W9 o
  76.         IIC_HAL_ERROR                        =        3,        //底层错误
    ; F, C/ I: b1 {* Z% ~( A0 t
  77.         IIC_STOP_ERROR                        =        4,        //等待结束错误
    # J  R  I: x3 K$ b* w
  78.         IIC_BUSY                                =        5,        //硬件忙
    5 k5 n5 M$ i: r" z5 v( }
  79.         IIC_NACK                                =        6,        //收到NACK了6 K. I9 o) j0 v) A2 j( m8 G
  80. }IIC_ERROR;# h, H" o* n6 X* Q7 [4 C

  81. & n, ^: w/ E* c  y: x

  82. % ?# `; w# C* G$ K* v( Z# q" I
  83. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs);        //硬件IIC初始化" n* X; j$ m. M1 g8 r
  84. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum);        //IIC读取寄存器(可以读取1个或者多个寄存器)* V8 D; ^8 m5 K$ s
  85. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum);        //IIC写寄存器(可以写1个或者多个寄存器)
    ; w" j8 d1 \+ ?  Z& C* L9 E9 g

  86. 3 s! Q& ?1 Z' \+ m( Y

  87. 8 {% }* k$ J' v; K3 ]: M$ `' T9 Y
  88. #endif //__STM32F7_IIC_H_
复制代码

3 h. z# D# Z9 s! l5 U' d
$ G3 `1 l, I$ Q4 R//初始化
5 }! s/ Q! @. M% c% h4 ?4 Z# S: P8 N9 Y. D* w
  1. IIC_Init(IIC_CH3, 200, 0);        //硬件IIC初始化
复制代码
: S% F) K! g: h" V: A

: G- g7 B( W: n& `//调用9 {& Y# t0 ^) ^& B. P7 w- V

  1. ' [; d& o0 N5 s) W
  2. //触摸屏IIC读取寄存器接口
    ' ]4 c4 o( m5 b! y. D  e* N
  3. bool TP_FT5336_IIC_ReadReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)
    4 P$ }# i5 F* z% p. H
  4. {* w+ Y6 e" o3 m9 ~  A' |; a  p# M
  5.         if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)
    9 u: O/ F5 L6 |6 F7 ~0 R3 Y9 }3 D- q
  6.         {
    1 {) |/ r$ ?1 q1 {9 r3 |* I
  7.                 return TRUE;. t4 F) T4 [  O# I5 I
  8.         }+ ?$ j2 r) c' ^" X% T, L
  9.         else
    , l9 B6 q) [, A7 V& `
  10.         {
    4 F! U3 w4 R# K
  11.                 return FALSE;
    ) N; q# Z) D1 K: @$ q9 c
  12.         }' t& S1 u- a0 H# i" A
  13. }3 G2 p3 L5 |1 H8 M
  14. 8 a: B) l9 G( e+ X+ d( n: B
  15. //触摸屏IIC写寄存器接口0 k: D- \( n) x0 z* j: E
  16. bool TP_FT5336_IIC_WriteReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)
    , M3 |2 R% m. d. M8 f: x4 I
  17. {; f; _3 u( Z$ }: m5 R
  18.         if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)
    + M; I- \  S# ~0 W
  19.         {6 [- E* P# v! Y& X, |( L) G. G
  20.                 return TRUE;
    $ V) @% L) `2 m2 U4 ^1 i% C+ }, h
  21.         }9 D. L% ?, a, O9 w) x1 o
  22.         else% h! m! L, D' b- W& G
  23.         {
    0 ?" Z7 ]& Y  T
  24.                 return FALSE;) G$ {$ x2 ?" ?0 e
  25.         }" w  h% a' @5 Y1 _# J. z
  26. " w* E/ q$ w6 {2 q
复制代码
7 L5 w/ V# h# V% o

2 x) Y% V* Q% u  N" H8 Z# b1 S; i7 z0 X, S
收藏 评论0 发布时间:2021-12-11 12:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版