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

HAL库的I2C模块函数库改造

[复制链接]
shiyongzhu 发布时间:2015-8-14 14:10
本帖最后由 shiyongzhu 于 2015-8-14 14:55 编辑
6 Q3 g1 f2 y3 o6 r
0 G, J- Q4 I, r+ ]1 Z( V
STHAL库的I2C模块函数库中提供了大量的函数,方便了用户的使用。近期由于需要使用下I2C接口,对HAL库中的函数以及相关的例程进行了一下研究,发现当mcu处于从机的时候,其提供的函数只能满足从机处于接收或者发送状态之一(本人观点,欢迎指正),当主机既需要对从机既需要读又需要写时,特别的不方便。为此本人对HAL库中的I2C进行了一下改造,使其处于从机时收发皆可。
主要的思想是开启地址匹配中断,主机对从机进行读或写时进入该中断后,在中断中读取状态寄存器ISR,看主机是读还是写,然后分别进入相关的子程序即可。 捕获.JPG
具体实现以stm32f072为例,初始化,注意开启中断:
  1. void MX_I2C1_Init(void)
    9 g0 k* A1 S5 k5 D
  2. {) G" v- _  _0 T1 ~6 o2 c

  3. 1 j) g/ @* d  h
  4.   hi2c1.Instance = I2C1;; r# I, @$ @2 y) x, a4 T+ B8 T
  5. //  hi2c1.Init.Timing = 0x00700000;                                                                                                        //1MHz,100ns,100ns,slave
    ( @  D% E: U2 K* t% N- i5 I
  6.         hi2c1.Init.Timing = 0x00900000;                                                                                                                //400kHz,10ns,10ns,slave9 y- f; \. f) F# D
  7.   hi2c1.Init.OwnAddress1 = ADDRESS;                                                                                                //µçµ÷µØÖ·
    ) B) T1 {3 }* q% v  N* R, D
  8.   hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;                // µØַΪ7λ
    . x) y; I. e" U: n8 k  a
  9.   hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;$ e7 b6 E# D+ b
  10.   hi2c1.Init.OwnAddress2 = 0;
    - J! l+ `" w) m
  11.   hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;. h' @! P( s6 q2 l) S& w8 C
  12.   hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;8 {2 q8 H: O3 d- u7 x3 T
  13.   hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED;+ v  m2 ^( p9 X) i7 o
  14.   HAL_I2C_Init(&hi2c1);) a' T" N2 D- E9 b( d
  15. 0 a5 D4 {8 C& c* @0 a6 v
  16.     /**Configure Analogue filter 3 ?( z# s7 V4 ^$ o7 s) H$ f- X+ ^
  17.     */
    + H0 y* r% ^; x9 ^& m
  18.   HAL_I2CEx_AnalogFilter_Config(&hi2c1, I2C_ANALOGFILTER_ENABLED);9 _/ q" O0 c8 q9 h- s. t: r! ?0 _2 ?
  19.         2 l8 w% c! v( m; O$ Z1 w
  20.         HAL_NVIC_SetPriority(I2C1_IRQn, 0, 0);                //i2c15 r) ^! e, C9 _. I; g  q
  21.   HAL_NVIC_EnableIRQ(I2C1_IRQn);
    9 S+ X7 w. y* M5 r
  22. }
复制代码
; C4 X* q# V2 @, X
然后写I2C中断服务函数void I2C1_IRQHandler(),具体程序如下
  1. void I2C1_IRQHandler(void)
    # l5 ~6 \- h& F! Z1 r9 M
  2. {
    2 G8 t; t0 _$ c/ K
  3.   if (hi2c1.Instance->ISR & (I2C_FLAG_BERR | I2C_FLAG_ARLO | I2C_FLAG_OVR)) {
    * O6 K( \. }) ]9 o; a
  4.     HAL_I2C_ER_IRQHandler(&hi2c1);  Q! k6 C9 s7 v5 K% y% p
  5.   } else {
    ' ?& X) a) j" o$ o+ B; \7 b
  6.     HAL_I2C_EV_IRQHandler(&hi2c1);
    2 I7 i) W9 D9 F0 |# l
  7.   }) k  f  A7 q# j4 p  y8 |
  8. }
复制代码
- E) K- n" v. r% N# Z
具体干活的程序如下,本处对原有的函数库进行了改造
  1. void HAL_I2C_EV_IRQHandler(I2C_HandleTypeDef *hi2c)1 V3 f+ w' a+ \- z( g
  2. {
    , d. h1 z8 k2 j# I6 p, t- B1 q
  3. if ((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_ADDR) == SET) && (__HAL_I2C_GET_IT_SOURCE(hi2c, I2C_IT_ADDRI) == SET))
      W. q( y6 ]  p/ @
  4.   {
    * |) H8 [- v4 R+ p0 m
  5.                 HAL_I2C_SlaveRxTxCallback(hi2c);
    0 Y0 X& ?6 P  \; r" M: l5 \- }
  6.   } / |' {' `4 O8 B
  7.        
    # D' a, X  x1 K) r7 g5 W( ?+ O
  8. }
