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

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

[复制链接]
zero99 发布时间:2016-6-16 17:50
       stm8不需要专门配置GPIO口,执行初始化就可以啦!有些stm8需要打开EEPROM设置I2C(看官方文档)。
# ^8 L0 D# B& s7 U. d# W% K- u
       stm8主要靠SR1和SR3状态寄存器判断I2C的情况(while(!XXXXX)就是出自这里),多半大家调不通!就是卡在这里(需要注意的是 寄存器有些位,只要读寄存器就可以清除,在仿真的时候,最好不要打开寄存器页面)。这里分软故障和硬故障:
' B7 S1 Q+ ]" i. Y7 T- o
       首先是硬故障: 一般是stm8芯片IO口坏啦,有些时候stm8能够写程序而且IO别的功能都是好的,单单是I2C用不起!还有就是IO上拉电压不够!我就遇到这样的问题,我IO 加上逻辑分析仪后就可以调通,不加就通不了。这个也搞啦我很久。
0 e% `" V% {1 Z2 o/ O6 `& c0 j
       软故障: 一般主要是设置CR1和CR2问题,只要按照我的参考程序设置就可以!
7 ^# g7 i/ h7 c* ~
       我详细的讲讲,寄存器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...可能就是这个问题(切记!切记!很多例子都没有加上这句,包括风驰 的例子!! 不过 他没有加循环! 如果他再循环一次就会出现问题。)

3 s2 E$ H5 R; n$ u. S! X
       随便说说仿真调试!在调试过程中,最好不要打开I2C寄存器看!因为对寄存器的读,也会造成寄存器有些位重置!直接按Go,然后暂停。进去程序看卡在那里啦。

- N2 y* \( Y5 W6 O7 |* J  h/ d
      操作库和寄存器编写程序,其实没有分别!不过为啦更好的理解,我在这里是操作寄存器!网上有人说加入中断会对I2C产生影响,我这里没有加中断。希望有后来人补全!反正我这几天运行没有发现问题!

7 z5 O5 A# m" j3 N: e: g5 ^
附录1 主要I2C程序( {, g7 V" W; S* \# o

  K3 }' @8 Y* W2 c; w/*******************************************************************************
% n! e* f, }4 \5 \/ Z8 O* N% [8 `( y * 名称: Read_8816( P$ E7 p* m' t' Y% [+ e! r- Q
* 功能: 读取温度数据" a+ ~  ^) L1 Y# H
* 形参: *pBuffer 返回读取数据指针) s* U/ X: r- K- w) i* ]3 w
         index 温度寄存器地址/ W0 w9 k; B% P& H
         NumByteToRead 需要读取字节数
* 返回: 无" f- r2 V0 u7 \! F" `8 Z" d# F
* 说明: 该函数直接操作stm8寄存器!; k8 y3 L  Z3 h
         寄存器I2c_CR2 应答使能位(位2)ack=1,当stm8接受到数据后,自动发送ACK.不需要手动ack
         为个在收到最后一个字节后产生一个NACK 脉冲,在读倒数第二个数据字节之后,必须清除ack位(ack=0)
5 }- O+ Q) N& V/ h' d6 K# ]' x$ f: X         当接收到最后一个字节,需要重新使能ack=1.(如果不设置ack=1,循环开始后,收到第一个字节stm8不会发送ack,造成除每次循环第一个字节正常外,后面收到的数据都是0xFF....stm8一直不给ack)      
$ x9 y! U/ L3 ^* w" p         需要注意的是 寄存器有些位,只要读寄存器就可以清除(不需要专门写入寄存器,在仿真的时候,最好不要打开寄存器页面),' U& a. v4 [9 C! [6 o7 r* \
******************************************************************************/
' ]. J# K% e. ^0 c2 Y( `3 F  W9 ^0 H) l
void Read_8816(u8 *pBuffer, u8 index, u8 NumByteToRead) 8 {% n* U- C, {8 h/ h4 G( }4 g
{  
- z$ u0 }; S3 p; r0 A1 O# D  while(I2C->SR3 & 0x02);  //等待总线空闲   检测i2c-SR3 busy位  0 O* @( {( R# Y5 R
  //以下见stm8s中文数据手册P251(图96主设备发送模式发送序列图)0 @& C# c9 X4 D5 ~+ q
  //S 起始条件
$ a; ]* {7 {0 j  I2C->CR2 |= 0x01;  //产生起始位            CR2 start位      
5 Q  g7 v" H9 b' Y3 m  //EV5:SB=1,读SR1 然后将地址写入DR寄存器将清除该标志。! S9 l; N8 Q  j7 Y- K3 r9 [. y
  while(!(I2C->SR1 & 0x01));  //等待START发送完 E53 o; e# V7 Q- G  e' G* A5 ]" P0 U
  //ADDRESS (发送模式)
" B) C8 T# c1 j2 ]  I2C->DR = 0x00;  //发送MLX90615器件地址(最后一位是0,表示发送)' p1 P6 [* k# @
  while(!(I2C->SR1 & 0x02));  //等特7位器件地址发送完并且收到ack,ADDR置1# z" k! s# y( \! z  ~7 S
//EV6:ADDR 在软件读取SR1后,对SR3寄存器读操作 将清除改位
/ F+ ^1 m) o; H% c/ C1 |4 z5 A I2C->SR1; //见P251 读SR1 (实验证明可以不要)0 L" T6 c3 X- a# ]
I2C->SR3; //然后读SR3 清  ADDR(等于库函数I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED))
0 J7 t& t/ K7 H/ _/ q  //DATA 发送寄存器地址
$ U) [) o  S2 N* h; D' q' t* l5 I  I2C->DR = (u8)(index); 3 q% r  H/ V! ^) n/ i
  //EV8_2 TxE=1 ,BTF=1,产生停止条件时由硬件清除。1 t: P) [% q$ X# j9 V$ `- k
  while(!(I2C->SR1 & 0x84));  //检测SR1 TXE1 BTF位置(只有当stm8收到ack,TxE才会置1,其实这句相当于判断收到ack没有?)
