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

基于stm8调试硬件I2C经验分享

[复制链接]
zero99 发布时间:2016-6-16 17:50
       stm8不需要专门配置GPIO口,执行初始化就可以啦!有些stm8需要打开EEPROM设置I2C(看官方文档)
: W' T" X6 L9 ~( ~* @
       stm8主要靠SR1和SR3状态寄存器判断I2C的情况(while(!XXXXX)就是出自这里),多半大家调不通!就是卡在这里(需要注意的是 寄存器有些位,只要读寄存器就可以清除,在仿真的时候,最好不要打开寄存器页面)。这里分软故障和硬故障:

- q# o  m4 {' v1 H/ s
       首先是硬故障: 一般是stm8芯片IO口坏啦,有些时候stm8能够写程序而且IO别的功能都是好的,单单是I2C用不起!还有就是IO上拉电压不够!我就遇到这样的问题,我IO 加上逻辑分析仪后就可以调通,不加就通不了。这个也搞啦我很久。

2 f7 C7 Y# h- C
       软故障: 一般主要是设置CR1和CR2问题,只要按照我的参考程序设置就可以!
  c: K6 g' |: \% _
       我详细的讲讲,寄存器I2c_CR2 应答使能位(位2)ack。首先是理解:官方文档上面说的是ack应答使能,对是使能!很多人包括我自己 开始都认为是发送ack,导致每次stm8收到数据后,我们都手动在每次收到字节后加I2C_AcknowledgeConfig(I2C_ACK_CURR)无任何意义,因为在接收模式下,收到完整字节后,自动发送ack(提前是CR2 ack位使能,不需要专门CR2 ack位置1)   ,都是软件虚拟I2C用多啦!想当然啦!
       还有就是使用这个ack!设置ACK都必须在接收字节前,也就是说为个在收到最后一个字节后产生一个NACK 脉冲,在读倒数第二个数据字节之后,必须清除ack位(ack=0)!设置ack同理! 还有需要 主要的地方 如果设置 ack=0; 下次需要重新产生ack的时候!需要手动置位ack!记住在开始接收之前!如果你只有一个字节正确,后面全部是0xFF...可能就是这个问题(切记!切记!很多例子都没有加上这句,包括风驰 的例子!! 不过 他没有加循环! 如果他再循环一次就会出现问题。)

& J+ \' E: v, g0 k" R* q; f; ^1 w
       随便说说仿真调试!在调试过程中,最好不要打开I2C寄存器看!因为对寄存器的读,也会造成寄存器有些位重置!直接按Go,然后暂停。进去程序看卡在那里啦。

: k) k, N# i, j) w0 E/ V$ S
      操作库和寄存器编写程序,其实没有分别!不过为啦更好的理解,我在这里是操作寄存器!网上有人说加入中断会对I2C产生影响,我这里没有加中断。希望有后来人补全!反正我这几天运行没有发现问题!
) H3 n4 z) r4 |) c! \
附录1 主要I2C程序
) p$ }7 q' R- u1 H- e% r: ~5 ~! K# N( s6 `$ Y5 p9 I! `- W' }& q$ d0 s
/*******************************************************************************- u- K* a/ n, a7 @; L
* 名称: Read_88166 A- p5 x" a% b) Y
* 功能: 读取温度数据6 e/ f/ J) C% v
* 形参: *pBuffer 返回读取数据指针
9 ^# A3 F! k) a2 j& W         index 温度寄存器地址6 u& Q3 f: D: B1 i- i
         NumByteToRead 需要读取字节数
* 返回: 无
3 J' o# E. T9 ?4 z6 o; `. b * 说明: 该函数直接操作stm8寄存器!
+ E. Z8 q2 D! Y/ v. N         寄存器I2c_CR2 应答使能位(位2)ack=1,当stm8接受到数据后,自动发送ACK.不需要手动ack
         为个在收到最后一个字节后产生一个NACK 脉冲,在读倒数第二个数据字节之后,必须清除ack位(ack=0): ~% F/ l( Z  Z( t5 \- m
         当接收到最后一个字节,需要重新使能ack=1.(如果不设置ack=1,循环开始后,收到第一个字节stm8不会发送ack,造成除每次循环第一个字节正常外,后面收到的数据都是0xFF....stm8一直不给ack)      + C7 s' Q5 y* D' |! T( @6 }
         需要注意的是 寄存器有些位,只要读寄存器就可以清除(不需要专门写入寄存器,在仿真的时候,最好不要打开寄存器页面),
. P/ n( J- I7 v9 q ******************************************************************************/
, g& ]% \$ U7 I) w9 Z1 {) @1 H" l$ M. n& z
void Read_8816(u8 *pBuffer, u8 index, u8 NumByteToRead)
+ U6 N& n0 D8 U+ c) R' r1 ~; Z# z0 ^{  
+ M6 {5 ^2 O% ]0 I  while(I2C->SR3 & 0x02);  //等待总线空闲   检测i2c-SR3 busy位  
9 p+ G4 m; L1 s/ L8 m3 T, Q  //以下见stm8s中文数据手册P251(图96主设备发送模式发送序列图)
& r/ V) v) \5 B) s/ x: U4 X  //S 起始条件4 s. f# G) \5 p5 x# _
  I2C->CR2 |= 0x01;  //产生起始位            CR2 start位       ( R, E5 J6 J) l7 M: A6 Q1 o
  //EV5:SB=1,读SR1 然后将地址写入DR寄存器将清除该标志。
