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

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

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
目前只实现了主设备模式,一般也只用到主设备模式,IIC如果不能使用硬件方式,读取大量数据的时候效率很大,由于只有1个字节的缓冲区,根本不能使用中断模式(实际使用过程中,IIC会造成100us以内间隔的中断,单片机根本扛不住的),所以建议数据少就直接阻塞,1个字节也就几十us,数据多直接用DMA,将线程阻塞,等待DMA传输完成,而不会阻塞CPU(上传的代码没有实现DMA部分,便于理解)。
0 I/ ^0 w3 e* H4 p) j6 v( p! L
目前已经做了完善的错误处理,读写操作前都会清除中断,遇到错误会软复位,所有位置均做了超时处理,防止程序卡死,目前只测试了几个字节的读写,大量的,长时间的读写均表现稳定,目前手上开发板没有eeprom,无法做大数据的连续读写,如果你在使用过程中遇到问题,欢迎指正。
2 @, H1 o+ q( f* }- _  n1 }8 n# M: {2 _6 O7 H
下面是IIC读写的时序例子,可以先熟悉一下,这样比较容易上手,哪一个环节出了问题也要调试。
  q% e* Q  S5 I% u" }- y  F8 }) g4 ~" K" M$ M$ [% g
20200216194202434.png

1 ?0 @8 C, I$ T$ W
& b/ X' I" g' v2 t: c
20200216194219185.png
4 I9 A9 `. q  D

  C2 }) t% e' v# C: @$ o- w% Z3 N
20200216194234908.png

1 f4 h3 \& }, O* H+ b, y9 m3 r$ d7 ]" g& K1 `& L2 J# V! J
1 P3 K. l+ Y3 G0 v
下面简要说明一下STM32F7硬件IIC的驱动设计方式(建议先百度学习一下IIC的时序要求):
- `+ d( e! P! S7 y4 Y" r5 n* @( F+ e
' o, n( `3 a  q( g1 }0 [1 e+ K[基本的初始化]- T7 |7 _7 a0 A) i

5 ?5 t, z0 J+ E& U9 N9 `" ~- [1.初始化IIC时钟,IO(IIC IO必须设置为复用开漏输出,这个很重要)。) w0 u, Y2 `; {" w! B6 A

3 }4 C$ S0 R- \2 e1 _2.CR1先赋值为0,复位IIC.
! h3 p. v5 A& I0 e0 ^2 M: z% K& ]
  ^' E+ e1 S! s* p8 x$ Z7 b" ~3.除了TIMINGR寄存器需要自己计算设置好,其余寄存器全部复位为0: G, R: R' R3 b6 e; m( r
; j; x7 t  i" N' P6 A
4.设置CR1使能IIC。
1 s0 y( _1 v# H4 M4 G
$ d  }3 e) R4 c$ K注意:上面说到,IIC的IO必须初始化为复用开漏输出,我之前初始化为复用推挽输出,测试很久,只要一启动传输,就会立马收到NACK,然后是STOP中断,数据根本没法发送,弄了好久才发现是这个IO初始化的问题。; v2 A7 e  N9 B9 w% f9 d0 ?
* n  r" ~7 y1 v- M! |) _
4 K! o' i! c2 F7 g& J, D