% z5 N" o4 P, W8 [1 Y, `9 }( u  //在发送地址和清除ADDR 之后,I2C接口进入主设备接收模式。以下见stm8s中文数据手册P252(图97主设备接收模式接收序列图); }$ A& v2 \- `7 ^2 X. U
  //S 重复起始条件
$ V" |! E; q1 t% R$ o  I2C->CR2 |= 0x01;  //产生重复起始位2 ^5 @- W  e  c& A
  //EV5:SB=1,读SR1 然后将地址写入DR寄存器将清除该标志。4 w3 \% ^  I/ {  T6 B
  while(!(I2C->SR1 & 0x01));  //等待START发送完. m" J( G3 C- q7 Q
  //ADDRESS (接收), _) h* r% N" Y" ^* ?3 G5 {* A
  I2C->DR = 0x01;  //发送MLX90615器件地址(最后一位是1,表示接收),发送完后自动发送ack(提前是CR2 ack位使能)& l7 V  Z+ j! d( s
  //EV6:ADDR 在软件读取SR1后,对SR3寄存器读操作 将清除改位, \' M# F. C5 N6 w# B
  while(!(I2C->SR1 & 0x02));  //等特7位器件地址发送完并且收到ack,ADDR置1
) _. r& U2 }1 E! ~! e I2C->SR1; //见P251 读SR1 (实验证明可以不要)
$ b# z# w. i1 E% ]* G I2C->SR3; //然后读SR3 清  ADDR(等于库函数I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED))
9 G+ O; p8 F. s- q7 U% X  L //循环读取数据
" }5 w% r7 y2 T  @% g; B: F  while(NumByteToRead)  , p# C; q# f. W6 J0 ]/ h$ U
  {
  r8 U& @, m- m7 e      //EV7_1 :RxNE=1 ,读DR寄存器清除该标志。设置ACK=0和STOP 请求。(在接收最后一个字节前) % q; |6 W9 k7 r+ n; g+ I3 h
        if(NumByteToRead == 1) //实验证明在最后一个字节前后都一样
* P& L' n: V) U; k; e2 h    { - t* ~- H+ c  }3 B, Q' p: T
      I2C->CR2 &= ~0x04; //ack使能/ I% g, C$ v' l- |1 {  R9 l% A& H' i
      I2C->CR2 |= 0x02;  //停止位产生stop  ~8 H4 I6 f1 A
    } . o. y& K  \+ ]) g( T& I
      ///测试EV7 RxNE=1(收到一个字节后RxNE置1) ,判断DR寄存器有数据  f! t# J, Z2 w1 ]
    if(I2C->SR1 & 0x40)
, `5 r9 o7 h. s% L    {
4 U0 ^5 D8 Z' ]       *pBuffer=I2C->DR;//在接收模式下,收到完整字节后,自动发送ack(提前是CR2 ack位使能,不需要专门CR2 ack位置1)' _" E( Z6 n; c' R4 L6 V
              //在风驰里面例子,在每次收到字节后加I2C_AcknowledgeConfig(I2C_ACK_CURR)无任何意义,
4 ^3 Y* \; C% l& Z4 k       pBuffer++;  9 y9 ]7 i7 x, U
       NumByteToRead--;   $ f6 H) u4 o. r  n
    }   ; M! E+ |2 A$ V& q5 f
  }* q! ]; `1 H" J/ u5 d
I2C->CR2 |= 0x04;//为一下循环开始 设置 ack使能,上面 EV7_1设置ack=0发送stop后;需要手动设置ack=1使能,必要在接收数据之前8 n$ Z/ J2 c! n& i" C$ l$ R  b
//切记!切记!很多例子都没有加上这句,包括风驰 的例子!! 不过 他没有加循环! 如果他在循环一次就会出现问题。CR2 ack位其实就是使能的意思!!很多人都理解成需要手动设置!5 d; _% b& s2 s
}
赞 收藏 4 评论8 发布时间:2016-6-16 17:50

