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

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

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
目前只实现了主设备模式,一般也只用到主设备模式,IIC如果不能使用硬件方式,读取大量数据的时候效率很大,由于只有1个字节的缓冲区,根本不能使用中断模式(实际使用过程中,IIC会造成100us以内间隔的中断,单片机根本扛不住的),所以建议数据少就直接阻塞,1个字节也就几十us,数据多直接用DMA,将线程阻塞,等待DMA传输完成,而不会阻塞CPU(上传的代码没有实现DMA部分,便于理解)。
+ Q0 z/ r7 E6 t" x) D; `+ M" j* a# f( r
目前已经做了完善的错误处理,读写操作前都会清除中断,遇到错误会软复位,所有位置均做了超时处理,防止程序卡死,目前只测试了几个字节的读写,大量的,长时间的读写均表现稳定,目前手上开发板没有eeprom,无法做大数据的连续读写,如果你在使用过程中遇到问题,欢迎指正。
$ i, _, U/ S( `. i- _$ y" r1 v" ?! n, R4 _- f' a1 ~, \6 s
下面是IIC读写的时序例子,可以先熟悉一下,这样比较容易上手,哪一个环节出了问题也要调试。: [4 T+ i0 k% b7 ?* e
9 o  k, b7 `* a/ ], D; `, B
20200216194202434.png
" T% J) `# C( r9 h7 X

# ?1 A! i  L* ]6 u# [
20200216194219185.png
, Z, d$ E& Q2 v" ^. G

2 r) @. H$ B, P: b& K
20200216194234908.png
6 P4 l! Q: Y0 v# g8 X" J9 D' l9 @0 u

4 {  A: _+ b. V; [; e1 I9 Z" O; p0 o- K& `
下面简要说明一下STM32F7硬件IIC的驱动设计方式(建议先百度学习一下IIC的时序要求):1 Y; ]  P% V- h/ I& u% E" d# F
/ c" a6 F7 \$ ?2 e, R
[基本的初始化]' H8 L& n4 T) \

6 G  O. k; [0 O1 p- G5 f1.初始化IIC时钟,IO(IIC IO必须设置为复用开漏输出,这个很重要)。4 ~6 {) `$ E: v& Y' c7 @

- K) U+ L2 u7 y# k, {3 S2.CR1先赋值为0,复位IIC.
5 e, @" R4 o3 f& o/ m2 I
% p( u9 [  N6 M2 d) f3.除了TIMINGR寄存器需要自己计算设置好,其余寄存器全部复位为0& u; c# q/ Q3 J7 ?) c. a; `0 `

8 e; [3 g: }: B, {& x- c4.设置CR1使能IIC。
7 }9 U3 b+ Y$ M0 j  o/ j( z4 m9 R( K# Q
! X! m8 A$ H5 d- y' a  w  q( U注意:上面说到,IIC的IO必须初始化为复用开漏输出,我之前初始化为复用推挽输出,测试很久,只要一启动传输,就会立马收到NACK,然后是STOP中断,数据根本没法发送,弄了好久才发现是这个IO初始化的问题。
/ s. {; R! f% s. j& K1 w; a( }6 ^

4 ?1 z5 Q* Y0 k' U$ _: _9 P; K, l9 G  Y  d0 [9 P1 _; \
[读取]3 E- {$ r0 U1 Y+ k) X' l
$ u6 q- R% v& L9 T' b' y$ N
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。
% O0 z) Z1 u9 h* P( E% w1 k9 z( v% F' f% B
2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)软件STOP,写模式,启动传输。+ a! L) [9 ]$ d9 T7 D
. W. `9 {' m/ [, N7 V* K  k
3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。  s7 t4 |. f" }

' g3 L0 _$ Q- P: P1 {4.等待TC置位,意味着上面的1-2字节的寄存器地址以及写完成了。
3 a: R4 H- B) l. u* z$ o4 e% c9 Z' O) s" D0 A/ V6 w& L9 }
5.根据要读取的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。- Q3 L0 o' N, `/ O( x1 l3 z
! t, G# ^% _) K
6.设置了从机地址,要读取的数据长度,之后设置方向为读取,然后启动START(从写切换到读要重新发送START,这个跟软件模拟是一模一样的)。. M; E5 l$ ?: u% p

* ^2 y: L! D7 r4 v7.循环一个字节一个字节的读取数据,字节读取需要等待RXNE有效,只有读取RXDN寄存器,直到所有数据读取完成。2 E3 Q6 ~. M( l' g

1 b) i. C3 c0 ]" M, J8.读取完成后等待STOP有效,因为前面在最后一包数据读取的时候使能了自动STOP,这个时候检查STOP是否生成。7 @  C2 l9 i$ u* q

$ w! W6 X. b" {7 i( U& W. o9.需要注意的是,所有的操作都要给超时,并且是自己可控的,绝对不要有死循环,之所以一直说STM32的IIC死机很大程度上都是由于这个地方没有涉及好,我的程序设计方法是:一旦出现了异常,就复位IIC,如果不复位就会导致下次进去的时候IIC一直忙,因为还处于上一个通讯过程。
- C. c- ]) b$ Z: ^, o
! p& X9 b1 X" ^, _
- O. a7 `0 P! [" V
7 L0 j  U1 x5 y: I[写入]% D  S4 J  X, ~: u5 V6 l9 L
; h; l. u( z  C0 G
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。2 ~9 A7 D, S. C+ Q- j8 ]/ S# t4 I

- M# H' C2 o+ |3 i* a2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)自动重载,写模式,启动传输。) c% ?& Y. N* v
* x  l7 Y8 c8 c. a$ b: b! a
3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
6 ]( ]/ d: d# L5 t, l+ ^9 G  T+ o+ X1 o/ ]) n
4.等待TCR置位,意味着上面的1-2字节的寄存器地址以及写完成了,已经发生重载了,后续可以继续写入数据了。
5 F* _. g4 P; Z) ~
6 z' \$ E! y- R, ]4 }5.根据要写入的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。6 o) l3 n, B- x5 f, t) @- I
- u" Y$ j; A9 C; ]4 }% V
6.设置了从机地址,要写入的数据长度,之后不用切换方向,不用启动START(都是写,不用重复发送START,这个与读取有区别)。: G6 ?$ f" ^4 i- X4 d2 k) o
# n' o$ O8 g( q% {0 ^- E1 S0 H: V4 l
7.循环一个字节一个字节的写入,字节写入与步骤3一样,等待TXIS置位,就可以写入数据到TXDR。2 f) r2 q: z( {

- b; O& j6 J% \6 P) A7 Q& [8.等待STOP有效,因为前面在最后一包数据写入的时候使能了自动STOP,这个时候检查STOP是否生成。9 _# x: ?0 u7 {' W
! l, y7 g  C! {, d
9.需要注意的是,所有的操作都要给超时,跟读取一样。
9 [6 h/ n. b. P# c2 j8 D2 o7 \5 ]

- W) ~% Y) R+ B8 o- r
# k8 K# b/ F) i( I0 N注意:IIC的读取实际很短,超时也不用给很长,以标准的100KHz通讯时钟速度,一个字节大概在90us左右,超时可以给个5-10B时间,也就是450-900us左右。
1 e3 a8 _7 {( a# j2 }6 H. W
! Z$ ^! S& N5 `0 x+ O. e/ h6 E+ I: T  ]: i& h; w, K% T5 H3 u
  l$ W3 W2 x' [2 K) m+ Y& }$ j