4 k( b* `4 |3 [/ I/ |5 r[读取]* d7 U: Z5 I: R$ c: v' C
% p& b3 }8 \6 }( M
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。
4 l6 C9 U8 u$ R0 n# x9 U! b5 B& ^' E7 g$ V2 }) \+ d, y
2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)软件STOP,写模式,启动传输。
* V2 Y5 C- t+ E/ n+ O& q! n( t4 m7 ^
% ^2 ~0 \; b$ z) z3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
. _8 F; X9 Q9 A7 w7 q; r, {5 g6 J" V4 _, N1 p  V- v
4.等待TC置位,意味着上面的1-2字节的寄存器地址以及写完成了。
6 R/ s' {( E; |' p4 {+ V
" D6 |  @* s, j) z5.根据要读取的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。
' R5 V9 C1 |2 p2 O  q9 F/ w
2 ?6 \1 ?/ o0 W. C; u- w6.设置了从机地址,要读取的数据长度,之后设置方向为读取,然后启动START(从写切换到读要重新发送START,这个跟软件模拟是一模一样的)。
' `/ i6 X# ^0 E0 U; m3 L/ Y$ e- o: s& Z4 ]2 j. I
7.循环一个字节一个字节的读取数据,字节读取需要等待RXNE有效,只有读取RXDN寄存器,直到所有数据读取完成。" q9 A/ l" O& v0 S- Q

! k/ x( Z8 O7 i4 c  L" k- Q8.读取完成后等待STOP有效,因为前面在最后一包数据读取的时候使能了自动STOP,这个时候检查STOP是否生成。
8 a6 V5 Y' h' A) T) K8 D' E( t; i8 R8 w" J. w. r  c; F1 x2 j
9.需要注意的是,所有的操作都要给超时,并且是自己可控的,绝对不要有死循环,之所以一直说STM32的IIC死机很大程度上都是由于这个地方没有涉及好,我的程序设计方法是:一旦出现了异常,就复位IIC,如果不复位就会导致下次进去的时候IIC一直忙,因为还处于上一个通讯过程。( H% g  C" g8 c9 m6 U0 ?

8 w9 _3 P. m7 `; ^
- @( s  L# s. r3 @/ G# _2 z+ R' l- S' J5 ?
[写入]
2 ?. f4 B: ~+ Q' h" P
8 U% h; }" @  S  S1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。; w+ F  G! N% I; a# g+ q$ u# b
2 f! v- N4 Q; i- N* b) t
2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)自动重载,写模式,启动传输。
- V) g% Y! b; @+ i) j" b) d: t( [8 M: ~. C- ?
3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
: e, r, b" ?" r; w. r7 S$ v9 [% R. P8 K: ?. U+ p5 H
4.等待TCR置位,意味着上面的1-2字节的寄存器地址以及写完成了,已经发生重载了,后续可以继续写入数据了。% s$ u: u# o) Y* Y0 D2 q

( s+ O/ R) E9 X: ~4 p9 o- k9 X5.根据要写入的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。
' B/ u& l8 |* T: l' i; h1 q& |* s- E9 h2 M! l+ m' z
6.设置了从机地址,要写入的数据长度,之后不用切换方向,不用启动START(都是写,不用重复发送START,这个与读取有区别)。
) e; V" r5 d; k' _  O% L1 I3 _! ?) H
1 N4 h) F/ U1 h; w: O8 v7.循环一个字节一个字节的写入,字节写入与步骤3一样,等待TXIS置位,就可以写入数据到TXDR。
% }5 G1 n# j* }) c0 @# w
9 p$ v1 t7 B. I0 [8.等待STOP有效,因为前面在最后一包数据写入的时候使能了自动STOP,这个时候检查STOP是否生成。. ]5 B6 u6 q8 @) o9 G$ }3 F, a: n6 x
& g  t! @# C+ E
9.需要注意的是,所有的操作都要给超时,跟读取一样。
3 D6 r9 ?' j; f4 o2 c3 {6 ~2 r6 [8 P
/ h* T4 P$ y/ y3 O) m* T/ Q

' b# ~7 l4 m/ q% w注意:IIC的读取实际很短,超时也不用给很长,以标准的100KHz通讯时钟速度,一个字节大概在90us左右,超时可以给个5-10B时间,也就是450-900us左右。
* c- s" ~4 W, t0 r" J2 E$ I( h  o9 x6 {6 b8 B, t) x9 q, D
! {" m3 H8 F  s4 T4 H0 j
! l. v8 w* Q4 R8 N3 |/ s
好了说了这么多,具体的看代码中的注释,直接上代码(我只测试过I2C3,其余的理论上都是一样的,就是IO初始化部分有区别,别的通道没有硬件进行测试)0 `& O. N& b& i
" Y1 p# y$ D- v& m8 A1 }
  1. /*************************************************************************************************************: M+ W) l4 a; }. r, W
  2. * 文件名                :        stm32f7_iic.c
    / j" a$ E1 O- h/ `; W
  3. * 功能                        :        STM32F7 IIC接口驱动
    0 p5 J9 m$ T, {/ N$ C# x- q% m
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ) a4 x/ \4 y' _
  5. * 创建时间                :        2020-02-09
    $ S( c% ?) ?' i
  6. * 最后修改时间        :        2020-02-09
    # d; K* f- r3 q2 h
  7. * 详细:                        只支持主机模式,7bit地址,默认APB1为IIC提供时钟2 ?( z  }2 `7 d
  8.                                         涉及到读写1字节的超时时间是us,其余的是ms
    6 X& p( t4 q  I9 {; \
  9.                                         注意:IIC的IO必须初始化为复用开漏输出。9 R/ O1 K* B' u) \
  10. *************************************************************************************************************/        * [! V' S: B( A2 N4 y' X1 O  \7 \
  11. #include "stm32f7_iic.h"! K/ y. r0 k( x$ u: V
  12. #include "system.h"
    1 l( V  \) {; i5 s( K
  13. #include "dma.h"
    8 `) b4 N6 d3 w

  14. , }! Q0 J2 R/ F& U, h$ M
  15. #define IIC_FLAG_MASK  ((uint32_t)0x0001FFFF)        //中断标志掩码
    % N$ C/ a& Z4 z$ y& A9 Z7 t

  16.   b6 n! j6 P' q  h& f+ a# o
  17. //自动结束或自动重载设置(重载与自动结束只能二选一,或者都不选)4 o: j3 a, E) b, w/ C5 h2 a* {
  18. typedef enum
    7 b, H& Y+ a7 P+ Y# W; W3 z/ j" X
  19. {
    9 n8 z8 s0 `& d
  20.         IIC_SOFTEND_MODE                =        0,        //手动结束,并不开启重载# \( q  e6 Q! a0 J! o
  21.         IIC_AUTOEND_MODE                =        1,        //自动结束,用于最后一次通讯完成后自动发送STOP结束通讯
    : r0 u4 Q8 j6 O0 K" T( ^% J
  22.         IIC_RELOAD_MODE                        =        2,        //后续还有数据,本次通讯后自动重载,重新设置后继续通讯7 Y7 f5 |' W% f# y* M. B
  23. }IIC_RELOAD_END_MODE;
    : k( h2 Q" B* j& @: n6 M" I! [
  24. ( _; Q' \; O& q
  25. //读写与开始模式控制
    - u: `, |" }" B# O0 J
  26. typedef enum2 S8 Q) Z7 L6 o+ C/ v) d1 K. z
  27. {
    , x- ?1 }, n( @4 b9 @' R5 `, `+ }* `
  28.         IIC_NOSTART_WRITE                =        0,        //没有开始的写-用于后续数据的写入& [' ^4 R: w; z+ L) c1 y
  29.         IIC_NOSTART_READ                =        1,        //没有开始的读-用于后续数据读取0 c9 o! n1 d2 s
  30.         IIC_START_WRITE                        =        2,        //生成开始写-用于通讯开始时,写地址或数据2 r5 r: K+ q# k" u) V
  31.         IIC_START_READ                =        3,        //生成开始读-用于读取数据时切换到读取方向,并读取后续数据4 T. G; }# [0 Q) b  \/ \  q8 ^! x
  32. }IIC_START_WR_MODE;
    - p$ t# \7 b2 C7 s' z
  33. " k+ f! V9 W' Y0 J- X
  34. //IIC句柄
    & b' h# K# {/ M! _  H6 o
  35. typedef struct- P! _2 t) W  b3 f
  36. {' z! h: T/ q2 A1 h8 Q
  37.         IIC_CH_Type ch;                        //当前通道
    4 u1 v  e4 I, q+ w# D) r) G" X
  38.         I2C_TypeDef *I2Cx;                //当前通道外设结构体
    1 Y# T  k  p# ?3 [) Y4 r
  39.         u32 TimeOutUs;                        //操作超时,单位us8 Q6 `; P+ I3 `' m
  40.         u16 Speed_KHz;                        //通讯速度,单位KHz
    0 M0 R/ {6 l6 a7 j% y; x& X; f% U
  41.         bool isMasterMode;                //是否为主设备模式-目前只支持主设备模式! ?7 i( E; l& e& M2 H
  42. }IIC_HANDLE;0 m! u  T) |  a! S6 S5 V! |
  43.   f$ m; j6 W, O8 V; _" X' |
  44. //IIC外设结构指针. |) }! m# h; {. j1 t9 J
  45. static const  I2C_TypeDef * const I2C_TYPE_BUFF[IIC_CH_COUNT] = {I2C1,I2C2,I2C3,I2C4};
    8 b! J. d3 F2 T# F0 T
  46. //IIC通道句柄定义  m0 R$ `' k/ U* r; T
  47. static IIC_HANDLE sg_IIC_Handle[IIC_CH_COUNT];9 M5 q, ]8 j2 ?$ Q* U$ p4 b
  48. ! M! {9 u0 o, s5 M" M1 E$ j
  49. //发送NAK
    7 l7 u8 i0 ~" V9 l4 O* L
  50. //static __inline void IIC_SendNAK(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT15;}
    - l2 s6 Q6 N- D5 X$ Q
  51. //发送STOP
    5 i2 B) K5 s  z* w: |3 M# `
  52. static __inline void IIC_SendStop(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT14;}
    7 S, F- |* {! v/ v6 e2 b
  53. //发送START
    * }  R( ~  T; N- [
  54. //static __inline void IIC_SendStart(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= I2C_CR2_START;}
    , l5 p% @- w. l4 d4 E
  55. //获取中断状态
    6 H) d3 v4 u0 q
  56. static __inline u32 IIC_GetISR(IIC_HANDLE *pHandle) {return pHandle->I2Cx->ISR & IIC_FLAG_MASK;}
    . \/ c( ]2 `( B  X' l0 @! R* T
  57. //清除中断状态
    ( i- u  v% `: N* t
  58. static __inline void IIC_ClearISR(IIC_HANDLE *pHandle, u32 IsrFlag) {pHandle->I2Cx->ICR = IsrFlag & IIC_FLAG_MASK;}5 b, w: V5 ?. g# S, X7 k
  59. //复位CR2寄存器
    $ m6 l! u4 E, r
  60. static __inline void IIC_ClearCR2(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 = 0;}
    ' t7 h% V7 S, E: ~# U

  61. & V4 `# O; c( L0 X5 p
  62. static void IIC_SoftReset(IIC_HANDLE *pHandle);//硬件IIC软复位(会使能IIC)
    0 y, f7 D. F7 z5 T* G1 u
  63. static u32 IIC_CalculationTiming(u16 Speed_KHz);//硬件IIC时序计算
    8 N9 R, \5 e. F, \% c
  64. , X" k, `* l$ \4 z5 r
  65. # `' x# B4 {. X) X$ I
  66. /*************************************************************************************************************************; o! ~6 L6 a+ W7 O
  67. * 函数        :                        bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)7 `/ V! j& O( }2 e2 y. f3 t% s
  68. * 功能        :                        硬件IIC初始化
    " U0 j5 l: M5 Z
  69. * 参数        :                        ch:IIC通道;Speed_KHz:速度10-1000(如果速度是100,则按照SMBUS时序);TimeOutUs:操作超时us(0:自定计算超时). z0 w9 R3 d/ E8 X5 \
  70. * 返回        :                        IIC_ERROR
    ; \% h9 K5 N. i/ q1 m* W( N
  71. * 依赖        :                        底层宏定义; o; f$ O/ }. a
  72. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ! f1 K# g: t6 p+ f, I% u
  73. * 时间        :                        2020-02-15# W5 Y4 X/ {8 K# o+ C
  74. * 最后修改时间 :         2020-02-15
    ( Y8 q' }# j2 S0 o
  75. * 说明        :                         速度只是个大概的计算值,设置为100KHz时会严格的按照SMBUS时序,其余的不保证SMBUS兼容,正常情况下只要时钟速度符合要求,1 W/ ]  S8 S. x2 Z4 d9 ]9 \
  76.                                         时钟上升沿到来前数据以及稳定的切换了即可保证通讯稳定性
      {: D1 u$ Y- {% K
  77. *************************************************************************************************************************/
    ! K" c* z) [$ |& u: k+ E0 k- d
  78. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs), `( O" L3 {0 o  n/ m
  79. {# w6 q3 D+ C; _9 {% }' U9 H
  80.         SYS_DEV_CLOCK DevClock;  P, I  T& i3 x
  81.         IIC_HANDLE *pHandle;
    , ?. m, l% M/ [
  82.         
    * Y5 g4 I6 i( i9 P* E* v
  83.         switch(ch)
    ' n6 c+ s3 c* g5 R' B( r, d9 _
  84.         {
    * y* K9 X9 I7 h& w* ]; J
  85.                 case IIC_CH1        :        //IIC1
    5 B( ~& Z7 o0 M! C! b
  86.                 {- p0 r) j5 B8 A8 V& v: V
  87.                         RCC->DCKCFGR2 &= ~(0x3 << 16);        //清除设置,使用APB1作为时钟源$ w3 }& D) |" Y: d; i0 ]5 _
  88.                         DevClock = DEV_I2C1;
    6 H$ B# @2 Y7 Z& R1 s
  89.                         //初始化I2C IO
      o& N4 q8 ]) }) e* t" c, P' C$ f+ `
  90. #if(IIC_CH1_IO_SELECT==IIC_CH1_PB6_7)        //I2C1        使用PB6/70 x/ L) z: P. I, i* F/ z
  91.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟# c3 e+ B2 B6 D( W( P
  92.                         SYS_GPIOx_OneInit(GPIOB, 6, AF_OD, SPEED_25M);                //PB6
    ( T: T. W; f. p
  93.                         SYS_GPIOx_OneInit(GPIOB, 7, AF_OD, SPEED_25M);                //PB7% D5 h* M+ A- ]5 c0 q
  94.                         SYS_GPIOx_SetAF(GPIOB, 6, AF4_I2C1);                                //AF47 U7 A7 X) h( _' _' J6 @7 _" e: R
  95.                         SYS_GPIOx_SetAF(GPIOB, 7, AF4_I2C1);                                //AF4* A5 X1 k8 ^/ u2 L1 k: V' Y
  96. #elif(IIC_CH1_IO_SELECT==IIC_CH1_PB8_9)        //I2C1        使用PB8/9: q0 Y  o& G9 s5 q& D; Z3 \
  97.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟( d% Y5 [1 _, h, b
  98.                         SYS_GPIOx_OneInit(GPIOB, 8, AF_OD, SPEED_25M);                //PB89 D0 c+ @; R; r: f% p
  99.                         SYS_GPIOx_OneInit(GPIOB, 9, AF_OD, SPEED_25M);                //PB9
    6 n: y% D8 S" l! n+ D# U- T, s
  100.                         SYS_GPIOx_SetAF(GPIOB, 8, AF4_I2C1);                                //AF4& b$ o7 a! W1 f( {* U+ b& v
  101.                         SYS_GPIOx_SetAF(GPIOB, 9, AF4_I2C1);                                //AF4
    & f/ F  w+ s+ a2 \5 |' h
  102. #else
    1 Y* @2 i5 P- T: s: d
  103.                         #error("无效的I2C1 IO选择");# N& _5 U; K( e
  104. #endif //IIC_CH1_IO_SELECT( a$ M" U+ a+ e  z
  105.                 }break;' u- m! I6 H! t& j0 v
  106.                 case IIC_CH2        :        //IIC2
    ! [" u4 l6 @( W2 n& O
  107.                 {; C" \! k' ~, D
  108.                         RCC->DCKCFGR2 &= ~(0x3 << 18);        //清除设置,使用APB1作为时钟源* y% N8 i# n  T8 \- v
  109.                         DevClock = DEV_I2C2;
    9 R, E$ p$ D- Y5 n# [) j8 p* h1 H
  110.                         //初始化I2C IO+ ^3 l# ?0 z3 e9 [$ v3 X1 w/ V
  111. #if(IIC_CH2_IO_SELECT==IIC_CH2_PB10_11)        //使用PB10,PB112 u, p4 b6 c! K
  112.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    + B' R! I/ ~) J3 G
  113.                         SYS_GPIOx_OneInit(GPIOB, 10, AF_OD, SPEED_25M);                //PB10% a# t- D% @  I" e6 H" Z
  114.                         SYS_GPIOx_OneInit(GPIOB, 11, AF_OD, SPEED_25M);                //PB11
    1 }. e) K6 h3 L2 w1 x. w
  115.                         SYS_GPIOx_SetAF(GPIOB, 10, AF4_I2C2);                                //AF4  t/ u" ?# I7 `  U  D" k
  116.                         SYS_GPIOx_SetAF(GPIOB, 11, AF4_I2C2);                                //AF4
    / H' I' n, L' q3 R) \
  117. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PF0_1)        //PF0,PF1, `& h# }2 ~! G" \1 o: S1 ~
  118.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟
    - `; V; ^2 _# C9 ~  O
  119.                         SYS_GPIOx_OneInit(GPIOF, 0, AF_OD, SPEED_25M);                //PF0
    ' \; T) _: M3 _7 B
  120.                         SYS_GPIOx_OneInit(GPIOF, 1, AF_OD, SPEED_25M);                //PF1
    ( ?. Q$ X! u; L
  121.                         SYS_GPIOx_SetAF(GPIOF, 0, AF4_I2C2);                                //AF4
    ' M4 [$ `  _1 H. A& X
  122.                         SYS_GPIOx_SetAF(GPIOF, 1, AF4_I2C2);                                //AF4
    6 \' R# s) V4 U/ a7 U
  123. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PH4_5)        //PH4,PH51 J* w4 e6 U! i3 a, H8 h
  124.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    ( |: ?& T2 E" \9 k
  125.                         SYS_GPIOx_OneInit(GPIOH, 4, AF_OD, SPEED_25M);                //PH4
    ) r8 z. k  g. g. {+ V+ u% U
  126.                         SYS_GPIOx_OneInit(GPIOH, 5, AF_OD, SPEED_25M);                //PH5; j9 B  U4 g; L
  127.                         SYS_GPIOx_SetAF(GPIOH, 4, AF4_I2C2);                                //AF4* i, D* s4 `  g- W9 V3 [" V  K' l
  128.                         SYS_GPIOx_SetAF(GPIOH, 5, AF4_I2C2);                                //AF4                        ; O6 H2 h$ G/ o% x, E( i. U
  129. #else& p' A/ P' {6 }# {5 l. D$ S
  130.                         #error("无效的I2C2 IO选择");
    8 c7 H: V% K( |7 P4 m
  131. #endif //IIC_CH2_IO_SELECT# w5 p/ A; ]: q( z- E/ `, \2 N! S
  132.                 }break;                        
    , J# T. g9 _: o6 G6 s
  133.                 case IIC_CH3        :        //IIC3
    0 e" e' M2 y+ e8 E& f
  134.                 {: m3 w: T7 p! C3 Z8 W1 K. m
  135.                         RCC->DCKCFGR2 &= ~(0x3 << 20);        //清除设置,使用APB1作为时钟源
    . \0 K- k* f# ~' x  Z+ D
  136.                         DevClock = DEV_I2C3;6 h6 I4 }4 j7 I' R: }( m. V4 z' [# h
  137.                         //初始化I2C IO
    ! p% ?6 G  d4 g" ?
  138. #if(IIC_CH3_IO_SELECT==IIC_CH3_PH7_8)                //PH7,PH8% z3 U7 h  U  @0 T" P- O6 Z
  139.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    + s% c, x+ s$ t$ C1 S% n
  140.                         SYS_GPIOx_OneInit(GPIOH, 7, AF_OD, SPEED_25M);                //PH7
    9 N3 V; c" d! D2 L) ^
  141.                         SYS_GPIOx_OneInit(GPIOH, 8, AF_OD, SPEED_25M);                //PH8, Q6 P) y" `% U7 g" ~  d
  142.                         SYS_GPIOx_SetAF(GPIOH, 7, AF4_I2C3);                                //AF45 {% ^6 H/ A. B' s2 F) S0 |; f
  143.                         SYS_GPIOx_SetAF(GPIOH, 8, AF4_I2C3);                                //AF4" O& s' M  |% [$ @$ v$ m: t
  144. #elif(IIC_CH3_IO_SELECT==IIC_CH3_PA8_PC9)        //PA8,PC95 i8 P$ ]( ~1 r# V3 C) ^4 `/ r% S
  145.                         SYS_DeviceClockEnable(DEV_GPIOA, TRUE);                                //使能GPIOA时钟
    # I" ~* l6 j1 P
  146.                         SYS_DeviceClockEnable(DEV_GPIOC, TRUE);                                //使能GPIOC时钟
    ' q! z& B* k/ i/ S$ i( K; b: m
  147.                         SYS_GPIOx_OneInit(GPIOA, 8, AF_OD, SPEED_25M);                //PA8: {8 j  i7 X) G( l/ n' w
  148.                         SYS_GPIOx_OneInit(GPIOC, 9, AF_OD, SPEED_25M);                //PC9
    3 P0 y8 P0 `: |1 ]9 D1 W( k3 C
  149.                         SYS_GPIOx_SetAF(GPIOA, 8, AF4_I2C3);                                //AF4
    % K( ]& B& A& i5 p: Z) @  f& H
  150.                         SYS_GPIOx_SetAF(GPIOC, 9, AF4_I2C3);                                //AF4               
    5 h- S4 X% z  y
  151. #else+ _6 L& Q* v/ W
  152.                         #error("无效的I2C3 IO选择");* X% U1 h0 E# ?, A5 ?
  153. #endif //IIC_CH3_IO_SELECT                        6 O& @2 s+ M3 n- H4 j% w4 Z2 c
  154.                 }break;                        
    / B% ~8 g+ j& N- I
  155.                 case IIC_CH4        :        //IIC4
    3 {, S* \9 U( ^3 g
  156.                 {& I  [' e- [" X9 c
  157.                         RCC->DCKCFGR2 &= ~(0x3 << 22);        //清除设置,使用APB1作为时钟源  U6 {7 e* J" A' h. e! u
  158.                         DevClock = DEV_I2C4;
    # g+ V% g5 @  A1 ^% i, E, o- T
  159.                         //初始化I2C IO
    ' b. M6 h2 j. n
  160. #if(IIC_CH4_IO_SELECT==IIC_CH4_PD12_13)                //PD12,PD133 T* a7 E/ X& u8 U$ r
  161.                         SYS_DeviceClockEnable(DEV_GPIOD, TRUE);                                //使能GPIOD时钟
    7 O) I( r' |! @+ z9 x
  162.                         SYS_GPIOx_OneInit(GPIOD, 12, AF_OD, SPEED_25M);                //PD12
    6 V  R6 Z  @3 B
  163.                         SYS_GPIOx_OneInit(GPIOD, 13, AF_OD, SPEED_25M);                //PD13
    7 w7 O- g" O3 S
  164.                         SYS_GPIOx_SetAF(GPIOD, 12, AF4_I2C4);                                //AF4( G; k' v% w7 F/ K( J7 \4 q
  165.                         SYS_GPIOx_SetAF(GPIOD, 13, AF4_I2C4);                                //AF4
    1 o$ J, ~8 a% ~; b( K. `
  166. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PF14_15)        //PF14,PF15$ Z# x  H/ E' d( f6 k4 f
  167.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟2 v+ q5 r4 e4 [1 M( U
  168.                         SYS_GPIOx_OneInit(GPIOF, 14, AF_OD, SPEED_25M);                //PF144 E; G/ |% {7 g  |$ k; ]9 U9 j! o8 f
  169.                         SYS_GPIOx_OneInit(GPIOF, 15, AF_OD, SPEED_25M);                //PF15- ~. f% }6 h% W6 w* ?+ [. g4 a
  170.                         SYS_GPIOx_SetAF(GPIOF, 14, AF4_I2C4);                                //AF4
    2 Q; L: _1 T" g- ~2 R" h
  171.                         SYS_GPIOx_SetAF(GPIOF, 15, AF4_I2C4);                                //AF4
    1 j) u% u( ]2 R; _: G" D
  172. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PH11_12)        //PH11,PH12
    1 i8 R9 g+ q5 W, H
  173.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟" H$ |% {+ G' e2 H8 U3 _1 n
  174.                         SYS_GPIOx_OneInit(GPIOH, 11, AF_OD, SPEED_25M);                //PH11
    1 k% I) d% P7 O! `' b, ~: q& c( m9 B
  175.                         SYS_GPIOx_OneInit(GPIOH, 12, AF_OD, SPEED_25M);                //PH12
    7 _! N* V7 Z' u
  176.                         SYS_GPIOx_SetAF(GPIOH, 11, AF4_I2C4);                                //AF4
    6 P7 J' x7 m" L
  177.                         SYS_GPIOx_SetAF(GPIOH, 12, AF4_I2C4);                                //AF4                        ' _" n) u4 T5 x
  178. #else% |; ~0 Q# ~6 A
  179.                         #error("无效的I2C4 IO选择");! Q4 U8 W) J6 N$ Y, M1 m
  180. #endif //IIC_CH4_IO_SELECT                        
    8 ?9 m! W4 f2 v. t
  181.                 }break;
    3 u& j+ ~  r7 M. Q# i3 T- f
  182.                 default:
    ) `# `, H' F7 j" d; _
  183.                 {' d& n# _. e" F+ Q
  184.                         DEBUG("初始化IIC失败:无效的IIC通道%d\r\n", ch);( h2 G8 p& ]; A) ?' f; Z
  185.                         return FALSE;
    : W# C, }# H  r
  186.                 }* o7 W1 i: v: S, o
  187.         }
    - J, `: M9 `1 `! E* |
  188.         pHandle = &sg_IIC_Handle[ch];                                                        //获取相关通道的句柄
    , L: v/ x9 v! e0 t* v6 [- @4 `; |
  189.         if(pHandle == NULL)
    0 ]2 l( v, X6 r- p% B
  190.         {/ W$ I( @2 R6 Y) u. k4 i
  191.                 DEBUG("初始化IIC失败:无效的IIC句柄\r\n");
    2 x1 c! c* U$ a. a6 o
  192.                 return FALSE;. ?/ d% o1 z7 l+ v
  193.         }$ s7 U" {/ ^: t) M2 U
  194.         
    % Y& y* a4 j% e: ?& f6 h2 [% R' e: l
  195.         SYS_DeviceClockEnable(DevClock, TRUE);                                        //使能时钟; b. j$ q% [# ]+ f- t% U+ `6 L
  196.         SYS_DeviceReset(DevClock);                                                                //外设复位
    * D7 j% d# ^; u) v  b
  197.         pHandle->I2Cx = (I2C_TypeDef *)I2C_TYPE_BUFF[ch];                //外设指针" h# j) h9 @8 Z
  198.         pHandle->I2Cx->CR1 = 0;
    - ~, F$ {1 p% g- {3 M
  199.         Delay_US(1);                                                8 [* U1 o& a$ e5 k# M3 q
  200.         pHandle->I2Cx->CR1 |= 2<<8;                                                                //设置噪声滤波器,关闭所有中断9 n: ]! q  ^4 |( H  v) U, I- W* N
  201.         pHandle->I2Cx->CR2 = 0;
    & ~: F* O- X6 b
  202.         pHandle->I2Cx->OAR1 = 0;$ N+ \# H- {8 c; l. ]. Z4 [
  203.         pHandle->I2Cx->OAR2 = 0;
    : i) f; J; X7 d: I
  204.         if(Speed_KHz > 1000) Speed_KHz = 1000;  [1 B' y, Q/ l  ^% a
  205.         if(Speed_KHz < 10) Speed_KHz = 10;
    ; A# w2 x# C% V6 F# m
  206.         pHandle->Speed_KHz = Speed_KHz;                                                        //记录速度
    - y( N: T; m/ A- d
  207.         if(TimeOutUs == 0)                                                                                //需要自动计算超时时间,时钟周期*10*10
    4 d* n. u/ S/ B( g
  208.         {
    ) @1 O0 D6 k4 M, W) l5 H" h
  209.                 TimeOutUs = 1000/Speed_KHz;                                                        //时钟周期
    : w% @, _0 y, y5 L
  210.                 TimeOutUs *= 10;                                                                        //字节周期
    1 y, o& U, O- K: y) E
  211.                 TimeOutUs *= 10;                                                                        //超时时间为10个字节时间7 j' J7 n: t9 r& f$ x
  212.         }
    0 Y3 d$ _2 g4 s0 s) b6 m
  213.         if(TimeOutUs < 3) TimeOutUs = 3;
    % c1 K6 e; s: ?! K/ x# k7 [$ X8 ]  Q
  214.         pHandle->TimeOutUs = TimeOutUs;                                                        //记录通讯超时时间% v7 A; L' H- `  T) g
  215.         uart_printf("IIC超时时间:%dus\r\n", pHandle->TimeOutUs);
    ! A: I* K7 q0 X3 t, L
  216.         pHandle->I2Cx->TIMINGR = IIC_CalculationTiming(pHandle->Speed_KHz);//0x40912732;                                        //时序; X0 a2 {: Q+ ^' R/ @3 o3 F
  217.         pHandle->I2Cx->CR1 |= BIT0;                                                                //使能IIC2 D: w7 i- U4 R: I/ |9 @  I* n' n8 q
  218.         pHandle->isMasterMode = TRUE;                                                        //主设备模式
    4 F$ b) X# F7 W
  219.         Delay_US(1);
    , ~3 ]' O& [3 b% m8 \7 V
  220. 0 E; |6 S7 W6 c+ u
  221.         return TRUE;
    & v2 n4 `3 N1 c( v8 @8 P5 g
  222. }
    . Y$ r3 q  V) l9 H
  223. + P# e7 s( A" T& C
  224. % o# `; X. l) u. {8 b
  225. /*************************************************************************************************************************
    1 c( y7 t" B+ K) T  L) G2 g6 ~
  226. * 函数        :                        static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)
      U, I8 k5 v# E( C+ ?# e" i
  227. * 功能        :                        检查是否有NACK中断状态,如果有则清除掉
    8 x! |4 W# F) B+ u
  228. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us
    - Z: w$ n9 A4 p5 i+ C
  229. * 返回        :                        IIC_ERROR
    3 S3 p0 `% ]: `
  230. * 依赖        :                        底层宏定义
    ; M. \* V* e+ y, T
  231. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>+ x& M' K! O6 e; P$ p- T
  232. * 时间        :                        2020-02-15. k, k2 \. z$ k4 Q- j
  233. * 最后修改时间 :         2020-02-15
    ( H3 q6 t$ x, Z/ C: T  u& R
  234. * 说明        :                         如果有NACK中断,则先产生停止位,然后清清除掉所有的中断,并复位IIC,然后返回错误( _* C: `0 Q/ f9 J6 f1 v( `
  235. *************************************************************************************************************************/  
    - a! O* k+ t( u2 u% C% e" @
  236. static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)$ I8 h, h0 {5 U2 A4 S9 `5 I
  237. {
    6 E9 e; W' L1 e, ~1 E3 A0 n+ ]
  238.         IIC_ERROR Error = IIC_OK;+ \4 _# |/ M# a/ d2 F# q
  239.         
    4 w3 x$ @4 l1 ~* v
  240.         if(IIC_GetISR(pHandle) & IIC_FLAG_NACKF)        //接收到否定应答标志
    - D7 h+ Y! L: h: Q
  241.         {/ x! P# X. C* ^( A
  242.                 uart_printf("NACK : IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);
    4 t- U3 t4 p6 t
  243.                 uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);5 t1 {$ {  ~: [; p: P
  244.                 uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));7 n9 ]" C: D' A$ Q1 f% j- a( L
  245.                 //主设备下,如果没有开启自动产生停止位,则手动产生停止位
    1 ~3 }% e( A# H% d
  246.                 if(pHandle->isMasterMode && ((pHandle->I2Cx->CR2 & I2C_CR2_AUTOEND) == 0))
    9 e: \2 E6 W. {6 o4 N6 F
  247.                 {! T5 b& [4 s$ l, M# K$ {  s! x/ @
  248.                         IIC_SendStop(pHandle);                        //send stop
    1 [8 q3 K0 H& x
  249.                 }
    - d4 P8 x% t* Q1 i6 F
  250.                 //等待STOP标志有效  D) {% p- l  a
  251.                 while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)% j3 D" ]) W; H2 t6 [
  252.                 {0 F# c. `* @, j
  253.                         if(TimeOutUs == 0)                                //检查是否超时了
    - }- f6 }5 p5 a9 ^9 a* J( b3 U2 m7 {
  254.                         {
    # j! x4 ~1 J4 o7 E8 S1 t
  255.                                 break;
    5 j$ L% q( @& i- i
  256.                         }                        $ e5 f( v) F! M
  257.                         TimeOutUs --;
    , h9 ~: m) r  T9 j& ?7 L  m5 r( U
  258.                         Delay_US(1);                                                //延时" c  J8 q  m; O3 ]
  259.                 }
    # r/ w: w, l% j4 M9 }: g
  260.                 //清除相关的中断标志
    / R5 T7 ]( e) t& c3 X  z
  261.                 IIC_ClearISR(pHandle, IIC_FLAG_NACKF | IIC_FLAG_STOPF);        //清除NACK,STOP标志" L* n* \9 }2 f% D2 h; {. e) E
  262.                 pHandle->I2Cx->CR2 = 0;                                                                                //清除CR2寄存器7 }3 Q6 ~$ q4 D
  263.                 IIC_SoftReset(pHandle);                                                                        //执行软复位6 H5 D/ g1 s. E* F7 ~- o, |0 W
  264.                 if(TimeOutUs == 0)                                                //没有超时,就是硬件通讯出错了. M7 S: z( i5 Q: h  K! ]
  265.                 {
    ' x& H% I1 X) y6 y1 _' K
  266.                         DEBUG("IIC发送stop超时\r\n");, {0 N2 J- K0 o: b" Z6 T
  267.                         Error = IIC_TIMEOUT;                                //超时1 o$ y3 @! L$ \& C
  268.                 }; T3 W* Z% T: v) i0 m6 V
  269.                 else6 s4 h$ g% Z, Y4 Y6 W3 p) R+ e
  270.                 {
    8 R% k2 i. Z& p3 ~+ [" G& F$ W
  271.                         Error = IIC_HAL_ERROR;                                //底层错误
    & i  O- w' f( g% x0 }
  272.                 }
    1 B7 C, \& k: ]* `" b
  273.         }0 S+ ]) M/ \2 T. P
  274.         : ]* U" F6 |0 @. o( U( t
  275.         return Error;/ O5 T, i6 L: `) c, \0 C& C
  276. }% M/ ~" A1 o. G8 S
  277. , x3 g; f: J3 p+ A

  278. 7 r7 @' O7 ~1 D+ q) f' o

  279. $ r- S$ ^# ?( d/ t; y+ B& P
  280. /*************************************************************************************************************************1 r- g  V4 o' U% F+ U" C
  281. * 函数        :                        static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)! Z7 x. v% J/ @0 `: @$ O- s4 I
  282. * 功能        :                        等待TXIS中断有效(等待 I2C_TXDR 发送寄存器为空)/ q1 @+ c+ n: y+ V3 F
  283. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us1 l: m$ w2 y& W) [. `
  284. * 返回        :                        IIC_ERROR
    # ?5 a" z) f/ e( _4 D. o9 ]3 l
  285. * 依赖        :                        底层宏定义& o1 h" Z" I1 Z& o8 g
  286. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>0 O* A& ?& V2 j$ H5 J" u
  287. * 时间        :                        2020-02-15
      G* v& t9 Z. Y# y  Q, w  p
  288. * 最后修改时间 :         2020-02-15
    / L& E4 Q* M) |
  289. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的
    & s7 |- L7 ^9 q3 g
  290. *************************************************************************************************************************/  
    ! O% g5 w, r8 F9 v# b
  291. static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
      G$ f! X- b, b# E0 H/ e  v' T4 l
  292. {- u, K9 n( e  l
  293.         //等待TXIS中断有效
    : u8 |  v' Q, h( G
  294.         while((IIC_GetISR(pHandle) & IIC_FLAG_TXIS) == 0)& H' y8 X/ U2 X1 A* m
  295.         {. G! S& M9 v6 x4 ?$ n- j7 D
  296.                 //有NACK中断,进行处理
    . H: Q1 I" z" e/ E
  297.                 if(IIC_isCheckNackFlag(pHandle, TimeOutUs) != IIC_OK)        
      z+ V9 e2 b& J
  298.                 {7 @# W8 H& `1 ^3 X# _4 r
  299.                         DEBUG("检测到NAK错误\r\n");5 ]4 [, Y7 s8 w; C* y4 C. j! U
  300.                         return IIC_NACK;
    " V% |5 }6 V9 ^2 D
  301.                 }
    1 A" }9 w7 L8 v- M8 O& P
  302.                 ' q" [' \" ]" U
  303.                 if(TimeOutUs == 0)                                        //检查是否超时了
    + z( q" k8 }$ d! {3 [, f6 N
  304.                 {
    , m! j6 N6 S+ Z" V2 l4 K
  305.                         uart_printf("IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);$ Q' a1 _3 V. O4 ~9 x4 S$ L
  306.                         uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    1 v0 z2 Y2 \/ t9 X
  307.                         uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));& n1 K  ]0 J/ j% r& Q: t$ t
  308.                         5 U8 J3 `9 r" C+ X9 L
  309.                         IIC_SoftReset(pHandle);                //执行软复位$ n) E8 S8 y4 V
  310.                         return IIC_TIMEOUT;                                //超时
    , p) u! k8 r. J: y% }: h: s. ^) Y2 p' \
  311.                 }                        
      s5 J9 X! D9 a7 P5 S. \
  312.                 TimeOutUs --;
    6 h0 x& c2 K% ^' R
  313.                 Delay_US(1);                                                //延时0 _# g0 e9 N0 v% ^1 I  W# d( d
  314.         }, ?3 V; z6 F2 |
  315.         
    & ^6 A, C+ `2 I' ?: J$ u; w2 z
  316.         return IIC_OK;9 e) p% B8 _& e' o" Q
  317. }
    1 o7 t/ l- P; o/ a+ J5 P8 _

  318. 3 g$ u& h6 \; o" o8 @; B
  319. # Z( j/ v8 ?! O& ?6 E& d. X
  320. /*************************************************************************************************************************
    ' ?1 Y4 e2 ^2 m- G' X0 _
  321. * 函数        :                        static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)& M" C1 W; T: B6 E* {. A/ x
  322. * 功能        :                        等待STOP中断有效(等待 发送结束 )
    * @& Y  N1 g% m: G7 T2 {& Q5 ~
  323. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us
    ; S, x; ^$ H5 @' G( a
  324. * 返回        :                        IIC_ERROR
    # a8 m7 R( _- J2 }$ S0 |
  325. * 依赖        :                        底层宏定义! D, q. `) i: _. l+ z5 G
  326. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    4 [6 ]2 C1 {6 q8 l: b* l
  327. * 时间        :                        2020-02-15* e9 E/ O9 I: g5 }& u" j1 F
  328. * 最后修改时间 :         2020-02-15
    5 T& b0 N* |" `3 _$ o! P
  329. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的$ F" N/ E' j) F7 Z0 ~$ M( S
  330. *************************************************************************************************************************/  
    / _# u& }$ S0 a0 L; V" R
  331. static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)
    , S. ^, Q8 U& r9 d
  332. {
    5 {+ ^4 O7 k1 o8 p9 {2 i
  333.         //等待STOPF中断有效0 x4 c9 w' U% ?" U! g) T, Z
  334.         while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)
    # u$ w, ?( x* q5 L* r% z; B. s
  335.         {( p2 _4 T. y+ j
  336.                 //有NACK中断,进行处理  c0 C: |( X1 P  s, ?: @7 w
  337.                 if(IIC_isCheckNackFlag(pHandle, 5) != IIC_OK)        
    2 G) q  y1 o8 L; G1 S! l) P4 b- ?
  338.                 {! @5 U- c/ [7 |( p( Q2 v# D
  339.                         return IIC_HAL_ERROR;+ P3 j( y) I/ S* ^* g
  340.                 }
    ) u4 D. t( L% Z9 R
  341.                
    - M  [  E) w$ B9 b; M
  342.                 if(TimeOutUs == 0)                                        //检查是否超时了! k1 v. U4 ?0 [5 b% r) r; j% T
  343.                 {
    * s. r9 q- l! j4 X2 I! r$ N
  344.                         IIC_SoftReset(pHandle);                //执行软复位' p+ z& {0 O/ M4 N$ q5 z' M
  345.                         DEBUG("IIC等待结束超时\r\n");  f2 ~/ }0 l5 w4 D& V/ A" d
  346.                         return IIC_TIMEOUT;                                //超时) i, J# U( ^( }7 e& T5 x# G) \
  347.                 }                        
    * E. r7 [! F! Z2 U, P
  348.                 TimeOutUs --;# N8 S) X1 ~% c. ~  ^- N# c/ }3 H
  349.                 Delay_US(1);                                                //延时! H9 @2 R. h  k0 p$ S- A$ \) ?  f
  350.         }' O& d: R0 P5 c8 K8 j, r6 x1 V( e! a
  351.         
    8 U+ W% n: e* n9 R
  352.         return IIC_OK;' \- M4 b0 Y0 o
  353. }
    $ E0 L9 w+ W7 H9 H! j. I, A7 u1 Y
  354. 4 N' W! Q) M. g, |3 \- Y; h; g

  355. 4 D" h: [& B/ {/ L/ K
  356. /*************************************************************************************************************************/ Y  `9 b6 e6 P' m
  357. * 函数        :                        static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)6 E0 p4 D! F, B
  358. * 功能        :                        等待中断有效5 v6 e$ S$ y  i3 L  ?4 w
  359. * 参数        :                        pHandle:句柄;Flag:需要等待的flag,见IIC_FLAG_xxx;isWaitFlagSet:TRUE:等待标志有效,FALSE:等待标志复位;TimeOutUs:超时时间,单位Us
    7 e5 |- \' }& S$ F  J
  360. * 返回        :                        IIC_ERROR2 k* z9 Z2 I( t3 |) z
  361. * 依赖        :                        底层宏定义' w" O* F1 Z; F
  362. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    % }. k# j, m' ~5 ~
  363. * 时间        :                        2020-02-158 S# f/ z# G7 i9 ]7 F
  364. * 最后修改时间 :         2020-02-15, u- _& }  Z7 Y, c" M3 Y. A" q7 w* m
  365. * 说明        :                         5 G7 g9 D, E9 X
  366. *************************************************************************************************************************/  
    / K. c' }: o4 z% _& c
  367. static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)' Q7 p7 Q0 D) a8 E. g
  368. {! h0 f- G* ^8 N: m% Q2 c0 w# Z
  369.         if(isWaitFlagSet)        //需要等待标志有效
    " k2 q4 v! D* z6 s& W& y4 w: E# u
  370.         {
    ( m, f7 V" q1 ^
  371.                 while((IIC_GetISR(pHandle) & Flag) == 0)8 v* I$ O* q& u! p" u
  372.                 {
    7 T& {3 W3 w7 e2 r1 p9 J
  373.                         if(TimeOutUs == 0)                                        //检查是否超时了" ]) E4 t5 O: U  ^5 [/ O: ]6 J
  374.                         {+ u: J# s& x9 C+ Q, d1 k
  375.                                 return IIC_TIMEOUT;                                //超时& e1 t7 @5 b1 y+ ]- |$ T0 ^
  376.                         }                        ' [: D3 u: w0 _; F5 F0 X
  377.                         TimeOutUs --;
    2 ^6 N1 m8 |* Q$ m; b; Z
  378.                         Delay_US(1);                                                //延时
    5 Q# F; n; ~5 h1 n. D( o
  379.                 }
    ' W4 {: L  {( S8 X0 ^
  380.         }# U; \9 V. h4 @5 W6 L
  381.         else                                //需要等待标志复位3 n) S8 V' C: N3 w+ a0 Y
  382.         {
    / o: t0 g  S. a+ w# @* x8 w
  383.                 while((IIC_GetISR(pHandle) & Flag) != 0)5 P, E& O) ^5 U' L: ^" C% Z( G% k0 \0 Y
  384.                 {( k% G- C1 ~7 m0 B* a7 ^. o& ^( j
  385.                         if(TimeOutUs == 0)                                        //检查是否超时了# u6 ^; M. O. q$ g  x: U8 C
  386.                         {
      V' y: X( Y2 }# |( w  R
  387.                                 return IIC_TIMEOUT;                                //超时# b  W5 X( g9 F7 Q
  388.                         }                        
    ' E+ i2 M6 W! I$ K+ V
  389.                         TimeOutUs --;6 V  C0 _  y5 {
  390.                         Delay_US(1);                                                //延时0 {/ g' t" U0 q( |
  391.                 }
    ' j; t" y8 k! W  g7 A! A
  392.         }
    ) s. e. a8 P, G: c

  393. 2 B: }8 w6 X2 s9 {
  394.         return IIC_OK;
    0 T% D6 [+ F3 E9 B! `% Q
  395. }1 `6 E* y$ I1 N& |- l

  396. . @9 ~: _5 p, P) c' N7 B6 M  R5 b
  397. + J8 R9 M' B, ~2 w7 l) f
  398. 0 \  E0 v1 Q( l- _2 n2 W
  399. 1 t3 G$ a2 {1 Z4 S0 i
  400. /*************************************************************************************************************************
    ( W& F* k5 t+ M
  401. * 函数        :                        static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR); b" A. F2 W8 u9 g7 G7 F& _
  402. * 功能        :                        主设备传输配置(配置CR2寄存器)6 i- n  V1 Z+ s
  403. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;TransByteCount:需要传输的数据长度;EndorReload:自动结束还是重载设置,见IIC_RELOAD_END_MODE;StartAndWR:开始读写控制,见StartAndWR$ x) N( j/ f; _7 W  H
  404. * 返回        :                        无9 }, ~0 R/ R' o0 x; T. t
  405. * 依赖        :                        底层宏定义
    4 u+ Z7 O8 i6 T) C; K% G  a
  406. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    * \! O9 R. b( {* g* ?7 X
  407. * 时间        :                        2020-02-15
    6 E: e8 M5 ~$ H2 C, P' p! }
  408. * 最后修改时间 :         2020-02-16+ x1 }: U' O/ E0 ~
  409. * 说明        :                         在往 NBYTE 中设置最后一次传输的字节数前,必须把 RELOAD 位清零便于后续自动发送STOP。" }: S8 S5 D9 a: c- ]& U9 g: }
  410.                                         当 RELOAD 位置 1 时,AUTOEND 位将不起作用;4 @$ y# A! S/ S" L
  411. *************************************************************************************************************************/  
    : j* r! L2 S9 {& U
  412. static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)+ `. |% F" j  L  i! n- ?
  413. {' @* F' b1 Y3 L/ M, \
  414.         u32 temp = 0;
    4 c1 T; _7 K+ h0 k
  415.         1 E: }3 l; w" C, f' Z$ D
  416.         //先读取CR2寄存器的值
    . C2 s7 p) F7 H
  417.         temp = pHandle->I2Cx->CR2;4 p6 |6 H+ e" ?3 t' @; ~
  418.         //清除掉相关的字节
    3 ]7 W6 B  E. e% `* y6 h+ [
  419.         temp &= (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND |I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP));5 W8 t! P" g, A/ N/ q% G
  420.         //生成配置数据
      O" g3 N7 b% P/ [0 d
  421.         temp |= (u32)(((u32)SlaveAddr & I2C_CR2_SADD) | (((u32)TransByteCount << 16 ) & I2C_CR2_NBYTES));$ ?/ @- {- r1 Z$ y/ i: b
  422.         //重载与自动结束只能二选一
    5 Z+ ?/ u6 V7 }" r2 x+ i) I  `
  423.         if(EndorReload == IIC_AUTOEND_MODE)         & q; q5 Q- W, n" O
  424.         {
    / I& [6 l, S$ O6 ?8 j3 c
  425.                 temp |= I2C_CR2_AUTOEND;        //自动结束模式9 `8 T( d* Q( n( H
  426.         }0 K- D3 j: F1 ?' b! t
  427.         else if(EndorReload == IIC_RELOAD_MODE)
    - X# w* a' j% }$ `% E$ q4 [" I$ }, x
  428.         {  n3 B: p  x, {, D
  429.                 temp |= I2C_CR2_RELOAD;                //NBYTES 重载模式
    2 J* _. k# X& v* a, g) ]
  430.         }
    ' q; l2 Q+ {# P+ Y
  431.         6 _! \- k' c! Z: n7 G
  432.         switch(StartAndWR)8 a' l& K4 o* ~) Q$ e6 \
  433.         {; M- Q' {7 R: F. F* J  W
  434.                 case IIC_NOSTART_WRITE        :        break;        //没有开始的写-默认就是这样的
    ) d7 [) `" G8 p% F( I) b0 Y
  435.                 case IIC_NOSTART_READ        :                        //没有开始的读-用于后续数据读取
    # C1 c9 e& }' n) Y! }
  436.                 {) j& O; d* e4 e! A5 i) U
  437.                         temp |= I2C_CR2_RD_WRN;                        //读取: Q8 q- `2 j! z  c  e( }& Q
  438.                 }break;; H; T4 b% C  W9 ^0 D
  439.                 case IIC_START_WRITE        :                        //生成开始写5 W- _( K: X9 n& ~5 M  q
  440.                 {& x- Y" u% k& X" V' M: |/ D* b
  441.                         temp |= I2C_CR2_START;                        //启动传输
    6 W) m  {( b! a6 u  f# G
  442.                 }break;5 ~; A. _) R5 c, c' a
  443.                 case IIC_START_READ                :                        //生成开始读        
    ( L* F8 l3 @9 e8 w7 X1 [5 k* C
  444.                 {
    6 ^. ~8 z8 r* C( [3 ]4 a: g7 ]
  445.                         temp |= I2C_CR2_RD_WRN;                        //读取
    . `2 M$ F$ u" k# u
  446.                         temp |= I2C_CR2_START;                        //启动传输
    ; B; J! W' W5 O: v+ z
  447.                 }break;
    0 C) X' ]5 t6 n  j7 l9 |/ ^& U
  448.                 default:break;8 [- B1 Z' H' N* S& J6 b+ l+ Q
  449.         }5 u$ P7 W5 ~! X8 |
  450.         ! ?: D6 m+ F5 p8 K
  451.         //uart_printf("准备写入CR2=0x%X\t", temp);9 S* Z8 P7 l. @0 k
  452.         //更新到寄存器6 m1 Y/ Q' z8 j1 g
  453.         pHandle->I2Cx->CR2 = temp;  //测试# }: o$ d! Q3 |1 Q5 ?
  454.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    4 o6 L9 P6 e% E; T8 g6 d
  455.         Delay_US(100);5 [) L" Z' ?0 [& x
  456. }& G# @: a3 N1 S8 y* G; }4 ]+ J

  457. ) ]4 g6 L2 _. o8 @( Y3 x7 n

  458. + S. m4 `3 b  o8 c# I" _
  459. /*************************************************************************************************************************9 C* A# i+ D) Z0 D4 U
  460. * 函数        :                        static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)
    & O& @0 V$ y5 i1 g  S
  461. * 功能        :                        IIC发送一字节8 }* T& u' a& Y7 [  u
  462. * 参数        :                        pHandle:句柄;data:待发送数据;TimeOutUs:超时时间,单位us
    9 |0 u. z8 |/ d' M  I8 s
  463. * 返回        :                        IIC_ERROR
    9 p: v+ C  {. X0 u- A; k
  464. * 依赖        :                        底层宏定义2 f5 G% i8 N9 W
  465. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>: `' f! f* C8 D2 X1 {, j
  466. * 时间        :                        2020-02-15+ A+ H5 v( a+ L' F
  467. * 最后修改时间 :         2020-02-16
    . ?( i( P7 `3 C& b" f
  468. * 说明        :                         TXIS有效后才会进行数据发送,不会检查数据发送是否完成。
      s7 j  W! [7 n, L
  469.                                         如果最后一个字节发送完成后不会再触发TXIS中断,只会触发TC中断4 }/ W2 {3 Y. A9 l$ L  l
  470. *************************************************************************************************************************/  ) K% w; i1 _. `$ e0 E
  471. static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)* q: S" ^( Y' Q" N" F% e8 M- z( h1 ^
  472. {2 c' k1 a4 }% g) S, h+ b* F, X& x
  473.         IIC_ERROR Error = IIC_isWaitTXIS(pHandle, TimeOutUs);                                //先等待可以发数据
    9 M/ C( B5 C9 ?
  474.         if(Error != IIC_OK) return Error;
    ( x0 q3 Z; T4 t8 Q
  475.         pHandle->I2Cx->TXDR = data;                                                                                        //写数据到发送寄存器-不会等待数据发送完成        
      t$ \5 i6 l- e

  476. " q1 n+ Z* R$ L7 _0 j' y: ?3 [& l
  477.         return IIC_OK;0 Q' }" e5 |4 n6 E4 Q" ]$ A
  478. }
    8 f( R- n+ P" U/ s
  479. / l6 O% R1 N2 ^: ?. n8 t" f% A
  480. /*************************************************************************************************************************  U- p( h& }( m7 ]3 k$ x. L
  481. * 函数        :                        static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    ; B- V; _4 w: O
  482.                                                 bool isRead,u32 TimeOutUs)
    9 s3 Z# a5 h0 [) K5 a
  483. * 功能        :                        主设备请求发送从机地址与目标寄存器地址
    9 {& |- C  Z3 c: ?* b
  484. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;RegAddr:寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,
    4 G) K0 x! {' `
  485.                                                 FALSE:16bit寄存器地址;isRead:TRUE:这个操作是读取寄存器;否则是写入寄存器;TimeOutUs:超时时间,单位us
    2 X1 P0 \6 J! p( i4 {8 @0 `
  486. * 返回        :                        IIC_ERROR: C! K2 z8 |2 n: x
  487. * 依赖        :                        底层宏定义) ~0 Z) i. s* X% x( x
  488. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>- w$ b2 c+ M% l
  489. * 时间        :                        2020-02-15
    $ f: T$ O' f2 [6 u9 B
  490. * 最后修改时间 :         2020-02-16
      n1 z, H: M1 D, k: M# M* Q
  491. * 说明        :                        
    9 [6 X3 A: z# B' ?
  492. *************************************************************************************************************************/  
    4 P9 e1 C9 L  U
  493. static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,bool isRead, u32 TimeOutUs)4 N9 s' e6 X: g) l( p
  494. {        
    * N( B6 {; `: N+ G% S
  495.         IIC_ERROR Error;
    - l+ v5 u' B9 A
  496.         # h6 k- e+ \/ J; x8 F0 d
  497.         //uart_printf("WriteAddr1:CR1=0x%X\t", pHandle->I2Cx->CR1);& Y: s; h  m# n6 ~
  498.         //uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
      [4 ~: K, q9 U: P5 m: L3 j, E) |* P
  499.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    6 h/ x. s- W0 D7 U, K
  500.         //传输配置,并启动传输,发送起始序列,开始IIC传输了  y4 ]. c/ S" H7 q! Z
  501.         //如果是读取则使能软件结束,如果是写则是自动重载5 Q! d, I; ~" v! G( ~3 i
  502.         IIC_MasterTransConfig(pHandle, SlaveAddr, (is8bitRegAddr==FALSE)?2:1, (isRead)?IIC_SOFTEND_MODE:IIC_RELOAD_MODE, IIC_START_WRITE);        //传输相关配置-写,并启动传输
    * s; G0 \( Z  }
  503.         1 k* _' a+ G7 g# P8 d% }: Y
  504.         //开始发送寄存器地址
    ' e/ V: _& P$ V
  505.         if(is8bitRegAddr==FALSE)                                                                                                //寄存器地址是16位的,IIC通常是MSB高位在前,需要进行高低位对调( _2 c" P  D3 [7 a* j
  506.         {
    + S$ E$ r8 w; S" [( K& R
  507.                 Error = IIC_SendByte(pHandle, RegAddr>>8, TimeOutUs);        //先发送MSB-非最后一字节/ y- Y  @; b4 i* L# [: ?
  508.                 if(Error != IIC_OK)
    ; O, ]# S- V' [) S- ~: o
  509.                 {
    4 j2 {1 R# @0 w* q. [2 O
  510.                         DEBUG("IIC发送寄存器地址MSB失败\r\n");2 _( p. f4 x) f: C" N
  511.                         return Error;
    % P* g6 C% G, Q1 H0 S# l9 x8 T3 y
  512.                 }        
    , {9 U$ u6 M# p1 M! P1 O
  513.         }
    ! S  ^  [) `1 l, f, t" g
  514.         Error = IIC_SendByte(pHandle, RegAddr & 0xFF, TimeOutUs);        //再发送LSB-最后一字节. ^, J3 x- Z# I$ Y% T; e: t+ U6 p" q
  515.         if(Error != IIC_OK)2 z  k2 t0 U. E7 H& s( R
  516.         {# Y8 h! p& ?- m9 i' {
  517.                 DEBUG("IIC发送寄存器地址LSB失败\r\n");& \, K% c" _. B, j8 @
  518.                 return Error;
    ; V- E6 K; f+ B- _  @
  519.         }
    * e" ?2 \3 |4 A; G; N" w6 C( D" I
  520.         //等待全部数据发送完成4 u3 \1 ]! ]0 b
  521.         if(isRead)        //读取方向-非重载,等待数据传输完成 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。
    $ U& [: g; z8 L; W5 I
  522.         {0 q- C( y1 {6 f9 _2 C/ T
  523.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TC, TRUE, TimeOutUs) != IIC_OK); w4 L* c% S% h" N9 R. E8 d8 r9 c5 a
  524.                 {
      ?+ B: w6 v2 z; Y: P
  525.                         return IIC_TIMEOUT;5 x& u; h* ]9 E7 m. g1 k
  526.                 }
    $ p$ g! n. H+ m5 g% r: ]# S4 ~1 K3 a4 ?
  527.         }        - S& R6 v2 K$ O' g# y
  528.         else //写入方向,等待重载* @" o3 `! m# a2 @
  529.         {
      v. h6 G- d* q; Q; a& l, P
  530.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TCR, TRUE, TimeOutUs) != IIC_OK)5 a( d3 Q  X  O6 o% ^
  531.                 {& O* K- B% Z+ q3 A2 v$ h
  532.                         return IIC_TIMEOUT;- J. L- Q: i1 g. ^' p' {. {  ?
  533.                 }
    % X% P- X" @! |! v/ j$ _
  534.         }
    8 y) R" ^1 A! \5 G6 Z+ O
  535.         . f' J" Q% }# T, Y& ]- V9 Q+ k
  536.         return Error;  Z2 a% m* v% v& ?0 {' V: e' |- z" w" E
  537. }: U: _2 z7 u; v4 G3 N, [0 H
  538. 3 c: G; i; K, F: t* u
  539. $ ?$ }, Y( o+ b0 t4 \# X- ?
  540. /*************************************************************************************************************************& p! @- e2 K+ _# {
  541. * 函数        :                        static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)3 @) k( ]2 E- s" m* S' }
  542. * 功能        :                        等待接收一字节数据& B& y4 F: |! j6 Q) l% F
  543. * 参数        :                        pHandle:句柄;pData:接收的字节数据缓冲区;TimeOutUs:超时时间,单位ms% Q0 }0 w: G! s5 V# Z9 H6 L( {" j
  544. * 返回        :                        IIC_ERROR% }( I' r' |( ?& @% r7 _" V
  545. * 依赖        :                        底层宏定义; ^! A4 J! t, D) S1 h! C6 P; \
  546. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>3 y6 e5 }  r0 r) ?' `6 P
  547. * 时间        :                        2020-02-15
    / A' v9 A" m+ r' c# V
  548. * 最后修改时间 :         2020-02-15. Q* g* h" ^/ J3 [* u
  549. * 说明        :                         当RXNE有效后读取一条数据,否则可能会超时2 j5 z) T+ R( _
  550. *************************************************************************************************************************/  
    ; H3 d/ l# Z- Q5 K+ u7 j
  551. static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)3 l" ^7 ?$ ]/ _3 K
  552. {. s" u7 Z2 e- ?0 `
  553.         while((IIC_GetISR(pHandle) & IIC_FLAG_RXNE) == 0)        //等待RXNE有效
    8 G1 k4 `# Y; A4 I" ~1 V
  554.         {
    $ A$ j2 F( o, g! Z( ?3 m
  555.                 if(TimeOutUs == 0)                                        //检查是否超时了9 \0 c' F, l0 I: P* m. o
  556.                 {
    ' A" _6 R3 N2 W( [
  557.                         DEBUG("IIC等待接收超时\r\n");) d4 N3 B7 ^# I: q+ X0 M' `
  558.                         return IIC_TIMEOUT;                                //超时3 ?7 h% A6 q! n# R; k
  559.                 }                        
    3 I5 T* g% U% u9 v5 q+ K3 J* ~$ U
  560.                 TimeOutUs --;
    $ D! i( D' R  a0 p* c$ P
  561.                 Delay_US(1);                                                //延时
    4 t/ a0 Q$ N  q  ]; f
  562.         }" Y5 z! d5 E# C6 Y( r
  563.                
    # t/ h2 V4 Z: y5 b' N
  564.         *pData = pHandle->I2Cx->RXDR;                                                        //读取收到的数据
    $ _% c# F; k" \' L
  565.         return IIC_OK;
    8 A4 @. }+ x* e8 w
  566. }" }" Y  i# ?9 m* r

  567. : R' J, }: p7 r
  568. ; B9 ?/ \# H& Y3 h& m! N
  569. /*************************************************************************************************************************
    . D1 I7 I, y* U  u  D
  570. * 函数        :                        IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    - b6 ?) F, w4 ]3 n
  571.                                                 u8 *pDataBuff, u16 ReadByteNum)
    , s) ^5 q* b  R8 Z# ^8 y+ D
  572. * 功能        :                        IIC读取寄存器(可以读取1个或者多个寄存器)2 ~: W0 e- {* [5 ?4 J. c/ R' B
  573. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要读取的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;
    0 u! y. w7 o+ @: Q
  574.                                                 pDataBuff:接收的字节数据缓冲区;ReadByteNum:要读取的寄存器数量;. \& K* Q0 e/ X% `' C! `9 k$ @) s
  575. * 返回        :                        IIC_ERROR- |' G% i# P( y- e8 o
  576. * 依赖        :                        底层宏定义  \- m/ s; e) @0 u
  577. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    : c. T  e5 ^# I+ O9 b% P5 S
  578. * 时间        :                        2020-02-15
    8 C( J8 k1 q. }
  579. * 最后修改时间 :         2020-02-15
    . y( O/ e3 K& R( R# S5 H
  580. * 说明        :                         读取的数据都是小端模式,如果是16bit的寄存器,请读取偶数个数据,并且需要另外进行高低字节对调最后组成16bit数据. `0 g6 q% a5 Y
  581.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如
    * p! A: s& I5 M; F+ S' m+ U7 L
  582.                                                 增加信号量2 H/ U  f( K9 `! V# E" k  E
  583.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在/ g" t8 Y3 j+ o
  584.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。* U. Z' L5 i# V( ~
  585. *************************************************************************************************************************/
    ( E' ?9 F: k. J* L; Y# o& m
  586. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum)" j4 _5 N1 u, E' u5 K
  587. {
    : \! `  A# L( U1 y4 C; [
  588.         IIC_ERROR Error = IIC_OK;
    5 g7 ?- W! m% O2 d; Z5 T
  589.         u16 ReadCount;
    $ Z; p5 Y) B4 O5 s* M2 ~
  590.         IIC_HANDLE *pHandle;& B6 R4 }8 E; q; @: _
  591.         
    0 u( V% Q. g! r$ D! \
  592.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || ReadByteNum == 0), P2 [7 ?; S3 X; x
  593.         {2 T" j0 T  U1 @# c. H2 z
  594.                 DEBUG("IIC错误:无效的参数\r\n");
    7 [7 l; B# U( R9 X! ~3 H
  595.                 return IIC_PARAMETER_ERROR;
    5 j+ l  x0 X5 g3 A5 C2 r6 H$ h% G# C
  596.         }
    8 Q, D: b* n, {7 Q* }
  597.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄6 Q1 t. o7 P2 J- ]8 y3 ?, O
  598.         # A9 d9 I+ v6 ]# k' g; e' n
  599.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙: e7 V- @. O' O6 v/ A6 j
  600.         {+ d, F! f: g. L- J" v( o+ H
  601.                 IIC_SoftReset(pHandle);: a  d) @: n. h$ w
  602.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");
    ) W9 P" |' i6 Q! M. c* v
  603.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙
    7 \, D5 q# S8 n( i0 J9 g8 A
  604.                 {
    % y' e) x8 p" ?" _+ \7 h% @% |6 n1 e
  605.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");
    ; ?+ s9 I9 \/ B
  606.                         Error = IIC_BUSY;, J& T& K' p. Y
  607.                         goto end_loop;" C7 R# Y$ x' U. K* y5 Y
  608.                 }
    , l/ U& A/ b+ a2 j' B
  609.         }" S3 }% A: Y* @; f
  610.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    ; \; c% h2 e' v. a/ d  [8 x' f
  611.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器7 J) f7 T+ I1 z
  612.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    ) G* L6 g- \4 B" w* A. e
  613.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,TRUE, pHandle->TimeOutUs);
    ! M# ?$ M2 R. H8 y8 a
  614.         if(Error != IIC_OK)
    " T+ G: U8 M( T9 h  ^' }0 ^! p
  615.         {
    # Y$ U  v# Y6 M/ c3 c! Y2 f! G
  616.                 goto end_loop;
    ' v% ?3 o& ?6 f" D( t4 c4 H  m
  617.         }& O5 j( l* s  d' v: Y
  618.         //发送后续数据( Y& |% Q& g* q# `" D
  619.         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取-后续还有数据,需要重载0 V* u0 z5 m( I" `; U
  620.         {
    / v2 v* p& v# \! w( y- ?
  621.                 ReadCount = 255;        //本次需要读取的数据长度255
    " y# w2 o, z' f! Y
  622.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输                1 \7 h. t0 z; O1 _9 I
  623.         }, m% P) x# ^1 l% h# g
  624.         else& q6 L7 U2 W9 F9 g; o* A% v
  625.         {
    1 f0 L& V. C' \3 w# {0 M: K5 l
  626.                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯后自动结束
    # W' g1 m5 g* I, V* ?8 H: I
  627.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输
    : Q# H/ P) v+ p8 {
  628.         }; X  ]- b$ q9 L
  629.         
    & t: f* H9 {0 c8 \+ R
  630.         //循环等待接收数据完成+ ]+ u: V; x+ z# h
  631.         do1 a5 m; n. V+ f0 G: \2 n
  632.         {3 B6 _; m7 k' [0 w/ v
  633.                 //uart_printf("读ISR=0x%X\r\n", pHandle->I2Cx->ISR);, @; E; v0 S( ^( s  E; C* D$ V1 t
  634.                 Error = IIC_WaitRxOneByte(pHandle, pDataBuff,  pHandle->TimeOutUs);                                        //接收1字节数据" J6 W8 s7 U$ k, J& W
  635.                 if(Error != IIC_OK)$ _. s9 N5 f5 p
  636.                 {/ f1 B* s. K- A1 i/ K
  637.                         goto end_loop;: \0 i: v9 H4 @  X
  638.                 }, A4 j0 x/ h9 A/ _
  639.         
    - Y4 [) h# d, J4 B
  640.                 pDataBuff ++;
    9 G% Y8 B* k. b2 C( K; D6 D
  641.                 ReadCount --;
    $ j' }2 y: l- e2 u5 i
  642.                 ReadByteNum --;
    : C/ a4 A# J* ^4 F( C) o: w$ `% j
  643.                 if((ReadByteNum > 0) && (ReadCount == 0))        //还有数据要读取& P5 H' X- [% Z* h; Z
  644.                 {
      z2 [5 M0 I* R/ G1 d( \
  645.                         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取
    " o+ f; V& }. L) a  j& J' o
  646.                         {
    ; O+ g5 ^/ _+ ~) N6 l  I8 Z
  647.                                 ReadCount = 255;        //本次需要读取的数据长度255-后续还有数据,需要重载
    & ?; P, F, ], f. @" _4 z
  648.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
    $ `, D4 F$ G) S+ @; K, t" G8 u
  649.                         }& q* X/ ]$ C+ X$ d: w& l' J
  650.                         else% z0 j" O8 [' X+ \  _* ^* p  J
  651.                         {
    & D, b& X) k& K, v2 f
  652.                                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯,自动结束+ C* D5 S4 g5 Q) u" R
  653.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
    : O- [5 Y/ L  l+ S2 o' D" J5 g# I/ F
  654.                         }3 n0 w4 K3 q* L6 N+ o2 c9 H
  655.                 }
    ( y  V3 S: j, d  g$ B, k
  656.         }while(ReadByteNum);
    / Z, W* {( U6 C5 n" r$ X
  657.         //读取完成了,等待STOP位有效' e. w; i' D& N8 B0 G! L% P0 \( x0 b" ]! S
  658.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);
    : ]5 H/ U+ X7 z. c3 x* v
  659.         if(Error != IIC_OK)
    9 e9 r: g: ?( P: G8 j3 q( H
  660.         {
    3 I3 ~; U9 x$ p
  661.                 Error = IIC_STOP_ERROR;
    % s0 k: `8 b3 I% [2 m
  662.                 goto end_loop;" z7 o3 O! D+ A/ d- _
  663.         }        / S4 u* f2 m( A* P' a# n, }/ B" B$ K
  664.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    ! G, i6 d4 L" ?. G' C  A
  665.         2 n2 D: S, X( i# ^5 f+ S
  666. end_loop:        
    9 c1 F) d" X3 z2 z0 x) U
  667.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        ) s' k0 b' t' S2 j7 U' }3 l
  668.         if(Error != IIC_OK)
    4 N7 E1 b7 d# S8 t( i. M
  669.         {
    1 r" S: r- [# g+ z  O
  670.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误  x/ Q- |- I5 x( T: ~
  671.                 DEBUG("[IIC R错误]:%d\r\n", Error);
    6 G- M+ [% V" M3 @
  672.         }9 j$ S! Q" Z, [% g; B
  673.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的
    ! h7 I1 |$ c, J7 i
  674.         {
    / H: v/ T( ?$ v$ X/ X1 ~3 T( c7 [
  675.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    # i" ?: b) @: d- z
  676.                 DEBUG("IIC R结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);               
    9 {* |' R3 Z! z  d! ?8 n0 U, p: C
  677.         }+ O, L9 l7 z2 O9 r, E: f+ n& @8 c
  678.         : h6 n7 N6 O! A
  679.         return Error;
    + n  h! {: D7 [- k1 |9 C
  680. }
    5 P! c) R3 f* j
  681. 0 d* S+ E# A2 L+ `! O

  682. 8 H5 f! Q9 U7 C+ _
  683. /*************************************************************************************************************************: V% A' O( _3 s3 q
  684. * 函数        :                        IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, ' Z8 H% n) V! |7 x, c! {5 f
  685.                                                 u8 *pDataBuff, u16 WriteByteNum)4 T3 h1 }& h0 Z" P
  686. * 功能        :                        IIC写寄存器(可以写1个或者多个寄存器)
    % W7 s, J! I, M9 u) D
  687. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要写入的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;0 }' Y) t: i" Z; C
  688.                                                 pDataBuff:写入的字节数据缓冲区;WriteByteNum:要写入的寄存器数量;8 {; |# g4 F) K! w% J4 \. I
  689. * 返回        :                        IIC_ERROR
    0 M, y" Y) r; Y+ R' O% W
  690. * 依赖        :                        底层宏定义
    4 {9 f8 }4 b9 R/ r% ^
  691. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    : P9 C  {) ^( q# f5 r0 r+ N4 A
  692. * 时间        :                        2020-02-16
    % l/ Y8 r; w* x+ |1 |  W$ K, O
  693. * 最后修改时间 :         2020-02-16
    & }6 _+ k, G/ i2 H& o
  694. * 说明        :                         写入的数据都是小端模式,如果是16bit的寄存器,请写入偶数个数据,并且需要提前进行高低字节对调最后组成高字节在前的数据buff
    $ r+ }. ], ?' ?, s6 O) R
  695.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如+ i3 z5 X/ e7 p
  696.                                                 增加信号量
    ( z0 L0 j. ^- i, A* Q! Z" s" u- X1 y0 n
  697.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在' Q% V8 j! w4 l5 `  }9 x, o4 U2 l
  698.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。+ B* H. G( x" F# j7 `' h  m  H8 i
  699. *************************************************************************************************************************/
    ' V3 ?9 v2 M  N" a; K: X+ T
  700. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum)
    9 V" F$ f; g% P
  701. {. t# c! |( {, \* Q  \# M' x. G
  702.         IIC_ERROR Error = IIC_OK;' s! Q1 W7 N1 l3 z
  703.         u16 ReadCount;
      |; B* G  K- ?1 I3 |% Q, N7 `
  704.         IIC_HANDLE *pHandle;
    " o8 A5 `: W: _% d/ B& E
  705.         
    & P2 [8 G# g# _1 b4 c
  706.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || WriteByteNum == 0)
    , m5 s: P6 D' B- N! v7 \
  707.         {- I8 p3 p/ E# C% C2 S" O6 W  e
  708.                 DEBUG("IIC错误:无效的参数\r\n");' l* T/ D$ A* H0 v; I: R6 Q
  709.                 return IIC_PARAMETER_ERROR;
    5 ]& q; \. ^; A; H+ X
  710.         }9 b- Q8 S% {. S8 N
  711.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄
    ( d, Z. _+ \7 R) a* P/ t& w. S8 O8 j
  712.         8 e3 u) p# |& n; B6 C0 f
  713.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙
    3 m) j) z% K- O" i  {3 p
  714.         {
    5 `% ^6 m0 i8 M% c; I; j5 U
  715.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");) c1 z; P: E' `' Y5 R8 \+ W5 P9 T
  716.                 IIC_SoftReset(pHandle);
    , O0 u( z, X. z; I! k2 \
  717.                
    4 N7 y& O$ K% K+ B
  718.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)        //忙
    ! O1 D$ F: s0 C# c& C
  719.                 {4 ?: T# N2 N0 y; ]. e8 s, e' |
  720.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");& L& Q& |, H4 s. o- `1 I
  721.                         Error = IIC_BUSY;, l3 e) G- A2 v# P0 B" q. T
  722.                         goto end_loop;
    7 p% m, i  r1 h( D+ P
  723.                 }
    ; a0 Y7 t- ]8 o" O
  724.         }( n3 U  ~. B7 L
  725.         9 E& F6 I0 \: r3 C! l
  726.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    : O" k5 T5 S" u; J, d2 C+ Q
  727.         IIC_ClearCR2(pHandle);                                                //复位CR2寄存器
    , U! d0 ]$ Z: V) F2 ^4 C) a
  728.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    & o6 ]: w8 a+ m* j* h
  729.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,FALSE,  pHandle->TimeOutUs);. N! T# ~1 Y- b0 L: L6 }
  730.         if(Error != IIC_OK)
    5 i8 `5 I9 }7 F: q: H2 r
  731.         {
    , Z# Y! }$ K! V
  732.                 goto end_loop;8 P2 Y* g# r# `! g' f7 N
  733.         }/ G( {/ |* v( O+ ^1 V- I0 V9 a
  734.         //发送后续数据( |1 I; c% w; i5 \+ J
  735.         if(WriteByteNum > 255)                        //如果超过255字节,则需要分多次写入-后续还有数据,需要重载
    % I/ R7 s/ m: e0 F
  736.         {
    9 r( a  [/ g9 A* V
  737.                 ReadCount = 255;                        //本次需要写入的数据长度255
    3 B; R0 ]2 A( S
  738.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入                ) Y( S( f* J- H& O0 z% g
  739.         }
    , Z4 W9 F+ y: o9 [
  740.         else
    ) B2 P% ], }# e' R0 V
  741.         {( u" s8 V2 K3 m7 d& C' u
  742.                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯后自动结束
    ) \5 n6 i, F0 m) o: i4 w
  743.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入
    6 T* V" D4 Z2 ]8 h: Y+ E2 i7 Y: w/ x$ M
  744.         }4 k& |  T2 [" ?/ |$ b
  745. ! u9 |0 y$ d" i$ ~
  746.         //循环发送数据
    ! V1 I( O& H5 G: `
  747.         do
    * E7 H- U! q8 v- x1 N  U1 s. n6 W
  748.         {
    7 p$ _1 p& D$ \/ w, E
  749.                 Error = IIC_SendByte(pHandle, *pDataBuff, pHandle->TimeOutUs);        //发送一字节 2 t+ x' ~+ O- G( t* ?
  750.                 if(Error != IIC_OK) 7 e; ~$ b7 o( t! R. x
  751.                 {' r, N4 I0 f/ |9 u. L
  752.                         goto end_loop;
    & [3 Y0 a' Y& C; M3 K0 {0 M' S# e
  753.                 }
    . g1 I2 [) _  W; q6 f" [
  754. 9 W" F; a! W0 Q1 B3 l. \" g6 `
  755.                 ReadCount --;
    " o7 n6 Y+ q5 @, n! w& |8 |
  756.                 WriteByteNum --;
    , _4 B& y1 n& B. F7 a! z
  757.                 pDataBuff ++;1 O: ]6 [+ Q6 S" o$ B' w( C1 T
  758.                 $ T* B* J; D0 A1 i" q( t
  759.                 if((WriteByteNum > 0) && (ReadCount == 0))        //还有数据要读取1 s( U- r  g0 y
  760.                 {; U. v% k) r+ s1 _4 n6 `
  761.                         if(WriteByteNum > 255)        //如果超过255字节,则需要分多次读取
    % B8 f: K0 \9 B: X  ]1 ?
  762.                         {4 B# Z! L$ D$ y& p/ f1 w1 w% A. Y
  763.                                 ReadCount = 255;        //本次需要写入的数据长度255-后续还有数据,需要重载' Q4 k9 y2 B* b" L1 r
  764.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入1 `  n4 G! m; |% }0 ]  R6 u# h
  765.                         }6 H7 y. ^4 u$ y9 J
  766.                         else( T1 I9 a/ |) c* L% z* ?
  767.                         {! H) c2 a0 e2 u* `4 H& L) [
  768.                                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯,自动结束
    . c% }, A$ D- p
  769.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入               
    3 N( d: b- F/ u$ k0 ?
  770.                         }% K* V- U- v% L) k+ q( l3 N
  771.                 }
    - G! h! f+ m" F7 y! G, y" E
  772.         }while(WriteByteNum);        ; M' g* E9 h/ l6 u
  773. * Y0 p1 b  h6 H* H1 Y. p; T2 `
  774.         //写入完成了,等待STOP位有效+ C3 v( I: J1 F8 k: E3 R* {
  775.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);
      x' f. W0 S5 S  w7 z, ]
  776.         if(Error != IIC_OK)
    ; S, Q- g9 q0 y
  777.         {* r7 C% @6 e  f
  778.                 Error = IIC_STOP_ERROR;# a6 C2 `) k; |9 R4 z
  779.                 goto end_loop;
    0 k) d. Q4 e, i
  780.         }
    0 h$ u7 t, k1 {1 k9 K7 }- o  Q
  781.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    * Q0 [- ~8 }9 L4 ]$ y2 Q
  782.           v* {5 K- Q3 g! A  @0 h2 z
  783. end_loop:        * \5 q2 N6 H9 B& a+ @# y; ]
  784.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        . {3 [. }. L) K; X3 w
  785.         if(Error != IIC_OK)' p6 _# O2 R7 W0 a
  786.         {
    - K- B5 T! b) b
  787.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误
    8 w8 w: h9 J$ L) A1 q, h8 m  V5 J+ Y
  788.                 DEBUG("[IIC W错误]:%d\r\n", Error);
    ! r7 H' s* u: W+ t; O# Q3 w
  789.         }
    # l' V4 t# j' W1 h! D3 U" W
  790.         
    # L. o% a  s& M! g
  791.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的7 t$ T; z3 h0 Z2 `% ~) A8 K( _
  792.         {
    $ N) d' w) H4 y+ w+ i( S' _
  793.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    8 x8 ?1 N" G! ~1 T# J+ ^
  794.                 DEBUG("IIC W结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);                3 L0 i/ s* z  k
  795.         }9 N- R4 Y% f5 C, Z' K: @% K0 ~
  796.         return Error;
    9 E7 A8 N, r1 Y" d3 X
  797. }
    3 H2 F9 E; }2 L" u+ T! l

  798. ) a: t: N1 i2 O3 ^0 ^: _( R
  799.   }6 A5 b" V- J* m4 j2 c) Z
  800. /*************************************************************************************************************************, c  ?- y) y3 H0 s
  801. * 函数                        :        void IIC_SoftReset(IIC_HANDLE *pHandle)! G7 M- y+ {: x; k
  802. * 功能                        :        硬件IIC软复位(会使能IIC)6 C% ~  g! U8 W: J
  803. * 参数                        :        ch:IIC通道
    : c7 `, h4 N* |  C0 i; o
  804. * 返回                        :        IIC_ERROR
    9 y0 K/ L( D1 D: y. j
  805. * 依赖                        :        底层宏定义
    / z( c" c9 F. t2 v% a& ?3 R2 V
  806. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ) ^. @9 S8 f! D+ X! R% \& z
  807. * 时间                        :        2020-02-153 R  b4 {; D5 {
  808. * 最后修改时间         :         2020-02-15
    0 h& [  b! G. ]1 f( z. g& M2 h9 O) }
  809. * 说明                        :         IIC软复位;必须使 PE 保持低电平持续至少 3 个 APB 时钟周期,才能成功执行软件复位。
    / `+ v( s' |" {7 p8 h  d' O
  810. *************************************************************************************************************************/3 [. q1 y+ |  J' i1 A" ?
  811. static void IIC_SoftReset(IIC_HANDLE *pHandle)
    4 z% h  d9 G! Q' h8 \+ [7 K
  812. {: c. j' |) }% l' M  V$ [, g) \& V+ q
  813.         pHandle->I2Cx->CR1 &= ~BIT0;                //关闭IIC后执行软复位
    2 c0 w% D& a# c6 T8 r( ]
  814.         Delay_US(1);        4 g9 L, B" J- S2 u5 I: H3 P6 ^
  815.         if(pHandle->I2Cx->CR1 & BIT0)
    : ]& ^+ n: f6 N- K. ^
  816.         {/ {/ |6 P- a! E, L) f
  817.                 DEBUG("IIC软复位失败\r\n");
    ; y8 d0 F: u# g2 _; P4 V  f/ G% `
  818.         }
    ) u  C0 T7 Y( J0 r
  819.         pHandle->I2Cx->CR1 |= BIT0;                        //重新启动  b; k" _* _$ X+ a
  820.         Delay_US(1);        / \7 N% P* D3 Q5 w2 g$ I
  821. }
    $ h) e$ {/ ?( k% }) v

  822. $ }* f& ]/ v! Z* @

  823. # I/ R! ~2 t& D+ g- ~8 g
  824. % H7 M2 a) U% h
  825. /*************************************************************************************************************************& M% @9 J8 N% q, L: V, S) r
  826. * 函数                        :        static u32 IIC_CalculationTiming(u16 Speed_KHz)# }) \5 U9 @& D$ N# Z
  827. * 功能                        :        硬件IIC时序计算- R$ Q- c: B$ b4 B- |9 |
  828. * 参数                        :        ch:IIC通道;Speed_KHz:速度10-1000+ e$ C- v: u; u: v
  829. * 返回                        :        IIC_ERROR) P0 c0 u, {9 p5 V
  830. * 依赖                        :        底层宏定义
    6 b; U% r# x+ H" O: h0 {& `
  831. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    " D0 }4 ?8 B: B! j
  832. * 时间                        :        2020-02-15
    9 M% O0 \: c5 X' N5 H& W/ [
  833. * 最后修改时间         :         2020-02-15
    ' b2 V* T6 B1 F- U2 T
  834. * 说明                        :         IIC使用的是APB1时钟,将IIC总线时钟控制在100KHz        
    + o, b5 Q/ C& ~9 p$ v
  835.                                         APB1时钟:最大不能超过45MHz        ; [8 H; E0 j0 `3 Q
  836.                                         如果速度是100,则按照SMBUS时序
    3 l" d) n- i5 u( T' `/ ?5 C
  837. *************************************************************************************************************************/+ x" R; q, z0 G; T% ^0 b
  838. static u32 IIC_CalculationTiming(u16 Speed_KHz)' Q! N$ M# G7 `) r
  839. {8 X  d* b" [+ I( ?
  840.         u32 tTime = 0;4 F* K$ C# o( {8 m
  841.         u32 temp;& B) Y# U5 s. R, M8 ~5 Z
  842.         u32 time_temp = SYS_GetAPB1ClockSpeed() / 1000000;                //先获取APB1时钟速度! h! [+ @7 W6 I* {: }# B4 |
  843.         u32 Th = 1000/Speed_KHz/2;                                                                //计算高电平时间(低电平时间一样),单位ns
    ) M1 S4 h& [! e' i
  844.         
    % ?' w9 _$ c8 [3 T3 \8 F' c2 U
  845.         if(time_temp < 20) time_temp = 20;
    ( Q; y& E5 s2 }7 p) P/ y- ?
  846.         time_temp = 1*1000 / time_temp;                                                        //单位ns. }+ Q! y+ }8 A5 ^7 d' c
  847.         uart_printf("IIC时钟计算->APB1周期:%dns\t", time_temp);8 Y7 Z+ ?& M6 ~/ S0 o* C1 |
  848.         if(Speed_KHz == 100)        //如果是100,则按照SMBUS时序& I6 @; y# \2 `- v7 B$ k
  849.         {
    , W+ \; D) w* I  Q# J% [1 p8 m: a
  850.                 //主时钟分频系数固定为3
    - e) e6 c! W( V- C
  851.                 time_temp *= 3;                        //主时钟周期
    " I3 M0 z: p, o6 `- g  [# K
  852.                 uart_printf("IIC时钟周期:%dns\t", time_temp);% f+ {: P  k' S' ]
  853.                 tTime |= (3-1) << 28;        //PRESC,时钟预分配
    4 q+ n3 h, c; M. I! e
  854.                 //计算数据建立时间,要求最小250ns
    1 {$ P2 a( U* Z" a
  855.                 temp = 250 / time_temp;" a4 _3 X, h1 e4 V) }' T7 @
  856.                 if(temp > 15) temp = 15;3 ?( J7 w# t9 d( r' P
  857.                 if(temp < 1) temp = 1;3 a8 X- p* a0 v* |
  858.                 tTime |= temp << 20;
    , G* s& ]4 j' p/ s: u8 B3 b
  859.                 //计算数据保持时间,要求至少300ns% v6 K" K, p+ @) g
  860.                 temp = 300 / time_temp;
    4 Q- z- j- q) L" A+ q
  861.                 if(temp > 15) temp = 15;
    / g- Y/ d7 }5 U8 z" w/ c! u
  862.                 if(temp < 1) temp = 1;$ A. O. Y% u2 R0 g0 i
  863.                 tTime |= temp << 16;
    * u! ?" J2 a7 d$ l  m4 |
  864.                 //计算高电平周期5us
    6 Y0 B. t& e6 e
  865.                 temp = 5*1000 / time_temp;
    1 H- ?, s4 K% d
  866.                 if(temp > 255) temp = 255;
    2 l% s8 U. u' Z/ A) w& N+ g4 f
  867.                 if(temp < 1) temp = 1;
    2 T, j$ p; E$ M6 j! ?% c
  868.                 tTime |= temp << 8;
    ) n: W) O0 Y0 }4 W4 k
  869.                 //计算低电平周期5us
    + d& R4 V+ r. ?
  870.                 temp = 5*1000 / time_temp;
      x" |9 f. T$ ~% h
  871.                 if(temp > 255) temp = 255;
    ' t+ Q& I: Y# J5 j( ^8 b
  872.                 if(temp < 1) temp = 1;
    - n( S2 _0 i6 u3 O
  873.                 tTime |= temp << 0;
    + Z+ D& t- x  G; R; j
  874.         }
    " c+ W7 k$ I8 T, ]1 r. J
  875.         else if(Speed_KHz < 100)
    1 X/ Z: Q" b/ ^$ n
  876.         {) ?& r2 x# V; |0 z) D
  877.                 //主时钟分频系数固定为6/ x2 [6 W; \8 Y4 P7 q
  878.                 time_temp *= 6;                        //主时钟周期
    & U' J( L. e! h/ g0 G
  879.                 uart_printf("IIC时钟周期:%dns\t", time_temp);
    $ O; e3 e5 g# d0 b
  880.                 tTime |= (6-1) << 28;        //PRESC,时钟预分配$ H! E- s- x0 g1 y& r( T* r
  881.                 //计算数据建立时间,要求最小250ns, i* D, i: l( q7 d( u0 Y# J+ C; u
  882.                 temp = 250 / time_temp;8 S$ r2 Q) Q: r- ?
  883.                 if(temp > 15) temp = 15;
    ; l' _( g0 M7 b5 q1 `
  884.                 tTime |= temp << 20;
    " G8 D# z% s" D0 r
  885.                 //计算数据保持时间,要求至少300ns
    4 a6 |! C, l. A4 `
  886.                 temp = 300 / time_temp;9 W3 ~% V! y- s) {, g/ L7 U; `, Q8 _
  887.                 if(temp > 15) temp = 15;! I6 e/ D" r7 J- b. q2 m) k6 K
  888.                 tTime |= temp << 16;1 f9 J( H& R1 j3 c" i" G
  889.                 //计算高电平周期Th us
    ' g7 J: D# |( b5 i
  890.                 temp = Th*1000 / time_temp;  P' Z' ~8 z4 {
  891.                 if(temp > 255) temp = 255;. G. t+ P  t7 X! d; q% n2 y& a
  892.                 if(temp < 1) temp = 1;
    : B8 T6 i+ t5 N" _) c1 A! B: C+ x
  893.                 tTime |= temp << 8;6 Z8 J$ l6 a1 _3 i3 k! \: d
  894.                 //计算低电平周期 Th us+ \, ]6 S6 z6 j2 \' k
  895.                 temp = Th*1000 / time_temp;
    . U% Q3 w* S( M& i9 A
  896.                 if(temp > 255) temp = 255;
    5 o$ P# u7 a/ u% `
  897.                 if(temp < 1) temp = 1;) E8 ]! \7 [' B  g# N
  898.                 tTime |= temp << 0;
    3 H! Z( k9 o$ q! n4 ^' E1 }8 Q4 b- O
  899.         }
    2 L+ }- l; F- Z7 o# G
  900.         else //>100
    , w5 V2 J4 a( M
  901.         {1 M. x0 H2 c0 G# M3 R5 ~0 |- c  F
  902.                 //主时钟分频系数固定为2
    ( T7 j0 b+ v4 A& x
  903.                 time_temp *= 2;                        //主时钟周期# [+ D8 N, A; ]9 m- P  q
  904.                 uart_printf("IIC时钟周期:%dns\t", time_temp);- |  W; |+ Q0 y7 m
  905.                 tTime |= (2-1) << 28;        //PRESC,时钟预分配
    4 }5 \/ @; w5 k- x7 F
  906.                 //计算数据建立时间,随便给100ns
    + S# D8 o' G/ L- n, K6 I- @
  907.                 temp = 100 / time_temp;
    6 A( D  U3 d& q  M. m4 A+ h; Y
  908.                 if(temp > 15) temp = 15;
    9 z/ v# p4 ?' e' d+ \9 r
  909.                 tTime |= temp << 20;
    + J3 G$ _; x- s5 L
  910.                 //计算数据保持时间,给100ns% I8 W  _! n  z' b4 e  `
  911.                 temp = 100 / time_temp;
    ' e9 p# O+ C! J3 ^
  912.                 if(temp > 15) temp = 15;
    7 H2 s* h" T) A7 O3 }$ v
  913.                 tTime |= temp << 16;
    4 J, l: e7 W0 O$ Q3 X3 c7 J$ @
  914.                 //计算高电平周期Th us
    ' v# e' r* l+ k" C  Z9 x% i4 H6 |
  915.                 temp = Th*1000 / time_temp;" Z1 `% D, B) [- b& S
  916.                 if(temp > 255) temp = 255;
    7 Z. C2 G1 K+ |% i7 J
  917.                 if(temp < 1) temp = 1;
    9 Y; _; {+ @8 b7 c3 I) v
  918.                 tTime |= temp << 8;
    6 G3 O$ X8 d0 G2 P
  919.                 //计算低电平周期 Th us/ h6 C/ r# o% X+ Z5 E, C. s
  920.                 temp = Th*1000 / time_temp;( t' r, s! K; T( J1 |) O' J/ _
  921.                 if(temp > 255) temp = 255;1 Y/ J4 U' _3 I
  922.                 if(temp < 1) temp = 1;- H/ d+ m3 u+ c- w& L1 t! V
  923.                 tTime |= temp << 0;" g7 B: `& ]& y& |  w
  924.         }
    . R/ _' h! d3 T. _0 C8 I; r
  925.         2 H# f% m3 b4 {; X# K2 o
  926.         uart_printf("时序寄存器结果为:0x%X\r\n", tTime);* h* O% l( ~- A8 a) c
  927.         
    7 i% B# n) m: e4 |9 j1 a; d
  928.         return tTime;
    + N. s' x" i: S: p2 i4 G
  929. }
复制代码
! N1 U% \8 _) f& M
8 v- R1 {' w2 Q; s- t
  1. /*************************************************************************************************************
    2 o1 s4 t, w2 g0 L
  2. * 文件名                :        stm32f7_iic.h7 b+ ^3 q; V$ v& j# j, `
  3. * 功能                        :        STM32F7 IIC接口驱动
    9 P' r4 c" _: {; Z+ p( ?9 t* y& V4 _
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>4 B: Z* E5 J+ H( f5 o7 ?
  5. * 创建时间                :        2020-02-09  v4 k% g& D9 g  j* C
  6. * 最后修改时间        :        2020-02-09& Q; l6 |$ U9 L3 a5 N, }
  7. * 详细:                        & e: G0 P! k2 |  a  g/ S9 a
  8. *************************************************************************************************************/               
    1 {# S8 c& I: t  ]3 X0 ~
  9. #ifndef __STM32F7_IIC_H_
    * ]' y1 S3 p5 z% ^. D/ R$ T6 F
  10. #define __STM32F7_IIC_H_
      H* w( x9 ?3 ?0 o+ O, c+ P9 [2 i
  11. #include "system.h" ( r& u# a1 ^3 I; m7 {! l
  12. ; e( t0 P& r; }0 l" \: A. a
  13. //16位整形数高低对调
    % E$ F& Q& H$ ?! Z7 @3 [/ b
  14. #ifndef SWAP16& n0 U& H& u9 Z7 f/ [  i
  15. #define SWAP16(x)   (((x & 0xff00) >> 8) | ((x & 0xff) << 8))
    9 o9 n! w% |3 K& ?9 q
  16. #endif  //SWAP16
    ! Q8 Z" a  u' @% H9 o

  17. - c0 }4 A& A8 W  Y- S0 P
  18. //硬件IO口选择. x6 q9 y( A4 y+ j# t
  19. //I2C1 IO定义与选择
    # j1 o# c0 f+ J( t
  20. #define IIC_CH1_PB6_7                                0                                        //PB6,PB77 I+ L5 [) [" m9 u" {0 L$ I
  21. #define IIC_CH1_PB8_9                                1                                        //PB8,PB9
    8 C8 M: V5 G- ~* E) L
  22. #define IIC_CH1_IO_SELECT                        IIC_CH1_PB6_7                //选择I2C1 的IO        4 O' ?$ n9 o4 {$ q

  23. + J* G7 T- T: V( O8 L4 _9 E
  24. //I2C2 IO定义与选择6 X: D7 f1 @1 @1 n
  25. #define IIC_CH2_PB10_11                                0                                        //PB10,PB11  X/ Q2 b. e  w. t: f4 _
  26. #define IIC_CH2_PF0_1                                1                                        //PF0,PF19 o0 r  a$ y2 S: u5 O6 m
  27. #define IIC_CH2_PH4_5                                2                                        //PH4,PH5
      n0 h/ T4 t( ~* F' a5 d
  28. #define IIC_CH2_IO_SELECT                        IIC_CH2_PB10_11                //选择I2C2 的IO
    * B9 F9 I, C5 N: V9 O* [

  29. 2 I& v4 R$ A6 ?" ~$ [( B( b& ~, j7 f
  30. //I2C3 IO定义与选择
    8 }3 P3 h& z* ?: l% U! ?! M
  31. #define IIC_CH3_PH7_8                                0                                        //PH7,PH8# I6 U, f, F0 m& T( ^+ i- j
  32. #define IIC_CH3_PA8_PC9                                1                                        //PA8,PC9; w3 g4 o5 C3 U9 ~: C" h# |  y; |
  33. #define IIC_CH3_IO_SELECT                        IIC_CH3_PH7_8                //选择I2C3 的IO
    . q8 J8 g3 x8 Z

  34. ( l- E2 \% _- E: ]& Y9 ?6 c% b
  35. //I2C4 IO定义与选择2 t: i5 ?. x$ w5 J6 _0 ?" b
  36. #define IIC_CH4_PD12_13                                0                                        //PD12,PD13
    % N4 G# H# B  V1 H) [% ~8 s( p5 ~
  37. #define IIC_CH4_PF14_15                                1                                        //PF14,PF15
    - c2 X; p' x. {
  38. #define IIC_CH4_PH11_12                                2                                        //PH11,PH12& M5 L6 r# ?- L% x
  39. #define IIC_CH4_IO_SELECT                        IIC_CH4_PD12_13                //选择I2C4 的IO
    9 L6 e( t" Q& m: H) x0 T' h

  40. 4 {" ^, ~% X; C! I7 e0 z
  41. //IIC硬件接口选择' q" ^' W6 y" B- ?/ N6 h+ \, a+ {6 B
  42. typedef enum) V& [9 d5 X% t! U! U
  43. {7 X3 U3 ^8 s$ |4 J  C$ R
  44.         IIC_CH1        =                0,        //IIC1
    & s: x& q* J" D' T9 B$ z. B
  45.         IIC_CH2        =                1,        //IIC2  Q' L7 w% w) B- u  T
  46.         IIC_CH3        =                2,        //IIC3
      G6 P; ^5 \( T: J8 x
  47.         IIC_CH4        =                3,        //IIC4
    ' r! Z1 Q5 f" K, _9 t  J3 c
  48. }IIC_CH_Type;7 p8 x' P! Y, o: Y
  49. #define IIC_CH_COUNT        4        //4个IIC
    3 \, P) l  j/ U# M

  50. / Y; n3 g3 R  }* d! Z
  51. / M2 H: b7 J! r+ c6 t8 I3 L3 K
  52. //中断状态3 e& C) b% a' T! P+ x& y
  53. #define IIC_FLAG_TXE                    BIT0        //发送数据寄存器为空(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。
    8 v& p" X( n% @5 |4 O# x
  54. #define IIC_FLAG_TXIS                   BIT1        //发送中断状态(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1,待发送的数据必须写入 I2C_TXDR 寄存器。
    5 j% o" g8 i& T! l+ m
  55. #define IIC_FLAG_RXNE                   BIT2        //接收数据寄存器不为空(接收器); 当接收到的数据已复制到 I2C_RXDR 寄存器且准备就绪可供读取时,该位由硬件置 1。读取I2C_RXDR 时,将清零该位。" a1 n4 @. Z4 m3 M
  56. #define IIC_FLAG_ADDR                   BIT3        //地址匹配(从模式); 接收到的地址与使能的从设备地址之一匹配时,该位由硬件置 1。该位由软件清零,方法是将ADDRCF 位置 1。
    $ i/ V) @6 x& P
  57. #define IIC_FLAG_NACKF                  BIT4        //接收到否定应答标志; 传输完字节后接收到 NACK 时,该标志由硬件置 1。该标志由软件清零,方法是将 NACKCF位置 1。6 l1 K( R) {+ q5 s$ I$ V$ F$ b. U, k
  58. #define IIC_FLAG_STOPF                  BIT5        //停止位检测标志; 当在总线上检测到停止位,且外设也参与本次传输时,该标志由硬件置 1( _+ B( [% Y. F
  59. #define IIC_FLAG_TC                     BIT6        //传输完成(主模式); 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 START位或 STOP 位置 1 时,该标志由软件清零。
    : O9 k/ B" Q% X. d+ Q- k
  60. #define IIC_FLAG_TCR                    BIT7        //传输完成等待重载; 当 RELOAD=1 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 NBYTES 写入一个非零值时,该标志由软件清零。
    / T; R: N! G0 X0 @0 [' k# H
  61. #define IIC_FLAG_BERR                   BIT8        //总线错误; 当检测到错位的起始位或停止位,而外设也参与传输时,该标志由硬件置 1。在从模式下的地址阶段,该标志不会置 1。该标志由软件清零,方法是将 BERRCF 位置 1。" `$ A# \) M0 @$ f  F9 W9 \! z! S
  62. #define IIC_FLAG_ARLO                   BIT9        //仲裁丢失; 发生仲裁丢失时,该标志由硬件置 1。该标志由软件清零,方法是将 ARLOCF 位置 1。0 X, M( W, L$ {9 h7 e" C2 T* k
  63. #define IIC_FLAG_OVR                    BIT10        //上溢/下溢(从模式); 在从模式下且 NOSTRETCH=1 时,如果发生上溢/下溢错误,该标志由硬件置 1。该标志由软件清零,方法是将 OVRCF 位置 1。) K' c, q6 P/ x0 w% _  j
  64. #define IIC_FLAG_PECERR                 BIT11        //接收期间的 PEC 错误; 当接收到的 PEC 与 PEC 寄存器的内容不匹配时,该标志由硬件置 1。接收到错误的 PEC 后,将自动发送 NACK。该标志由软件清零,方法是将 PECCF 位置 1。% Z9 e& ^7 q' r
  65. #define IIC_FLAG_TIMEOUT                BIT12        //超时或 tLOW 检测标志; 发生超时或延长时钟超时时,该标志由硬件置 1。该位由软件清零,方法是将 TIMEOUTCF 位置 1。
    & s" M$ [: F2 n2 l/ V
  66. #define IIC_FLAG_ALERT                  BIT13        //SMBus 报警; 当 SMBHEN=1(SMBus 主机配置)、ALERTEN=1 且在 SMBA 引脚上检测到 SMBALERT 事件(下降沿)时,该标志由硬件置 1。该位由软件清零,方法是将 ALERTCF 位置 1。
    7 X9 u9 I6 q" M- o+ d) n
  67. #define IIC_FLAG_BUSY                   BIT15        //总线繁忙; 该标志用于指示总线上正在进行通信。当检测到起始位时,该位由硬件置 1。当检测到停止位或 PE = 0 时,该位由硬件清零。2 r+ ~* ]  _! H8 _+ I, H
  68. #define IIC_FLAG_DIR                    BIT16        //传输方向(从模式); 该标志在发生地址匹配事件时 (ADDR=1) 更新。;0:写;1:读
    # B3 A7 t" t9 A6 x. r$ @$ x( _( s
  69. 2 W/ _$ e# [$ `, O; G- }9 [; G
  70. //通讯错误状态9 ~) n, V% ^5 B. K
  71. typedef enum
    + U- E: ^, {& j7 ?1 I+ T3 S$ a
  72. {/ c& ?7 ?2 W/ Z) m/ q
  73.         IIC_OK                                        =        0,        //没有错误) S# ^* C, e' W: ?
  74.         IIC_PARAMETER_ERROR                =        1,        //参数错误" q, j1 F& K% W/ R
  75.         IIC_TIMEOUT                                =        2,        //超时错误,也可能是底层错误  Y& y! ~( _, C, }6 R
  76.         IIC_HAL_ERROR                        =        3,        //底层错误
    ' A! W: Z0 p# a) L7 D
  77.         IIC_STOP_ERROR                        =        4,        //等待结束错误
    1 \% q7 L; F4 Z* B
  78.         IIC_BUSY                                =        5,        //硬件忙/ W9 j; z" p2 d* }( [8 v
  79.         IIC_NACK                                =        6,        //收到NACK了
    4 e7 j) X7 x2 m) ]
  80. }IIC_ERROR;
    & m- z4 g& B  D) I

  81. / K2 l% T: z, H$ Q5 G

  82. ) X9 @  t9 E7 P) k+ R; \2 C
  83. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs);        //硬件IIC初始化; f0 P# x" o1 t3 z7 l8 h; {0 l& f
  84. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum);        //IIC读取寄存器(可以读取1个或者多个寄存器)# p6 S! U* ], b- _1 R. o. s5 a
  85. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum);        //IIC写寄存器(可以写1个或者多个寄存器)
    5 G) \, b* r6 Q
  86. 0 Q# O: ?3 d% C' t3 ^) v6 E# K% \
  87. 9 z5 A) f2 c3 ~& @6 s; K  m
  88. #endif //__STM32F7_IIC_H_