复制代码
* r, P( V$ m5 z" }# J
HAL_I2C_SlaveRxTxCallback(hi2c)为自己写的函数,具体如下
  1. void HAL_I2C_SlaveRxTxCallback(I2C_HandleTypeDef *hi2c)                . y6 B4 Q' |; y5 O: D/ X5 h8 x
  2. {
    5 i  u9 t* U3 m
  3.         if(hi2c->Instance==I2C1)
    . B. i/ w/ @  X7 l* p
  4.         {1 z) q* U4 i# h; B) D7 a9 I- n0 z
  5.                  /* Slave mode selected */
    5 V6 X$ H' T" E3 x2 y- z
  6.     if (hi2c->State == HAL_I2C_STATE_READY)5 [9 K5 q1 Z9 x9 |* y
  7.     {
    * h8 C0 v) t% i5 U0 L
  8.       __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ADDR); // ÇåÖжÏ
    1 T/ Z2 }7 @4 a+ L! t  M) T
  9.                         if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_DIR))                // ÊÕ·¢·½Ïò
    . w8 b+ B) ~2 |, S* O
  10.                         {
    & l3 ~) e7 _& W1 C, Z1 K" [$ P
  11. HAL_I2C_Slave_Transmit_DMA_NEW(hi2c,(uint8_t*)i2c1_tx_buffer, sizeof(i2c1_tx_buffer));& ~" N+ t/ y* s* ~
  12.                         }# O! ]* s, g8 H5 D
  13.                         else
    ' C2 E8 T) e4 e% m( Y
  14.                         {- q+ y& q# d8 ]) j
  15. HAL_I2C_Slave_Receive_DMA_NEW(hi2c,(uint8_t*)i2c1_rx_buffer, sizeof(i2c1_rx_buffer));
    7 J* V; i7 c/ b
  16.                         }; D/ q$ n: ?- S2 c$ r& \0 r9 B: G
  17.     }# h1 n/ A8 Q2 B2 A
  18.         }3 f* p. r1 E5 U. G/ v' `# w# S

  19. # W# u* e: Y. f; B
  20. }
复制代码

% ]" g' k: B4 J3 S% z- t3 g
上面函数中的函数:
HAL_I2C_Slave_Transmit_DMA_NEW(hi2c,(uint8_t*)i2c1_tx_buffer,sizeof(i2c1_tx_buffer))
HAL_I2C_Slave_Receive_DMA_NEW(hi2c,(uint8_t*)i2c1_rx_buffer,sizeof(i2c1_rx_buffer));
HAL_I2C_Slave_Transmit_DMAHAL_I2C_Slave_Receive_DMA_NEW的改造,删除了原有函数中的地址匹配和方向判断的内容。
5 j1 Z3 W/ E$ D: w, v& }
使用时,只要开启地址匹配中断一切就OK了
  1. __HAL_I2C_ENABLE_IT(&hi2c1,I2C_IT_ADDRI);
复制代码

. A# w/ f: a9 B% ?  ^2 i; B