好了说了这么多,具体的看代码中的注释,直接上代码(我只测试过I2C3,其余的理论上都是一样的,就是IO初始化部分有区别,别的通道没有硬件进行测试)
* \" g) \5 D, {7 S  [
, [0 g: _7 l* a) W* J' ~
  1. /*************************************************************************************************************
    1 D1 w+ J2 G) g7 h2 r! u# m
  2. * 文件名                :        stm32f7_iic.c
    ! M( j6 E! a% M; ?( f. K
  3. * 功能                        :        STM32F7 IIC接口驱动
    9 j- B  s( k+ Q/ \
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    7 a- E/ H, e6 L% i! z8 r! u9 \) j
  5. * 创建时间                :        2020-02-09
    2 z) G( o. E& V1 u+ a, r7 H
  6. * 最后修改时间        :        2020-02-09
    1 _) A. O' b4 l5 o6 \8 [
  7. * 详细:                        只支持主机模式,7bit地址,默认APB1为IIC提供时钟) ?3 x' j% f+ m+ R" E; W1 f
  8.                                         涉及到读写1字节的超时时间是us,其余的是ms
    4 @. i: L+ D, K0 ?% k6 o
  9.                                         注意:IIC的IO必须初始化为复用开漏输出。
    # m& o7 f: s+ G1 }* d+ _
  10. *************************************************************************************************************/        % V* M4 Y1 o- x/ u
  11. #include "stm32f7_iic.h"% P+ h- h6 y, I* s6 ]6 p0 q
  12. #include "system.h" # @/ J* c# k$ S  O1 j
  13. #include "dma.h"; |, S7 G. |9 m  ~8 o/ H: L

  14. & r8 D' V- E2 D2 q6 t7 i3 T
  15. #define IIC_FLAG_MASK  ((uint32_t)0x0001FFFF)        //中断标志掩码
    5 d% {* W/ H' z

  16. 7 \' J! v$ T# @: x0 T% J
  17. //自动结束或自动重载设置(重载与自动结束只能二选一,或者都不选)2 g2 t" }" l) s" Q8 `9 u+ [& A- X7 v
  18. typedef enum ( ~$ O8 C4 l/ P" M- c* J/ `( o
  19. {
    9 F- H: L' l  F; }- a
  20.         IIC_SOFTEND_MODE                =        0,        //手动结束,并不开启重载
    % O9 q/ n. p( M: f0 f
  21.         IIC_AUTOEND_MODE                =        1,        //自动结束,用于最后一次通讯完成后自动发送STOP结束通讯: L( O8 |. Z% {" \/ g2 d, F! ^
  22.         IIC_RELOAD_MODE                        =        2,        //后续还有数据,本次通讯后自动重载,重新设置后继续通讯
    + Y) Q& o: x8 x* S8 c
  23. }IIC_RELOAD_END_MODE;- ~, L3 P3 H! k( X! e7 J
  24. ) B! |, F$ V8 Q0 x
  25. //读写与开始模式控制; x, K4 A2 s, k
  26. typedef enum9 k4 S( N3 T- |8 G
  27. {
    9 Q5 T2 u. X8 k1 Q
  28.         IIC_NOSTART_WRITE                =        0,        //没有开始的写-用于后续数据的写入5 _# q; {2 l5 K& M6 s) T+ j: Z, [
  29.         IIC_NOSTART_READ                =        1,        //没有开始的读-用于后续数据读取
    & p/ p& g% N" u. Z: r9 R
  30.         IIC_START_WRITE                        =        2,        //生成开始写-用于通讯开始时,写地址或数据
    1 j3 N+ M1 v- x# J( ?, q: S# T
  31.         IIC_START_READ                =        3,        //生成开始读-用于读取数据时切换到读取方向,并读取后续数据0 o+ w6 \7 W: K- C$ h( }7 |% O
  32. }IIC_START_WR_MODE;
    3 K0 T: S' ]7 X* ~

  33. ! `  F! ], o6 [/ J/ O
  34. //IIC句柄8 w' p- {+ C3 @' ^6 B
  35. typedef struct% O1 n6 b# }' {% _1 `7 V
  36. {7 O+ [0 I* ?8 ~/ q
  37.         IIC_CH_Type ch;                        //当前通道
    ' M+ \$ y9 D7 T% C2 w1 i2 G  k
  38.         I2C_TypeDef *I2Cx;                //当前通道外设结构体
    9 a1 j- N! t$ t0 _& p4 j8 m: U
  39.         u32 TimeOutUs;                        //操作超时,单位us/ {: q2 D+ \* `; k3 \, ~6 s" B
  40.         u16 Speed_KHz;                        //通讯速度,单位KHz: |* o4 N0 K/ `, U' A$ {+ J
  41.         bool isMasterMode;                //是否为主设备模式-目前只支持主设备模式6 s' d" O* t* }7 |. G
  42. }IIC_HANDLE;  Q) F0 G; l/ c! M& T
  43. + M/ ^3 X: u3 l- n, l; r
  44. //IIC外设结构指针
    4 o+ a; L- ^9 x% _
  45. static const  I2C_TypeDef * const I2C_TYPE_BUFF[IIC_CH_COUNT] = {I2C1,I2C2,I2C3,I2C4};/ L; _7 L: Y% f! ^0 f2 n/ [) a
  46. //IIC通道句柄定义
    8 k- r% N, k* W6 ~; q
  47. static IIC_HANDLE sg_IIC_Handle[IIC_CH_COUNT];4 q* H4 h+ q+ E( O/ n: K5 [# w

  48. 4 o* ]9 p0 O$ w2 H, F9 d; U1 u7 q
  49. //发送NAK3 b: d4 u4 S- s& w( O+ k6 ^+ k5 A; c
  50. //static __inline void IIC_SendNAK(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT15;}
    , h! T3 B3 ^: I  l: o. b  J9 A; W
  51. //发送STOP
    % d0 Y! f2 w" w9 k
  52. static __inline void IIC_SendStop(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT14;}$ _& P- L/ D- G; }. r8 [$ d# I
  53. //发送START  ?0 f( {3 V5 U( Z
  54. //static __inline void IIC_SendStart(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= I2C_CR2_START;}3 d! Q3 B/ {5 Y0 A
  55. //获取中断状态
    ) b, f' _, c9 |$ j
  56. static __inline u32 IIC_GetISR(IIC_HANDLE *pHandle) {return pHandle->I2Cx->ISR & IIC_FLAG_MASK;}) t% Z; R- d+ d& r4 N- C
  57. //清除中断状态
    0 ?/ t! X( s" x6 H- Y
  58. static __inline void IIC_ClearISR(IIC_HANDLE *pHandle, u32 IsrFlag) {pHandle->I2Cx->ICR = IsrFlag & IIC_FLAG_MASK;}5 l; \- y/ h" q  r2 g7 \9 ?* O/ {7 }
  59. //复位CR2寄存器) ^5 ^0 I8 S5 z. T4 D
  60. static __inline void IIC_ClearCR2(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 = 0;}$ P% P$ G; T2 Z* K! l& f

  61. ; P, }8 ^1 Z+ x0 S* c3 y
  62. static void IIC_SoftReset(IIC_HANDLE *pHandle);//硬件IIC软复位(会使能IIC)( F4 @6 t8 g" R. ?2 @
  63. static u32 IIC_CalculationTiming(u16 Speed_KHz);//硬件IIC时序计算) p: v8 m8 C4 Q4 [  z" }) Z) f
  64. ( J# E/ h! ~8 i  V0 ~3 R0 N# E
  65. 9 C6 T! Z4 s* s, T( Y
  66. /*************************************************************************************************************************4 K  F: _; j+ o8 \, r9 @, c
  67. * 函数        :                        bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)
    % a; U8 I3 H8 A! U1 i2 B
  68. * 功能        :                        硬件IIC初始化0 n" k: X: T3 e* t6 R
  69. * 参数        :                        ch:IIC通道;Speed_KHz:速度10-1000(如果速度是100,则按照SMBUS时序);TimeOutUs:操作超时us(0:自定计算超时)3 }! I6 q+ D4 w5 k$ h
  70. * 返回        :                        IIC_ERROR
    ' Z- E) ^9 t7 @9 Q& B1 B' A
  71. * 依赖        :                        底层宏定义8 N9 i; _5 \. E3 T( t; H
  72. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ( P- f# s9 i+ p: a" Q7 f. h
  73. * 时间        :                        2020-02-15# R" e) u& W: ?  S; f& _: L8 D
  74. * 最后修改时间 :         2020-02-151 W& _: l; K6 k, r$ t0 n
  75. * 说明        :                         速度只是个大概的计算值,设置为100KHz时会严格的按照SMBUS时序,其余的不保证SMBUS兼容,正常情况下只要时钟速度符合要求,
    $ ^- [3 w5 D: b2 l
  76.                                         时钟上升沿到来前数据以及稳定的切换了即可保证通讯稳定性
    8 L+ \. u0 J" I; O* \/ I
  77. *************************************************************************************************************************/
    ; d0 V. t# L. ?' z/ ^( r, ~
  78. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)6 g' f3 z7 L% A% X3 m% L
  79. {
    : S( D1 F- M1 F6 \" [3 B
  80.         SYS_DEV_CLOCK DevClock;; v" A7 G0 X6 ~7 [/ T
  81.         IIC_HANDLE *pHandle;
    0 f+ b( Z! ?& V4 `$ M" Y
  82.         
    / z# L2 Y2 q+ w% O* S4 H
  83.         switch(ch)
    , N+ \) s* [9 u4 E
  84.         {
    % H& K; w+ r! ?" p
  85.                 case IIC_CH1        :        //IIC1& ^' A' r2 u' j& F. N
  86.                 {# D$ b9 l/ d) i7 q* ~- ?% ?/ r
  87.                         RCC->DCKCFGR2 &= ~(0x3 << 16);        //清除设置,使用APB1作为时钟源# B, O/ i) X, U. X
  88.                         DevClock = DEV_I2C1;# T3 Q4 j" B7 W2 ~
  89.                         //初始化I2C IO
    " f% j, |+ X" X/ K. {
  90. #if(IIC_CH1_IO_SELECT==IIC_CH1_PB6_7)        //I2C1        使用PB6/7  Z+ e" k, F' A: u' _
  91.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    " j5 F$ @' ?  @( H
  92.                         SYS_GPIOx_OneInit(GPIOB, 6, AF_OD, SPEED_25M);                //PB64 Z; }" n, w! {2 U/ r
  93.                         SYS_GPIOx_OneInit(GPIOB, 7, AF_OD, SPEED_25M);                //PB7: F! a/ P$ @" w3 _
  94.                         SYS_GPIOx_SetAF(GPIOB, 6, AF4_I2C1);                                //AF45 Z& G3 D* {# Y2 ?4 y! w
  95.                         SYS_GPIOx_SetAF(GPIOB, 7, AF4_I2C1);                                //AF4. `& ]9 G6 z1 r% M/ x
  96. #elif(IIC_CH1_IO_SELECT==IIC_CH1_PB8_9)        //I2C1        使用PB8/9! U# T$ @" ?2 O
  97.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    + U1 r; E4 H; z
  98.                         SYS_GPIOx_OneInit(GPIOB, 8, AF_OD, SPEED_25M);                //PB8! z* C3 m- j& d/ A  h8 h) o6 K
  99.                         SYS_GPIOx_OneInit(GPIOB, 9, AF_OD, SPEED_25M);                //PB9
    + h, S8 @3 v$ V7 a  Y
  100.                         SYS_GPIOx_SetAF(GPIOB, 8, AF4_I2C1);                                //AF4
    6 g) z3 n1 ^1 U/ _3 }# D  t! s
  101.                         SYS_GPIOx_SetAF(GPIOB, 9, AF4_I2C1);                                //AF4
    8 N% l, m! s3 p% t. @
  102. #else
    5 K% z1 ^  {9 ?% o+ |) O
  103.                         #error("无效的I2C1 IO选择");
    " }% s! ^: O& R$ ?
  104. #endif //IIC_CH1_IO_SELECT
    ' Z5 u, C) M, V/ c+ M
  105.                 }break;7 s) W3 t6 \  ^6 Y& Q: q( J" e5 s
  106.                 case IIC_CH2        :        //IIC2
    2 E9 P0 C4 i& T
  107.                 {$ ]9 c: f" p: a' }+ h8 O
  108.                         RCC->DCKCFGR2 &= ~(0x3 << 18);        //清除设置,使用APB1作为时钟源7 n- @% S  j& X5 L
  109.                         DevClock = DEV_I2C2;
    ! Y! E+ @* R2 Q7 V) K3 A+ K
  110.                         //初始化I2C IO
    " W; [/ d( k9 U4 u( J! w& \; W
  111. #if(IIC_CH2_IO_SELECT==IIC_CH2_PB10_11)        //使用PB10,PB11  A# z1 B( x1 V: W5 Y. c/ R) D
  112.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    8 D0 C# g1 |, N) d$ n, _
  113.                         SYS_GPIOx_OneInit(GPIOB, 10, AF_OD, SPEED_25M);                //PB10
    7 S% j6 ~3 {* x3 M
  114.                         SYS_GPIOx_OneInit(GPIOB, 11, AF_OD, SPEED_25M);                //PB11
    " V6 o+ m; [9 f8 q2 ]$ H, X+ D) r
  115.                         SYS_GPIOx_SetAF(GPIOB, 10, AF4_I2C2);                                //AF4
    7 ^: D2 ^1 {% \" P+ `' N! W) u2 b) x
  116.                         SYS_GPIOx_SetAF(GPIOB, 11, AF4_I2C2);                                //AF4
    5 V# q+ ]0 d3 o2 c
  117. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PF0_1)        //PF0,PF1
    4 b" U8 v. g* @0 i3 J3 s
  118.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟4 n# d  K2 x5 X. f  j( u& n6 s
  119.                         SYS_GPIOx_OneInit(GPIOF, 0, AF_OD, SPEED_25M);                //PF0% g' Z! V" E# y. y2 |  E$ F5 l
  120.                         SYS_GPIOx_OneInit(GPIOF, 1, AF_OD, SPEED_25M);                //PF14 k# w/ e. o' S& t- K
  121.                         SYS_GPIOx_SetAF(GPIOF, 0, AF4_I2C2);                                //AF4
    ' m2 W# K+ y) O6 f1 R& s9 j: x3 S& T/ A
  122.                         SYS_GPIOx_SetAF(GPIOF, 1, AF4_I2C2);                                //AF4
    + J( b* f& N2 ^
  123. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PH4_5)        //PH4,PH5
    + _9 V( T1 k6 J" C
  124.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    6 T; `) \2 n, L# S; I- J
  125.                         SYS_GPIOx_OneInit(GPIOH, 4, AF_OD, SPEED_25M);                //PH4
    : H! J( F6 {6 b# c
  126.                         SYS_GPIOx_OneInit(GPIOH, 5, AF_OD, SPEED_25M);                //PH5
    # L$ s) U/ P2 m6 Z
  127.                         SYS_GPIOx_SetAF(GPIOH, 4, AF4_I2C2);                                //AF4
    & Y$ }+ J/ L2 s6 n
  128.                         SYS_GPIOx_SetAF(GPIOH, 5, AF4_I2C2);                                //AF4                        
    , ]! v. y& `- L) y  o
  129. #else
    ' ?8 {2 {1 L( B) Y- ~  a7 r$ M
  130.                         #error("无效的I2C2 IO选择");
    6 a% f/ L8 c1 a- R' W
  131. #endif //IIC_CH2_IO_SELECT; h/ A$ L$ U- ?% G* a% M% ~
  132.                 }break;                        . h7 K8 Z; J& j1 D0 x3 M. \, T& V
  133.                 case IIC_CH3        :        //IIC3
    " ^. e$ \6 W( F- {/ P* \
  134.                 {( ?% ^, K& V" u& h8 [$ `( h7 y9 P
  135.                         RCC->DCKCFGR2 &= ~(0x3 << 20);        //清除设置,使用APB1作为时钟源3 b* w' f( l2 c7 V* f
  136.                         DevClock = DEV_I2C3;
    ' H6 u% m$ E, `- D* F
  137.                         //初始化I2C IO
    0 j& k* u9 y9 M5 h
  138. #if(IIC_CH3_IO_SELECT==IIC_CH3_PH7_8)                //PH7,PH82 |/ B+ c# t: q& W- A% U% [, N
  139.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    * l( R9 ]: m, P! S* l
  140.                         SYS_GPIOx_OneInit(GPIOH, 7, AF_OD, SPEED_25M);                //PH7. A- A/ W( n! x
  141.                         SYS_GPIOx_OneInit(GPIOH, 8, AF_OD, SPEED_25M);                //PH8
    4 G5 j1 \- v. e9 M6 J& h! Q
  142.                         SYS_GPIOx_SetAF(GPIOH, 7, AF4_I2C3);                                //AF4
    ( q! i# k, p) `. i+ V. x4 l
  143.                         SYS_GPIOx_SetAF(GPIOH, 8, AF4_I2C3);                                //AF41 |. u$ u0 f4 r$ W
  144. #elif(IIC_CH3_IO_SELECT==IIC_CH3_PA8_PC9)        //PA8,PC9
    ) }' a  \2 y+ y# @
  145.                         SYS_DeviceClockEnable(DEV_GPIOA, TRUE);                                //使能GPIOA时钟8 c& z0 z& U$ Z8 l8 m; I
  146.                         SYS_DeviceClockEnable(DEV_GPIOC, TRUE);                                //使能GPIOC时钟# J; }, O4 D' S1 }4 T( z
  147.                         SYS_GPIOx_OneInit(GPIOA, 8, AF_OD, SPEED_25M);                //PA8
    6 c. a$ l6 Q' P9 S, ^1 Z/ a
  148.                         SYS_GPIOx_OneInit(GPIOC, 9, AF_OD, SPEED_25M);                //PC9
    6 k1 r( }  D/ ^6 ~3 I
  149.                         SYS_GPIOx_SetAF(GPIOA, 8, AF4_I2C3);                                //AF4% v! Y  @( V% ]* `3 e9 i
  150.                         SYS_GPIOx_SetAF(GPIOC, 9, AF4_I2C3);                                //AF4                ) H' Z9 l* A  p2 Q3 B$ e) w
  151. #else. \  B/ V  x" E. {" W
  152.                         #error("无效的I2C3 IO选择");8 v5 k# T9 g7 K. _
  153. #endif //IIC_CH3_IO_SELECT                        
      G5 y  C3 {6 J8 ?
  154.                 }break;                        ' b$ g8 ~8 [+ Y; y% u
  155.                 case IIC_CH4        :        //IIC4; ~) D" e( R9 p& q/ r2 Q/ z# D
  156.                 {
    7 F, ]$ Q8 L& b4 \
  157.                         RCC->DCKCFGR2 &= ~(0x3 << 22);        //清除设置,使用APB1作为时钟源
    4 y% |9 E8 Y' C5 t" a
  158.                         DevClock = DEV_I2C4;+ y; U3 Z$ h$ e  G& g/ Q2 A  C
  159.                         //初始化I2C IO, Y* m, o- H; V# q* d& Q
  160. #if(IIC_CH4_IO_SELECT==IIC_CH4_PD12_13)                //PD12,PD13
    # `! g2 I4 `- E2 c6 D
  161.                         SYS_DeviceClockEnable(DEV_GPIOD, TRUE);                                //使能GPIOD时钟
    . \6 g5 \4 ]/ |, z$ ~& w" g
  162.                         SYS_GPIOx_OneInit(GPIOD, 12, AF_OD, SPEED_25M);                //PD12
    3 V0 i7 o8 ?+ Y- u
  163.                         SYS_GPIOx_OneInit(GPIOD, 13, AF_OD, SPEED_25M);                //PD13# |, H  ]/ L$ _( m
  164.                         SYS_GPIOx_SetAF(GPIOD, 12, AF4_I2C4);                                //AF4; F' p3 }6 y  Y, u& U$ D- y
  165.                         SYS_GPIOx_SetAF(GPIOD, 13, AF4_I2C4);                                //AF43 i2 W4 ?8 c- n9 l9 _% f8 _
  166. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PF14_15)        //PF14,PF15, C0 r! X/ L; I$ ]2 \
  167.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟. i6 O" K* g" ?) N
  168.                         SYS_GPIOx_OneInit(GPIOF, 14, AF_OD, SPEED_25M);                //PF145 H+ h  a' N/ j+ D2 V0 L7 }
  169.                         SYS_GPIOx_OneInit(GPIOF, 15, AF_OD, SPEED_25M);                //PF15" i7 P; @" C- t! j8 K
  170.                         SYS_GPIOx_SetAF(GPIOF, 14, AF4_I2C4);                                //AF4
    5 b' `4 {8 y; Z4 o6 @3 }1 S
  171.                         SYS_GPIOx_SetAF(GPIOF, 15, AF4_I2C4);                                //AF4+ j, q7 c7 w9 `! }
  172. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PH11_12)        //PH11,PH12
    - m7 u+ H6 r1 K0 N
  173.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    7 I" o" A9 Z3 S% b* n
  174.                         SYS_GPIOx_OneInit(GPIOH, 11, AF_OD, SPEED_25M);                //PH11- C+ ]! o8 u; z5 g% G0 r) E/ X' _, K
  175.                         SYS_GPIOx_OneInit(GPIOH, 12, AF_OD, SPEED_25M);                //PH12
    ( w1 `( Q; |7 W5 X9 I; K
  176.                         SYS_GPIOx_SetAF(GPIOH, 11, AF4_I2C4);                                //AF4
    9 U6 R3 G" f  p9 z% Q
  177.                         SYS_GPIOx_SetAF(GPIOH, 12, AF4_I2C4);                                //AF4                        9 B, a, s, t8 ?
  178. #else
    7 h" v2 n  v6 e1 t! ~6 n2 ]
  179.                         #error("无效的I2C4 IO选择");7 P" X( ?0 A6 R; W0 `% n8 P3 f/ a
  180. #endif //IIC_CH4_IO_SELECT                        
    3 f. w/ j6 B9 u6 f
  181.                 }break;
    ' q8 k/ A7 |1 l! I% A
  182.                 default:
    7 b& A5 Q- I, _2 D+ @2 Z) Y
  183.                 {
      L* A( f" y/ P9 T2 t) \* Z7 _5 V
  184.                         DEBUG("初始化IIC失败:无效的IIC通道%d\r\n", ch);
    & v4 q2 B! X+ c9 b8 B% W5 l4 n, I! h
  185.                         return FALSE;
    : L1 l6 b, q: ]7 {
  186.                 }  U) [6 g3 d/ p5 m- J) c8 T
  187.         }
    # [0 a9 Z  J9 `" U
  188.         pHandle = &sg_IIC_Handle[ch];                                                        //获取相关通道的句柄
    & b. S- c$ v" g; S& i
  189.         if(pHandle == NULL)
    : u2 o0 m9 j3 v; Q* |3 ^, o# W
  190.         {
    ' d2 R# S/ X9 R2 b" k* N
  191.                 DEBUG("初始化IIC失败:无效的IIC句柄\r\n");  K: {4 v; l- {. B
  192.                 return FALSE;
      |8 A% r5 O6 Y) }
  193.         }
    8 i* C/ q! u" r# i  G
  194.           `3 N1 i) F* |. h
  195.         SYS_DeviceClockEnable(DevClock, TRUE);                                        //使能时钟
    0 p5 S  Z" N* t3 L! O
  196.         SYS_DeviceReset(DevClock);                                                                //外设复位6 D4 m5 n$ R+ f4 D% o
  197.         pHandle->I2Cx = (I2C_TypeDef *)I2C_TYPE_BUFF[ch];                //外设指针0 Z+ k) Y" ^' n- S. F. x
  198.         pHandle->I2Cx->CR1 = 0;
    / ~* ~" s3 a3 I
  199.         Delay_US(1);                                                
    3 t* v8 Z5 o" P6 Y  U) a; u
  200.         pHandle->I2Cx->CR1 |= 2<<8;                                                                //设置噪声滤波器,关闭所有中断
    " G9 G; x  L8 \* w3 f2 Y) i
  201.         pHandle->I2Cx->CR2 = 0;
    : R+ M, F; F2 {- r8 u* T% Y4 I
  202.         pHandle->I2Cx->OAR1 = 0;7 f" R4 H: s7 f$ [
  203.         pHandle->I2Cx->OAR2 = 0;
    / C. i* ^/ r  n4 C1 o# N
  204.         if(Speed_KHz > 1000) Speed_KHz = 1000;
    - h7 i5 S# R2 f
  205.         if(Speed_KHz < 10) Speed_KHz = 10;7 R% M3 M+ O0 a
  206.         pHandle->Speed_KHz = Speed_KHz;                                                        //记录速度: ?9 V- i7 _9 S, l
  207.         if(TimeOutUs == 0)                                                                                //需要自动计算超时时间,时钟周期*10*10
    & M" ^& K! F" w) B! h/ @1 x, A6 V: j
  208.         {
    $ S! u3 R0 W' V# h; Z5 U1 v
  209.                 TimeOutUs = 1000/Speed_KHz;                                                        //时钟周期2 P; ], y, ?# W/ d
  210.                 TimeOutUs *= 10;                                                                        //字节周期
    : y, C, U  a& {! W! B& a5 h" ?5 W
  211.                 TimeOutUs *= 10;                                                                        //超时时间为10个字节时间$ R3 R. D6 ?4 o# b! m& X& g
  212.         }
    $ f; ~8 q6 Q$ K( J8 u0 Q- ^
  213.         if(TimeOutUs < 3) TimeOutUs = 3;
    1 g( U+ e0 ]8 W# q  _# Y+ O
  214.         pHandle->TimeOutUs = TimeOutUs;                                                        //记录通讯超时时间8 C1 z' f# P0 ]  d
  215.         uart_printf("IIC超时时间:%dus\r\n", pHandle->TimeOutUs);6 W3 x/ m; o" S) \
  216.         pHandle->I2Cx->TIMINGR = IIC_CalculationTiming(pHandle->Speed_KHz);//0x40912732;                                        //时序
    $ H, j$ @2 j0 W  e8 F
  217.         pHandle->I2Cx->CR1 |= BIT0;                                                                //使能IIC
      k9 G* M' @* u6 ]# v. J) V
  218.         pHandle->isMasterMode = TRUE;                                                        //主设备模式
    . O1 s+ l3 H5 }5 }* a8 I
  219.         Delay_US(1);
    ) @* R/ v, A8 D9 B6 m

  220. 4 k/ |' e9 C( T* i- h6 ~3 j
  221.         return TRUE;/ m* b# [# x( \3 |$ n/ c8 s  |. a! i2 S
  222. }! ^' Y! e( J% I' S& p

  223. # @5 E' T: E0 {: Y5 K7 u

  224. 4 p5 k% G& m2 F9 f% z9 h
  225. /*************************************************************************************************************************; P9 F$ C  i+ l4 S
  226. * 函数        :                        static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)' K, X/ i; r: }
  227. * 功能        :                        检查是否有NACK中断状态,如果有则清除掉
    1 p/ v' H, X8 {+ p' J- @3 N
  228. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us4 x6 j# n9 n  X% ~
  229. * 返回        :                        IIC_ERROR9 a4 S/ E0 z. M$ w
  230. * 依赖        :                        底层宏定义' k8 o/ O- Y5 Y# ~1 x
  231. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    : S  q: E% v, y; m9 I) l0 h6 c
  232. * 时间        :                        2020-02-154 I0 G& h' |% y9 ?" W8 Q* _
  233. * 最后修改时间 :         2020-02-15: v1 e) U/ `1 R( k3 W- b& j5 \
  234. * 说明        :                         如果有NACK中断,则先产生停止位,然后清清除掉所有的中断,并复位IIC,然后返回错误9 D4 M/ u$ v6 \- ^5 `
  235. *************************************************************************************************************************/  / K! F  r: O# `8 l5 u5 Q
  236. static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)7 V" ^) @& a. d4 A
  237. {
    0 N0 I. Q3 V0 g/ g  E7 V* @5 X
  238.         IIC_ERROR Error = IIC_OK;7 }% m' ~8 ]' D7 g6 v
  239.         
    + P+ O& g6 e6 Z; v# A7 E" z
  240.         if(IIC_GetISR(pHandle) & IIC_FLAG_NACKF)        //接收到否定应答标志# t; B0 D* p5 \* {( O
  241.         {: O7 a4 U. {- ~9 c
  242.                 uart_printf("NACK : IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);/ B2 T" i# Y5 ]- E. M
  243.                 uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    5 h" k. r" f- L/ }1 j2 @3 E8 N/ A4 c
  244.                 uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));
    ! N6 \: m) C' {1 \- `8 u! I
  245.                 //主设备下,如果没有开启自动产生停止位,则手动产生停止位% U( v+ `& d- P0 g6 F- R: V
  246.                 if(pHandle->isMasterMode && ((pHandle->I2Cx->CR2 & I2C_CR2_AUTOEND) == 0))( E4 f$ i3 |, T
  247.                 {! G9 l6 R% G7 z
  248.                         IIC_SendStop(pHandle);                        //send stop
    2 H0 B0 t3 e! Y: h% G
  249.                 }7 D% i; `9 ]+ t  B& r: D5 w) f
  250.                 //等待STOP标志有效
    0 }: y. O6 g# a9 G$ V  N
  251.                 while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)7 q( J% `' u& A8 {6 c: v( R, G5 R
  252.                 {) F* ~5 N' x9 Q( @) C9 p& |9 z/ F* x
  253.                         if(TimeOutUs == 0)                                //检查是否超时了8 y  ~6 U; o2 h
  254.                         {
    , b; F1 G0 v6 g
  255.                                 break;$ t% S* C6 l3 r; V( x
  256.                         }                        
    , k" [# a3 u8 l# [* u! p9 v
  257.                         TimeOutUs --;
    ; k$ _2 t* @4 P
  258.                         Delay_US(1);                                                //延时, }" n' z' m! s6 H" _+ B
  259.                 }
    / m3 b6 E7 O5 j/ s9 K
  260.                 //清除相关的中断标志' Y8 l3 }- l/ g) j2 O, j% \7 W( \$ V
  261.                 IIC_ClearISR(pHandle, IIC_FLAG_NACKF | IIC_FLAG_STOPF);        //清除NACK,STOP标志: d  K; p! O3 R- k7 o- @
  262.                 pHandle->I2Cx->CR2 = 0;                                                                                //清除CR2寄存器
    ' C  g' [' T- H; w+ i: S% b: Z
  263.                 IIC_SoftReset(pHandle);                                                                        //执行软复位
    / A5 N2 x& {5 O& }3 _6 P8 ?
  264.                 if(TimeOutUs == 0)                                                //没有超时,就是硬件通讯出错了
    4 D  z/ k  C* g. Z* I
  265.                 {% P# Q: R5 g5 y/ D. a4 _, B4 t+ j
  266.                         DEBUG("IIC发送stop超时\r\n");
    6 O" I' H1 G4 L. K. S3 X
  267.                         Error = IIC_TIMEOUT;                                //超时
    3 u9 C) r! m; }5 l/ I2 Z
  268.                 }; W0 g- e4 z6 o$ J3 f; n
  269.                 else( Y- C0 K' @: y
  270.                 {
    ( {3 }5 G: n% W; w5 D; H
  271.                         Error = IIC_HAL_ERROR;                                //底层错误; @$ {$ x1 x9 r6 H2 g
  272.                 }1 j7 F0 K( O& Y2 a5 F3 U% p
  273.         }
    8 R3 ~( b1 I: K( a
  274.         
    9 j/ ^- {9 y! K1 U
  275.         return Error;
    " w) |2 w3 o* S
  276. }% }  b) P, [& f: R0 |
  277. / c9 z6 S! S. e0 r" ~* O( _0 s! `

  278. ) S3 p) E0 h* t& v1 p0 F

  279. - L- F& f) H+ x3 D* H& p
  280. /*************************************************************************************************************************
    2 f: j, i2 V$ k, n% S* ~2 e
  281. * 函数        :                        static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
    0 N5 W( I0 |% ?  C9 b5 U& v
  282. * 功能        :                        等待TXIS中断有效(等待 I2C_TXDR 发送寄存器为空)
    & k8 z& F% @  q& K0 g
  283. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us7 b+ u! K* r5 b4 V. T/ p
  284. * 返回        :                        IIC_ERROR
    # P& H  g! J4 Y% G. g
  285. * 依赖        :                        底层宏定义4 l& l% \6 B+ p
  286. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>  f* J; C& q: I4 Q' x
  287. * 时间        :                        2020-02-15- _4 H: W7 X. z( s* f+ O3 W
  288. * 最后修改时间 :         2020-02-15
    1 F. W1 R6 G% B1 d2 B
  289. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的* U. O, H' t+ N* @/ Z
  290. *************************************************************************************************************************/  ' t/ n8 A( p/ v! i
  291. static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
    4 j; e% E3 }+ w, G
  292. {2 s) n& f$ _6 W# B8 K
  293.         //等待TXIS中断有效; C) j$ f# s2 B2 W5 Q" _
  294.         while((IIC_GetISR(pHandle) & IIC_FLAG_TXIS) == 0)" S7 w4 B% ]4 O0 e- X3 z) k
  295.         {, b1 O& I3 m$ M
  296.                 //有NACK中断,进行处理
    * D. W. C3 N+ x0 s- `( t5 s
  297.                 if(IIC_isCheckNackFlag(pHandle, TimeOutUs) != IIC_OK)        
    5 e; k* T' A. D+ [) i( I" |6 \6 o
  298.                 {
    $ ^, h6 x, E% i- G$ a  B0 |' f
  299.                         DEBUG("检测到NAK错误\r\n");
    9 U: [2 z7 j2 c7 o
  300.                         return IIC_NACK;) r  I7 M0 q1 }5 y* s5 H. {
  301.                 }
    : A( n$ X/ A& R; r7 S4 i
  302.                 ! @/ z+ `+ D, ]8 E' V
  303.                 if(TimeOutUs == 0)                                        //检查是否超时了
    7 V# y) I& z3 k# |
  304.                 {
    # k% g- A1 `4 n( v$ J* @! U/ X7 F
  305.                         uart_printf("IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);
    $ y' R5 r1 q& E( D. v
  306.                         uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);  W8 w) e1 g6 ?; z0 d0 d
  307.                         uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));
    ) a5 B3 G) G$ ?' b% v9 J
  308.                         
    " F* M, F  B% b' g! @9 b8 e9 s% A
  309.                         IIC_SoftReset(pHandle);                //执行软复位) M) t: z; A, v
  310.                         return IIC_TIMEOUT;                                //超时
    ( J8 v: W& _* j2 x/ X  t
  311.                 }                        
    1 p' c1 c" I' D$ |/ d: {. U
  312.                 TimeOutUs --;* N2 ^2 o% V" Y: Q/ V7 [
  313.                 Delay_US(1);                                                //延时* `' x$ ?" `3 r$ v& d/ Q
  314.         }
    - K0 M+ |& j# g/ ]* D2 N  g5 ~
  315.         
    ) A) Q* w; ?$ v+ Z# N) N: N
  316.         return IIC_OK;
    / J! O( g# ?& L6 n/ P6 p) R# X/ M
  317. }
    * E5 H# G. m4 `% G

  318. 1 o0 y; i9 f# o

  319. 4 z4 t# ?. L. V
  320. /*************************************************************************************************************************/ C1 i; S+ I' j; {- P: z1 t, S
  321. * 函数        :                        static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)
    2 u; a6 l# I* ^
  322. * 功能        :                        等待STOP中断有效(等待 发送结束 )
    % }  l/ d$ _" O- V
  323. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us  Y( ~/ M& B0 r$ n# b/ H/ m: |9 T  f
  324. * 返回        :                        IIC_ERROR) m4 J' o% l) j  F
  325. * 依赖        :                        底层宏定义# R* ~& Q0 c( x; j
  326. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    4 n( D- C6 @/ w8 H8 r7 E
  327. * 时间        :                        2020-02-15
    6 n& P1 u, F, u
  328. * 最后修改时间 :         2020-02-15# u' ]. X6 y( T2 t3 o2 [- i; n/ ^
  329. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的5 ^# G5 ^. K5 U" `. H! k
  330. *************************************************************************************************************************/  
    1 G4 q" ]4 Y9 h5 F1 ]
  331. static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)3 }6 T" o. P" g* a8 b+ h
  332. {- r" z8 `+ q1 V2 M2 x, F" f
  333.         //等待STOPF中断有效
    ' ~7 M1 w* ^6 A' v
  334.         while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
    8 h& ~3 f; v, v6 t
  335.         {
    $ b. j, t& q6 p. f* s
  336.                 //有NACK中断,进行处理
    + V$ \' a* m" ^. ~
  337.                 if(IIC_isCheckNackFlag(pHandle, 5) != IIC_OK)        
    - J/ l) R% a/ F+ t) y. A
  338.                 {# Q9 _" \" G* E) @$ B, J6 [
  339.                         return IIC_HAL_ERROR;
    8 ]0 U) R7 t$ C; V
  340.                 }* r' e  b& w+ \$ K5 Q; A& t- @
  341.                 , N% b% u, [  J5 r5 P9 D1 y% O
  342.                 if(TimeOutUs == 0)                                        //检查是否超时了; J- S, B% W/ j  D
  343.                 {
    0 y3 {6 T4 Y. }8 n3 B
  344.                         IIC_SoftReset(pHandle);                //执行软复位
    * w1 @( [" n7 u* u
  345.                         DEBUG("IIC等待结束超时\r\n");
    ) N9 e& M5 f+ i* ~2 j
  346.                         return IIC_TIMEOUT;                                //超时+ [- c' P5 x" d) T4 H
  347.                 }                        
    0 D% `5 ]6 }* S0 ^7 _2 h
  348.                 TimeOutUs --;
    5 g) |' E, _; G9 q% n8 z
  349.                 Delay_US(1);                                                //延时
    + u8 Y- h6 B9 A3 R! C, _
  350.         }
    0 S) l" r6 C) @- X) n' G4 e, o7 {
  351.         
    9 X7 @7 N( e' K- D
  352.         return IIC_OK;
    " Y# {# A: w1 H2 S; y8 \
  353. }* [: H2 {$ `( B1 P
  354. 2 Z, Q) F2 A- Q3 W) ?
  355. $ a4 h) @$ F9 U. X
  356. /*************************************************************************************************************************5 D+ S/ R$ E6 X7 v6 t
  357. * 函数        :                        static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)1 T0 l& J- a4 _3 G/ B4 X/ Z( t( s
  358. * 功能        :                        等待中断有效  ?8 X- ~1 g, C6 G
  359. * 参数        :                        pHandle:句柄;Flag:需要等待的flag,见IIC_FLAG_xxx;isWaitFlagSet:TRUE:等待标志有效,FALSE:等待标志复位;TimeOutUs:超时时间,单位Us
    * n& [+ L1 x: r0 B5 W
  360. * 返回        :                        IIC_ERROR
    ! I2 l, \' Y* n( u& d9 @
  361. * 依赖        :                        底层宏定义
    / Q: }( u* v" ~5 N- h) V
  362. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ; A! c5 c  l+ J& ]( t6 D
  363. * 时间        :                        2020-02-15
    6 ~6 ~: u# T/ p' P
  364. * 最后修改时间 :         2020-02-15
    % w- G+ i  C0 e
  365. * 说明        :                        
    % i( }/ @: A  }7 a4 x) |8 ?
  366. *************************************************************************************************************************/  
    0 s# }" y' \! K6 E
  367. static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)8 H. X  K; {9 I
  368. {
    2 _) \. W0 X1 y2 L) A# I; u& O
  369.         if(isWaitFlagSet)        //需要等待标志有效
    ) n3 v+ V/ u; c' }# v8 P8 o0 f
  370.         {
    ! N1 T8 w  V  _" p) ~
  371.                 while((IIC_GetISR(pHandle) & Flag) == 0)
    8 Z8 E, f! b, s
  372.                 {
    0 a) v5 n( q+ M0 `/ H2 ~
  373.                         if(TimeOutUs == 0)                                        //检查是否超时了% n6 n' N4 m2 K. g: q# ]3 w
  374.                         {# B& H( T+ x9 V$ Z0 a
  375.                                 return IIC_TIMEOUT;                                //超时5 c4 Y; M- [3 c( ]9 U
  376.                         }                        - o0 O4 y- l& o( w5 ~4 c/ ^
  377.                         TimeOutUs --;
    % t% W% N& `, h9 `: Y
  378.                         Delay_US(1);                                                //延时
    1 P( J! _: h( V& R
  379.                 }! I7 ?2 v  a7 }/ h$ ?, a% ~
  380.         }) H) ], m+ E3 c: y) [
  381.         else                                //需要等待标志复位
    - D3 r/ G: M) `2 m: q4 l% ~
  382.         {4 d# P: _8 u4 R* Z6 g9 R# |
  383.                 while((IIC_GetISR(pHandle) & Flag) != 0)  _8 B( ~: x7 [9 w) W
  384.                 {$ N9 k- G  N; R, C
  385.                         if(TimeOutUs == 0)                                        //检查是否超时了
    # C% y6 ~# I# I+ s
  386.                         {6 q; u' }* N& O8 W& M( b
  387.                                 return IIC_TIMEOUT;                                //超时* x) s: j. d$ J, I
  388.                         }                        
    6 Y& a1 r) V' b
  389.                         TimeOutUs --;
    / e2 H( a+ @( b8 u
  390.                         Delay_US(1);                                                //延时; s2 o  E, Z6 g! w% a5 K0 c
  391.                 }
    $ }' V8 a) N. F8 W% ]2 v
  392.         }
    " B7 T, M# m# |$ C
  393.   r5 e% ]$ L% S% y4 ]2 M
  394.         return IIC_OK;; Q( K& S5 N" r; |
  395. }
    & I2 u9 z2 H0 ^; p& t+ C
  396. ; V; q. s/ D0 ^6 p. \! o/ h

  397. 4 ^: z5 k  s7 w3 v+ ]
  398. 2 |9 ?1 t5 H+ e+ A5 {+ I/ D; }
  399. ( q1 X& Z- {# o: U7 u# V# @# `
  400. /*************************************************************************************************************************8 X5 X$ e$ P, A4 U# w
  401. * 函数        :                        static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)
    $ V0 J9 w7 ^+ M
  402. * 功能        :                        主设备传输配置(配置CR2寄存器)
    # q0 i, X' k) S# z% g
  403. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;TransByteCount:需要传输的数据长度;EndorReload:自动结束还是重载设置,见IIC_RELOAD_END_MODE;StartAndWR:开始读写控制,见StartAndWR4 w2 r1 L9 x+ q& A; }
  404. * 返回        :                        无
      a# U* A! U  {  Z
  405. * 依赖        :                        底层宏定义% j5 l) ?3 A6 F9 W5 {! |
  406. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    . ]- m+ `; c# \7 H( @: x
  407. * 时间        :                        2020-02-15* F7 C4 @/ M' Z5 m2 O3 v( Y
  408. * 最后修改时间 :         2020-02-161 n  }1 r& L& Z6 E( P
  409. * 说明        :                         在往 NBYTE 中设置最后一次传输的字节数前,必须把 RELOAD 位清零便于后续自动发送STOP。
    - c- i8 r: v& p: ^0 w
  410.                                         当 RELOAD 位置 1 时,AUTOEND 位将不起作用;
    ( S# [7 }+ W5 S. T
  411. *************************************************************************************************************************/  ; f# e# U$ q& u* q% n/ c6 ]
  412. static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)- \: r7 j3 c- r6 }$ K
  413. {
    , ~; @" O! F6 k+ J
  414.         u32 temp = 0;
    ' U' V& l8 \& X* j/ N
  415.         ! y7 S+ a" R. K
  416.         //先读取CR2寄存器的值+ w% E- _' V& I+ S: o; h9 x
  417.         temp = pHandle->I2Cx->CR2;
    ; X3 H2 B- _4 F2 R1 l) ~" s
  418.         //清除掉相关的字节
    : s# c0 [' Z+ s) U, S5 A
  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));
    & J$ U- G% o) P  Q
  420.         //生成配置数据+ F- A2 _% Y" v( a
  421.         temp |= (u32)(((u32)SlaveAddr & I2C_CR2_SADD) | (((u32)TransByteCount << 16 ) & I2C_CR2_NBYTES));
    3 |; E; x9 O$ G) ^, |4 _0 D: s" t
  422.         //重载与自动结束只能二选一
    8 o5 S9 d( n: @' y$ p
  423.         if(EndorReload == IIC_AUTOEND_MODE)         
    : R' Y; z7 C  P
  424.         {. O6 Y& M) i% g% K5 X4 G: b
  425.                 temp |= I2C_CR2_AUTOEND;        //自动结束模式
    ( j: F# i+ D  {
  426.         }
    4 W/ ^6 j: p; O8 a: Z
  427.         else if(EndorReload == IIC_RELOAD_MODE)7 t3 Z. y  x/ a9 X: }( L
  428.         {8 w9 C1 r' c( e1 u3 P9 c" D
  429.                 temp |= I2C_CR2_RELOAD;                //NBYTES 重载模式/ @7 \. P" [: z
  430.         }9 U5 K" K) P: _/ C. N3 f4 x0 p
  431.         
    0 O+ U3 o  V% r  w+ n- b: D7 T7 ?) ~
  432.         switch(StartAndWR)# I0 P. o8 G) _2 H. o
  433.         {
    ( z$ L2 z4 f8 c6 V4 n$ f
  434.                 case IIC_NOSTART_WRITE        :        break;        //没有开始的写-默认就是这样的% X2 p( m7 A7 k0 P# Z5 B
  435.                 case IIC_NOSTART_READ        :                        //没有开始的读-用于后续数据读取% s; ~0 o  s  r1 c0 n5 V
  436.                 {
    8 a8 I! {' W1 f! o, i( @4 ]
  437.                         temp |= I2C_CR2_RD_WRN;                        //读取( J- j7 [; t% _8 s' q4 I
  438.                 }break;
      E8 f% r2 W8 t; Q, D8 D- h1 {; w- }; ^7 N
  439.                 case IIC_START_WRITE        :                        //生成开始写2 B' R  V; ~- n2 `1 ~% K
  440.                 {
    2 u( m' w) @6 b: b
  441.                         temp |= I2C_CR2_START;                        //启动传输& e; r% M. f# j) {7 v- N2 C4 G
  442.                 }break;
    $ M8 u+ Z4 |, q  g
  443.                 case IIC_START_READ                :                        //生成开始读        
    6 C0 @: X" X8 F$ z9 k! m) I. `
  444.                 {
    . R) F( [) ~# E5 l7 u0 Q: s0 ]
  445.                         temp |= I2C_CR2_RD_WRN;                        //读取
    ( H+ @' {1 x/ W' K9 `* H) Q& e( A
  446.                         temp |= I2C_CR2_START;                        //启动传输
    5 g; d* D) S+ }2 g3 H- G
  447.                 }break;
    6 W; I7 o4 d) n5 v$ c
  448.                 default:break;; h5 \& a9 h) |# V* X4 u1 H
  449.         }# N) K4 ?/ B" T" ^( ]# {" \2 l- p
  450.         
    ' ?: a! C: F4 u$ @
  451.         //uart_printf("准备写入CR2=0x%X\t", temp);, t7 G. A5 s% u; b* W7 m, N( Z
  452.         //更新到寄存器# M. t6 N! Q6 w. ~. h0 T
  453.         pHandle->I2Cx->CR2 = temp;  //测试
    4 c# Z) \  S# V& t/ i; ?  U
  454.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);& U  x+ J( u( G; e
  455.         Delay_US(100);
      X  H" a& @; ^  F. r
  456. }
    . s) ?9 x, x0 g" y% Q) P8 D
  457. $ R, G6 K0 c+ v/ u& W/ d

  458. % m7 \" S" [0 u" V5 R; A  r( i
  459. /*************************************************************************************************************************
    9 B( |. S3 D- S
  460. * 函数        :                        static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)
    * N! Z0 P' J4 C& C" p, p
  461. * 功能        :                        IIC发送一字节
    . C! \5 b2 A% B! U. T$ n
  462. * 参数        :                        pHandle:句柄;data:待发送数据;TimeOutUs:超时时间,单位us6 w( ?; o; j3 p9 I
  463. * 返回        :                        IIC_ERROR
    # v' w/ \. s  J2 H3 p* J4 W
  464. * 依赖        :                        底层宏定义
    - _  g9 r" d) E
  465. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>! r( O! x( S$ `+ O+ P1 Y1 i
  466. * 时间        :                        2020-02-153 X1 n; T7 d7 r
  467. * 最后修改时间 :         2020-02-16
    / N6 M, O1 z" H" J) A! z) e
  468. * 说明        :                         TXIS有效后才会进行数据发送,不会检查数据发送是否完成。
    . t/ [2 X- w$ T" r$ h5 f# i
  469.                                         如果最后一个字节发送完成后不会再触发TXIS中断,只会触发TC中断
    2 m9 I2 x- S' s3 y
  470. *************************************************************************************************************************/  
    - X: b- ?8 \( V$ ?9 K
  471. static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs); Y, H2 T" ^+ f2 N0 ~- }
  472. {
    , L* E9 M4 h/ U$ s$ t7 z1 G# v- x
  473.         IIC_ERROR Error = IIC_isWaitTXIS(pHandle, TimeOutUs);                                //先等待可以发数据1 |7 }" L! @% A
  474.         if(Error != IIC_OK) return Error;
    7 z+ f4 m) Z' K2 \% Q
  475.         pHandle->I2Cx->TXDR = data;                                                                                        //写数据到发送寄存器-不会等待数据发送完成        
    4 G' \5 q! x6 g) h; g) E

  476. ( k  e# ]8 l! V
  477.         return IIC_OK;8 y( _( {8 h3 U- y, i+ W& e* F
  478. }
    7 i8 d* S2 y& x9 s5 [: W
  479. - m+ h) g0 y# k) V0 S
  480. /*************************************************************************************************************************' c2 x3 @( [' I" [* O2 l
  481. * 函数        :                        static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    7 h9 X1 h+ s; J
  482.                                                 bool isRead,u32 TimeOutUs)
    4 f( n% u6 K3 [+ ?" g8 I/ c
  483. * 功能        :                        主设备请求发送从机地址与目标寄存器地址5 x+ Z6 K; [; V6 D" e, E4 t/ e
  484. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;RegAddr:寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,4 ^# f# K! \1 g* D/ H
  485.                                                 FALSE:16bit寄存器地址;isRead:TRUE:这个操作是读取寄存器;否则是写入寄存器;TimeOutUs:超时时间,单位us! p1 x1 G- o. Q: [8 |; v; d
  486. * 返回        :                        IIC_ERROR) E* Z* |+ m* Y
  487. * 依赖        :                        底层宏定义, O* Y- K6 q+ S/ H$ _& l
  488. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    : E' B  t1 L  B7 r' u. r! G
  489. * 时间        :                        2020-02-158 {0 A1 ^% |8 ]' A1 W9 q
  490. * 最后修改时间 :         2020-02-16
    " C: u6 Q( v, d: i* p, U$ @
  491. * 说明        :                         2 Y" @( j% K1 A8 B* O
  492. *************************************************************************************************************************/  
      P% f- C& O0 v8 d
  493. static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,bool isRead, u32 TimeOutUs)! C( q) s  D$ K" L
  494. {        ' m" P6 L5 u$ W( M
  495.         IIC_ERROR Error;/ e4 D- Q0 }) e; D# t1 p" {
  496.         
    ' \: K! m# M3 {. ]" s& @9 l9 T
  497.         //uart_printf("WriteAddr1:CR1=0x%X\t", pHandle->I2Cx->CR1);6 _5 [: B; w% U6 ?5 [
  498.         //uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);# a! T& ^, \; b. y% B+ Q
  499.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);6 W' D7 x! f8 F
  500.         //传输配置,并启动传输,发送起始序列,开始IIC传输了& Z# b" r& ~+ D- k" ^; C( a
  501.         //如果是读取则使能软件结束,如果是写则是自动重载$ O: C2 X- Z5 s0 w! _; Z
  502.         IIC_MasterTransConfig(pHandle, SlaveAddr, (is8bitRegAddr==FALSE)?2:1, (isRead)?IIC_SOFTEND_MODE:IIC_RELOAD_MODE, IIC_START_WRITE);        //传输相关配置-写,并启动传输! s& S+ O* P& W  O+ E* ]
  503.         
    1 l2 z% W1 v3 S0 X) t. o) U
  504.         //开始发送寄存器地址! K3 ^$ }. L5 {) S" V
  505.         if(is8bitRegAddr==FALSE)                                                                                                //寄存器地址是16位的,IIC通常是MSB高位在前,需要进行高低位对调
    # j/ J9 K8 q/ J# C$ n
  506.         {
    2 a/ r% w% R8 |: k2 v9 _
  507.                 Error = IIC_SendByte(pHandle, RegAddr>>8, TimeOutUs);        //先发送MSB-非最后一字节- _; I6 b- d- k( `
  508.                 if(Error != IIC_OK)8 o8 m& x- Y) Y! i6 f& _0 U8 I" D
  509.                 {; }; \$ Q! v" r0 `0 l/ `
  510.                         DEBUG("IIC发送寄存器地址MSB失败\r\n");7 j9 ?0 r' {5 {& B4 P6 r
  511.                         return Error;& |7 J2 J' K* s, w9 X
  512.                 }        / `! O: R6 |# T& \5 R. Y
  513.         }
    2 Y( \: b9 {: [! o  t1 g2 M% G
  514.         Error = IIC_SendByte(pHandle, RegAddr & 0xFF, TimeOutUs);        //再发送LSB-最后一字节
    " Q0 c2 X7 p( J. W$ ^4 R" |* V
  515.         if(Error != IIC_OK)
    & d7 j9 O$ H6 ^" F& G: _: Q
  516.         {. a8 W+ J+ Q; }6 ^% v
  517.                 DEBUG("IIC发送寄存器地址LSB失败\r\n");8 P0 J, F, c, j( u$ u1 {) m( e
  518.                 return Error;/ @5 O) g" f4 b2 l7 A; ~
  519.         }
    9 t7 j- B" O4 a& h
  520.         //等待全部数据发送完成- c9 y* @# Z' i, p9 g
  521.         if(isRead)        //读取方向-非重载,等待数据传输完成 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。: m5 d2 \+ j8 O+ h1 E$ W
  522.         {# Q8 e$ Q- D5 h! Y
  523.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TC, TRUE, TimeOutUs) != IIC_OK)
    " Q' J: \% V# u+ F4 ]  T
  524.                 {
    " ?2 g$ G$ k3 e# t7 o6 u/ S
  525.                         return IIC_TIMEOUT;
    ) G5 u+ E) t; d( M2 P0 P3 y
  526.                 }
      Y% t; F" v2 W, `( n0 v
  527.         }        0 W0 Y; y5 b3 N1 X
  528.         else //写入方向,等待重载( ^- t. W6 h3 G, ?4 J7 }
  529.         {! I$ w; F6 g4 ~0 d: M  p  O
  530.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TCR, TRUE, TimeOutUs) != IIC_OK)
    / X, [% V$ ]* a( e, N% o
  531.                 {
    9 Q; C+ c3 h, c* z9 m- M3 g! ~! S
  532.                         return IIC_TIMEOUT;8 j5 ?* ~# y- L* P( u0 f2 G1 ^  {
  533.                 }% K' A4 K1 T( ~; K3 ?( \# F2 g+ b4 |& W
  534.         }5 ]; i8 {0 D: X* @: ]; j
  535.         
    % b$ ~4 r' O& n' Q0 |' ?
  536.         return Error;1 i( s- Z+ e$ R7 }. K
  537. }
    # X( A- }& ], Q' X8 Y
  538. 2 `: E# |* Q/ W3 J. ]' D/ B$ k% R5 |
  539. . R, ]- M) b& r; F+ r' Y# h! k
  540. /*************************************************************************************************************************
    * b+ q/ ~9 W: F" m. k
  541. * 函数        :                        static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
    ) s* M- g2 U, y7 h) O* G5 j5 U
  542. * 功能        :                        等待接收一字节数据  z; k! r3 p: _3 E" G% x
  543. * 参数        :                        pHandle:句柄;pData:接收的字节数据缓冲区;TimeOutUs:超时时间,单位ms+ h' z. B. l, [- g$ X/ Q& U
  544. * 返回        :                        IIC_ERROR
    6 K" q1 g3 b& V0 }
  545. * 依赖        :                        底层宏定义, f, b  V- I* ]# |  L+ O3 p5 Z
  546. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    , P0 q+ o! K' a; l- y
  547. * 时间        :                        2020-02-15" V/ M5 y5 H0 G
  548. * 最后修改时间 :         2020-02-15
    ) p" [: W- h* v( W' b' Y9 ?8 b
  549. * 说明        :                         当RXNE有效后读取一条数据,否则可能会超时
    . k. {4 F% H$ }/ l) v  s% d6 b1 J
  550. *************************************************************************************************************************/  
    ! t6 Y5 n- T$ ~
  551. static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)+ a$ n, A( w! {, g' F+ I( g
  552. {! I. C7 J$ S; G/ e4 b& Z
  553.         while((IIC_GetISR(pHandle) & IIC_FLAG_RXNE) == 0)        //等待RXNE有效
    ! p! ^- z( z, i  u. w
  554.         {9 h6 E$ b( B! z% d# A' s& m. w$ v
  555.                 if(TimeOutUs == 0)                                        //检查是否超时了. i  ?/ R5 b+ O6 h6 x
  556.                 {
    : V4 m" \2 j0 B
  557.                         DEBUG("IIC等待接收超时\r\n");
    , l4 P% ]- k& I- v" A
  558.                         return IIC_TIMEOUT;                                //超时
    ' k# c1 m4 m6 Q
  559.                 }                        ! z( [$ C  q7 l9 ]3 k4 h
  560.                 TimeOutUs --;
    ; u9 E/ c7 f9 I8 [
  561.                 Delay_US(1);                                                //延时. a8 o) t; c9 I7 `, @( A: S
  562.         }8 @# m* b( c1 Q- s( N
  563.                 ) N/ R2 m& }5 L& o, J$ R. x# v
  564.         *pData = pHandle->I2Cx->RXDR;                                                        //读取收到的数据% l  q$ b* B0 c/ p6 Y" n8 J
  565.         return IIC_OK;7 K4 n- P. W( a) f. k# n" H" v
  566. }
    0 F: ?/ {1 `1 ?6 s( \" d7 K

  567. ) j4 z' |" v. r7 n5 i' S. R
  568. + \* v: k' @, ~" a$ q8 G
  569. /*************************************************************************************************************************# O" H" N9 y4 P% ?: `9 l% j
  570. * 函数        :                        IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, + M  A( {# r+ C) i4 T1 \
  571.                                                 u8 *pDataBuff, u16 ReadByteNum)2 B" [' L0 J7 W9 e( U/ q( R' y
  572. * 功能        :                        IIC读取寄存器(可以读取1个或者多个寄存器)
    $ R* N. y7 d; I* b/ j0 l
  573. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要读取的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;
    # Z! i: k- v3 J+ m% n
  574.                                                 pDataBuff:接收的字节数据缓冲区;ReadByteNum:要读取的寄存器数量;
      `* K. u1 O; K7 k
  575. * 返回        :                        IIC_ERROR4 O( ], T2 b( F( H3 M
  576. * 依赖        :                        底层宏定义% ?5 y2 j" }* J7 N8 a% _; L
  577. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>; C9 W  M- R% t; Q, u- i! C
  578. * 时间        :                        2020-02-15# [& P# j. _; X  i) A
  579. * 最后修改时间 :         2020-02-15
    3 ~& B. [9 O9 T4 Q* X8 @
  580. * 说明        :                         读取的数据都是小端模式,如果是16bit的寄存器,请读取偶数个数据,并且需要另外进行高低字节对调最后组成16bit数据2 E" m% Q$ ]* p! x
  581.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
    ; V7 Z8 v5 |+ R/ \5 Z* u
  582.                                                 增加信号量& u, f2 t1 A; u7 a, g/ m
  583.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在7 e8 Q7 o# G! {( U
  584.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。. ?0 `! i( p# z* O" J
  585. *************************************************************************************************************************/7 `( ~  ?- d  D4 p. p' P  y/ {7 s1 I
  586. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum)
    $ d# J. w7 L9 h6 _. _9 V: z( o
  587. {
    4 D3 x7 n- d, _6 ~. {' Q
  588.         IIC_ERROR Error = IIC_OK;
    ! @3 G+ b7 g6 u% r7 Z
  589.         u16 ReadCount;" R+ C& ]6 E9 H8 |7 {/ b" w
  590.         IIC_HANDLE *pHandle;
    3 r! g' O+ W) ]2 [7 l# w
  591.         7 U+ ]( p9 y+ }. ?$ E
  592.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || ReadByteNum == 0)
    ! z8 ^9 t- D9 j* x
  593.         {/ @) w& w8 W8 v$ x3 {9 A0 |5 Q
  594.                 DEBUG("IIC错误:无效的参数\r\n");6 X4 e( M# a+ K$ ~8 e7 _7 Z
  595.                 return IIC_PARAMETER_ERROR;
    / S3 O+ E6 B% B* e$ Z
  596.         }
    8 n& j  ~; M+ _+ w
  597.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄- T7 A- L! T4 r9 ~. M6 M
  598.         4 u6 y* q' D% t
  599.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙
    : Y* \" l8 d$ _! Z' J. Y9 E
  600.         {* b) t7 T+ [5 V$ ?# f
  601.                 IIC_SoftReset(pHandle);
    & ^" q3 [, [" V* {& A
  602.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");! F- n7 c$ ^7 g4 C. e  W: s; Z5 z) _
  603.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙
    8 z# R7 v2 d2 ~6 x/ R  u6 O7 l4 L
  604.                 {
    $ b( T3 A& H0 a5 _
  605.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");
    & M; T0 A! f% z
  606.                         Error = IIC_BUSY;
    5 K8 r, d2 r6 y* q3 `/ t7 b% ?5 T
  607.                         goto end_loop;9 ^5 a1 m+ v- _2 G# r* W2 ^; T
  608.                 }6 j) l9 U4 I! ~. v/ |- ~
  609.         }' ^. `) |6 X$ {7 ^( {
  610.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态1 ^2 }$ l8 f% m, e/ h6 R+ Y
  611.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器# D- ^! A# n2 d. W1 T$ `, Z  k5 o
  612.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START. `# S, h, N) R( d, j
  613.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,TRUE, pHandle->TimeOutUs);
    ! g% g. ]& B: f5 u* ~. ~# b
  614.         if(Error != IIC_OK)
    9 b8 \2 I4 _- O5 G* B
  615.         {
    1 t4 E& P; h) l4 C
  616.                 goto end_loop;- y) ~" j) i! v( x: f2 ]2 A
  617.         }
    1 p( J' r; B, M' {; \% U
  618.         //发送后续数据% E" y3 e; m  A7 f% G
  619.         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取-后续还有数据,需要重载
    9 d! C% y7 D: Q5 l5 e  A
  620.         {
    ; w) C, X3 T9 }9 s# [  n
  621.                 ReadCount = 255;        //本次需要读取的数据长度255- E. n  s" s- e8 S& \$ [1 i
  622.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输               
    5 l; e3 l# g" N6 Q
  623.         }7 g# [4 {4 l# d9 q: i1 `  X. J
  624.         else
    9 p6 r# s: p+ ~+ s& z
  625.         {
    4 M$ }7 l3 o) x; R( u$ N3 X4 T
  626.                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯后自动结束6 L1 E  ?, j# o8 g+ b8 V5 O
  627.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输  s+ ]2 {9 d" N8 K5 I. G
  628.         }3 D& _1 c  j, c; ^# M$ |' U$ _
  629.         & l" d; Y- @9 u$ P3 X
  630.         //循环等待接收数据完成3 s" h0 y5 I0 u( n$ \
  631.         do5 J! D$ s( _% @7 V7 \
  632.         {  |) a/ J/ |9 q, G& H! P3 ]1 P  W
  633.                 //uart_printf("读ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    0 i0 A4 C4 O/ ?; {- g
  634.                 Error = IIC_WaitRxOneByte(pHandle, pDataBuff,  pHandle->TimeOutUs);                                        //接收1字节数据
    7 B; p" S& z# c5 }" |1 @9 Y
  635.                 if(Error != IIC_OK)
    4 _) K5 U. e, L# x# U
  636.                 {
    + E: O% h" L9 A& C) i; S
  637.                         goto end_loop;
    & |: w) e# ~, J0 R$ N4 ~
  638.                 }
    8 n, c- k3 r" l% g8 G, K
  639.         
    6 }8 k5 b* K4 X: s
  640.                 pDataBuff ++;  j) ~6 F( f$ k( n: h
  641.                 ReadCount --;# H: V% d  H6 [  }
  642.                 ReadByteNum --;
    # L) v7 y- D- |+ A8 }% I1 a
  643.                 if((ReadByteNum > 0) && (ReadCount == 0))        //还有数据要读取9 ^5 @2 b1 I5 K! ^/ w% `$ f
  644.                 {
    ( b! Z3 q3 H& R' E; M6 h2 _- ^
  645.                         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取( u7 a9 j. s0 V/ t8 v/ H$ ~
  646.                         {" q* c: G! a: @( e
  647.                                 ReadCount = 255;        //本次需要读取的数据长度255-后续还有数据,需要重载  [. X1 }7 R6 {4 N. P
  648.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
    9 u- D! U& e7 G/ l$ Y; H
  649.                         }
    ( C& \. J+ A" E
  650.                         else' Y' p! F4 N4 d- K& E/ E
  651.                         {
    / h" `# U5 L! I8 Y
  652.                                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯,自动结束, h0 l! ^! L, u
  653.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        + c8 y5 b2 n- I! `4 A7 W3 [3 a
  654.                         }
    & U, v; w6 J, V8 V5 T9 d
  655.                 }7 h7 M9 y" l# S( d# Q
  656.         }while(ReadByteNum);+ b4 H+ P5 A; i0 [# d; g9 `
  657.         //读取完成了,等待STOP位有效
    0 C( h) d, ?! W2 I* _8 T9 e
  658.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);
    / P& Q4 I% |/ e7 ~
  659.         if(Error != IIC_OK)
    ( ~* _  Q3 w# s; d! P$ [6 c
  660.         {8 g  Y# F" e2 O1 L) L" r
  661.                 Error = IIC_STOP_ERROR;% s) U  y  Y5 ?; `) \
  662.                 goto end_loop;6 h- A+ e5 H; I- O4 }, {
  663.         }        
    # l. N& d/ f; w( _: O8 D8 V7 s4 F! y
  664.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态4 \9 g9 Y% H4 o, X4 Z( ^; k+ L: x2 O
  665.         & _) ^! \  g% M, B+ e
  666. end_loop:        - t) o3 M* W, [) i8 d/ k" c: V- [
  667.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        + \8 t! o3 ~$ b# G; A6 U  K
  668.         if(Error != IIC_OK)4 N* x; m: `1 S# h7 W" Z* M
  669.         {, h! e/ ~/ ^" ?  g: i+ ?
  670.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误# ]3 q- Z9 ?* s/ k
  671.                 DEBUG("[IIC R错误]:%d\r\n", Error);4 e- R6 L3 J% J3 b. K
  672.         }+ R: x/ z/ |7 {, S, X. z% [2 l
  673.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的
    & b! Z" p# [3 A
  674.         {
    : ^5 ^3 F- z6 I& L! M
  675.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    * D0 p& n1 ?0 p, k2 Y" a5 y
  676.                 DEBUG("IIC R结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);                " t' E( w7 ]: ]
  677.         }
    : L4 u0 t. [3 V" `
  678.         
    . y+ q1 U5 Z+ N
  679.         return Error;
    % O; ], E  b6 Q8 o* L$ y3 X7 w$ J
  680. }
    9 I. G1 j* u* m" i! Y

  681. 8 q( y' F) N0 P9 k1 f! V
  682. + N; ^, I* S* G; c
  683. /*************************************************************************************************************************( v- }; P7 V9 T( C/ v$ R) x4 ^" ]
  684. * 函数        :                        IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, 2 R' h4 K: j$ v3 O
  685.                                                 u8 *pDataBuff, u16 WriteByteNum)" Z, Q" Y, W* |" }
  686. * 功能        :                        IIC写寄存器(可以写1个或者多个寄存器)3 q, K3 U/ G0 @* s! p( Y
  687. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要写入的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;3 U% V. ]1 q; ], n, G
  688.                                                 pDataBuff:写入的字节数据缓冲区;WriteByteNum:要写入的寄存器数量;
    # i! V" y: `( ~) k7 Q
  689. * 返回        :                        IIC_ERROR/ T7 H8 h9 p. i+ i
  690. * 依赖        :                        底层宏定义1 z% U* Q1 M3 S3 R8 I
  691. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>0 h- c$ V0 I1 N8 w/ t8 K# Z
  692. * 时间        :                        2020-02-168 x! K7 X$ ]/ h5 x* f) s
  693. * 最后修改时间 :         2020-02-169 ^# G" R  i% Z' G! M& \
  694. * 说明        :                         写入的数据都是小端模式,如果是16bit的寄存器,请写入偶数个数据,并且需要提前进行高低字节对调最后组成高字节在前的数据buff/ ?. A+ `% O# ?4 @1 X3 o( X
  695.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如  q5 g1 M, v4 q2 D2 L7 K
  696.                                                 增加信号量
    2 K: q; V% H/ s7 q5 G: T5 y
  697.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在( g, H+ i3 Y( B& F) U3 B5 R
  698.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。" ]6 p# [5 a, D: ]+ y
  699. *************************************************************************************************************************/
    # h# x5 f3 \# k3 y5 V
  700. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum)( a, s* k2 Y1 P8 ]# D
  701. {
    ) Y+ k" S4 q% ?$ q
  702.         IIC_ERROR Error = IIC_OK;
    3 ~5 s6 {3 M$ p% g! C0 a
  703.         u16 ReadCount;/ D( K' O' l0 A. d6 C! N- x8 y$ q
  704.         IIC_HANDLE *pHandle;, Q; |& f  E3 C: l1 K4 e, G
  705.         8 u% @8 X8 K' q$ R0 s' ]
  706.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || WriteByteNum == 0): I" Q2 B. \3 o8 I9 h1 Z
  707.         {' G2 z7 F! w8 r8 m- Y
  708.                 DEBUG("IIC错误:无效的参数\r\n");
    5 e6 L* R$ t" \" k$ |
  709.                 return IIC_PARAMETER_ERROR;
    ! y6 V5 Z7 B" r. O( _2 E
  710.         }: \4 V; X: l$ z$ {: t
  711.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄
    " h1 W; b% Z( {% c8 ^! u" R7 q6 [
  712.         
    ; X' C+ C; u# m" }2 \2 T# w& C
  713.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙$ v: b' z$ c0 n$ a5 A, I* `% r
  714.         {
    3 R& l5 ~5 ?3 c; Q5 [- [
  715.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");, V* e. t0 z6 v: ]9 j2 ?" _. s% ^
  716.                 IIC_SoftReset(pHandle);
    # d4 s, h9 A; I  i4 X
  717.                
    ) D( d+ _6 A% \+ k7 T) S
  718.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)        //忙
    4 q  L# C9 }$ L$ U
  719.                 {" [7 T7 y" |. v2 m; w, \
  720.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");
      L0 G' i7 {: B6 J) [1 F
  721.                         Error = IIC_BUSY;
    3 j5 ^/ \2 Q0 [! k
  722.                         goto end_loop;# _- W3 B5 V  |
  723.                 }
    ' H$ z$ c( ^- H  o4 ?
  724.         }1 D0 l' X1 I) w3 Z5 M
  725.         . P9 i  m& @! o' @- {: C
  726.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态$ k' t- V# L) d1 D2 n9 X- T
  727.         IIC_ClearCR2(pHandle);                                                //复位CR2寄存器% j" F+ S) d/ ^- R8 k2 |5 J( Y
  728.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    2 p1 w' |* k6 |& f% b' P+ Q5 b
  729.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,FALSE,  pHandle->TimeOutUs);1 h( S( i7 N8 z% l3 t) ^# S" v
  730.         if(Error != IIC_OK)
    7 Y1 {8 j' e+ Q$ N
  731.         {
    " ~5 ]$ c/ x6 Y1 q
  732.                 goto end_loop;" W* o' s7 d9 |) q/ F( `+ R; F( ]
  733.         }
    " U/ \4 Y& K$ y1 j" P/ H
  734.         //发送后续数据$ u& k/ ]3 {! M: p) b% T
  735.         if(WriteByteNum > 255)                        //如果超过255字节,则需要分多次写入-后续还有数据,需要重载% v% I5 L1 H& ~4 \1 _# ?" J
  736.         {
    ; o* S$ J3 T' y9 C
  737.                 ReadCount = 255;                        //本次需要写入的数据长度255
    5 A. l( j& |& r1 k
  738.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入                + o% W( o( x  g1 B4 h
  739.         }  o2 y$ x$ u. w8 d" K! W
  740.         else
    7 Q9 d+ E6 [) r7 H6 {( ~+ e8 H0 I
  741.         {
    " r7 a, _8 g# i: Z
  742.                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯后自动结束2 \# X$ f. Q; ?; e
  743.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入$ E3 X! y4 H5 z9 m1 l
  744.         }
    & u  W; N+ m1 x1 B

  745. $ U1 D7 B. H! J0 Y2 b' p
  746.         //循环发送数据
    ( `1 T, n' \- x# ^
  747.         do7 Z& `* n( j: z0 X" c' {5 z. F
  748.         {
    " v  ~- H. o- F/ T! f* r
  749.                 Error = IIC_SendByte(pHandle, *pDataBuff, pHandle->TimeOutUs);        //发送一字节
    0 n' B$ V: _! S9 `" a4 {5 z7 z+ r( U
  750.                 if(Error != IIC_OK) 4 f" |& P# e) K7 T
  751.                 {
    # `4 Y4 k, L6 p9 `; z9 V$ j: W
  752.                         goto end_loop;
    / |8 E: ^+ p1 a; S8 n0 B7 z
  753.                 }
      V* d- J; s# _& }( Y/ s

  754. % |+ h4 J  a$ d7 W+ i+ v+ I
  755.                 ReadCount --;$ s. i  i* V, |& w% U! w1 C8 y, Q
  756.                 WriteByteNum --;. n# x: C' _  w3 v: B! Q1 X
  757.                 pDataBuff ++;
    2 @3 i3 [0 q/ k* `
  758.                 " G* N0 Z4 y. ^% l+ t  j$ y+ B
  759.                 if((WriteByteNum > 0) && (ReadCount == 0))        //还有数据要读取
    1 e" R9 r+ ^3 ^8 T' w2 J& T2 M  y
  760.                 {" _. K  _' E/ X6 A0 ~4 R3 X0 ]
  761.                         if(WriteByteNum > 255)        //如果超过255字节,则需要分多次读取$ n5 q4 _- e5 d1 `
  762.                         {8 R9 Q& g+ j. ]6 l% ~5 Q
  763.                                 ReadCount = 255;        //本次需要写入的数据长度255-后续还有数据,需要重载
    ! ]3 ~0 L1 w8 _1 E# x; {
  764.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入
    4 s  l. G# k9 ~: ]2 X" x- Y6 o
  765.                         }
    ( k, e. c$ Q  c: g& o! b' i
  766.                         else
    0 q, k4 g# p* Z! R
  767.                         {
    ( Z' _' P# W: K% Y& @$ ?
  768.                                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯,自动结束
    . ^1 z; c% l8 y. y
  769.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入                - Q5 B# R% R1 C
  770.                         }0 v: _) y7 S# Z: n+ C
  771.                 }
    4 o% @3 q3 }+ j# l% v2 g7 i
  772.         }while(WriteByteNum);        3 D; k" s- m3 Q5 S
  773.   n4 m/ v' K" k$ x  X% b4 r! R- u
  774.         //写入完成了,等待STOP位有效7 m6 `  t9 [2 ~$ B
  775.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);+ W& O. K( D- T/ C$ I! t% R2 c: X
  776.         if(Error != IIC_OK)
    1 N1 j/ @0 ?" H9 h1 L# v/ W
  777.         {) |( N) L6 f( i
  778.                 Error = IIC_STOP_ERROR;
    " R; G/ Q# s7 X  {  o5 a/ m" A
  779.                 goto end_loop;3 v, `; X  S" K. f" H
  780.         }! H' \7 I, s3 O
  781.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    8 z: q% r8 g$ \
  782.         3 f1 ~5 p' O# d7 G
  783. end_loop:        
      {! v! t, I7 e. K
  784.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        
    2 d: j8 O2 L9 A: i! q" ]0 o& x, s
  785.         if(Error != IIC_OK)) U8 ~- c* D0 ?0 X3 |( ~% w2 u
  786.         {+ m3 x2 V* l: U
  787.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误
    ( Y7 J9 R/ J. A  I: K3 y! m( N* ]# X
  788.                 DEBUG("[IIC W错误]:%d\r\n", Error);
    # {1 l% g( c! a# v0 k& [5 k/ @
  789.         }: I/ }7 L( q* z& c% z
  790.         
    ! M& X7 j4 \$ d  Z  m
  791.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的
    0 d# L% o: F' ]7 i/ k: j& V, h
  792.         {4 S# R4 r8 b) D8 O) q0 S
  793.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    4 h' r  L5 J- X6 Z
  794.                 DEBUG("IIC W结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);               
      ?2 p% O% M7 f5 Q& m& }
  795.         }$ V' g% a+ P3 B) H2 W& ^! ]+ z
  796.         return Error;
    5 C+ J  h) |5 v; }9 z3 g
  797. }) k- Y4 [4 _9 F9 j  U/ f

  798.   e7 f2 L" Q+ N6 Y. X3 s% \

  799. 0 s& q- ~" v! u. R( e6 r
  800. /*************************************************************************************************************************
      |9 p- O  R& x
  801. * 函数                        :        void IIC_SoftReset(IIC_HANDLE *pHandle)
    ( q$ H+ X2 o/ t3 r4 M8 m- l
  802. * 功能                        :        硬件IIC软复位(会使能IIC)5 _5 u/ Q9 b0 T
  803. * 参数                        :        ch:IIC通道
    ( l( S- o5 t. d5 t5 b
  804. * 返回                        :        IIC_ERROR0 ]: m" q7 K& u- A
  805. * 依赖                        :        底层宏定义
    % ~$ r* x! V; Z$ V
  806. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>. `  d  L! z, T& @$ [/ y! V
  807. * 时间                        :        2020-02-15; e2 }; G6 F- ?* F9 ?
  808. * 最后修改时间         :         2020-02-15
    / [6 E8 U- ~( j: _% K$ _1 R/ q
  809. * 说明                        :         IIC软复位;必须使 PE 保持低电平持续至少 3 个 APB 时钟周期,才能成功执行软件复位。
    - C. J% S! b" b4 J
  810. *************************************************************************************************************************/
    4 f2 A( u* ?# {0 b# U
  811. static void IIC_SoftReset(IIC_HANDLE *pHandle)
    & T" [4 j3 v6 T4 ^4 A# T
  812. {$ S% A# _0 m' B, W2 F- j+ f
  813.         pHandle->I2Cx->CR1 &= ~BIT0;                //关闭IIC后执行软复位
    $ L7 u) _. O( j% a) F  N0 x
  814.         Delay_US(1);          |7 E' Q. N4 o' H# D+ n4 `
  815.         if(pHandle->I2Cx->CR1 & BIT0): e8 h- l5 i( E3 C
  816.         {
    # W# q! m5 D/ B8 y: Z  \, K7 }; F
  817.                 DEBUG("IIC软复位失败\r\n");
    3 r' ]# O( x8 M/ x; g' j7 P; p
  818.         }' x: G' H& _3 Q% u& K
  819.         pHandle->I2Cx->CR1 |= BIT0;                        //重新启动
    ( c& j  L8 \% ^! A) O
  820.         Delay_US(1);          J6 {* ^) x' w. a2 I* {
  821. }
    / I4 E7 B% \& @! ?( H* u
  822. 9 A& v: Y" m$ M4 {
  823. ( T) b+ F8 e, c' g7 r+ `) N# i
  824. % B$ e% J. H& R5 d1 ^
  825. /*************************************************************************************************************************  t7 p1 r" T3 j7 q% h
  826. * 函数                        :        static u32 IIC_CalculationTiming(u16 Speed_KHz)
    7 T# V1 J4 p% q! q  D- J' Z* U
  827. * 功能                        :        硬件IIC时序计算
    . m+ _  I+ v+ F+ H4 I8 f
  828. * 参数                        :        ch:IIC通道;Speed_KHz:速度10-1000
    6 l( c7 N. M9 k& O. Q( L) Y  A
  829. * 返回                        :        IIC_ERROR2 ?# m" e' V% R3 }) f' F7 B  }
  830. * 依赖                        :        底层宏定义* S6 Z+ ^7 _3 g6 n- P0 J& k# z# C7 U# L
  831. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>1 _5 x# ?: g* ^; b) D! N
  832. * 时间                        :        2020-02-15
    / {2 g& v) H+ m6 K. S' y
  833. * 最后修改时间         :         2020-02-155 v0 v, a, Z* d& k/ R  F
  834. * 说明                        :         IIC使用的是APB1时钟,将IIC总线时钟控制在100KHz        
    - P1 i/ N8 R  A0 Q
  835.                                         APB1时钟:最大不能超过45MHz        & N" x5 r. M+ Z% @5 A
  836.                                         如果速度是100,则按照SMBUS时序8 i# B9 n5 A7 n& G% b  _0 G
  837. *************************************************************************************************************************/
    ) Q, @) p% I$ C$ V6 M" r
  838. static u32 IIC_CalculationTiming(u16 Speed_KHz)7 N2 ~) ?4 N1 X
  839. {
    * d+ K9 C! N! y2 c5 Y8 {
  840.         u32 tTime = 0;0 c/ x9 N6 u, y( V3 O
  841.         u32 temp;: w% W4 b( x0 f% F# b
  842.         u32 time_temp = SYS_GetAPB1ClockSpeed() / 1000000;                //先获取APB1时钟速度
    + O  h8 K$ ]$ B* w* U  u
  843.         u32 Th = 1000/Speed_KHz/2;                                                                //计算高电平时间(低电平时间一样),单位ns
    0 m% m+ b" P1 Y0 O! F
  844.         : m, n+ d  I# S0 L& d' }6 [2 Q, t, [
  845.         if(time_temp < 20) time_temp = 20;
    ! H) U: i& W2 m) r" ^
  846.         time_temp = 1*1000 / time_temp;                                                        //单位ns
    % t1 t8 T! U, n- j5 R
  847.         uart_printf("IIC时钟计算->APB1周期:%dns\t", time_temp);: a! v6 ]' J  S. ^1 _& d
  848.         if(Speed_KHz == 100)        //如果是100,则按照SMBUS时序2 W9 |+ F6 Q5 v' Z9 O- s7 ?0 E
  849.         {
    5 B- d$ O" {* j+ ]
  850.                 //主时钟分频系数固定为3
    % V+ l8 V4 i3 e# M2 p2 D
  851.                 time_temp *= 3;                        //主时钟周期) u4 V& P; _% I. r( o2 L7 I
  852.                 uart_printf("IIC时钟周期:%dns\t", time_temp);3 j+ ^8 R5 {$ k) |3 F3 H
  853.                 tTime |= (3-1) << 28;        //PRESC,时钟预分配- Q7 ^; V' |& U$ L; M
  854.                 //计算数据建立时间,要求最小250ns" [* s0 g2 _0 @+ [9 K' X5 l
  855.                 temp = 250 / time_temp;
    + g, b, `6 |* |7 A4 _2 w& g+ j
  856.                 if(temp > 15) temp = 15;# X" F4 k0 y+ R0 q7 g
  857.                 if(temp < 1) temp = 1;! @2 \1 m; v# k( M  c
  858.                 tTime |= temp << 20;- D" P4 V$ J" q2 f/ p
  859.                 //计算数据保持时间,要求至少300ns
    & s4 g1 r! c- C
  860.                 temp = 300 / time_temp;
    / t0 j5 g& O: f
  861.                 if(temp > 15) temp = 15;
    : n) Y; |8 U# j+ f
  862.                 if(temp < 1) temp = 1;
    8 D1 r9 c( E& j" z
  863.                 tTime |= temp << 16;
    4 ?, g  b" p& }( r6 k. y
  864.                 //计算高电平周期5us
    ! ?4 Y$ I' x9 l# V
  865.                 temp = 5*1000 / time_temp;- F) s  m& m& v7 C
  866.                 if(temp > 255) temp = 255;" T$ C) B# w, C+ o$ ~* w8 K
  867.                 if(temp < 1) temp = 1;
    8 c. y2 v& R! B3 y7 J! ^
  868.                 tTime |= temp << 8;
    ! O2 C% M  V( O" H+ T1 ?1 r
  869.                 //计算低电平周期5us
    ( _+ {% C* q4 ^* M/ ^# ?& w
  870.                 temp = 5*1000 / time_temp;
    ! d, L) c1 J+ Z" Y: W* a
  871.                 if(temp > 255) temp = 255;
    / e2 v/ K! P8 x0 t- \. I8 D0 @
  872.                 if(temp < 1) temp = 1;, H8 g/ r/ A* h; _; n+ U  ~+ i8 T
  873.                 tTime |= temp << 0;# J8 o! N) `4 i
  874.         }7 o. b+ z; S  Z* n
  875.         else if(Speed_KHz < 100)
    1 q8 ]7 `5 T* v1 f7 Z2 p% S
  876.         {
    2 A$ }0 S7 b  i$ n' M( B* m0 y
  877.                 //主时钟分频系数固定为6
    8 y6 p6 b+ }+ a9 ?5 L" r9 m
  878.                 time_temp *= 6;                        //主时钟周期
    : b: c  o. |/ R+ k
  879.                 uart_printf("IIC时钟周期:%dns\t", time_temp);% M( ]2 Y$ _& v: O0 T+ O: y
  880.                 tTime |= (6-1) << 28;        //PRESC,时钟预分配6 S/ l7 J% V* W& I1 v& t6 o
  881.                 //计算数据建立时间,要求最小250ns
    . E" G7 }8 W! J- m3 B, Z- W
  882.                 temp = 250 / time_temp;
    7 W! S( f/ h4 D7 W
  883.                 if(temp > 15) temp = 15;
    ; X; c) K& M5 Y
  884.                 tTime |= temp << 20;1 f6 T  o- w# s2 a8 {! P6 y! |
  885.                 //计算数据保持时间,要求至少300ns
    9 a$ j' i; z* p2 n5 E6 U$ }
  886.                 temp = 300 / time_temp;
    , [8 Y9 h& q, ]: V8 Q, m! N
  887.                 if(temp > 15) temp = 15;
    9 ^2 {3 I* g& g; T5 g9 P
  888.                 tTime |= temp << 16;
    / G* Q, k; O# H8 B# r2 L7 Y
  889.                 //计算高电平周期Th us
    8 y5 |; V3 o2 n2 x7 z0 E
  890.                 temp = Th*1000 / time_temp;
    , \2 X1 J$ B* h) E
  891.                 if(temp > 255) temp = 255;
    ) e( F& v4 N: _; _) C
  892.                 if(temp < 1) temp = 1;, g) w. Y7 l; P6 G5 B/ J. [4 x  B
  893.                 tTime |= temp << 8;' p# S& D. f3 X1 P9 |+ T
  894.                 //计算低电平周期 Th us3 N3 l8 {" X. ]2 e, _1 z" i) J
  895.                 temp = Th*1000 / time_temp;: x- Y2 D$ ~7 s8 J. b
  896.                 if(temp > 255) temp = 255;1 ]+ v; x; |7 z
  897.                 if(temp < 1) temp = 1;# }( W& o2 u! z7 b& M1 {
  898.                 tTime |= temp << 0;
      c/ _5 n7 f# |/ _
  899.         }
    7 R% j, W1 m1 |5 y9 M) G7 i
  900.         else //>100
    6 s2 p, ^$ Y& n2 @7 \8 u/ @% y! ~
  901.         {
    % p; V, A3 v# E
  902.                 //主时钟分频系数固定为2
    0 e& U% _: M& s" g3 Z5 d6 \$ _
  903.                 time_temp *= 2;                        //主时钟周期
    ; S2 R" P4 h) ^/ t6 f& [& O
  904.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    & `$ e2 g7 J3 I  @! |+ w7 E
  905.                 tTime |= (2-1) << 28;        //PRESC,时钟预分配2 i3 g0 D7 G" T0 B& H( h  `
  906.                 //计算数据建立时间,随便给100ns8 B$ V" M2 \# F0 p: j/ ]/ q
  907.                 temp = 100 / time_temp;
    5 [9 f0 f9 [4 C1 i- E% u  R% q
  908.                 if(temp > 15) temp = 15;
    - j$ b6 M) f5 k6 I5 E- |$ u
  909.                 tTime |= temp << 20;
    / A' V2 [5 @  v
  910.                 //计算数据保持时间,给100ns  @; o& k3 x6 X2 M' m( ~0 n3 W. ?
  911.                 temp = 100 / time_temp;; i4 o$ I" V2 q3 h, ?: _
  912.                 if(temp > 15) temp = 15;. k7 ]  i+ {2 s0 x- Y" {% T6 x
  913.                 tTime |= temp << 16;7 q6 y  h# Q( b4 ?
  914.                 //计算高电平周期Th us% J8 V- t8 {- }( R6 ?8 ~
  915.                 temp = Th*1000 / time_temp;6 u2 {1 i/ ^* L; S3 g
  916.                 if(temp > 255) temp = 255;
    5 X$ @1 z+ g: I" ^
  917.                 if(temp < 1) temp = 1;
    + }) P+ r" R+ j# S
  918.                 tTime |= temp << 8;9 r# `# r  w4 E& h' ~
  919.                 //计算低电平周期 Th us
    ( j7 ]3 R) J$ t0 g! C, s
  920.                 temp = Th*1000 / time_temp;4 P5 J# X5 h. K) b2 Y7 k) x5 L' c
  921.                 if(temp > 255) temp = 255;: W4 H1 b4 Y" r$ N" Y% P
  922.                 if(temp < 1) temp = 1;
    4 q" D8 y5 z& l/ n
  923.                 tTime |= temp << 0;
    5 [( S9 i3 g6 r0 V6 ^6 {4 q- N9 S
  924.         }9 G! E: p6 }0 u$ [
  925.         
    ( W6 d5 W. J2 l. @7 i) G. v- B
  926.         uart_printf("时序寄存器结果为:0x%X\r\n", tTime);. @& X% G$ M3 |' c9 L8 V
  927.         
    ' y' u/ y5 L; ?2 S" Y  c( Y
  928.         return tTime;
    - I! w9 k* m0 H
  929. }
复制代码
& P+ Y; L  X! X- v/ b
' ~9 D" l- m5 B8 K$ `
  1. /*************************************************************************************************************5 t! }/ z, y' i- V. @0 O8 k
  2. * 文件名                :        stm32f7_iic.h- k# v2 C, C! C7 d8 v+ G
  3. * 功能                        :        STM32F7 IIC接口驱动) b; M+ m0 q( C2 G9 x
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    . e2 U6 ^# m8 u  y
  5. * 创建时间                :        2020-02-09! s% K0 M0 b# ?3 G# W0 A* |
  6. * 最后修改时间        :        2020-02-095 s8 c& K/ X# z1 c
  7. * 详细:                        
    4 V1 V- T' S! q
  8. *************************************************************************************************************/                # e  d& c" D, A  Q8 G
  9. #ifndef __STM32F7_IIC_H_
    4 c) s" e+ y# C, D  q+ U3 Q
  10. #define __STM32F7_IIC_H_( i8 q- J3 h& a8 l2 b8 V
  11. #include "system.h" 3 P& D; B4 h) y' T% I- l- }* b

  12. % x! p1 W0 |( _' J6 i( Q
  13. //16位整形数高低对调  x# j" M$ N0 P% W2 G4 k9 o; W
  14. #ifndef SWAP16& G" w3 e' W3 @9 [" Z
  15. #define SWAP16(x)   (((x & 0xff00) >> 8) | ((x & 0xff) << 8))
    3 f! ~: j0 Q% ?2 G% n- q
  16. #endif  //SWAP16% {/ F5 o, I- f  |% t

  17. - P! j% v1 \! T: S% G2 O( a
  18. //硬件IO口选择
    2 L& T9 I" E, L
  19. //I2C1 IO定义与选择
    , }) a( g3 p- d2 a9 |! y
  20. #define IIC_CH1_PB6_7                                0                                        //PB6,PB7
    $ [6 F4 w. ^  |0 P
  21. #define IIC_CH1_PB8_9                                1                                        //PB8,PB9/ ^% \/ y& x& N+ p3 P
  22. #define IIC_CH1_IO_SELECT                        IIC_CH1_PB6_7                //选择I2C1 的IO        3 l  a5 ?* k; [7 b1 u/ G+ h

  23. 9 M4 z' j% B7 [' y
  24. //I2C2 IO定义与选择- _8 R, ~5 `7 F+ Q: N6 t) P
  25. #define IIC_CH2_PB10_11                                0                                        //PB10,PB11
    " f; V! q1 T( O3 P" u( |) X. G7 K
  26. #define IIC_CH2_PF0_1                                1                                        //PF0,PF1
    ( ^( _4 p; C' @2 B7 @: r# S( K% G; B
  27. #define IIC_CH2_PH4_5                                2                                        //PH4,PH5
    $ L# M. ~3 u; O* P" b# k0 ?. E
  28. #define IIC_CH2_IO_SELECT                        IIC_CH2_PB10_11                //选择I2C2 的IO
    0 d0 l: t6 f( y
  29. ; C; n$ l; f3 u3 ^6 u
  30. //I2C3 IO定义与选择- S* f& V# N0 S7 _: l* ]  A8 y
  31. #define IIC_CH3_PH7_8                                0                                        //PH7,PH8: L1 ?2 r4 Y0 |: e7 x! J
  32. #define IIC_CH3_PA8_PC9                                1                                        //PA8,PC9
    4 N1 I: I3 K! T' u& f
  33. #define IIC_CH3_IO_SELECT                        IIC_CH3_PH7_8                //选择I2C3 的IO
    ! X' b9 p" r3 w2 u
  34. 8 E/ n9 R) M8 W* d
  35. //I2C4 IO定义与选择
    ' f& j1 V# b; p! z# g
  36. #define IIC_CH4_PD12_13                                0                                        //PD12,PD13+ Y4 j9 w1 G% ~! d4 k
  37. #define IIC_CH4_PF14_15                                1                                        //PF14,PF15; n1 d; o9 p$ w* K
  38. #define IIC_CH4_PH11_12                                2                                        //PH11,PH12
    9 I% r' O' z% ^6 c5 W% p2 g
  39. #define IIC_CH4_IO_SELECT                        IIC_CH4_PD12_13                //选择I2C4 的IO8 |; U: b& u6 y) i4 N1 |6 Y

  40. - y1 R8 `0 u3 @
  41. //IIC硬件接口选择& x) U: O5 x, t, t: \3 o% d
  42. typedef enum
      p) f5 j* h) e: s4 A
  43. {
    & l, X: b) J% x1 Y3 n6 w
  44.         IIC_CH1        =                0,        //IIC1
    2 o+ o& g6 ?6 u4 w3 a' H  b
  45.         IIC_CH2        =                1,        //IIC2  x. k: \% N0 P
  46.         IIC_CH3        =                2,        //IIC37 _! Z4 }8 a" Z3 o/ {. I
  47.         IIC_CH4        =                3,        //IIC4
    3 t6 J8 }5 d& z; v6 g
  48. }IIC_CH_Type;
    - c, k9 b; |( n
  49. #define IIC_CH_COUNT        4        //4个IIC+ s1 @8 P, B$ n& ^

  50. # w/ V! ?. k* s# }

  51.   F1 t$ w$ c+ C. q
  52. //中断状态. U5 m& U& i7 n
  53. #define IIC_FLAG_TXE                    BIT0        //发送数据寄存器为空(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。* i- v, p$ S, ?9 J
  54. #define IIC_FLAG_TXIS                   BIT1        //发送中断状态(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1,待发送的数据必须写入 I2C_TXDR 寄存器。* d& q9 L+ v4 t/ v2 D' ]/ \
  55. #define IIC_FLAG_RXNE                   BIT2        //接收数据寄存器不为空(接收器); 当接收到的数据已复制到 I2C_RXDR 寄存器且准备就绪可供读取时,该位由硬件置 1。读取I2C_RXDR 时,将清零该位。3 K+ Q5 q5 c8 B2 L+ Q
  56. #define IIC_FLAG_ADDR                   BIT3        //地址匹配(从模式); 接收到的地址与使能的从设备地址之一匹配时,该位由硬件置 1。该位由软件清零,方法是将ADDRCF 位置 1。4 N8 d- }$ m/ q* W
  57. #define IIC_FLAG_NACKF                  BIT4        //接收到否定应答标志; 传输完字节后接收到 NACK 时,该标志由硬件置 1。该标志由软件清零,方法是将 NACKCF位置 1。1 {0 g& r! ]1 Z: z7 p; |* A1 z
  58. #define IIC_FLAG_STOPF                  BIT5        //停止位检测标志; 当在总线上检测到停止位,且外设也参与本次传输时,该标志由硬件置 13 m# e: n$ e0 c( B# s7 q2 b' ?! R1 H
  59. #define IIC_FLAG_TC                     BIT6        //传输完成(主模式); 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 START位或 STOP 位置 1 时,该标志由软件清零。* b5 r: j5 m/ a- L0 I( Z  k$ F0 @
  60. #define IIC_FLAG_TCR                    BIT7        //传输完成等待重载; 当 RELOAD=1 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 NBYTES 写入一个非零值时,该标志由软件清零。2 x/ |9 H. ~8 i" J5 ?0 k
  61. #define IIC_FLAG_BERR                   BIT8        //总线错误; 当检测到错位的起始位或停止位,而外设也参与传输时,该标志由硬件置 1。在从模式下的地址阶段,该标志不会置 1。该标志由软件清零,方法是将 BERRCF 位置 1。& X8 P4 s; w- v# s+ u
  62. #define IIC_FLAG_ARLO                   BIT9        //仲裁丢失; 发生仲裁丢失时,该标志由硬件置 1。该标志由软件清零,方法是将 ARLOCF 位置 1。
    ! Z; D9 q6 s2 u# c
  63. #define IIC_FLAG_OVR                    BIT10        //上溢/下溢(从模式); 在从模式下且 NOSTRETCH=1 时,如果发生上溢/下溢错误,该标志由硬件置 1。该标志由软件清零,方法是将 OVRCF 位置 1。' Z% t! I; `2 Y" W, H7 d- `
  64. #define IIC_FLAG_PECERR                 BIT11        //接收期间的 PEC 错误; 当接收到的 PEC 与 PEC 寄存器的内容不匹配时,该标志由硬件置 1。接收到错误的 PEC 后,将自动发送 NACK。该标志由软件清零,方法是将 PECCF 位置 1。
    ! b* S) V" ]: e; r. `) _
  65. #define IIC_FLAG_TIMEOUT                BIT12        //超时或 tLOW 检测标志; 发生超时或延长时钟超时时,该标志由硬件置 1。该位由软件清零,方法是将 TIMEOUTCF 位置 1。" G+ D: Z2 o0 I7 F; q, z5 c
  66. #define IIC_FLAG_ALERT                  BIT13        //SMBus 报警; 当 SMBHEN=1(SMBus 主机配置)、ALERTEN=1 且在 SMBA 引脚上检测到 SMBALERT 事件(下降沿)时,该标志由硬件置 1。该位由软件清零,方法是将 ALERTCF 位置 1。
    $ d6 p4 z2 }3 [' ?, Z' ]9 Y# c" I
  67. #define IIC_FLAG_BUSY                   BIT15        //总线繁忙; 该标志用于指示总线上正在进行通信。当检测到起始位时,该位由硬件置 1。当检测到停止位或 PE = 0 时,该位由硬件清零。
    * e) c# m! H* r3 u
  68. #define IIC_FLAG_DIR                    BIT16        //传输方向(从模式); 该标志在发生地址匹配事件时 (ADDR=1) 更新。;0:写;1:读
    8 `3 a- M3 r$ G) R/ r, ^! E
  69. " L1 G9 Y; d/ o* `* }, c6 B( w+ }; N
  70. //通讯错误状态
    # n$ e' F( r5 ?8 U$ _
  71. typedef enum# v* \" A: \* \3 d  l/ r+ w. l" ^
  72. {
    / o! Z5 ~- e2 O: r
  73.         IIC_OK                                        =        0,        //没有错误7 `# E1 s5 N" U: `0 f+ O
  74.         IIC_PARAMETER_ERROR                =        1,        //参数错误
    3 H/ `" r9 ]6 @8 j' H
  75.         IIC_TIMEOUT                                =        2,        //超时错误,也可能是底层错误. E* P7 d0 |5 t9 ]$ U* t
  76.         IIC_HAL_ERROR                        =        3,        //底层错误
    1 ?" l# C9 a+ t% K' r
  77.         IIC_STOP_ERROR                        =        4,        //等待结束错误+ D# ]  j9 d) v
  78.         IIC_BUSY                                =        5,        //硬件忙! K1 T; E* ^1 B: e
  79.         IIC_NACK                                =        6,        //收到NACK了
    . f' N' Q* ?- p8 }& y$ a' b' k
  80. }IIC_ERROR;/ Y" Q7 Y0 D; j1 t. _: s  {2 z/ d+ j
  81. 6 }" x4 W3 H. n/ k- u0 t* i

  82. ) Z! c! X- r4 P9 g* [
  83. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs);        //硬件IIC初始化
    ! s8 u4 L* U1 q9 @+ H3 ~( }
  84. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum);        //IIC读取寄存器(可以读取1个或者多个寄存器)
    8 ^0 Q0 T6 q) Z" q5 L9 O! d
  85. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum);        //IIC写寄存器(可以写1个或者多个寄存器)
    + e9 o; v/ e6 X+ ?  k) E6 O

  86. 0 M3 _  {$ @$ ]9 O3 h" }; j- j3 ?/ Y
  87. / i: G2 Y6 d5 c" |5 W
  88. #endif //__STM32F7_IIC_H_
复制代码
8 j* Q# z& h/ f8 e8 N5 E
; C6 S& s6 M$ g0 l; E. Y
//初始化
/ G. a4 W" z1 P% r6 Y* U6 d! J$ z: H7 o7 Q
  1. IIC_Init(IIC_CH3, 200, 0);        //硬件IIC初始化
复制代码
  |: v* ~$ w2 Y; \1 O& T7 {

9 O0 V- L! l6 t5 E8 ?( ~//调用/ R5 B  |$ _1 S; i+ w2 `: Q

  1. 8 u5 C0 }/ _5 Q# c1 ^; D
  2. //触摸屏IIC读取寄存器接口
    0 X3 T# W6 A" t7 A3 h% G6 ?
  3. bool TP_FT5336_IIC_ReadReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum); o: E2 ?+ j6 B, b
  4. {! J, c5 [0 i' Z( j5 q
  5.         if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)3 V: \, v; k; g+ q, e  t8 \5 V
  6.         {0 U8 G/ I/ D& s# N3 T
  7.                 return TRUE;9 @) k, i6 m* y! l* ]$ s
  8.         }+ Q$ [* d: r1 D/ `$ U9 r* M
  9.         else
    7 U( h1 t# G( ?
  10.         {, S. D. C. }2 \9 g
  11.                 return FALSE;
    # S1 }8 J9 H7 z) }/ u( e+ j* W
  12.         }
    4 V& T2 t) g6 U& Q
  13. }! s1 q+ |% @: d
  14. , J- q( W7 k4 i, E. e+ W
  15. //触摸屏IIC写寄存器接口
    : l* z. m# G8 R/ y6 w) T
  16. bool TP_FT5336_IIC_WriteReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)8 i, S9 s% G7 P. l9 S( C
  17. {
    $ l& O6 ^6 @. L# ]
  18.         if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)
    / ^5 K. N: L* J: b6 @& [5 a; U
  19.         {2 r. Z8 \/ {# M) [8 T
  20.                 return TRUE;
    . f0 l* t8 x- a
  21.         }& I) o' U: X3 x! y' H8 g  j
  22.         else$ m/ p+ S0 W2 u) t
  23.         {
    7 `4 X8 U# {) R( e9 F. |  h
  24.                 return FALSE;
    - B$ I  U0 \( g' O* L
  25.         }4 K$ W/ D5 \0 L- a3 o! _  B' y
  26. ! P7 E$ X- f: r6 R( m9 Y
复制代码
1 Y( r6 _  |, n1 V+ V. C$ l

) e4 N# {) Z# P. h( K3 e8 O$ F1 Y" N. a" H1 k- p+ I8 i
收藏 评论0 发布时间:2021-12-11 12:00

举报

0个回答

所属标签

相似技术帖

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