复制代码
; r( j8 u  k3 c* w
/ s  C& b; v, M! d, x
//初始化
$ u: z0 M( O  {  Y
+ j- z. i! U) y" b
  1. IIC_Init(IIC_CH3, 200, 0);        //硬件IIC初始化
复制代码

" Z  W7 U1 c3 R5 B. [5 m) t+ ]( H  J8 A1 p' ^- e; }6 \) B
//调用
3 ~! N% |0 C; R7 e0 i& D
  1. ; j2 ~# C1 u) z/ h2 Q* G& ~
  2. //触摸屏IIC读取寄存器接口# O% O4 g, K( d* e
  3. bool TP_FT5336_IIC_ReadReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)$ F+ i1 w: S% j* [
  4. {
    # Y. q0 l4 d( ?  q7 U, B0 z
  5.         if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)
    4 g. J% e3 ?" l  C
  6.         {
    ; F  O& x% M6 [. K) C/ T
  7.                 return TRUE;' e6 g" @1 t! c6 x! [, h6 R& v& u
  8.         }
    - x+ T( r8 T, ]! l! g, ?
  9.         else
    2 e7 n+ x. K; L( ]. ?  z  \8 t% b9 H
  10.         {
    - w+ D& K; K# p0 O
  11.                 return FALSE;
      `: ?: w, o# O+ T3 n( l5 ^
  12.         }
    ! S4 K6 R6 @8 J
  13. }' n* Q8 R0 g* t6 P/ N  R
  14. " ?# [+ q5 x; a' @3 Z
  15. //触摸屏IIC写寄存器接口
    7 {, m9 J% O/ b( H' A& X
  16. bool TP_FT5336_IIC_WriteReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)
    & f" c% u6 b5 K9 [
  17. {& T6 t6 ]: G0 }* ~
  18.         if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)9 G, s) M4 e9 S6 A
  19.         {  ^0 f9 \+ J8 }; [$ d7 s1 A
  20.                 return TRUE;6 R/ H3 |) {! {' R1 |5 e
  21.         }
    # q- d3 l  I6 J' C! Q9 o$ S4 \
  22.         else; X- H% Y8 L$ M& l
  23.         {
    , M( K0 |& X! j; `0 ~' T
  24.                 return FALSE;
    * D8 z4 V' W$ p
  25.         }2 k. V" a2 O  w9 C1 i; Q
  26. 5 a- y9 o6 F6 K( V
复制代码

( u, E" z3 q2 m! T1 e' Z
: ^! U9 o2 v+ W% ]& x* n0 x4 u# O/ F1 R. I! f
收藏 评论0 发布时间:2021-12-11 12:00

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版