3 F' L! j& ?/ Y, Z0 g5 R. R. D) f  while(!(I2C->SR1 & 0x01));  //等待START发送完 E5
0 l- w; v! L  i* S$ ]1 t  //ADDRESS (发送模式)
  b. v+ c& N* }+ v6 c+ b! f  I2C->DR = 0x00;  //发送MLX90615器件地址(最后一位是0,表示发送)2 [: x; H, o2 @  H* q! |
  while(!(I2C->SR1 & 0x02));  //等特7位器件地址发送完并且收到ack,ADDR置1: Q% J' F2 j. I2 o+ R9 P0 |
//EV6:ADDR 在软件读取SR1后,对SR3寄存器读操作 将清除改位( z+ R! ]8 r( }: @: J, J
I2C->SR1; //见P251 读SR1 (实验证明可以不要)
* ?& d$ ?8 `; ?9 k9 _, X: W I2C->SR3; //然后读SR3 清  ADDR(等于库函数I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED))
+ l8 t* d, _+ ?  W: [8 y' Y0 d  //DATA 发送寄存器地址
9 c4 w  m0 ?6 i  I2C->DR = (u8)(index);
; Y" J5 k4 e5 h7 Y0 r  //EV8_2 TxE=1 ,BTF=1,产生停止条件时由硬件清除。
2 y+ b- U: _1 T  while(!(I2C->SR1 & 0x84));  //检测SR1 TXE1 BTF位置(只有当stm8收到ack,TxE才会置1,其实这句相当于判断收到ack没有?)
& q' J, A7 A( ~1 W' ]2 t2 T: U4 t  //在发送地址和清除ADDR 之后,I2C接口进入主设备接收模式。以下见stm8s中文数据手册P252(图97主设备接收模式接收序列图)2 ^% x  l* A. N3 A- a  q, v$ g4 p
  //S 重复起始条件& U; \0 [) N/ y4 z+ N+ G
  I2C->CR2 |= 0x01;  //产生重复起始位# o# A' R  f7 ?
  //EV5:SB=1,读SR1 然后将地址写入DR寄存器将清除该标志。1 e. s- k) J9 f6 R+ D
  while(!(I2C->SR1 & 0x01));  //等待START发送完; @, t# ^6 m1 }( U. w7 |
  //ADDRESS (接收)
/ S6 B9 P" S3 J. F: Y  I2C->DR = 0x01;  //发送MLX90615器件地址(最后一位是1,表示接收),发送完后自动发送ack(提前是CR2 ack位使能)
4 U  j7 B# w5 C  //EV6:ADDR 在软件读取SR1后,对SR3寄存器读操作 将清除改位. p; E7 A3 R' X; r9 o2 L
  while(!(I2C->SR1 & 0x02));  //等特7位器件地址发送完并且收到ack,ADDR置12 H0 g! r# [8 e; m
I2C->SR1; //见P251 读SR1 (实验证明可以不要)2 |# [' {7 i1 H% w# `! H
I2C->SR3; //然后读SR3 清  ADDR(等于库函数I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED))
% s2 L0 B  K+ w* V //循环读取数据. U" m2 }% Y# J7 P0 R
  while(NumByteToRead)  0 Q2 U+ w: m+ |% L. t
  {
: b8 y* ^9 X7 b1 V$ L      //EV7_1 :RxNE=1 ,读DR寄存器清除该标志。设置ACK=0和STOP 请求。(在接收最后一个字节前) 0 Y& T. q: J5 t7 Y7 z1 i) w
        if(NumByteToRead == 1) //实验证明在最后一个字节前后都一样- ]4 r- Z; R+ L; g. F
    {
" x, X. G; L, V      I2C->CR2 &= ~0x04; //ack使能. @- n3 b  R, i1 h" I9 L5 F7 A
      I2C->CR2 |= 0x02;  //停止位产生stop5 O3 G) r# t5 ?8 }" z$ v
    }
; g$ B6 z1 d7 P7 N) F! O' o0 w      ///测试EV7 RxNE=1(收到一个字节后RxNE置1) ,判断DR寄存器有数据- C3 N9 d; w/ R1 O$ _% V. v7 }* e# r
    if(I2C->SR1 & 0x40)4 h9 O6 T$ Y) o) H; A+ o
    {
# E! M. n9 d6 N       *pBuffer=I2C->DR;//在接收模式下,收到完整字节后,自动发送ack(提前是CR2 ack位使能,不需要专门CR2 ack位置1)0 T4 H3 c2 ~( K( W. X- D- ]- F, r9 H2 x
              //在风驰里面例子,在每次收到字节后加I2C_AcknowledgeConfig(I2C_ACK_CURR)无任何意义,
( }! p' z( l4 n' {       pBuffer++;  6 l" ^" W& p3 y  d) B. x: _3 m
       NumByteToRead--;     S5 J+ t$ z5 |! E% f: p
    }   " h1 |: V1 G; G, Q; |; H3 A
  }
