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

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

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
目前只实现了主设备模式,一般也只用到主设备模式,IIC如果不能使用硬件方式,读取大量数据的时候效率很大,由于只有1个字节的缓冲区,根本不能使用中断模式(实际使用过程中,IIC会造成100us以内间隔的中断,单片机根本扛不住的),所以建议数据少就直接阻塞,1个字节也就几十us,数据多直接用DMA,将线程阻塞,等待DMA传输完成,而不会阻塞CPU(上传的代码没有实现DMA部分,便于理解)。
& q" i3 Y) L4 r; \) Q1 q. E: {
4 L' b8 L( e! t/ c' f- M目前已经做了完善的错误处理,读写操作前都会清除中断,遇到错误会软复位,所有位置均做了超时处理,防止程序卡死,目前只测试了几个字节的读写,大量的,长时间的读写均表现稳定,目前手上开发板没有eeprom,无法做大数据的连续读写,如果你在使用过程中遇到问题,欢迎指正。
) W8 H; ~7 ^2 ?+ W* G( b: Y
% H. a1 b( p% H* ^+ x6 X$ G3 R下面是IIC读写的时序例子,可以先熟悉一下,这样比较容易上手,哪一个环节出了问题也要调试。8 i' e2 B7 l( u7 K2 ?. c4 K6 L

: L% {6 ^0 M& @3 _+ }+ z8 ]
20200216194202434.png
( B3 ?) u- X9 q/ X. C3 |2 U

0 v! f( y$ ^2 t+ }5 c7 M' L6 z
20200216194219185.png

7 x* V9 Z) N( Z8 Q6 H9 o1 W5 s" _* o! }9 D8 W  U8 o
20200216194234908.png

& F3 z4 Y5 ~) ]* _0 H
. a) T/ Y/ H7 [1 ^+ b# v8 W$ `) n/ U, j3 n
下面简要说明一下STM32F7硬件IIC的驱动设计方式(建议先百度学习一下IIC的时序要求):( e, i# `0 h- |1 K" M  ]8 n

' \4 i- w' g& P. k  d; t[基本的初始化]  m# f, y9 Y7 `! c1 D+ j

/ c& p/ ]8 w3 q: ?5 N4 X, g1.初始化IIC时钟,IO(IIC IO必须设置为复用开漏输出,这个很重要)。: d  k9 ?! F2 ^; ]/ J7 t
; `6 b" w5 B' \' l% L9 o
2.CR1先赋值为0,复位IIC.
( m' w7 X( ~; l6 E5 O2 k" x3 S7 r$ V- x
3.除了TIMINGR寄存器需要自己计算设置好,其余寄存器全部复位为06 z( R/ s8 b) r4 e) ]  m) C' M! q6 k

7 f* g" `" J( U4.设置CR1使能IIC。
. f; E# c$ O* e
8 r( l& r) a' f# |3 K$ Z注意:上面说到,IIC的IO必须初始化为复用开漏输出,我之前初始化为复用推挽输出,测试很久,只要一启动传输,就会立马收到NACK,然后是STOP中断,数据根本没法发送,弄了好久才发现是这个IO初始化的问题。, |6 T3 ]% a+ h, C( W5 P" Y
0 `3 ~) j9 U" K4 u  d# N0 M

) W' j6 U  D+ d5 P$ I% R$ c2 t" F& U1 C
[读取]6 u7 p& h/ J# W3 L
0 o4 m( z" S% I
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。
- i. D  Z. K/ A; ~* F7 f7 O# K! v
2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)软件STOP,写模式,启动传输。% R( X4 ^# D& b- P$ q+ m: ~$ N

, D2 S! b3 n' b! X$ l+ `3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。$ j/ O4 y3 o( E0 ?

, ^4 Y* {' X& @2 A4 v2 u4.等待TC置位,意味着上面的1-2字节的寄存器地址以及写完成了。
5 ]3 G- R9 _6 L1 u/ R: L9 c5 j( _, c7 f( f3 E
5.根据要读取的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。# g2 A; p8 E8 R, Z7 o; }

# b' X! p8 j' l* ~' l: Z: s* U6.设置了从机地址,要读取的数据长度,之后设置方向为读取,然后启动START(从写切换到读要重新发送START,这个跟软件模拟是一模一样的)。
+ w' I0 ~8 E1 C9 U
! m4 i. e0 a4 G, O7.循环一个字节一个字节的读取数据,字节读取需要等待RXNE有效,只有读取RXDN寄存器,直到所有数据读取完成。0 W# q0 t: \& k% x% i, `2 O
4 O- L  C; [& A  b# D* z+ W( I
8.读取完成后等待STOP有效,因为前面在最后一包数据读取的时候使能了自动STOP,这个时候检查STOP是否生成。4 m$ |0 ^% a& o! k
" j( u$ T; ^$ H; I' q
9.需要注意的是,所有的操作都要给超时,并且是自己可控的,绝对不要有死循环,之所以一直说STM32的IIC死机很大程度上都是由于这个地方没有涉及好,我的程序设计方法是:一旦出现了异常,就复位IIC,如果不复位就会导致下次进去的时候IIC一直忙,因为还处于上一个通讯过程。' G/ B8 m  c& b0 D& g$ [

  H2 \5 a9 P0 V( p. G4 N8 t
. T0 ~- E8 h/ j
  a& @8 V7 M; _: E8 y2 f/ y3 p[写入]
* v/ @* G; l* }$ a( n9 w% }1 m  m' y3 O
1.检查总线是否忙,如果忙的话可以根据你的需要时推出还是直接复位总线,清除中断状态。
  _! u% W4 K4 b5 A: \
# a9 o) O- L, Y" j9 ]2.设置CR2寄存器,从机地址,待写入数据长度(就是后面要发送的寄存器地址长度,通常1-2字节)自动重载,写模式,启动传输。5 l* z% O5 y. s

8 L/ R# I5 r. E3.等待TXIS置位,然后写入1字节的寄存器地址,如果寄存器地址有2个字节,重复上面过程。
& A3 m5 l0 n+ H, o5 D# g' t% c! k  S6 b- Y
4.等待TCR置位,意味着上面的1-2字节的寄存器地址以及写完成了,已经发生重载了,后续可以继续写入数据了。, R7 d2 l7 H! z0 l/ [0 x% q) B

9 R( n) F$ }5 R3 s* ?5.根据要写入的数据长度,去设置CR2寄存器,由于一次最大只能读取255字节(计数器只有8位),如果超出了就要分多次,这里有2种情况,如果当前是最后一包,则将自动STOP使能,RELOAD禁止;如果后面还有数据要发送,则将RELOAD使能自动STOP禁止;这2个是二选一的,而且RELOAD优先级高一些。
" }: j( W4 m2 V$ B$ x8 g0 j
" M1 B" D7 G3 b& T6.设置了从机地址,要写入的数据长度,之后不用切换方向,不用启动START(都是写,不用重复发送START,这个与读取有区别)。
. u7 {, I0 \: {, i% r9 T
8 W# P3 Z/ p+ P( T% F, Z9 a$ M7.循环一个字节一个字节的写入,字节写入与步骤3一样,等待TXIS置位,就可以写入数据到TXDR。( u! f# N9 x9 l0 H

' Q: j' J1 x8 g  m6 x3 W2 \8.等待STOP有效,因为前面在最后一包数据写入的时候使能了自动STOP,这个时候检查STOP是否生成。
3 d1 Q- C7 ^4 [0 g0 J: Q6 m. Y( }9 |* C! E( m% i- `- j
9.需要注意的是,所有的操作都要给超时,跟读取一样。
  t  T% x0 L/ B4 m( I% m% g2 s9 f# ]9 w
5 l0 U3 |$ t' u3 x
5 }5 e5 a3 ~" ^4 t$ Q6 _7 k+ C
注意:IIC的读取实际很短,超时也不用给很长,以标准的100KHz通讯时钟速度,一个字节大概在90us左右,超时可以给个5-10B时间,也就是450-900us左右。
+ F' S, z4 @! G4 B
. S7 K3 h' }8 _4 h
' V, h' k% l% |* ~" J- u- W8 `; u  h$ M  B% j
好了说了这么多,具体的看代码中的注释,直接上代码(我只测试过I2C3,其余的理论上都是一样的,就是IO初始化部分有区别,别的通道没有硬件进行测试)" a. ~7 ~& M* M+ F% e& n9 v

0 |8 j3 y& u$ @' c2 L* K2 W
  1. /*************************************************************************************************************
    - D% `* Z% O' q  Z" X
  2. * 文件名                :        stm32f7_iic.c) a3 ]% s9 h' ~, n
  3. * 功能                        :        STM32F7 IIC接口驱动2 g& z, |9 A, L2 }4 M4 `
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ; E6 m' w* h% p1 b, `
  5. * 创建时间                :        2020-02-09
    - t+ V& [( o- l8 o4 b2 [: V( J
  6. * 最后修改时间        :        2020-02-093 ]8 P5 K) [7 E6 v3 a$ W5 ~
  7. * 详细:                        只支持主机模式,7bit地址,默认APB1为IIC提供时钟
    2 \! B$ N# B" S, Q, z3 g3 Y
  8.                                         涉及到读写1字节的超时时间是us,其余的是ms+ i7 E0 L4 Z  u
  9.                                         注意:IIC的IO必须初始化为复用开漏输出。
    3 b/ a; m9 d3 ^& ~2 X: `3 @
  10. *************************************************************************************************************/        ( K: ]1 L) f, y5 |9 p' j. ]
  11. #include "stm32f7_iic.h"
    7 n$ N7 j. e. _+ Q  K
  12. #include "system.h" , ?/ h* |. H5 R# v' D
  13. #include "dma.h"/ e' ]+ o3 H/ r) c9 L
  14. 8 n1 T" a/ }+ o: C1 l
  15. #define IIC_FLAG_MASK  ((uint32_t)0x0001FFFF)        //中断标志掩码9 M7 a. a/ D2 H4 [/ w
  16. 5 a6 i+ C: Q) j0 S3 V1 J
  17. //自动结束或自动重载设置(重载与自动结束只能二选一,或者都不选)
    6 h/ `, [- c, ~" {0 N% B& ]
  18. typedef enum 8 v# X9 C3 g1 z
  19. {$ c4 ]7 d$ \: `: C
  20.         IIC_SOFTEND_MODE                =        0,        //手动结束,并不开启重载
    : `: P# R! t3 e0 m, j/ L1 i
  21.         IIC_AUTOEND_MODE                =        1,        //自动结束,用于最后一次通讯完成后自动发送STOP结束通讯
    ' v7 m7 a; W$ K) Q# ]; g1 b& W
  22.         IIC_RELOAD_MODE                        =        2,        //后续还有数据,本次通讯后自动重载,重新设置后继续通讯
    - j9 i% F/ w; e
  23. }IIC_RELOAD_END_MODE;
    ! y4 H) {' |, {) K% k2 J
  24. . z& {( N" r3 V
  25. //读写与开始模式控制$ T  p% D, d! g- x
  26. typedef enum& j1 }  C( R0 E+ V: ]* I# d4 `4 p
  27. {# U3 }- q* `0 W$ D2 L5 P5 m" [; M6 I
  28.         IIC_NOSTART_WRITE                =        0,        //没有开始的写-用于后续数据的写入
    # Z3 t3 |3 L" f; N  d
  29.         IIC_NOSTART_READ                =        1,        //没有开始的读-用于后续数据读取
    5 z, j' m* ?( E+ g
  30.         IIC_START_WRITE                        =        2,        //生成开始写-用于通讯开始时,写地址或数据
    4 U& d  C: E; C
  31.         IIC_START_READ                =        3,        //生成开始读-用于读取数据时切换到读取方向,并读取后续数据+ M: f$ X. Y* \7 r5 ?9 ]* z6 w3 f
  32. }IIC_START_WR_MODE;
    8 K3 r2 e6 n" q$ W) L; b

  33. & Y- z+ h7 J/ n! d; K
  34. //IIC句柄
    / l7 a" M; y4 F+ x
  35. typedef struct
    5 n# m, `) s7 a& P- Z3 J0 z
  36. {/ b& a+ F5 X$ k7 W
  37.         IIC_CH_Type ch;                        //当前通道1 U9 L8 C, ?7 ~' r( o
  38.         I2C_TypeDef *I2Cx;                //当前通道外设结构体% l8 o  z$ f6 i% K0 g
  39.         u32 TimeOutUs;                        //操作超时,单位us
    # |1 W4 y4 M$ _$ _8 X+ I. M- s0 w8 [
  40.         u16 Speed_KHz;                        //通讯速度,单位KHz7 L+ B  e- N' L4 P: n8 C. u
  41.         bool isMasterMode;                //是否为主设备模式-目前只支持主设备模式
      A" {% T; s) |6 y3 g% V
  42. }IIC_HANDLE;
    5 d0 s% I8 Q3 l3 K! K* Q4 [5 g
  43. ; B+ `& h: v! l# s' P- Z. H5 L# R
  44. //IIC外设结构指针
    * J# o  l6 A0 b/ L# w8 C
  45. static const  I2C_TypeDef * const I2C_TYPE_BUFF[IIC_CH_COUNT] = {I2C1,I2C2,I2C3,I2C4};
    4 v2 r% d# r+ @0 {1 f! Y% B8 H1 K
  46. //IIC通道句柄定义
    / w/ D* e  e3 j# p+ |
  47. static IIC_HANDLE sg_IIC_Handle[IIC_CH_COUNT];
    ! g! u) X+ _4 i$ r: ^
  48. ) z% Q6 _; O3 |+ f
  49. //发送NAK% p5 B9 P" `2 _; @
  50. //static __inline void IIC_SendNAK(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT15;}
    & U% {. K$ K. |7 b# J" o/ |
  51. //发送STOP" e: i( ^) f; ~: P  C% e
  52. static __inline void IIC_SendStop(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= BIT14;}
    0 g3 `* Z4 V; P( f, @
  53. //发送START
    / D$ a$ ^7 d$ \* {
  54. //static __inline void IIC_SendStart(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 |= I2C_CR2_START;}
    ( h. ]6 k9 ^0 E3 y3 D% l
  55. //获取中断状态4 O( `- G% d% b6 f
  56. static __inline u32 IIC_GetISR(IIC_HANDLE *pHandle) {return pHandle->I2Cx->ISR & IIC_FLAG_MASK;}8 Q1 b4 R% ]& b% C# C" `# P
  57. //清除中断状态) \/ k( |6 {* w" X) o5 v1 {
  58. static __inline void IIC_ClearISR(IIC_HANDLE *pHandle, u32 IsrFlag) {pHandle->I2Cx->ICR = IsrFlag & IIC_FLAG_MASK;}
    5 y, ]) r9 N. a6 q" S* {
  59. //复位CR2寄存器
    # m5 a% L1 A3 @; U: Y8 s
  60. static __inline void IIC_ClearCR2(IIC_HANDLE *pHandle) {pHandle->I2Cx->CR2 = 0;}3 s; F  [2 W6 C( u

  61. 9 K2 c6 L9 `$ e, r9 C  D6 m
  62. static void IIC_SoftReset(IIC_HANDLE *pHandle);//硬件IIC软复位(会使能IIC)
    ) @6 X- N; ?0 W7 n# X
  63. static u32 IIC_CalculationTiming(u16 Speed_KHz);//硬件IIC时序计算
    # e, W, X" e/ Y0 A' m: G
  64.   K$ Y7 [& M8 d+ g2 N
  65. / V& T3 l* X5 o
  66. /*************************************************************************************************************************
    9 ^" f: Y1 Y: }: o
  67. * 函数        :                        bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)
    2 P$ f0 l  y! x1 V; {
  68. * 功能        :                        硬件IIC初始化
    * R  ?2 n( e1 h$ p: n
  69. * 参数        :                        ch:IIC通道;Speed_KHz:速度10-1000(如果速度是100,则按照SMBUS时序);TimeOutUs:操作超时us(0:自定计算超时)
    6 a3 @; d$ }7 ~' I
  70. * 返回        :                        IIC_ERROR
    % P5 J9 [& F, [+ X
  71. * 依赖        :                        底层宏定义1 M* I+ \3 z! r; i* z# Q$ V
  72. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    $ }3 E2 A+ |1 ?5 A
  73. * 时间        :                        2020-02-15: h# @2 [/ s/ _% N
  74. * 最后修改时间 :         2020-02-15% q# m; k! S: |
  75. * 说明        :                         速度只是个大概的计算值,设置为100KHz时会严格的按照SMBUS时序,其余的不保证SMBUS兼容,正常情况下只要时钟速度符合要求,. K5 o9 k' R6 P4 [' f
  76.                                         时钟上升沿到来前数据以及稳定的切换了即可保证通讯稳定性
    % P8 r3 `, C6 f9 t) s3 {; t0 H
  77. *************************************************************************************************************************/7 w4 J& Y) O1 K  T* O; Q7 M
  78. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs)
    / V! e& C& @+ L# H; d7 R% ~
  79. {
    " b. d* b' Y) A4 _2 ~* Y
  80.         SYS_DEV_CLOCK DevClock;6 n+ T3 Y0 M! t( w$ Y4 \
  81.         IIC_HANDLE *pHandle;  B6 w. @: s/ L/ v8 T6 ]
  82.         
    6 U! _0 U$ i7 y# _' L) c
  83.         switch(ch)
    0 [, X; ~% g- X
  84.         {! @+ q$ o$ j  ^# T/ H  x
  85.                 case IIC_CH1        :        //IIC1
    ' A/ g5 ~: o/ }0 ?
  86.                 {$ x9 H" P* Y, L0 Z. B5 e3 b8 t
  87.                         RCC->DCKCFGR2 &= ~(0x3 << 16);        //清除设置,使用APB1作为时钟源
    ; K: @$ \1 T* Y# o- u) h$ b7 C
  88.                         DevClock = DEV_I2C1;
    * h* ^4 {# \. d  M8 b
  89.                         //初始化I2C IO& n$ a% [- U% n/ l
  90. #if(IIC_CH1_IO_SELECT==IIC_CH1_PB6_7)        //I2C1        使用PB6/7
    3 U; q% W  O( x1 H& ?
  91.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    6 Q/ [- ?' O9 {. m
  92.                         SYS_GPIOx_OneInit(GPIOB, 6, AF_OD, SPEED_25M);                //PB6& v- E/ R- @! j) v8 m
  93.                         SYS_GPIOx_OneInit(GPIOB, 7, AF_OD, SPEED_25M);                //PB7; T0 v% j$ p+ y: h
  94.                         SYS_GPIOx_SetAF(GPIOB, 6, AF4_I2C1);                                //AF4
    6 w) U5 }" l, b7 W
  95.                         SYS_GPIOx_SetAF(GPIOB, 7, AF4_I2C1);                                //AF4
    ; W  x& s: @2 R! l6 J; b! b6 ^
  96. #elif(IIC_CH1_IO_SELECT==IIC_CH1_PB8_9)        //I2C1        使用PB8/90 [8 z$ H# T# x; ^8 I
  97.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟  z, r) a& C3 l/ F: i" `
  98.                         SYS_GPIOx_OneInit(GPIOB, 8, AF_OD, SPEED_25M);                //PB8
    ; n9 |2 E3 ]2 D6 K8 n& b% [
  99.                         SYS_GPIOx_OneInit(GPIOB, 9, AF_OD, SPEED_25M);                //PB9
    % }/ b- b2 n% F! n8 F
  100.                         SYS_GPIOx_SetAF(GPIOB, 8, AF4_I2C1);                                //AF4
    ; X7 Y$ n8 e* z! @3 t
  101.                         SYS_GPIOx_SetAF(GPIOB, 9, AF4_I2C1);                                //AF4
    ) k7 H& Z1 Z  V1 C* D- H; y
  102. #else% J. K; J' `1 ~) L
  103.                         #error("无效的I2C1 IO选择");" l  n7 e7 \; T7 @+ I
  104. #endif //IIC_CH1_IO_SELECT. }+ u7 x9 f$ v, D5 ^- e
  105.                 }break;/ Z0 N+ [. m8 C( q+ Q3 M/ Y8 S7 c* T
  106.                 case IIC_CH2        :        //IIC2* o( ~5 I  y/ l& N  ]4 f0 q
  107.                 {
    ' h7 h" N) o$ {( n
  108.                         RCC->DCKCFGR2 &= ~(0x3 << 18);        //清除设置,使用APB1作为时钟源
    - E# X6 Z6 D" H5 z9 l  I
  109.                         DevClock = DEV_I2C2;3 f+ m1 D  r0 Z& }* Y* u6 V& Q
  110.                         //初始化I2C IO# }6 |" q$ T$ l1 k8 M
  111. #if(IIC_CH2_IO_SELECT==IIC_CH2_PB10_11)        //使用PB10,PB11; o- }" ~# c% x3 A$ I
  112.                         SYS_DeviceClockEnable(DEV_GPIOB, TRUE);                                //使能GPIOB时钟
    & |" d/ ?" _) g; c. ~6 I' d
  113.                         SYS_GPIOx_OneInit(GPIOB, 10, AF_OD, SPEED_25M);                //PB10+ m1 A) r  w; f+ C+ z; R
  114.                         SYS_GPIOx_OneInit(GPIOB, 11, AF_OD, SPEED_25M);                //PB11
    5 X3 V2 F: }  {  N: j- Y# I
  115.                         SYS_GPIOx_SetAF(GPIOB, 10, AF4_I2C2);                                //AF4  {5 K# [; C1 y
  116.                         SYS_GPIOx_SetAF(GPIOB, 11, AF4_I2C2);                                //AF4- r+ O) d! T5 B7 X# m- R
  117. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PF0_1)        //PF0,PF1
    1 G( D0 k+ Y+ \3 j2 [
  118.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟/ t) O" B8 G/ c. X( F0 h
  119.                         SYS_GPIOx_OneInit(GPIOF, 0, AF_OD, SPEED_25M);                //PF0" w" N6 p4 ~$ j, i* F+ x  r7 O
  120.                         SYS_GPIOx_OneInit(GPIOF, 1, AF_OD, SPEED_25M);                //PF1
    8 Q! `( p" M5 J" s% v; H. Z6 }1 ]
  121.                         SYS_GPIOx_SetAF(GPIOF, 0, AF4_I2C2);                                //AF47 f1 Y) ]. Y- V
  122.                         SYS_GPIOx_SetAF(GPIOF, 1, AF4_I2C2);                                //AF4) u* b" X# @' h% S; a% L
  123. #elif(IIC_CH2_IO_SELECT==IIC_CH2_PH4_5)        //PH4,PH5
    $ [5 U! H; G, m6 U, |6 [. t" p8 \
  124.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟, j" w2 i  e6 ^7 j( k
  125.                         SYS_GPIOx_OneInit(GPIOH, 4, AF_OD, SPEED_25M);                //PH4, K, N+ n# \" t5 o6 r+ E
  126.                         SYS_GPIOx_OneInit(GPIOH, 5, AF_OD, SPEED_25M);                //PH5
    , k( n: U" m$ p& {9 \: w$ a: @
  127.                         SYS_GPIOx_SetAF(GPIOH, 4, AF4_I2C2);                                //AF45 @8 C- I# U! w( I" u2 ?% Y7 o& c
  128.                         SYS_GPIOx_SetAF(GPIOH, 5, AF4_I2C2);                                //AF4                        
    # G7 A! v6 x6 v1 {: J
  129. #else
    2 t. I+ k; l" r5 _' z7 s5 Q0 X
  130.                         #error("无效的I2C2 IO选择");0 ~8 K7 H" ?7 F. K1 e: Q8 Y
  131. #endif //IIC_CH2_IO_SELECT. Z: i' y! R) j" u
  132.                 }break;                        ) k  l, J  q+ t6 x* M; e! A. Z
  133.                 case IIC_CH3        :        //IIC3! z1 T4 r9 [: f+ A6 O
  134.                 {% u0 O3 n; t2 j9 z/ E
  135.                         RCC->DCKCFGR2 &= ~(0x3 << 20);        //清除设置,使用APB1作为时钟源' ?* j7 Y3 j9 M# F* @
  136.                         DevClock = DEV_I2C3;
    # q+ g, v9 f5 [7 V3 F
  137.                         //初始化I2C IO
    * h0 G# [) @1 v8 F; w( M, f
  138. #if(IIC_CH3_IO_SELECT==IIC_CH3_PH7_8)                //PH7,PH8
    + }2 l6 @/ b9 X7 V
  139.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟; s1 d: n9 K8 V9 L' `8 J* K
  140.                         SYS_GPIOx_OneInit(GPIOH, 7, AF_OD, SPEED_25M);                //PH7/ o  ~/ k. P1 w( f9 |5 P
  141.                         SYS_GPIOx_OneInit(GPIOH, 8, AF_OD, SPEED_25M);                //PH8
    5 ^1 Z) F6 T% G( \
  142.                         SYS_GPIOx_SetAF(GPIOH, 7, AF4_I2C3);                                //AF4% O5 ]+ ~# a# K2 @+ [
  143.                         SYS_GPIOx_SetAF(GPIOH, 8, AF4_I2C3);                                //AF4
    " E8 l4 h! |0 E) ?+ y2 X1 S
  144. #elif(IIC_CH3_IO_SELECT==IIC_CH3_PA8_PC9)        //PA8,PC9% e8 H+ M" m. `' r6 B: ?
  145.                         SYS_DeviceClockEnable(DEV_GPIOA, TRUE);                                //使能GPIOA时钟
    % Z# j( T* X" J0 ?
  146.                         SYS_DeviceClockEnable(DEV_GPIOC, TRUE);                                //使能GPIOC时钟( {9 h# N1 w4 x
  147.                         SYS_GPIOx_OneInit(GPIOA, 8, AF_OD, SPEED_25M);                //PA8, M! x  `% S0 _5 K
  148.                         SYS_GPIOx_OneInit(GPIOC, 9, AF_OD, SPEED_25M);                //PC9
    3 E$ w6 T( u; D$ K5 C
  149.                         SYS_GPIOx_SetAF(GPIOA, 8, AF4_I2C3);                                //AF41 d& `9 Q; F% g9 Q% X9 [4 U
  150.                         SYS_GPIOx_SetAF(GPIOC, 9, AF4_I2C3);                                //AF4                ) h; D2 Z1 p% ^, I7 A% R
  151. #else
    0 A1 X9 L/ Z0 e  [% M2 }
  152.                         #error("无效的I2C3 IO选择");
    2 q5 e/ c( s$ t( @; p, u+ u
  153. #endif //IIC_CH3_IO_SELECT                        7 L9 X; i' `# J" R7 }
  154.                 }break;                        
    : {4 {4 I9 h* |  t7 O% b. ?1 u
  155.                 case IIC_CH4        :        //IIC4( ^/ C+ f1 M8 a
  156.                 {
    8 p! Q. |7 O; X# u
  157.                         RCC->DCKCFGR2 &= ~(0x3 << 22);        //清除设置,使用APB1作为时钟源
    4 W7 X3 l4 P3 p0 t
  158.                         DevClock = DEV_I2C4;
    & T( F/ @3 C$ O0 S' U
  159.                         //初始化I2C IO
    # q  k+ g5 V2 [. d: Z; @: r" X
  160. #if(IIC_CH4_IO_SELECT==IIC_CH4_PD12_13)                //PD12,PD13$ i# F/ b3 T7 I/ v1 t
  161.                         SYS_DeviceClockEnable(DEV_GPIOD, TRUE);                                //使能GPIOD时钟+ K( q1 x' J- m# u& s" N! z
  162.                         SYS_GPIOx_OneInit(GPIOD, 12, AF_OD, SPEED_25M);                //PD12
    # P' J5 ^' o, T4 v3 _7 ?! o
  163.                         SYS_GPIOx_OneInit(GPIOD, 13, AF_OD, SPEED_25M);                //PD13# i& C. y. _  b% ^' n/ x% j
  164.                         SYS_GPIOx_SetAF(GPIOD, 12, AF4_I2C4);                                //AF4
    & R9 j/ n5 f: V. T- l2 c; M* g" Q) M
  165.                         SYS_GPIOx_SetAF(GPIOD, 13, AF4_I2C4);                                //AF4
    ( \4 `: Y3 o# s8 r7 d1 l( A* n4 |
  166. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PF14_15)        //PF14,PF15
    % s, u9 N& V% G& Q6 N9 K# ], }1 |( H
  167.                         SYS_DeviceClockEnable(DEV_GPIOF, TRUE);                                //使能GPIOF时钟4 {' `& Y' p) i% z
  168.                         SYS_GPIOx_OneInit(GPIOF, 14, AF_OD, SPEED_25M);                //PF14$ M! T: j! A3 U
  169.                         SYS_GPIOx_OneInit(GPIOF, 15, AF_OD, SPEED_25M);                //PF15/ @% a1 @- b/ o6 [0 U
  170.                         SYS_GPIOx_SetAF(GPIOF, 14, AF4_I2C4);                                //AF4
    9 e& m- @; Q. x
  171.                         SYS_GPIOx_SetAF(GPIOF, 15, AF4_I2C4);                                //AF4! M2 Y% ~8 U; p, z6 u2 d& X
  172. #elif(IIC_CH4_IO_SELECT==IIC_CH4_PH11_12)        //PH11,PH12' n0 C7 Q; y5 q' g* k. F
  173.                         SYS_DeviceClockEnable(DEV_GPIOH, TRUE);                                //使能GPIOH时钟
    8 Y& ~- B% Q  j: E
  174.                         SYS_GPIOx_OneInit(GPIOH, 11, AF_OD, SPEED_25M);                //PH11
    * A7 |4 l8 c0 N0 C
  175.                         SYS_GPIOx_OneInit(GPIOH, 12, AF_OD, SPEED_25M);                //PH12  e1 h0 k4 I; _1 E  Y
  176.                         SYS_GPIOx_SetAF(GPIOH, 11, AF4_I2C4);                                //AF4- P2 R1 P9 m3 V3 K
  177.                         SYS_GPIOx_SetAF(GPIOH, 12, AF4_I2C4);                                //AF4                        0 `8 G' o1 K0 W8 O$ n, Z& |
  178. #else
    8 O3 U9 U# m7 i. S
  179.                         #error("无效的I2C4 IO选择");  o. q( G7 p: Q0 M
  180. #endif //IIC_CH4_IO_SELECT                        9 y- M1 ~# ^# D) g' h: K! d4 D
  181.                 }break;8 D/ D; k8 u( G
  182.                 default:
    . R# L  t. X; Q( L8 M" E
  183.                 {$ u0 L: S0 N! ]2 I  k7 Q
  184.                         DEBUG("初始化IIC失败:无效的IIC通道%d\r\n", ch);) ?# N2 c1 o) O/ _
  185.                         return FALSE;
    7 A1 A: T- g. M3 u- A
  186.                 }
    + ~, C" [% n$ j& s
  187.         }5 O& G( B: D- d* p
  188.         pHandle = &sg_IIC_Handle[ch];                                                        //获取相关通道的句柄% C5 G% A+ Q8 u0 F; p- Q4 Q9 ~
  189.         if(pHandle == NULL)0 D6 T0 s* Z: L
  190.         {. B, g, ?) `6 L" M9 \" `- [
  191.                 DEBUG("初始化IIC失败:无效的IIC句柄\r\n");& H) d+ p4 q" t& t4 B# T: Q$ b
  192.                 return FALSE;0 |# K, c5 L7 o# F" |+ R- Z
  193.         }
    ! B! j! g& Z! y
  194.         
    * Z: a. B4 J3 j* j; l
  195.         SYS_DeviceClockEnable(DevClock, TRUE);                                        //使能时钟$ k1 f4 U4 a; U2 z
  196.         SYS_DeviceReset(DevClock);                                                                //外设复位6 a4 s3 S1 Y" k5 t* l! k
  197.         pHandle->I2Cx = (I2C_TypeDef *)I2C_TYPE_BUFF[ch];                //外设指针
    - ~5 s5 |# c. I7 e
  198.         pHandle->I2Cx->CR1 = 0;' S' ~* Q# J  T- g  s8 E
  199.         Delay_US(1);                                                
      ~4 C3 Z& h* \: T
  200.         pHandle->I2Cx->CR1 |= 2<<8;                                                                //设置噪声滤波器,关闭所有中断
    ) p9 S4 w7 ~, @, l9 L
  201.         pHandle->I2Cx->CR2 = 0;0 s0 g9 R1 M% `) S( O9 k2 g
  202.         pHandle->I2Cx->OAR1 = 0;
      V! f2 r8 G7 s/ U+ D+ ?
  203.         pHandle->I2Cx->OAR2 = 0;
    7 a" `. {# S; ^. N2 K. M
  204.         if(Speed_KHz > 1000) Speed_KHz = 1000;3 N8 ?: w7 Q. c9 h: q4 p
  205.         if(Speed_KHz < 10) Speed_KHz = 10;- q1 h* o, U7 r6 Y
  206.         pHandle->Speed_KHz = Speed_KHz;                                                        //记录速度
    ! p; _! ?* N6 }
  207.         if(TimeOutUs == 0)                                                                                //需要自动计算超时时间,时钟周期*10*10 ; i% ]( k4 y! e4 Q3 y/ h1 _5 e% m5 l" N: p
  208.         {
    ' c( s! a, t! R3 c  N0 w+ R
  209.                 TimeOutUs = 1000/Speed_KHz;                                                        //时钟周期
    " g. a3 p6 h! W; s6 }; l
  210.                 TimeOutUs *= 10;                                                                        //字节周期" d8 r: A+ U/ Q5 ^/ U- w. T
  211.                 TimeOutUs *= 10;                                                                        //超时时间为10个字节时间
    # _! y. p) m) y, j5 n  X- K
  212.         }: X1 K" h% M3 J
  213.         if(TimeOutUs < 3) TimeOutUs = 3;
    7 C  d6 u& _% J  {: t: U0 F2 B
  214.         pHandle->TimeOutUs = TimeOutUs;                                                        //记录通讯超时时间
    * R( I/ y% v0 G; d
  215.         uart_printf("IIC超时时间:%dus\r\n", pHandle->TimeOutUs);( o! w  T3 f1 ]' @& F6 i) \' [
  216.         pHandle->I2Cx->TIMINGR = IIC_CalculationTiming(pHandle->Speed_KHz);//0x40912732;                                        //时序
    9 y3 ]$ b7 D/ T
  217.         pHandle->I2Cx->CR1 |= BIT0;                                                                //使能IIC
    % L4 X; j" W- u0 |4 Z' g' @
  218.         pHandle->isMasterMode = TRUE;                                                        //主设备模式
    # Y7 g# h0 o: r
  219.         Delay_US(1);
    ! q/ c+ `6 A, F' e9 L8 v5 A1 `

  220. " w2 F3 v( x: U- x, e
  221.         return TRUE;
    0 [6 [8 G: N$ T" R4 J5 S# E2 J
  222. }
    / E9 [3 `5 X" G, a; y

  223. - @& ?% p1 ^5 E* v- A
  224. ' N- p, w8 |( c, `* u7 N
  225. /*************************************************************************************************************************6 L* T' K2 ^$ J
  226. * 函数        :                        static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)
    2 H- t* k9 P" o$ P0 ~
  227. * 功能        :                        检查是否有NACK中断状态,如果有则清除掉& \$ L+ i' M9 L: j  _
  228. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us
    ( s6 k8 d! N' i
  229. * 返回        :                        IIC_ERROR
    3 E9 T$ N, ?9 G5 H( ]9 r
  230. * 依赖        :                        底层宏定义
    " Z5 O3 u3 J/ K7 v
  231. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    % P. a# w% L" g
  232. * 时间        :                        2020-02-15& Y3 R% ]) W4 {; {
  233. * 最后修改时间 :         2020-02-15! k! M3 s" p3 w
  234. * 说明        :                         如果有NACK中断,则先产生停止位,然后清清除掉所有的中断,并复位IIC,然后返回错误7 t7 b' _1 f/ g& _3 d6 c# B3 o
  235. *************************************************************************************************************************/  # l3 y! d9 [/ q3 s2 |; q
  236. static IIC_ERROR IIC_isCheckNackFlag(IIC_HANDLE *pHandle, u32 TimeOutUs)! b% [3 x( g- K7 g5 \
  237. {! R: e/ N, S3 y  |( @. Z; t1 M9 P
  238.         IIC_ERROR Error = IIC_OK;
    0 Q, f8 j, {0 m. _$ Q1 ~6 ?
  239.         
    & k; @4 L; Y* y% Q% ^
  240.         if(IIC_GetISR(pHandle) & IIC_FLAG_NACKF)        //接收到否定应答标志# N% Z! B4 |- i5 I( |3 z
  241.         {
    3 Y. b/ h' r% S! a5 r0 j; J
  242.                 uart_printf("NACK : IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);1 N3 |! i7 g# P$ A% r
  243.                 uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    5 W# H/ n4 e! x; F
  244.                 uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));
    3 M* x: n, I6 j" Z- p4 H6 U0 K
  245.                 //主设备下,如果没有开启自动产生停止位,则手动产生停止位
      W) {( ?3 C; ^
  246.                 if(pHandle->isMasterMode && ((pHandle->I2Cx->CR2 & I2C_CR2_AUTOEND) == 0))
    ) H+ r( _, e; {+ y( Z
  247.                 {
    3 Q, n5 s6 T( ^% P* R( N4 Y
  248.                         IIC_SendStop(pHandle);                        //send stop
    3 h% ^8 ]! w5 h0 f8 [. d% ^4 V3 J
  249.                 }
      W9 a+ S. V# @/ [3 F
  250.                 //等待STOP标志有效
    # r  }. U# C* ^. a
  251.                 while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)) A) y4 o9 X! P$ A% L% C
  252.                 {3 d! S! h6 `1 L' F: u
  253.                         if(TimeOutUs == 0)                                //检查是否超时了
    7 g% g7 ?& _/ {. k" B2 z
  254.                         {3 d' f4 R2 }. |5 w( ~. l7 u$ w: t
  255.                                 break;
    $ |- k# Q9 c+ d7 Q6 c( c4 U( i+ T
  256.                         }                        
    8 u3 l$ k1 M) J( b
  257.                         TimeOutUs --;
    # U6 ?. o9 l5 G5 P! D( p
  258.                         Delay_US(1);                                                //延时- A' a0 r# ]& {; B8 Y% i
  259.                 }
    ! ~: }) z* A1 R) F" o7 |
  260.                 //清除相关的中断标志
    & H( n" h  v  i2 T, e
  261.                 IIC_ClearISR(pHandle, IIC_FLAG_NACKF | IIC_FLAG_STOPF);        //清除NACK,STOP标志
    ; o! T; u9 `1 E8 q
  262.                 pHandle->I2Cx->CR2 = 0;                                                                                //清除CR2寄存器  r" c' g+ H2 Y" ~4 E8 |$ \5 G: f
  263.                 IIC_SoftReset(pHandle);                                                                        //执行软复位
    2 d/ `$ T+ v4 b  B
  264.                 if(TimeOutUs == 0)                                                //没有超时,就是硬件通讯出错了
    6 P; E5 [! Z) o$ K4 Q+ f0 i/ P
  265.                 {
    0 T" q3 P& [1 m! V1 c  v
  266.                         DEBUG("IIC发送stop超时\r\n");% |. I$ s- z6 N
  267.                         Error = IIC_TIMEOUT;                                //超时
    4 [: e$ S+ x: p( U$ g8 }  g% a9 j1 Z
  268.                 }
    $ {! D7 ]$ L, a8 s1 y
  269.                 else
    2 [. m' p& L0 o
  270.                 {$ I; K. k$ ]$ ~
  271.                         Error = IIC_HAL_ERROR;                                //底层错误$ F+ O- b5 s) M% n' }
  272.                 }
    # t) ~( x! u% C. A( K) u+ ~$ _) D
  273.         }+ F- K3 J$ w/ }8 V. }: L
  274.           v: O* b. ]; u
  275.         return Error;
    ! c' o+ F/ r! i5 k- S- K' u9 X
  276. }) `. ?! C$ ?/ s, O' I: @2 C
  277. 2 H! R, t, u- g# I8 e. Z
  278. $ O& {# T" w2 _. A( ~& b1 b/ H* A
  279. $ D. _/ K6 m1 R5 U! ?" l/ v
  280. /*************************************************************************************************************************5 a" C0 `3 O; Y4 F
  281. * 函数        :                        static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)
    * \5 _2 {! Y! E0 z0 W3 f+ m
  282. * 功能        :                        等待TXIS中断有效(等待 I2C_TXDR 发送寄存器为空)
    4 ^4 C5 D7 a: r0 ~4 I' P9 b
  283. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us. t: V, u( T# s9 J+ g  O8 }
  284. * 返回        :                        IIC_ERROR) {/ r9 L! Z8 G/ I
  285. * 依赖        :                        底层宏定义
    ; R, e) x& q8 [0 M
  286. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    2 q( V, S3 A: `- q
  287. * 时间        :                        2020-02-15$ z/ j& z" B( P- P$ ?1 d
  288. * 最后修改时间 :         2020-02-150 l1 k! j" Y2 [( m7 b" L
  289. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的
    7 R2 D4 ^4 u! z* b
  290. *************************************************************************************************************************/  
    . F5 ]5 G% x  Q$ r
  291. static IIC_ERROR IIC_isWaitTXIS(IIC_HANDLE *pHandle, u32 TimeOutUs)  d  @0 g+ X5 U. F- [
  292. {
    ; D9 t+ e; V  J% }# a
  293.         //等待TXIS中断有效. q4 N6 a! o. ?% r) g
  294.         while((IIC_GetISR(pHandle) & IIC_FLAG_TXIS) == 0)9 d1 R0 D3 p5 n0 g) Y' q
  295.         {
    9 n& S; N. S% O$ Q- w. p( n) B
  296.                 //有NACK中断,进行处理4 R" p; Y% r' H0 {
  297.                 if(IIC_isCheckNackFlag(pHandle, TimeOutUs) != IIC_OK)        4 W4 D. J# k# j. }* C6 C) @
  298.                 {
    6 Q' ^, H0 L  X9 F% f
  299.                         DEBUG("检测到NAK错误\r\n");+ ?$ `+ z7 g( R% M% B7 q
  300.                         return IIC_NACK;# K$ @- e# o" }; ]4 O) k" T3 {
  301.                 }
    + y7 t/ L, i; y
  302.                 , d& D- l7 I% R, X- T: v
  303.                 if(TimeOutUs == 0)                                        //检查是否超时了9 ?, m$ ^* `3 l, \% i3 B, Z. B5 _
  304.                 {
    6 [, \' z( L: m# n2 n4 A0 g  _6 y
  305.                         uart_printf("IIC_isWaitTXIS:CR1=0x%X\t", pHandle->I2Cx->CR1);
    " T9 V2 G0 c* Z3 ]
  306.                         uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);
    1 W4 {$ ^! K" o1 _# U- A5 V8 L0 O
  307.                         uart_printf("ISR=0x%X\r\n", IIC_GetISR(pHandle));0 g0 f! g1 g; M8 a: ^2 l
  308.                         
    , [% C4 U$ M/ C; h! a
  309.                         IIC_SoftReset(pHandle);                //执行软复位
    ; x4 Z- D" v; s1 L- O! k
  310.                         return IIC_TIMEOUT;                                //超时% m$ h5 t! W7 f% G$ d0 g) S* ?5 k$ G
  311.                 }                        : d. a! k1 u, ^% }4 b6 c6 x; H
  312.                 TimeOutUs --;
    ; T7 `1 Q$ c8 x
  313.                 Delay_US(1);                                                //延时
    ! X. l( w8 @2 K* h6 A3 h- t
  314.         }9 ~5 U& e& ]4 ~# Z! R3 q
  315.         
    7 d2 y: s3 a1 w# u/ ^
  316.         return IIC_OK;& T7 p) Q7 R, N  H6 a5 i& R
  317. }
    % i9 V/ T6 T1 x+ ]$ c2 ]- }6 Q* f

  318. ; k6 C4 x5 N8 _0 d
  319. 7 n# Y) E8 ^1 z) u+ k4 M
  320. /*************************************************************************************************************************/ a1 E6 v* Z# Y) @/ y) i3 n3 d
  321. * 函数        :                        static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs)
    % ^# l" I! n% v
  322. * 功能        :                        等待STOP中断有效(等待 发送结束 )! |; R5 K. _% Y
  323. * 参数        :                        pHandle:句柄;TimeOutUs:超时时间,单位us) D) v& ]' h* d2 T2 t, s
  324. * 返回        :                        IIC_ERROR
    / ?/ j, \- y! x( {
  325. * 依赖        :                        底层宏定义
    " B5 c# t9 n4 ^$ [
  326. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ! G. ?/ {3 e8 j3 S5 n
  327. * 时间        :                        2020-02-15
    7 o5 u, X5 D9 y* T0 E. I) ?; D7 z
  328. * 最后修改时间 :         2020-02-15. F9 L5 C2 {' v* N0 V4 ]9 R) f$ z8 t
  329. * 说明        :                         会先检查NACK中断,如果有NACK会直接退出的
    " l, C0 p; q: y& N
  330. *************************************************************************************************************************/  
    4 J/ Q' q9 S' t. V. a) U' l
  331. static IIC_ERROR IIC_isWaitSTOPF(IIC_HANDLE *pHandle, u32 TimeOutUs), I* y8 a8 G: _7 v4 A9 O2 I5 A9 s
  332. {9 i1 T. }) F6 @: ?, X$ [
  333.         //等待STOPF中断有效# R1 X2 W( q1 g
  334.         while((IIC_GetISR(pHandle) & IIC_FLAG_STOPF) == 0)+ q) j( P+ h) I; ^/ ]8 H. X
  335.         {
    0 H2 A* @$ F. ]! D6 N9 r9 s
  336.                 //有NACK中断,进行处理; o: U9 \5 `  G2 C( p3 H
  337.                 if(IIC_isCheckNackFlag(pHandle, 5) != IIC_OK)        
    - }2 L+ V  [$ ]" q  \/ W3 @$ |
  338.                 {. ]  x2 ], N; M. T- u
  339.                         return IIC_HAL_ERROR;7 J7 l8 N, C/ x
  340.                 }! g! q, p( s! A! ?: B) Q
  341.                
      q" o. [9 A3 g+ n  T
  342.                 if(TimeOutUs == 0)                                        //检查是否超时了
    / ?& w8 H  g) r, @( R7 f7 [& [
  343.                 {3 T, s( F) q1 v' }+ c
  344.                         IIC_SoftReset(pHandle);                //执行软复位
    ( P+ j  W" r* N  b
  345.                         DEBUG("IIC等待结束超时\r\n");4 z3 T$ k' D$ O( _) B
  346.                         return IIC_TIMEOUT;                                //超时5 x% C+ e2 ?: U: M0 X
  347.                 }                        * O$ J9 M0 i, @( q7 y
  348.                 TimeOutUs --;; {. ?8 M3 p9 N& c+ P( X0 h, c$ I
  349.                 Delay_US(1);                                                //延时* G4 L/ ~5 @& R2 z7 Q$ l% w
  350.         }# g8 P- U! `* p/ B9 ?% h
  351.         ( ]) X4 f: ]/ p3 L; f/ v
  352.         return IIC_OK;( e6 c! }/ {! X( N# F
  353. }
    $ t. |3 c* I0 m1 L0 s6 K5 m7 H" L$ t

  354.   ]3 J' i# M# x' U; o
  355. 9 H+ C6 J5 E! Q7 u( U5 U" T0 X
  356. /*************************************************************************************************************************% r7 w2 T5 N$ F. l; I' I- ]
  357. * 函数        :                        static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)
    7 ^) {. T7 p+ u2 e
  358. * 功能        :                        等待中断有效
    9 T( Y; @; E- V/ X" m3 u: j
  359. * 参数        :                        pHandle:句柄;Flag:需要等待的flag,见IIC_FLAG_xxx;isWaitFlagSet:TRUE:等待标志有效,FALSE:等待标志复位;TimeOutUs:超时时间,单位Us
    0 A, y* O3 e. `0 X4 ~$ i2 l, x  R2 z( o
  360. * 返回        :                        IIC_ERROR
    . z1 c- m8 N1 W  i. a" K# q( G* Y9 z
  361. * 依赖        :                        底层宏定义
      f3 E2 s2 H( J9 @% H& o! a& j
  362. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>- g& y) `* E4 n- G: q7 D8 C# G9 `+ L" D7 w
  363. * 时间        :                        2020-02-15
    8 `* _# F; @: _! N  p
  364. * 最后修改时间 :         2020-02-154 J5 B' o3 V( V* t( |9 m
  365. * 说明        :                         - Y, E# K. L% t% ~
  366. *************************************************************************************************************************/  
    / W( ?9 j5 m  S: L$ c: |
  367. static IIC_ERROR IIC_isWaitFlag(IIC_HANDLE *pHandle,u32 Flag,bool isWaitFlagSet, u32 TimeOutUs)  e; V0 k. V9 m/ K, Q& @
  368. {
    : F) W( x' h: Q5 `( l
  369.         if(isWaitFlagSet)        //需要等待标志有效
    4 f: t9 E- F. w4 O% ^7 h& N
  370.         {
    7 I: t% C( W) I
  371.                 while((IIC_GetISR(pHandle) & Flag) == 0)
    7 v4 s# u$ ]5 m, T: m2 |2 {% G$ _
  372.                 {
    2 G& W; l3 T/ F; h6 r
  373.                         if(TimeOutUs == 0)                                        //检查是否超时了: R8 F8 r: B1 V9 n5 b2 W% d0 c' V
  374.                         {
    ' g: N, F0 n0 n# a: F" P
  375.                                 return IIC_TIMEOUT;                                //超时* J" F, f! N3 u3 a* r/ o/ v8 n  R
  376.                         }                        
    ( T! }! g3 F1 V4 z& q
  377.                         TimeOutUs --;& i6 t3 C; W% o( L
  378.                         Delay_US(1);                                                //延时1 R, N' j2 y5 c9 V  P0 T6 O5 z
  379.                 }
      O* s  i- @3 Y% d3 r; a
  380.         }% P; j& j7 g  J* ]# Z, V+ t
  381.         else                                //需要等待标志复位
    ( j' D: P- a! T2 Z+ @
  382.         {' P+ G% e2 `5 W
  383.                 while((IIC_GetISR(pHandle) & Flag) != 0)
    * x4 g; D( _3 G5 N' Q0 q* u) _
  384.                 {
    & `( s; j9 w6 r( m  Q+ [+ V3 c
  385.                         if(TimeOutUs == 0)                                        //检查是否超时了
    8 \" X) f: j: x0 O# N! J
  386.                         {! ^+ B3 c: A1 B* D
  387.                                 return IIC_TIMEOUT;                                //超时
    - G/ }" K% o" V! }8 x+ ^
  388.                         }                        ! ]0 a# U# C" x* h
  389.                         TimeOutUs --;! ?- W; @6 ^% r* b1 {) P* ^1 b6 A
  390.                         Delay_US(1);                                                //延时# q  O* X5 c" @+ y" X: I
  391.                 }
    5 B$ O9 \0 t' N* E' \3 S
  392.         }
      G8 F! }* v) _2 _5 X6 _7 D
  393. 2 t3 J2 J- I# X. b, P) M
  394.         return IIC_OK;+ Q1 N7 q. s$ p- P: A; \# T
  395. }; y2 ?* ~2 s7 L* A1 p

  396. ; J4 U; b$ J/ ]+ a

  397. * j. F( I$ C( O0 e! {. g$ ~9 B
  398. : o. C4 Y  b" G7 j( d
  399. 8 k3 ^0 m0 [1 T+ X6 }
  400. /*************************************************************************************************************************2 |; V, v+ U. U- [, @
  401. * 函数        :                        static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR): l0 y; y6 T# ~% D$ \6 W
  402. * 功能        :                        主设备传输配置(配置CR2寄存器)$ X& D. e+ @+ t0 F: [* \- A% X+ u
  403. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;TransByteCount:需要传输的数据长度;EndorReload:自动结束还是重载设置,见IIC_RELOAD_END_MODE;StartAndWR:开始读写控制,见StartAndWR
    & r. f) m) z! F3 R
  404. * 返回        :                        无
    4 _6 L7 r; R1 D8 [0 h* ^
  405. * 依赖        :                        底层宏定义
    9 }0 D  ^( u( V9 p+ f7 J
  406. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    / h% z8 d6 v& ?! C, G5 J
  407. * 时间        :                        2020-02-15* \3 V/ i& J" E' \* t- Z
  408. * 最后修改时间 :         2020-02-16
    1 P: X6 ]: X% g. Z* A9 [! s/ r
  409. * 说明        :                         在往 NBYTE 中设置最后一次传输的字节数前,必须把 RELOAD 位清零便于后续自动发送STOP。3 b$ M5 O; z) |( O/ p
  410.                                         当 RELOAD 位置 1 时,AUTOEND 位将不起作用;$ n0 {5 V1 S3 ?, l
  411. *************************************************************************************************************************/  " w" r/ D% {# W
  412. static void IIC_MasterTransConfig(IIC_HANDLE *pHandle, u16 SlaveAddr, u8 TransByteCount, IIC_RELOAD_END_MODE EndorReload, IIC_START_WR_MODE StartAndWR)5 Z6 U& ?) G5 W! P5 _  h9 ~5 i
  413. {
    3 n: k/ O! a+ x. O! O! X' h; K0 V
  414.         u32 temp = 0;3 o( v1 ]) G; L: ~6 p; x' q
  415.         
    - y  l( p: L# _: ~5 P& B: i: E; q$ @
  416.         //先读取CR2寄存器的值) q5 b3 \. `: X. |' q5 v
  417.         temp = pHandle->I2Cx->CR2;
    , u- z8 @* j' H: u* E' ?7 \
  418.         //清除掉相关的字节
    5 ~. b  e/ \9 T! u
  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));4 L/ M3 w: n% r. D, x: l! ?- T
  420.         //生成配置数据8 _' L* s# j" r, ?$ q
  421.         temp |= (u32)(((u32)SlaveAddr & I2C_CR2_SADD) | (((u32)TransByteCount << 16 ) & I2C_CR2_NBYTES));% k! _3 G7 c9 z1 X8 k( C. ~5 a8 l
  422.         //重载与自动结束只能二选一
    5 o7 }0 Y& z4 X. a! g' X6 P1 z
  423.         if(EndorReload == IIC_AUTOEND_MODE)         
    8 e: a: v/ }; n' n
  424.         {' c6 M, I% m/ {# F; Z% Q, S
  425.                 temp |= I2C_CR2_AUTOEND;        //自动结束模式
    0 n) V  H! P6 U) o3 b) e
  426.         }
    0 G- I+ o! H. _' k7 F
  427.         else if(EndorReload == IIC_RELOAD_MODE)4 k& X- n# Q4 r. j* ^/ Z2 n) [. E
  428.         {2 `( q) i) d+ E; U
  429.                 temp |= I2C_CR2_RELOAD;                //NBYTES 重载模式3 O- P1 w6 k- I# x$ s7 I5 R
  430.         }3 L+ H' x& E' n0 n4 U# v- f
  431.         0 l! q' L  \' A
  432.         switch(StartAndWR)- o: H, g. `0 g* \5 B, ~6 i  i
  433.         {4 n3 m1 j$ q8 R! @. Z5 i
  434.                 case IIC_NOSTART_WRITE        :        break;        //没有开始的写-默认就是这样的; @1 W1 R: I: W
  435.                 case IIC_NOSTART_READ        :                        //没有开始的读-用于后续数据读取% U8 C& b& ]' p4 R# _
  436.                 {/ ?4 @5 d* S% v: A5 q/ c
  437.                         temp |= I2C_CR2_RD_WRN;                        //读取
    $ j; i; f' B  w+ U
  438.                 }break;
    # R  K8 S5 }7 w; b
  439.                 case IIC_START_WRITE        :                        //生成开始写) b. f! S4 y7 R) ]9 H# }( v
  440.                 {  Q! F/ r8 O( Y4 ]6 a( R! y
  441.                         temp |= I2C_CR2_START;                        //启动传输
    1 ~# ?) y" F' W4 x- T
  442.                 }break;$ b1 s: }3 w& z( u' `
  443.                 case IIC_START_READ                :                        //生成开始读        / b" S2 k1 e" ^( E( L: e
  444.                 {
    8 W9 e8 C9 a/ z) T7 U0 @
  445.                         temp |= I2C_CR2_RD_WRN;                        //读取
    / S$ q6 V) w5 P$ N% Z4 o
  446.                         temp |= I2C_CR2_START;                        //启动传输$ I" y4 N* I+ r* f
  447.                 }break;
    3 n( v  h% N0 e; B4 \5 b8 n
  448.                 default:break;! m& t0 ?6 y  L/ Q/ c( j4 Y6 U2 h
  449.         }
    9 [  ^( [1 E0 j3 S
  450.         
    & p6 [! n6 l8 M' T" I( j
  451.         //uart_printf("准备写入CR2=0x%X\t", temp);7 u# S6 V% y4 E- F% l4 I
  452.         //更新到寄存器7 I' z: `9 e9 W+ Q
  453.         pHandle->I2Cx->CR2 = temp;  //测试, k9 l  G1 E2 n+ w8 S
  454.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    $ t/ `7 t; |0 w: X+ k5 |7 X
  455.         Delay_US(100);. O. m4 |" F8 j& g- Q" x, y: p. `2 w
  456. }
    - `- I1 w8 M6 V2 S8 H! B% g

  457. # g  h& e# e  M5 o8 v% k
  458. , c9 J$ ~+ I$ C4 x9 A2 i5 p3 D; x, Y
  459. /*************************************************************************************************************************
    . Z7 ?$ m8 j# |8 I5 X+ T
  460. * 函数        :                        static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)
    9 Z. T, A+ @' Q' a% `
  461. * 功能        :                        IIC发送一字节
    ; l  W/ a2 d- ?
  462. * 参数        :                        pHandle:句柄;data:待发送数据;TimeOutUs:超时时间,单位us
    ' M% x- s. `0 M: c6 B( q
  463. * 返回        :                        IIC_ERROR; r4 Q  G, N! k1 \* g+ a/ Y
  464. * 依赖        :                        底层宏定义
    3 D# e  Y. q0 Y5 C$ O
  465. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    . v9 D( c  j: c& `; |5 t4 G
  466. * 时间        :                        2020-02-15
    " H6 Z" v( L' m2 a. h
  467. * 最后修改时间 :         2020-02-16
    $ f! F- C1 o6 G$ I8 }) P' e
  468. * 说明        :                         TXIS有效后才会进行数据发送,不会检查数据发送是否完成。$ r7 W) V/ h3 x) O
  469.                                         如果最后一个字节发送完成后不会再触发TXIS中断,只会触发TC中断
    3 n  f4 H8 q$ U# v
  470. *************************************************************************************************************************/  
    % ]+ u: N( b5 M9 Q; A0 L
  471. static IIC_ERROR IIC_SendByte(IIC_HANDLE *pHandle, u8 data, u32 TimeOutUs)8 g3 [$ y# o) Y
  472. {
    3 s. P- a4 E$ [) A0 B
  473.         IIC_ERROR Error = IIC_isWaitTXIS(pHandle, TimeOutUs);                                //先等待可以发数据/ ?8 m& V% y' q3 X
  474.         if(Error != IIC_OK) return Error;& e+ `2 b. r, b" |: H
  475.         pHandle->I2Cx->TXDR = data;                                                                                        //写数据到发送寄存器-不会等待数据发送完成        
    ! B, @3 ?! e  Y: j" p: [

  476. ) f- m3 M- n0 l1 V
  477.         return IIC_OK;
    $ }) I) p# b/ a
  478. }; p9 u; m' R# `$ |* z4 a
  479. 7 _& c7 Z+ N9 O( i( ]' {7 M& R1 Q
  480. /*************************************************************************************************************************
    1 O$ R9 I- U1 c, O
  481. * 函数        :                        static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    4 W0 U9 _4 s# y# v4 J/ e) q
  482.                                                 bool isRead,u32 TimeOutUs)2 q2 x/ N6 X; i
  483. * 功能        :                        主设备请求发送从机地址与目标寄存器地址: F% _' N. B7 `
  484. * 参数        :                        pHandle:句柄;SlaveAddr:从机地址;RegAddr:寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,( Q# g5 {. F, N" J4 F) c! V
  485.                                                 FALSE:16bit寄存器地址;isRead:TRUE:这个操作是读取寄存器;否则是写入寄存器;TimeOutUs:超时时间,单位us
      ?) R9 F# `3 J
  486. * 返回        :                        IIC_ERROR: H" ^" ^# D1 @( w9 ?
  487. * 依赖        :                        底层宏定义
    % p- ~* y1 z6 O" i' r( C* x
  488. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>, m! e0 w# B- ?3 o, A
  489. * 时间        :                        2020-02-15
    8 |1 Z( p; }' \# D3 s
  490. * 最后修改时间 :         2020-02-16
    , b! s, V# w' ^! W
  491. * 说明        :                        
    : j6 |; R* U0 Y: \1 E4 k4 ?" C
  492. *************************************************************************************************************************/  
    + R2 @- \. t' G* m8 P) z
  493. static IIC_ERROR IIC_MasterRequestWriteAddr(IIC_HANDLE *pHandle, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,bool isRead, u32 TimeOutUs)# v0 F  v0 m' S1 Q
  494. {        
    , R3 E& `, S5 p- ~7 h
  495.         IIC_ERROR Error;
    - E: z+ l! M4 p
  496.         
    # x1 H; h5 J  W6 U4 N0 y/ _) h
  497.         //uart_printf("WriteAddr1:CR1=0x%X\t", pHandle->I2Cx->CR1);  W3 i: M: A0 A2 p( L% c0 I5 S. K
  498.         //uart_printf("CR2=0x%X\t", pHandle->I2Cx->CR2);3 F$ q, V: h% p2 l( K, a
  499.         //uart_printf("ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    ) U2 A. i9 _7 K- l& ?( `
  500.         //传输配置,并启动传输,发送起始序列,开始IIC传输了
    ; r- F" s5 f' H- N0 c& Q1 z
  501.         //如果是读取则使能软件结束,如果是写则是自动重载+ y! g0 [1 G  D; r
  502.         IIC_MasterTransConfig(pHandle, SlaveAddr, (is8bitRegAddr==FALSE)?2:1, (isRead)?IIC_SOFTEND_MODE:IIC_RELOAD_MODE, IIC_START_WRITE);        //传输相关配置-写,并启动传输
    % v& [  u$ z/ e$ l0 |0 V
  503.         
    ( j- v$ p! y6 O/ H9 f
  504.         //开始发送寄存器地址4 }, i8 i+ w4 ^/ s
  505.         if(is8bitRegAddr==FALSE)                                                                                                //寄存器地址是16位的,IIC通常是MSB高位在前,需要进行高低位对调
    . j( p$ u' M. _$ T* H8 y
  506.         {
      ?2 t* p' T2 F) F
  507.                 Error = IIC_SendByte(pHandle, RegAddr>>8, TimeOutUs);        //先发送MSB-非最后一字节
    & M+ L# m) x- d: m- D
  508.                 if(Error != IIC_OK)
    8 \" L! [/ b) a4 |4 \$ Z: K
  509.                 {
    0 R& X9 q9 }  ^" C' t; A$ F
  510.                         DEBUG("IIC发送寄存器地址MSB失败\r\n");
    # k9 S0 O! m- p$ R- r) c
  511.                         return Error;
    " R) a' A1 ~" r$ H3 T; P7 j
  512.                 }        
    ! Y$ h; ?" t7 k6 ~4 G; Z
  513.         }/ i# t7 v+ b# O/ [. E) z: T
  514.         Error = IIC_SendByte(pHandle, RegAddr & 0xFF, TimeOutUs);        //再发送LSB-最后一字节
    7 }% N- n( r3 C
  515.         if(Error != IIC_OK)
    / i& s4 T2 f) R. |2 U
  516.         {. Q, R2 m% O; g
  517.                 DEBUG("IIC发送寄存器地址LSB失败\r\n");
    ) f: a* w, P' q2 V  q+ }/ h" T
  518.                 return Error;6 `& w5 e8 y, H' D
  519.         }
    . P' Y9 o/ N# t8 B8 @+ ^
  520.         //等待全部数据发送完成
    : S' ?( ~; X5 {* q
  521.         if(isRead)        //读取方向-非重载,等待数据传输完成 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。
    & W+ p7 Y! ?) n. u4 a5 e
  522.         {" ?1 Q  ?9 f% w8 ?/ I
  523.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TC, TRUE, TimeOutUs) != IIC_OK)( |# L) O, d- u2 M$ c
  524.                 {
    5 L+ a+ y8 q6 Q7 o  r7 `
  525.                         return IIC_TIMEOUT;5 A/ ~' ?  y8 W$ r
  526.                 }
    ) Y' |, O. X' S5 F; B% w
  527.         }        * B# B( B, q: G$ }6 H& Q1 }, E. ^& W
  528.         else //写入方向,等待重载
    : D2 {0 e5 v6 Z8 K
  529.         {7 v% C  I( b  k# h0 w  S. ?9 s% _
  530.                 if(IIC_isWaitFlag(pHandle, IIC_FLAG_TCR, TRUE, TimeOutUs) != IIC_OK)# a5 v4 ~9 w: H. N6 u$ o' E; I
  531.                 {
    + d/ F+ E+ p: s/ p. S8 C5 v
  532.                         return IIC_TIMEOUT;- w: Y. c0 D, K
  533.                 }2 p7 H$ r5 Q* U* B4 Z% c
  534.         }$ {3 u$ [1 ~" e% g2 G
  535.         $ s3 c; [# \  [# A- @5 E4 O1 Q: l
  536.         return Error;# f$ _* o5 K, h( Y5 X: _
  537. }
    0 z3 i$ q$ c) l) C* u2 f

  538. " [- }( w! a1 l5 ]
  539. / M( L. i& a, C: Y/ N0 T
  540. /*************************************************************************************************************************8 b! Y$ X% K# X
  541. * 函数        :                        static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
    ) S5 ?2 L/ ^. N; @& C. f
  542. * 功能        :                        等待接收一字节数据4 s+ ~# ?- w8 C5 T) b
  543. * 参数        :                        pHandle:句柄;pData:接收的字节数据缓冲区;TimeOutUs:超时时间,单位ms
    % [, c2 D- J2 D! d. }
  544. * 返回        :                        IIC_ERROR2 T2 w+ J6 G' e  _( P, T
  545. * 依赖        :                        底层宏定义* G9 T$ Y7 |* B# {  k& o3 r
  546. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    # v( U* N" G* m
  547. * 时间        :                        2020-02-15
    * w6 w/ w( t( j' ?2 X: y; J. K
  548. * 最后修改时间 :         2020-02-15
    * d+ ^' s8 ]- v& d1 D: [9 x( [
  549. * 说明        :                         当RXNE有效后读取一条数据,否则可能会超时0 D- R4 ?2 u* R1 M
  550. *************************************************************************************************************************/  
    : o5 q6 |6 v% u1 g" Z" U
  551. static IIC_ERROR IIC_WaitRxOneByte(IIC_HANDLE *pHandle, u8 *pData, u32 TimeOutUs)
    " K$ M3 ?4 n0 ?% W5 d
  552. {( [3 \) s5 l# z. Y
  553.         while((IIC_GetISR(pHandle) & IIC_FLAG_RXNE) == 0)        //等待RXNE有效$ F1 ?' ~& b, r
  554.         {& w3 Y4 i4 c7 u9 e: x0 V
  555.                 if(TimeOutUs == 0)                                        //检查是否超时了  C0 p. m, E* F! D( h
  556.                 {
    - }$ \" B! W2 j
  557.                         DEBUG("IIC等待接收超时\r\n");/ l* {6 ?' o, s4 _0 Y
  558.                         return IIC_TIMEOUT;                                //超时1 [0 j4 S% Y2 g+ w" K9 B
  559.                 }                        
    + K: R/ ~( J7 n+ J+ C
  560.                 TimeOutUs --;# ]1 w+ T* S4 T/ [
  561.                 Delay_US(1);                                                //延时
    + P$ b# H" P" ]$ Q) z
  562.         }& b+ q* E7 q- v2 b* F. ~2 x1 _
  563.                 4 x8 a* _/ t1 x4 v- c6 m
  564.         *pData = pHandle->I2Cx->RXDR;                                                        //读取收到的数据* P7 ~( i, Z( W* Z/ o. R
  565.         return IIC_OK;) S. }/ v- W2 y) O* k+ z$ i
  566. }
    : [+ l) u2 I1 C% e( z# o

  567. / m6 W2 `8 U+ X. B

  568. 9 _0 p6 x% R4 l3 Q
  569. /*************************************************************************************************************************0 o- F+ p" o* s& |2 d# x* J3 l' C
  570. * 函数        :                        IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, 5 O  g% y% l2 Y! w
  571.                                                 u8 *pDataBuff, u16 ReadByteNum)  z  l" Q7 G. B7 S# N7 w
  572. * 功能        :                        IIC读取寄存器(可以读取1个或者多个寄存器)$ h, P# m/ `7 c
  573. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要读取的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;, [* c! O+ {9 \( J0 j% a9 `
  574.                                                 pDataBuff:接收的字节数据缓冲区;ReadByteNum:要读取的寄存器数量;
    5 ~  r# K/ t: X  P, v0 A
  575. * 返回        :                        IIC_ERROR0 x0 E" K0 H6 W' J8 V# m3 T
  576. * 依赖        :                        底层宏定义
      p. A2 M  p5 v) Z, j
  577. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    3 ?$ s$ E$ k+ c0 {" \
  578. * 时间        :                        2020-02-15* C$ U3 \$ Z6 S/ Q; E9 f, ?
  579. * 最后修改时间 :         2020-02-15
    ) b2 X$ Z; e* j( o3 b' ]
  580. * 说明        :                         读取的数据都是小端模式,如果是16bit的寄存器,请读取偶数个数据,并且需要另外进行高低字节对调最后组成16bit数据' t4 V. `$ I. X) n
  581.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如2 j! a5 a$ h3 J. \5 l' l2 x
  582.                                                 增加信号量/ @1 [9 B: x% |
  583.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在3 u& \4 Y  }: V" m& N
  584.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。
    3 {' D3 q$ h" ^& \' p4 z& }# C
  585. *************************************************************************************************************************/
    6 q4 T" q; s; H% X
  586. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum)% n& {$ r# e, @
  587. {
    / s( D+ z/ G8 Z% ^
  588.         IIC_ERROR Error = IIC_OK;
    2 }3 m4 a  c9 v; t* {$ w
  589.         u16 ReadCount;( O, F4 W7 q; B6 p, k
  590.         IIC_HANDLE *pHandle;& P7 b* p) l2 e& {/ p6 \5 H6 F
  591.         4 [6 h6 L; l( D4 q: [& j2 O- q( a
  592.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || ReadByteNum == 0)' P' k! ?! i- P$ r( o. L" m
  593.         {
    ) N- F5 W) o  p, y" X
  594.                 DEBUG("IIC错误:无效的参数\r\n");
    . k4 h  w: {4 s6 T' E
  595.                 return IIC_PARAMETER_ERROR;& g- q  X3 g% U6 O
  596.         }7 b; u6 e7 z( W" o+ Q/ y
  597.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄
    0 q+ U- {. H6 z5 m# G" H) |- S
  598.         0 w2 C4 A: k6 j) J7 j
  599.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙
    * U  ~" w: Y$ v- ?
  600.         {
    0 a% O% a0 V: W( {+ m0 d
  601.                 IIC_SoftReset(pHandle);$ |6 N1 l& w: D2 x3 z9 e
  602.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");
    2 d1 V/ k7 N5 ~6 P# c* y
  603.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙! \7 U1 a3 Q% f% i+ b/ ?
  604.                 {/ z0 W: d" ]$ t: u
  605.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");
    . d. X* J' R( V( S. ~) k8 W4 g
  606.                         Error = IIC_BUSY;; Z5 B' P3 S1 n
  607.                         goto end_loop;4 ]" z, B, ?$ _0 R
  608.                 }
    , }6 \+ `# T" p4 K
  609.         }0 X" t6 T5 |! e7 F5 K( P) Z5 C
  610.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    " K! }: C' y/ `* Q4 G0 h- i! `
  611.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器+ J7 n9 T" s/ v8 C; _  I# U: h1 E
  612.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START
    9 o7 p: N$ X2 A% z3 d/ ]. C/ Q2 R
  613.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,TRUE, pHandle->TimeOutUs);
    ( w& L4 \: N, v  s$ [" k% ~1 x; `
  614.         if(Error != IIC_OK)) J5 G- c8 W; |& U* U; G! T+ o& n1 |
  615.         {# ]# }8 b% m& G+ ]0 w- s+ v9 ]
  616.                 goto end_loop;
    . M0 c$ D6 @+ Y% d; i. `% ~
  617.         }
    ; S+ P) f- T. x$ H, l
  618.         //发送后续数据2 a7 I5 }7 L! r- q5 x% h
  619.         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取-后续还有数据,需要重载
    , w! y: w. s1 i
  620.         {1 }: e4 ^) s8 e; P/ u9 r% @8 t6 |; O
  621.                 ReadCount = 255;        //本次需要读取的数据长度2557 v  E+ M- Z4 \" j& O. Y3 u! |
  622.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输               
    % ?4 ]' B. `/ I+ A- Y$ [
  623.         }, |* g1 h, j0 R3 ?6 i) U
  624.         else2 v! J/ T1 P1 ~# \# N1 R$ N4 L" ~8 o
  625.         {
    : h* y# ~2 C6 l3 y* [
  626.                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯后自动结束4 _* J0 K! [7 `. D/ K. s
  627.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_START_READ);        //传输相关配置-读取,并启动传输
    $ f. c  |+ j; k, y) C+ T4 i7 f
  628.         }* z5 U" D( Z: x9 c+ r
  629.         
    # t/ f" @" r- @
  630.         //循环等待接收数据完成( y2 ]0 z! I& H( s+ y; ?
  631.         do
    6 U  b% }- c. B# I- Y) k0 ^9 U
  632.         {
    $ X: K1 |. g6 x7 f1 J" V  I
  633.                 //uart_printf("读ISR=0x%X\r\n", pHandle->I2Cx->ISR);
    & X% c* w) P$ n) f+ ?- h; d
  634.                 Error = IIC_WaitRxOneByte(pHandle, pDataBuff,  pHandle->TimeOutUs);                                        //接收1字节数据
    , ^: g, p! C3 Y6 _
  635.                 if(Error != IIC_OK)
    6 }- P: _; Z- W; r- s
  636.                 {
    2 J# Z! T, h: z+ B: ?6 ^6 H
  637.                         goto end_loop;  y' H8 E" d# |  M$ v" k
  638.                 }
    - f% c5 I. R9 W& t
  639.         
    7 m% v# J7 a! U8 c' l% z
  640.                 pDataBuff ++;$ F6 F2 A* P5 L# M# E2 w
  641.                 ReadCount --;" ]& ^+ M3 e; E$ O. t/ j1 d
  642.                 ReadByteNum --;/ E; f7 `2 v& f* C
  643.                 if((ReadByteNum > 0) && (ReadCount == 0))        //还有数据要读取1 K# y5 c& f4 l. O
  644.                 {
    / B/ g) t4 d9 T! d* K2 ]- b
  645.                         if(ReadByteNum > 255)        //如果超过255字节,则需要分多次读取
    * d8 [; K2 ?4 X$ c6 q9 |/ U
  646.                         {& ^# I% Z& e3 f0 I; m6 t9 g: A
  647.                                 ReadCount = 255;        //本次需要读取的数据长度255-后续还有数据,需要重载
    6 V6 M, C- A2 n: i0 @' _5 |1 N
  648.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        
    , k" N; O3 p$ z% g, E
  649.                         }  y& |: {1 W0 x; ?: x+ H
  650.                         else  s: `& q, L9 V% h' W4 R3 a2 Y
  651.                         {
    5 }4 v8 d8 N' j5 }! }0 S1 G
  652.                                 ReadCount = ReadByteNum;        //记录本次需要读取的数据长度-最后一次通讯,自动结束
    5 K7 J, G2 K0 [, c0 D. X% A4 J
  653.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_READ);        //传输相关配置-读取,不启动传输                        : B& E( x% e* s2 W! ^
  654.                         }+ @* U' y# E  t  E
  655.                 }( n) {4 [4 Q# \* h5 H. s
  656.         }while(ReadByteNum);# ~8 e0 t! \& Q1 u5 ]+ G, v4 U+ ~' O7 ~
  657.         //读取完成了,等待STOP位有效
    + A1 p4 A4 ^3 R& H5 C" n
  658.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);
    ( Z# A, |/ K! q6 u& \1 ^
  659.         if(Error != IIC_OK)
    : Y+ ^/ u& H# @; \5 L) K9 N
  660.         {* X+ `8 e- C. j- r* j7 A' y
  661.                 Error = IIC_STOP_ERROR;
    8 X: l+ y" [! C  [
  662.                 goto end_loop;/ M0 U5 e; w* ?1 t
  663.         }        
    - i, p6 e. m7 K; I5 M+ O
  664.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    + M; }' i* m9 c' ?- |2 e$ ]
  665.         2 L6 P+ b- ?2 S0 l
  666. end_loop:        
    . _6 i# C" M, ]8 ?) @1 I; `% n* I
  667.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        
    - S1 K' n6 l7 P
  668.         if(Error != IIC_OK)
    ' q7 V* J( D' G7 U3 @
  669.         {
    ! I, ~6 t" [- g! Y8 |
  670.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误- S' h1 }3 x- t( X' r, F' w
  671.                 DEBUG("[IIC R错误]:%d\r\n", Error);6 ^- v" z3 P! {$ |1 Y2 N; X1 _! S
  672.         }) N1 w8 g, _! D2 G* F
  673.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的
    8 J3 H% D' h, c2 r; x
  674.         {6 I9 r& J% v+ S9 q
  675.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    0 l0 X) E7 d# v3 }' V9 h
  676.                 DEBUG("IIC R结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);               
    " t8 D% ~# B* c1 b4 }/ k
  677.         }" l+ w$ m5 w( ~/ l$ Q2 m
  678.           A8 A0 E/ z. X3 M( `7 q# m5 ]- A
  679.         return Error;
    8 T. w5 U8 V1 p" U
  680. }& t9 V  y) B( S

  681. / R, H# u1 ~# y7 `1 k. M# ]+ l2 P+ W

  682. ' k# R! ^5 J/ |8 d" V
  683. /*************************************************************************************************************************7 d7 k' L3 S$ i5 [
  684. * 函数        :                        IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr,
    $ Y$ u! c- U8 M/ ]4 g) C
  685.                                                 u8 *pDataBuff, u16 WriteByteNum)- o2 h9 R* h8 [5 ]$ P( ^
  686. * 功能        :                        IIC写寄存器(可以写1个或者多个寄存器)5 l8 B+ L4 [0 x
  687. * 参数        :                        ch:IIC通道,见IIC_CH_Type;SlaveAddr:从机地址;RegAddr:要写入的寄存器地址;is8bitRegAddr:TRUE:8BIT寄存器地址,FALSE:16bit寄存器地址;5 t) W3 o7 A" s% [
  688.                                                 pDataBuff:写入的字节数据缓冲区;WriteByteNum:要写入的寄存器数量;* R/ j* r, K: p2 g* R# [$ D
  689. * 返回        :                        IIC_ERROR
    / D8 s/ i3 Q- S+ R2 a* L8 R- G, ~
  690. * 依赖        :                        底层宏定义0 r" Z6 x2 Q$ e% _7 @1 Z- O7 Y
  691. * 作者        :                        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ' z+ P& `. y+ E2 F, X
  692. * 时间        :                        2020-02-167 V. x) P0 U7 V2 V8 r$ Q
  693. * 最后修改时间 :         2020-02-16
    $ _6 X0 k* l3 Q. W7 `9 ~
  694. * 说明        :                         写入的数据都是小端模式,如果是16bit的寄存器,请写入偶数个数据,并且需要提前进行高低字节对调最后组成高字节在前的数据buff4 q, ~$ O3 S% F# {( V
  695.                                         可能的意外:比如一个异常的操作可能会导致IIC一直忙,此处检测到忙后会直接复位IIC,但是必须在应用层做好重入保护,比如1 r( l* }1 K0 A% g1 h, y6 S% x
  696.                                                 增加信号量
    9 \3 i8 U. g& h4 ?- O& A3 |9 S1 V7 Q
  697.                                         通过测试发现:在函数进入的时候,清除掉中断状态,之后几乎检测不到IIC忙的情况,当然在结束的时候如果检测到忙会主动发送一个STOP,在4 ]& b3 K" Y+ b) r- V
  698.                                                 操作失败的情况下,会对IIC进行软复位,确保本次的错误不会影响下一次的IIC操作。
    ' p! A  I  U6 Q7 d& B% Q
  699. *************************************************************************************************************************/
    / s" X0 Q+ X. S/ Z  v
  700. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum)8 Z) n% C4 R9 @
  701. {& N) `/ z; E! X2 V3 `% w: x
  702.         IIC_ERROR Error = IIC_OK;2 l  S' i0 I4 _+ V4 T
  703.         u16 ReadCount;1 j- z; o. \# F  r* d( i0 h
  704.         IIC_HANDLE *pHandle;" p. c( s: B( O
  705.         + n. F/ |) x  q, Z+ A; z
  706.         if(ch > (IIC_CH_COUNT-1) || pDataBuff == NULL || WriteByteNum == 0)
    & B, p/ V% C( c! {# R9 u- r3 y- j! u
  707.         {" j3 ?! }! [6 I+ G- u* k- |/ }
  708.                 DEBUG("IIC错误:无效的参数\r\n");
    7 |4 m5 i9 f7 E8 R  y: D2 i3 _
  709.                 return IIC_PARAMETER_ERROR;
    + k' {# r' a/ D8 \( u, \
  710.         }+ x& l1 a( o+ X
  711.         pHandle = &sg_IIC_Handle[ch];                                        //获取相关通道的句柄
    ' ~$ {  |- [  ]+ L, s5 V
  712.         % y# p( Z6 y" E
  713.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                //忙/ M6 m3 }$ u, d0 h
  714.         {
    8 K6 a* R3 ~, i
  715.                 DEBUG("IIC错误:总线忙,复位总线,可能直接打断别的地方IIC操作,做好保护措施\r\n");: o: n, D: u$ y% ~& p
  716.                 IIC_SoftReset(pHandle);
    3 C. g6 p# c2 S( j1 l) u
  717.                
    . A: b& d: d: g! P% f
  718.                 if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)        //忙
    6 U% c/ V5 R' t4 @* c! @. P& d1 c% B
  719.                 {9 s8 \3 X' ]' k  `% a
  720.                         DEBUG("IIC错误:总线忙,复位后未恢复\r\n");
    ' }6 J" y- H4 K6 a' n+ z
  721.                         Error = IIC_BUSY;
    8 h6 }. n# S/ c8 H+ P; s6 g
  722.                         goto end_loop;# L$ @$ V! z* ~' @# N
  723.                 }$ G# R" |; v1 S. ]3 ?' G
  724.         }. f+ c2 H3 ^7 l# p0 r/ Z
  725.         
    ( ], x, U4 k/ c2 u! o7 {! _
  726.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态
    4 v$ `  j  L3 z0 v% ?; u
  727.         IIC_ClearCR2(pHandle);                                                //复位CR2寄存器) b9 ?  V& {/ |3 [2 P. G: O( q* j4 ~
  728.         //主设备请求发送从机地址以及寄存器地址-会切换到写方向,并发送START, }- ?$ o0 I+ i0 c" P
  729.         Error = IIC_MasterRequestWriteAddr(pHandle, SlaveAddr, RegAddr, is8bitRegAddr,FALSE,  pHandle->TimeOutUs);
    * E( P& I$ c6 k4 k. t
  730.         if(Error != IIC_OK)/ \* K1 s6 F. ]/ _) F
  731.         {
    " j0 X3 g! Y1 F7 W5 W& g
  732.                 goto end_loop;
    + n0 r. `6 ^2 h( |
  733.         }
    ( R- f* [' s$ I2 _! |7 @" C7 R, |
  734.         //发送后续数据
    ' e6 ]$ ]- {. M# N  q" Q; Q, ^
  735.         if(WriteByteNum > 255)                        //如果超过255字节,则需要分多次写入-后续还有数据,需要重载
    % W  d  |2 Q3 e! F, J& T6 k3 [
  736.         {
    . `" Z2 D  _4 B) \1 L( j
  737.                 ReadCount = 255;                        //本次需要写入的数据长度255
    5 l- b- \9 m* h
  738.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入                8 q6 ~% F# m+ ?% }* M5 O
  739.         }  J- \8 }0 f8 n# i; c+ M
  740.         else* a& P2 `3 Q9 B! h
  741.         {5 U( e% M3 A+ ?, {' Y% b0 o  [
  742.                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯后自动结束3 P* V% t) L, n& ]
  743.                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入
    - t! s2 r2 x0 \+ S( D# F+ s$ W
  744.         }: n7 g3 U! r# ^( E* t( A; F
  745. 7 B) ~) O# ~& z# D, G
  746.         //循环发送数据
    2 ~! z8 l$ n$ p3 Q+ W" a3 Z' k
  747.         do
    6 v4 g8 o' j; H  x9 @
  748.         {  J) T& d8 f- H8 l& i4 @$ X
  749.                 Error = IIC_SendByte(pHandle, *pDataBuff, pHandle->TimeOutUs);        //发送一字节 ( E9 `3 _6 q4 `, D
  750.                 if(Error != IIC_OK)
    + U3 |5 B8 w# V- _
  751.                 {: Z( }5 o, {' i+ a9 |1 p& }
  752.                         goto end_loop;
    $ b6 A$ @8 ^, j6 [: U- j
  753.                 }* }8 a3 M, l/ X/ t* _# D

  754. 2 E( G4 L) S7 C) J
  755.                 ReadCount --;
    6 g8 i5 w% b$ {0 }% d
  756.                 WriteByteNum --;( ?7 d7 c1 _- ~) Z) _
  757.                 pDataBuff ++;
    2 J' G: e& D3 Z* {  f: ^
  758.                 7 @: b) C- W. n# T
  759.                 if((WriteByteNum > 0) && (ReadCount == 0))        //还有数据要读取5 R' H0 H2 Z* U) e- K, J
  760.                 {/ [; N( c# `; n, a, o5 K9 r
  761.                         if(WriteByteNum > 255)        //如果超过255字节,则需要分多次读取% w  Q8 [+ z# B' \; B( b# ?/ f
  762.                         {
    * ^% z: v& v2 C- S7 Q4 b8 `/ s' y
  763.                                 ReadCount = 255;        //本次需要写入的数据长度255-后续还有数据,需要重载
    5 Z4 l6 w: e4 Y( x9 J# B& y0 f
  764.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_RELOAD_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入
    8 b3 ?( ?# `' P" s1 ^
  765.                         }% T7 G6 B2 Q. ?6 N$ F8 C
  766.                         else2 t# S! z6 _0 D4 |! u* c  [- @
  767.                         {
    " X5 N6 Q+ n' B& n6 O5 ]
  768.                                 ReadCount = WriteByteNum;        //记录本次需要写入的数据长度-最后一次通讯,自动结束
    4 E. I, \0 p1 L$ @
  769.                                 IIC_MasterTransConfig(pHandle, SlaveAddr, ReadCount, IIC_AUTOEND_MODE, IIC_NOSTART_WRITE);        //传输相关配置-不启动传输的写入                5 x0 R, R0 g2 n$ R3 ^
  770.                         }  c# |: f% R" Y+ O1 L8 J
  771.                 }) b2 M! x) g3 w2 A) ~
  772.         }while(WriteByteNum);        
    / C5 I4 z" w' X9 d$ _7 i4 A; G" ?, n

  773. 9 \% f4 d2 u. X! E
  774.         //写入完成了,等待STOP位有效
    2 i: w! s+ X$ c% r, e
  775.         Error = IIC_isWaitSTOPF(pHandle, pHandle->TimeOutUs);
    & H9 j( K0 s! V9 g. i! |; o
  776.         if(Error != IIC_OK)
    7 k: T4 O* I* t: T$ q3 p
  777.         {
    ! J2 ?/ t( J5 F! E+ ?: Z
  778.                 Error = IIC_STOP_ERROR;
    7 ]7 q9 X; v2 B
  779.                 goto end_loop;
    / n6 s, |2 w1 a1 H' \: L1 a1 |
  780.         }) X3 L0 X+ U5 h3 z/ A- B) Q
  781.         IIC_ClearISR(pHandle, IIC_GetISR(pHandle));                //复位错误状态+ o) L! H2 R1 d5 ~' N
  782.           K0 |& \( ]: z1 h( B5 U& @8 d
  783. end_loop:        & B/ J9 _. \0 O3 R
  784.         IIC_ClearCR2(pHandle);                                                        //复位CR2寄存器        
    . m" V' B/ O1 X# v/ C& x
  785.         if(Error != IIC_OK)
    5 k& l% H4 U% B' A0 d; g
  786.         {
    ( v& t$ a( M6 ^. \
  787.                 IIC_SoftReset(pHandle);                                                //IIC软复位,清除掉错误
    : C6 V  s/ _% }% K7 `# Y+ l; _; T* s
  788.                 DEBUG("[IIC W错误]:%d\r\n", Error);: ^' o% X9 |& Y: W
  789.         }
    2 y0 r. C9 M: u
  790.         
    ) ~4 w/ ?" N+ M# i
  791.         if(IIC_GetISR(pHandle) & IIC_FLAG_BUSY)                        //忙,注:奇怪的是高速读取的时候,此处可能会检测到忙,TC标志有效,正常此处不应该有TC标志的
    , F* w: Z' V2 b7 C
  792.         {( |" K1 S/ P9 u  x! M' l
  793.                 IIC_SendStop(pHandle);                                                //总线忙,发送一个STOP,释放掉总线
    ; Z+ O+ L. D/ t. C  b% \5 z
  794.                 DEBUG("IIC W结束:总线忙 ISR=0x%X\r\n", pHandle->I2Cx->ISR);               
    . u- h% D/ M6 Q. {  M' U/ Q0 q/ L
  795.         }7 D6 x9 R% D, M" }+ v+ e
  796.         return Error;7 ?; _6 n$ ?4 m0 w
  797. }+ c! k% a3 O& S1 R, ]4 J' I8 r

  798. 8 B4 {1 f) ~) y

  799. & i+ o% W5 B8 X! G
  800. /*************************************************************************************************************************
    7 ^5 T; Y* T# c0 j: @. B2 x6 F1 Y# N
  801. * 函数                        :        void IIC_SoftReset(IIC_HANDLE *pHandle)' u5 x1 r& k( Z6 Q# m3 G/ m# X
  802. * 功能                        :        硬件IIC软复位(会使能IIC)8 L% c& X$ a( W. p- h
  803. * 参数                        :        ch:IIC通道. l) X& V/ d  v  x3 D
  804. * 返回                        :        IIC_ERROR
    2 a' C3 E6 t! G
  805. * 依赖                        :        底层宏定义
    " [2 w" b0 F( [6 u9 L
  806. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    + z& v8 I% ^+ s! |  m, L; y: r) @' Q) p
  807. * 时间                        :        2020-02-15
    # {2 a* g0 s/ ^; N2 }( C$ s
  808. * 最后修改时间         :         2020-02-15* k# z/ w* r. e3 j% n! O
  809. * 说明                        :         IIC软复位;必须使 PE 保持低电平持续至少 3 个 APB 时钟周期,才能成功执行软件复位。- ^, e- a4 S) L6 D# ?; j7 ^0 m
  810. *************************************************************************************************************************/
    / h6 z) m- @# |% Q& t* \
  811. static void IIC_SoftReset(IIC_HANDLE *pHandle)9 |8 l5 h/ Y6 H( W
  812. {! F1 Z8 [) h. C
  813.         pHandle->I2Cx->CR1 &= ~BIT0;                //关闭IIC后执行软复位
    / i  j4 _% x7 G# n2 h1 D' d
  814.         Delay_US(1);        . C  e& }! r( Q* N
  815.         if(pHandle->I2Cx->CR1 & BIT0)& o  J! S5 _" R9 o  O7 \+ C  D
  816.         {% u7 g. A2 U' u+ T8 O$ g# _
  817.                 DEBUG("IIC软复位失败\r\n");) ~- M1 z& I" ]6 [9 K
  818.         }
    6 v! V  p/ X* T* M0 l; {" Y# u
  819.         pHandle->I2Cx->CR1 |= BIT0;                        //重新启动3 W% W0 ^5 e/ Y0 r, o! T  g; ]+ D
  820.         Delay_US(1);        # _: n; b3 W# e! J% J
  821. }# g) Q- H) K# a$ _/ h9 m) O9 @
  822. ) `5 A- P7 G3 d# @' {0 q; Q

  823. & D5 E$ A4 x+ `3 m
  824. + \, e3 D* D2 Q8 M
  825. /*************************************************************************************************************************
    : b: b. X% k( f& ]
  826. * 函数                        :        static u32 IIC_CalculationTiming(u16 Speed_KHz)4 W7 F2 J7 K5 P
  827. * 功能                        :        硬件IIC时序计算$ E0 m/ z( d3 P) z% D# C/ R
  828. * 参数                        :        ch:IIC通道;Speed_KHz:速度10-1000
    * j* ?% q2 p- }4 R# @3 Y
  829. * 返回                        :        IIC_ERROR
    ) e5 Y" {* Q" ~
  830. * 依赖                        :        底层宏定义
    1 D8 n, Y9 D1 ~) L& |! ~
  831. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>( `$ e" p' h; ]) N+ Q
  832. * 时间                        :        2020-02-15
    6 `6 y1 F6 n. S9 J7 k
  833. * 最后修改时间         :         2020-02-15* c$ I+ u3 i9 W" i' \* d7 X$ O# A
  834. * 说明                        :         IIC使用的是APB1时钟,将IIC总线时钟控制在100KHz        & X' i2 c& @1 ]" \3 c5 `
  835.                                         APB1时钟:最大不能超过45MHz        4 h1 n! s3 C5 L+ n2 C# r# ^. X
  836.                                         如果速度是100,则按照SMBUS时序2 F+ E3 I( j9 a  Q' b/ @. i
  837. *************************************************************************************************************************/
    5 r0 |; w, A8 f- n9 ~
  838. static u32 IIC_CalculationTiming(u16 Speed_KHz)
    * V6 X! i. X" Q5 X* I5 F  J2 y
  839. {% X4 y: F  U  ?, I% {1 ^# g
  840.         u32 tTime = 0;9 x2 ?; S) D2 v# a
  841.         u32 temp;
    + C# b/ ]5 a# ]. a4 b
  842.         u32 time_temp = SYS_GetAPB1ClockSpeed() / 1000000;                //先获取APB1时钟速度# `9 t- w, c# B7 R6 d; V% Z7 T
  843.         u32 Th = 1000/Speed_KHz/2;                                                                //计算高电平时间(低电平时间一样),单位ns- m0 D; Z, N+ v2 n5 j' d- L/ [/ z2 d
  844.         
    5 G# A' s' y/ G, ?' Y
  845.         if(time_temp < 20) time_temp = 20;/ F, d1 `6 {$ W! H- }. t
  846.         time_temp = 1*1000 / time_temp;                                                        //单位ns
    ( [& R# G5 _, U0 M. c. H
  847.         uart_printf("IIC时钟计算->APB1周期:%dns\t", time_temp);- V" N8 W+ i0 B3 ?! |. {( p6 _
  848.         if(Speed_KHz == 100)        //如果是100,则按照SMBUS时序! O- J( t( V! w0 o
  849.         {* p4 v' ^0 ^% M* i: |4 S
  850.                 //主时钟分频系数固定为3
    $ z" ~- r3 b) v( K9 ]8 W8 A$ O; U
  851.                 time_temp *= 3;                        //主时钟周期$ f' n. k. P& G- j' J
  852.                 uart_printf("IIC时钟周期:%dns\t", time_temp);: s7 p" w+ s1 {
  853.                 tTime |= (3-1) << 28;        //PRESC,时钟预分配
    : a0 y6 T, U! i2 q- n- q- l
  854.                 //计算数据建立时间,要求最小250ns, i  F' a  E9 W5 ~+ x( z3 [
  855.                 temp = 250 / time_temp;
    " F& \$ I  n" \# {: H. b
  856.                 if(temp > 15) temp = 15;
    4 U0 P( q! P7 j9 I1 h; ]( y6 F
  857.                 if(temp < 1) temp = 1;
    3 S+ W: M" v+ @4 P2 l# N
  858.                 tTime |= temp << 20;7 S" z( v2 @) B9 S5 n& Z( \
  859.                 //计算数据保持时间,要求至少300ns0 t0 R$ r, c8 S8 P" J! a4 l) X
  860.                 temp = 300 / time_temp;
    9 P/ w/ F/ C8 i4 b
  861.                 if(temp > 15) temp = 15;
    ! o% W7 ?3 X2 B' E" c5 @, V* \
  862.                 if(temp < 1) temp = 1;
    & H  B4 I/ n" l, U& h& @# m' n4 ]
  863.                 tTime |= temp << 16;2 C- {9 B' h  k# i, p; O/ \
  864.                 //计算高电平周期5us  I& o3 Z2 i* U: @
  865.                 temp = 5*1000 / time_temp;# [/ ^8 w8 p$ r$ t: x
  866.                 if(temp > 255) temp = 255;5 ]( {# C( {+ r
  867.                 if(temp < 1) temp = 1;% r( [. d) b. Z( u4 A
  868.                 tTime |= temp << 8;
    1 [# e0 X$ [4 i  z4 a# r2 U
  869.                 //计算低电平周期5us
    + l5 U+ A- _' m' ]' v
  870.                 temp = 5*1000 / time_temp;
    " |; J* \# h, z  I% G
  871.                 if(temp > 255) temp = 255;/ ]' L% U- l% c1 S; S; `# e
  872.                 if(temp < 1) temp = 1;. ^0 u9 ]- |0 u
  873.                 tTime |= temp << 0;/ K, y2 @# I9 B9 t% v' U* l
  874.         }
    ! ]( k* S3 _8 u
  875.         else if(Speed_KHz < 100)# s3 e; L! Y4 W5 V1 d, `; k( p0 V
  876.         {
    3 l/ t8 \, b3 p7 L
  877.                 //主时钟分频系数固定为6
    * F2 i3 J$ o) W! w5 ^$ ]# `1 V8 n" w
  878.                 time_temp *= 6;                        //主时钟周期  @3 P0 c$ c, H; a, V1 Y
  879.                 uart_printf("IIC时钟周期:%dns\t", time_temp);5 R4 W: t! K% w! O, Z% h! t4 W
  880.                 tTime |= (6-1) << 28;        //PRESC,时钟预分配* l+ W2 k! X9 c; H8 z% ^1 P
  881.                 //计算数据建立时间,要求最小250ns/ d% D9 @8 [1 Y  N" u
  882.                 temp = 250 / time_temp;5 b# f5 z" w/ P9 e  _; {7 a( r) l
  883.                 if(temp > 15) temp = 15;8 b0 L# i( J" h2 v" J' I
  884.                 tTime |= temp << 20;" l# V4 h9 l; h+ _& q
  885.                 //计算数据保持时间,要求至少300ns
    ) o: ~3 s9 N) ~4 M1 n5 e: V; P
  886.                 temp = 300 / time_temp;
    - H* o, B' N1 R* |5 e, q
  887.                 if(temp > 15) temp = 15;# {2 [% A$ }: F6 o, x4 ^3 v# q8 t$ Z
  888.                 tTime |= temp << 16;
    $ X4 {  r$ A& R) _% u3 y
  889.                 //计算高电平周期Th us4 \2 w0 O5 a1 F$ X' [# g
  890.                 temp = Th*1000 / time_temp;
    3 h/ D: w! I$ N, }# q4 O
  891.                 if(temp > 255) temp = 255;
    ' N- v& U" A8 h) W
  892.                 if(temp < 1) temp = 1;
    0 u1 I$ |* z3 A1 G( t
  893.                 tTime |= temp << 8;" Q# h0 N+ L( D9 Z- ~
  894.                 //计算低电平周期 Th us8 ~6 d% n; f: K& x
  895.                 temp = Th*1000 / time_temp;
    ' X$ Y+ r  _8 A+ T* P
  896.                 if(temp > 255) temp = 255;
    . c7 Y. y; J4 L5 V3 X
  897.                 if(temp < 1) temp = 1;6 _- D: a& p" Y/ v: u; m
  898.                 tTime |= temp << 0;
    0 L" ~7 N* i" G- _8 x
  899.         }- |/ O/ B4 |% b6 b* M3 U$ J3 v
  900.         else //>100' l' S. N$ ^3 {
  901.         {$ f+ r  y) d9 x/ r* |- I0 c. g! z2 U
  902.                 //主时钟分频系数固定为2
    4 z6 Y" z! U! [& ]
  903.                 time_temp *= 2;                        //主时钟周期
    " M+ ?! Z- s: s8 M: k" }+ v4 B: e) J
  904.                 uart_printf("IIC时钟周期:%dns\t", time_temp);8 u5 J* l# E/ T2 Q& q2 Y- z
  905.                 tTime |= (2-1) << 28;        //PRESC,时钟预分配
    ( ~( P' n6 Z# ~) p
  906.                 //计算数据建立时间,随便给100ns
    1 M" l" @) m* @) o$ [) ?
  907.                 temp = 100 / time_temp;2 a  p/ h4 M/ F3 E
  908.                 if(temp > 15) temp = 15;
    4 o$ E* {: z0 M. Y
  909.                 tTime |= temp << 20;' y7 [1 V- K: s
  910.                 //计算数据保持时间,给100ns3 }# q* t6 L9 Z# w
  911.                 temp = 100 / time_temp;6 d, H# O  D$ C' G5 V
  912.                 if(temp > 15) temp = 15;, G. U4 h: I' W
  913.                 tTime |= temp << 16;
    $ }9 \6 u$ I9 |, Q$ [- u
  914.                 //计算高电平周期Th us
    5 s5 N7 D2 C% V+ t+ A1 \4 N. w$ M
  915.                 temp = Th*1000 / time_temp;: H1 v$ G0 ~( l: C
  916.                 if(temp > 255) temp = 255;" j6 {: W, l# o
  917.                 if(temp < 1) temp = 1;
    7 C( P" Y) q2 I1 f) A3 Z
  918.                 tTime |= temp << 8;  f4 w# J' z% {9 Q8 F
  919.                 //计算低电平周期 Th us
      z' f! Z9 _/ Q/ ^" K' }
  920.                 temp = Th*1000 / time_temp;: f8 p! Z, _; J! W. Y
  921.                 if(temp > 255) temp = 255;/ H, L2 I5 Q5 H; u: D& u6 j
  922.                 if(temp < 1) temp = 1;# C" x% W0 {# V& }- }  l
  923.                 tTime |= temp << 0;
    ! D2 C0 V% E& O
  924.         }5 z# P5 q- ?& q' G7 W+ o
  925.         1 N% v% V3 ]( u0 B  J% x' l2 N1 L
  926.         uart_printf("时序寄存器结果为:0x%X\r\n", tTime);
    , _% q; m9 a& T+ Y( L
  927.         ( n) t1 U* }2 z+ e4 d3 a) h/ Z% s
  928.         return tTime;( O' F, ~/ q4 b
  929. }
复制代码

! R& R; I( U! h% }
, n% z2 F2 V, h6 U
  1. /*************************************************************************************************************  g3 S# L4 W+ X5 M
  2. * 文件名                :        stm32f7_iic.h
    ( y( `) w7 b! A4 s. {! c
  3. * 功能                        :        STM32F7 IIC接口驱动4 d; a8 E* _, d9 E- b6 b4 b
  4. * 作者                        :        <a href="mailto:cp1300@139.com">cp1300@139.com</a>
    ; k6 ?  p& ^& f
  5. * 创建时间                :        2020-02-099 b. j( q* n9 _+ P( j* K; E
  6. * 最后修改时间        :        2020-02-09
    # @) W9 P" L. ~; n+ p8 f' X
  7. * 详细:                        , K) C6 Y! d  ^3 A) A% N6 [
  8. *************************************************************************************************************/                ! Y7 v$ {6 L" _* U
  9. #ifndef __STM32F7_IIC_H_! E- X5 @" Y% X- i: _( g
  10. #define __STM32F7_IIC_H_* H/ K2 W- _/ }6 q, U
  11. #include "system.h" 1 M! o3 `0 H% c% R  T3 f

  12. / I4 ?2 g* _8 k8 v" h# M! H
  13. //16位整形数高低对调
    . k% |5 `# Y2 U' h6 E$ I* r
  14. #ifndef SWAP163 Y% X, z' J9 n- S) c
  15. #define SWAP16(x)   (((x & 0xff00) >> 8) | ((x & 0xff) << 8))
    + q! Q; T+ q# P( H# Z- p
  16. #endif  //SWAP162 j8 ]3 _4 S1 c. o! a4 D) M8 B

  17. ( j; J' K2 [/ A1 N" Y+ _9 ?
  18. //硬件IO口选择
    + v+ B8 r3 C/ ^3 a4 N
  19. //I2C1 IO定义与选择
    + G! z9 V5 w8 D5 v( a
  20. #define IIC_CH1_PB6_7                                0                                        //PB6,PB7
    2 s6 F8 F- s; i6 ~- J2 X4 w
  21. #define IIC_CH1_PB8_9                                1                                        //PB8,PB9
    8 x! t1 Y: `6 L8 }: _* P& z1 i
  22. #define IIC_CH1_IO_SELECT                        IIC_CH1_PB6_7                //选择I2C1 的IO        0 a) W( Y" r; |
  23. 4 f" l, W# c" Q
  24. //I2C2 IO定义与选择4 ~$ ^8 w* q8 b" u+ ]$ y
  25. #define IIC_CH2_PB10_11                                0                                        //PB10,PB11: ^, E$ ~% g* [4 F3 `& B+ x
  26. #define IIC_CH2_PF0_1                                1                                        //PF0,PF1
    , t" J# F5 o, E. y& z8 S) z0 _
  27. #define IIC_CH2_PH4_5                                2                                        //PH4,PH5, t$ e/ i5 s3 E$ S( F( e
  28. #define IIC_CH2_IO_SELECT                        IIC_CH2_PB10_11                //选择I2C2 的IO
    $ L9 r9 U- S9 R
  29. ! i2 n( {3 `! V9 i  A# A
  30. //I2C3 IO定义与选择- h0 `8 W4 q1 w2 c; S, r
  31. #define IIC_CH3_PH7_8                                0                                        //PH7,PH8
    2 i! G+ g. s5 C( a: j) F
  32. #define IIC_CH3_PA8_PC9                                1                                        //PA8,PC9
    ) G1 g/ T! H6 u
  33. #define IIC_CH3_IO_SELECT                        IIC_CH3_PH7_8                //选择I2C3 的IO* u6 ]9 g/ H: n
  34. 2 |: V8 _$ Q) g4 S) R
  35. //I2C4 IO定义与选择$ k% Y. w' {0 b8 p+ ^6 r
  36. #define IIC_CH4_PD12_13                                0                                        //PD12,PD13" o+ |; R2 a$ ?
  37. #define IIC_CH4_PF14_15                                1                                        //PF14,PF15
    5 C3 y) i% m5 r3 _& _3 B6 T
  38. #define IIC_CH4_PH11_12                                2                                        //PH11,PH12
    * g% k, L5 V0 ]8 _, b. Q
  39. #define IIC_CH4_IO_SELECT                        IIC_CH4_PD12_13                //选择I2C4 的IO. }8 r& w4 ^, _7 r
  40. ' W( ?/ l' u9 v. ^( w
  41. //IIC硬件接口选择
    " T4 f" x6 `+ N  E. q6 R
  42. typedef enum$ b5 b" F" n2 u+ g+ m6 o
  43. {
    % ~8 x) ^0 f" n# D. s) r
  44.         IIC_CH1        =                0,        //IIC17 T* f7 B2 |$ }
  45.         IIC_CH2        =                1,        //IIC20 o+ H9 p2 E( F) Z8 M
  46.         IIC_CH3        =                2,        //IIC3) Z1 M1 R7 k$ T0 K
  47.         IIC_CH4        =                3,        //IIC4; E' w. @" D( {6 t
  48. }IIC_CH_Type;/ z5 m0 B+ _8 \# Y  p' u
  49. #define IIC_CH_COUNT        4        //4个IIC
    & o! N% _- w/ m+ x
  50. 4 M; e, P4 e2 x3 o9 @5 K' L" [& \
  51. ' A2 d  D4 y: k# T7 y4 u
  52. //中断状态- F, M! N% p$ b. T3 Y
  53. #define IIC_FLAG_TXE                    BIT0        //发送数据寄存器为空(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1。下一个待发送的数据写入 I2C_TXDR 寄存器时,该位被清零。
    ( z; y$ o: n( h6 y0 B0 {  p' B6 }) ?
  54. #define IIC_FLAG_TXIS                   BIT1        //发送中断状态(发送器); 当 I2C_TXDR 寄存器为空时,该位由硬件置 1,待发送的数据必须写入 I2C_TXDR 寄存器。2 O; y+ m: y: b1 |, R2 @% g
  55. #define IIC_FLAG_RXNE                   BIT2        //接收数据寄存器不为空(接收器); 当接收到的数据已复制到 I2C_RXDR 寄存器且准备就绪可供读取时,该位由硬件置 1。读取I2C_RXDR 时,将清零该位。# o1 f" F4 V* S; ?
  56. #define IIC_FLAG_ADDR                   BIT3        //地址匹配(从模式); 接收到的地址与使能的从设备地址之一匹配时,该位由硬件置 1。该位由软件清零,方法是将ADDRCF 位置 1。3 K: Y1 I3 O# g9 g8 \; j9 d
  57. #define IIC_FLAG_NACKF                  BIT4        //接收到否定应答标志; 传输完字节后接收到 NACK 时,该标志由硬件置 1。该标志由软件清零,方法是将 NACKCF位置 1。
    0 T# H6 }. I' @' ~7 E. h6 b
  58. #define IIC_FLAG_STOPF                  BIT5        //停止位检测标志; 当在总线上检测到停止位,且外设也参与本次传输时,该标志由硬件置 1
    ! n+ z# _: c+ U/ `5 W# W
  59. #define IIC_FLAG_TC                     BIT6        //传输完成(主模式); 当 RELOAD=0、AUTOEND=0 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 START位或 STOP 位置 1 时,该标志由软件清零。2 r: ~1 B4 B5 J
  60. #define IIC_FLAG_TCR                    BIT7        //传输完成等待重载; 当 RELOAD=1 且 NBYTES 数据传输完成时,该标志由硬件置 1。当 NBYTES 写入一个非零值时,该标志由软件清零。
    ! n: E, H4 v2 w; T4 T2 |( p) p) J$ @' u: R
  61. #define IIC_FLAG_BERR                   BIT8        //总线错误; 当检测到错位的起始位或停止位,而外设也参与传输时,该标志由硬件置 1。在从模式下的地址阶段,该标志不会置 1。该标志由软件清零,方法是将 BERRCF 位置 1。
    4 i; _$ ^# Q) `$ i
  62. #define IIC_FLAG_ARLO                   BIT9        //仲裁丢失; 发生仲裁丢失时,该标志由硬件置 1。该标志由软件清零,方法是将 ARLOCF 位置 1。* Q! g3 x( b" `9 V3 e2 j: ~! ^
  63. #define IIC_FLAG_OVR                    BIT10        //上溢/下溢(从模式); 在从模式下且 NOSTRETCH=1 时,如果发生上溢/下溢错误,该标志由硬件置 1。该标志由软件清零,方法是将 OVRCF 位置 1。6 e+ ]& D' m8 O4 c3 }, v, m# y
  64. #define IIC_FLAG_PECERR                 BIT11        //接收期间的 PEC 错误; 当接收到的 PEC 与 PEC 寄存器的内容不匹配时,该标志由硬件置 1。接收到错误的 PEC 后,将自动发送 NACK。该标志由软件清零,方法是将 PECCF 位置 1。! [, F( O/ m( G8 J7 ]4 l6 z
  65. #define IIC_FLAG_TIMEOUT                BIT12        //超时或 tLOW 检测标志; 发生超时或延长时钟超时时,该标志由硬件置 1。该位由软件清零,方法是将 TIMEOUTCF 位置 1。
    , A. V$ R* B" e) F3 E5 X4 n
  66. #define IIC_FLAG_ALERT                  BIT13        //SMBus 报警; 当 SMBHEN=1(SMBus 主机配置)、ALERTEN=1 且在 SMBA 引脚上检测到 SMBALERT 事件(下降沿)时,该标志由硬件置 1。该位由软件清零,方法是将 ALERTCF 位置 1。3 z" V  S* X& @. n
  67. #define IIC_FLAG_BUSY                   BIT15        //总线繁忙; 该标志用于指示总线上正在进行通信。当检测到起始位时,该位由硬件置 1。当检测到停止位或 PE = 0 时,该位由硬件清零。. o$ \. Y6 ~7 B, P+ Q
  68. #define IIC_FLAG_DIR                    BIT16        //传输方向(从模式); 该标志在发生地址匹配事件时 (ADDR=1) 更新。;0:写;1:读, W- U1 K" e# N* Y, z0 u

  69. 8 L/ ^7 k; Q" r$ U0 f5 s- ]
  70. //通讯错误状态
    2 c4 Q+ N4 F" z0 `8 d
  71. typedef enum* D. ^/ C' F  o2 y& o8 ?/ t" G( a
  72. {" m+ R# h; T+ \. r" n, Q
  73.         IIC_OK                                        =        0,        //没有错误- s5 O& ~, q! x- h9 @% h
  74.         IIC_PARAMETER_ERROR                =        1,        //参数错误* G: g, ^3 b: @2 n5 Q6 G7 M
  75.         IIC_TIMEOUT                                =        2,        //超时错误,也可能是底层错误
    # `( w% S( x, G" Y4 Z% ^
  76.         IIC_HAL_ERROR                        =        3,        //底层错误
    0 I5 }0 F: W& u% S  {' y& _
  77.         IIC_STOP_ERROR                        =        4,        //等待结束错误. b1 o, E4 X2 X
  78.         IIC_BUSY                                =        5,        //硬件忙
    ' ]/ B, n" H* D* i, E
  79.         IIC_NACK                                =        6,        //收到NACK了: m8 }; B4 V4 D4 O% r" P& N$ e
  80. }IIC_ERROR;5 S* m/ J* N2 u- F( I6 ~" M; c2 |
  81. " J% h* J$ t- u2 @
  82. ; ?0 e* I  F+ P2 u0 N
  83. bool IIC_Init(IIC_CH_Type ch, u16 Speed_KHz, u16 TimeOutUs);        //硬件IIC初始化! G+ u/ S: H# r9 @( I- u/ o; T+ W
  84. IIC_ERROR IIC_MasterReadReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 ReadByteNum);        //IIC读取寄存器(可以读取1个或者多个寄存器)
    6 u/ O' Q5 K1 h* A9 I- `
  85. IIC_ERROR IIC_MasterWriteReg(IIC_CH_Type ch, u16 SlaveAddr, u16 RegAddr, bool is8bitRegAddr, u8 *pDataBuff, u16 WriteByteNum);        //IIC写寄存器(可以写1个或者多个寄存器)
    : f7 Z2 h5 t% @9 ^3 Y$ E; G

  86. - }1 e& d% X4 M
  87. # u5 O  k# q7 {$ L8 \) S
  88. #endif //__STM32F7_IIC_H_
复制代码
$ V1 T; G$ _8 q/ ]  C0 [2 K$ M
2 F3 ~# c9 H* t, I
//初始化2 `9 P6 g; [8 q8 Q7 d7 D) f

& G" H/ _: d8 N
  1. IIC_Init(IIC_CH3, 200, 0);        //硬件IIC初始化
复制代码

8 w1 C) W) n* W
. T: b% z: B, L; D! }5 w//调用
4 w) ~1 R* H( x

  1. ! h* V. j- I1 P  @0 m, \
  2. //触摸屏IIC读取寄存器接口
    ) V8 E& m1 d" V. G! e( ]( {
  3. bool TP_FT5336_IIC_ReadReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)! t9 ^1 g; Q, r% M  }; N1 l. v% ^
  4. {
    / r% _8 g" T& @6 Q
  5.         if(IIC_MasterReadReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)9 ~1 o6 F- e- b* {6 n) L
  6.         {, r5 h* w8 m2 L) T
  7.                 return TRUE;- n, ?, }$ T* R, M
  8.         }- P2 \5 D" S5 c
  9.         else* P: ~4 E/ p) p% n& }4 R/ J" R
  10.         {
    : K- S5 g4 i, j/ W
  11.                 return FALSE;
    ; v! s5 N( K  `8 J7 K) y- T! h6 ?( r
  12.         }
    0 Z9 f- Y6 n/ ^* L) _; g' H& b
  13. }) n. v( X# h6 f
  14. , g" z: n6 z: L( P
  15. //触摸屏IIC写寄存器接口
    & t8 v1 S7 h+ F& n
  16. bool TP_FT5336_IIC_WriteReg(u16 SlaveAddr, u8 RegAddr, u8 *pDataBuff, u16 ByteNum)$ ]+ @3 K6 i. x2 o  o
  17. {. d$ a- A# E, b
  18.         if(IIC_MasterWriteReg(FT5336_IIC_CH, SlaveAddr, RegAddr, TRUE, pDataBuff, ByteNum) == IIC_OK)" F# J2 u+ u% ~: ^3 I; I* i
  19.         {
    2 _% d) j# f; n+ [' Y% O! }# C) u/ e
  20.                 return TRUE;, z2 i) d2 s) a! \6 l* ]
  21.         }8 T+ R- H5 a( j1 f
  22.         else
    ( p$ M' e* u6 ^5 |5 }) a, ~
  23.         {
    4 d, L3 |+ {8 t' a% p* f
  24.                 return FALSE;  C& p; y# ?  c7 l, A6 q) c
  25.         }4 \/ b) H$ @# @5 E8 n( [2 W- M
  26. 1 E  h( i* k" d& r
复制代码

8 c7 `- i+ l: x- y/ B$ n
: e; {" _1 M) \3 k4 p" a6 a8 b4 u- p2 a  f
收藏 评论0 发布时间:2021-12-11 12:00

举报

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