% U# v) J: S- E* f  _5 P  a; m* Q7 S: e; q( b2 E/ n
收藏 5 评论16 发布时间:2015-8-14 14:10

举报

16个回答
moyanming2013 回答时间:2017-3-28 11:12:02
yc2168 发表于 2017-3-28 09:048 P9 ~$ D3 l# k0 Y& s4 `
是不是以结束位判断比较好呢?
! C$ v: l/ ?9 }% VIIC 都是以结束位结束,HAL库接收发送都要定长度,这很郁闷。 ...
4 a/ g+ H% s: C4 F8 p, X7 o: x, ^
IIC的结束符属于底层的细节(类似于物理层的协议),HAL库封装了IIC的实现细节,你直接关注上面的应用就行了。
. Y1 ?* s/ B2 s7 I6 B' t至于收发数量,即使你自己实现物理层也不会知道具体的数量吧?!你只是知道来了数据了,每次读若干个。
yc2168 回答时间:2017-3-28 12:29:39
moyanming2013 发表于 2017-3-28 11:12
% S7 {  s) H& Z9 _$ `" f. bIIC的结束符属于底层的细节(类似于物理层的协议),HAL库封装了IIC的实现细节,你直接关注上面的应用就 ...
. s( s" {! b& K' t* T1 n) k5 S0 Q+ i
如果上位机发过来的数据不定长怎么办? 我也不知道他要发多少字节。那我怎么知道应该接收多少个。
! X5 j  }) b0 z5 I! g; @以前其他单片机都是已结束位判断一次接收已经完成?
yc2168 回答时间:2017-3-28 09:04:06
moyanming2013 发表于 2017-3-27 20:35
( H, C# z( l8 V- y在中断回调函数中设置读1个字节,然后根据你的需要判断就可以了。接受完1个字节后根据需要再次打开中断。 ...

0 V: v2 t% D/ d0 }是不是以结束位判断比较好呢?
3 l7 z% S1 e% A" HIIC 都是以结束位结束,HAL库接收发送都要定长度,这很郁闷。
沐紫 回答时间:2015-8-14 14:47:11
谢谢楼主3 P: M0 a8 c( L- n, x( ^5 i- I6 @
: _7 [& ?' y. Z: Q% }# \
楼主在编辑帖子的时候,右上角有个添加代码文字按钮,用来放代码特别好用 QQ截图20150814144826.jpg
shiyongzhu 回答时间:2015-8-14 14:55:51
沐紫 发表于 2015-8-14 14:47
5 \& R5 j* l0 ?6 O! {谢谢楼主: o! g. `5 m$ n
% c3 r1 m8 w! |
楼主在编辑帖子的时候,右上角有个添加代码文字按钮,用来放代码特别好用 ...

& l; Y5 D, i' e2 h- e# G6 x谢谢沐紫,用了下效果好很多!
Paderboy 回答时间:2015-8-14 17:53:04
多谢楼主,学习了。。
党国特派员 回答时间:2015-8-16 14:07:36
多谢楼主,学习了。。
wamcncn 回答时间:2015-8-17 19:52:34
学习下的经验楼主
wyxy163@126.com 回答时间:2015-8-18 16:39:03
提示: 作者被禁止或删除 内容自动屏蔽
微雪电子 回答时间:2017-2-8 10:44:53
楼主有工程源码吗、可否发给我看下,最新一直在弄i2c 从模式。
草民星空 回答时间:2017-2-10 13:49:22
学习学习
yc2168 回答时间:2017-3-27 17:50:58
请问如何接收不定长的数据??
zbber 回答时间:2017-3-27 18:13:59

5 I. i$ u; K( t  q4 m,我只是路过打酱油的  b, T0 m- v. ~
moyanming2013 回答时间:2017-3-27 20:35:21
yc2168 发表于 2017-3-27 17:504 `) ~# X. X8 j: v4 n
请问如何接收不定长的数据??
0 D; h. j/ n5 J) y, M0 e
在中断回调函数中设置读1个字节,然后根据你的需要判断就可以了。接受完1个字节后根据需要再次打开中断。
12下一页

所属标签

相似分享

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