9 q% I9 Y. Z0 U: B2 S) c I2C->CR2 |= 0x04;//为一下循环开始 设置 ack使能,上面 EV7_1设置ack=0发送stop后;需要手动设置ack=1使能,必要在接收数据之前
# u+ ~3 W4 u6 z9 {4 K2 C //切记!切记!很多例子都没有加上这句,包括风驰 的例子!! 不过 他没有加循环! 如果他在循环一次就会出现问题。CR2 ack位其实就是使能的意思!!很多人都理解成需要手动设置!9 a8 t7 V9 N$ F7 a/ y4 T
}
收藏 4 评论8 发布时间:2016-6-16 17:50

举报

8个回答
一个老头 回答时间:2017-2-26 11:44:52
受教了。" }' d7 p9 w; ?1 ~" Q
fafa1 回答时间:2017-3-7 17:54:37
搞一个完整的上来吧,包括初始化的,谢谢!我遇到问题了,卡死!
小小超 回答时间:2017-3-8 11:20:56
谢谢分享!!!
leesoft 回答时间:2017-3-13 15:19:33
学习了,我正在写STM8S003F3的I2C,多谢
诗歌 回答时间:2017-3-13 20:14:36
网上down的资料吧
a试纸 回答时间:2019-4-10 11:35:08
你好我配置了,没有波形输出,怎么回事初始化配置:7 g6 |: o: u7 L1 P7 U9 ?+ Y8 L* H
void I2C_MASTERMODE_Init(void)5 P$ Z7 |( x- c2 K6 g* M9 _
{       
" ^5 {' T7 b8 X, B/ a        CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, ENABLE);% D% E0 d% h9 c  L* L

  a# v! I* {. Y5 d. n3 E7 s' P        I2C_Init(100000, 0x00, I2C_DUTYCYCLE_2, I2C_ACK_NONE, I2C_ADDMODE_7BIT, 16);
0 V1 }. C0 ^' V9 U        I2C_Cmd(ENABLE);
7 c4 o/ i3 b# G9 z1 c+ M4 V2 x( r" E}
1 E) w0 g) H& V, o9 F1 L; Awhile(I2C->SR3 & 0x02);
' L8 u& y" k+ i& T3 z* `0 ]. }) Q7 M, L9 K! _* c* U( k  N9 \% G
a试纸 回答时间:2019-4-10 11:35:45
myst 发表于 2019-4-10 11:35" U! ]7 U3 a; R' ?% x& F
你好我配置了,没有波形输出,怎么回事初始化配置:
6 w3 F" C9 `2 D& \7 Avoid I2C_MASTERMODE_Init(void)- N1 E% l3 r' X/ Y7 g0 l4 b2 D
{       
8 O. D, c  s+ ^2 Z
一直检测忙状态
yf14789652 回答时间:2019-12-27 08:34:44
正在移植硬件I2C 通信。 测试1:开始、设备地址、等待应答、延时,这个测试没问题。测试2:正常发写的接口函数,卡在了 EV8的判断。, j+ b7 t5 N, ]0 x1 F+ v, ?
' P! o* ^0 {% [7 Y) k
请问版主有什么分析和定位的方法吗?

所属标签

相似分享

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