举报

8个回答
一个老头 回答时间:2017-2-26 11:44:52
受教了。
1 ]! h; `4 e" j
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 i6 J9 E+ V4 V( w% e
void I2C_MASTERMODE_Init(void)8 U6 d4 g7 q# z& H- U7 M! K# @
{        7 ?! x9 r1 @9 v5 e9 Y" J
        CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, ENABLE);. G, q; H! \0 U4 d+ Y+ u% `* x
7 F' ^) V4 z$ b# t) S
        I2C_Init(100000, 0x00, I2C_DUTYCYCLE_2, I2C_ACK_NONE, I2C_ADDMODE_7BIT, 16);
. Q# [0 Q0 \( e        I2C_Cmd(ENABLE);: Z( s$ _& p& j
}9 K7 j+ e$ x" ~3 N/ f* E: S* J
while(I2C->SR3 & 0x02);
/ {( N1 F/ W. I' y
2 o1 P2 }' U2 b
a试纸 回答时间:2019-4-10 11:35:45
myst 发表于 2019-4-10 11:35( a' f$ F$ ]. z. z' ]* U
你好我配置了,没有波形输出,怎么回事初始化配置:6 D& x$ b- [. H/ w$ S
void I2C_MASTERMODE_Init(void)
" R' ]  o* ]5 @8 b7 p2 ~{       
- E+ K5 g- h5 C. @, C+ Q7 b
一直检测忙状态
yf14789652 回答时间:2019-12-27 08:34:44
正在移植硬件I2C 通信。 测试1:开始、设备地址、等待应答、延时,这个测试没问题。测试2:正常发写的接口函数,卡在了 EV8的判断。% A5 \. o: q( {7 Q. E! J9 G" I. G
+ A* _2 D$ D4 A$ Y7 V' ~
请问版主有什么分析和定位的方法吗?
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版