打印
[STM8]

stm8 调试硬件I2C心得

[复制链接]
21347|27
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
bigwudan|  楼主 | 2014-2-28 11:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
stm8 调试硬件I2C心得
  这次调试stm8的硬件真是艰辛,没有想到这样恼火!整整搞啦 我5天的时间,参考网上很多例子和风驰的stm8讲解!和自己的实践,终于搞通啦!特将自己在调试过程中一些心得希望的大家分享。由于本人水平有限也希望大家指出不足和错误的地方!
  Stm8不需要专门配置GPIO口,执行初始化就可以啦!有些stm8需要打开EEPROM设置I2C(看官方文档)
  Stm8主要靠SR1SR3状态寄存器判断I2C的情况(while(!XXXXX)就是出自这里),多半大家调不通!就是卡在这里(需要注意的是 寄存器有些位,只要读寄存器就可以清除,在仿真的时候,最好不要打开寄存器页面)。这里分软故障和硬故障:
  首先是硬故障: 一般是stm8芯片IO口坏啦,有些时候stm8能够写程序而且IO别的功能都是好的,单单是I2C用不起!还有就是IO上拉电压不够!我就遇到这样的问题,我IO 加上逻辑分析仪后就可以调通,不加就通不了。这个也搞啦我很久。
  软故障: 一般主要是设置CR1CR2问题,只要按照我的参考程序设置就可以!
  我详细的讲讲,寄存器I2c_CR2 应答使能位(位2ack。首先是理解:官方文档上面说的是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...可能就是这个问题(切记!切记!很多例子都没有加上这句,包括风驰 的例子!! 不过 他没有加循环! 如果他再循环一次就会出现问题。)
  随便说说仿真调试!在调试过程中,最好不要打开I2C寄存器看!因为对寄存器的读,也会造成寄存器有些位重置!直接按Go,然后暂停。进去程序看卡在那里啦。
  操作库和寄存器编写程序,其实没有分别!不过为啦更好的理解,我在这里是操作寄存器!网上有人说加入中断会对I2C产生影响,我这里没有加中断。希望有后来人补全!反正我这几天运行没有发现问题!
附录1 主要I2C程序

/*******************************************************************************
* 名称: Read_8816
* 功能: 读取温度数据
* 形参: *pBuffer 返回读取数据指针
         index 温度寄存器地址
         NumByteToRead 需要读取字节数

* 返回: 无
* 说明: 该函数直接操作stm8寄存器!
         寄存器I2c_CR2 应答使能位(位2)ack=1,当stm8接受到数据后,自动发送ACK.不需要手动ack

         为个在收到最后一个字节后产生一个NACK 脉冲,在读倒数第二个数据字节之后,必须清除ack位(ack=0)
         当接收到最后一个字节,需要重新使能ack=1.(如果不设置ack=1,循环开始后,收到第一个字节stm8不会发送ack,造成除每次循环第一个字节正常外,后面收到
         的数据都是0xFF....stm8一直不给ack)
           
         需要注意的是 寄存器有些位,只要读寄存器就可以清除(不需要专门写入寄存器,在仿真的时候,最好不要打开寄存器页面),
******************************************************************************/

void Read_8816(u8 *pBuffer, u8 index, u8 NumByteToRead)
{  
  
  while(I2C->SR3 & 0x02);  //等待总线空闲   检测i2c-SR3 busy位  
  
  
  //以下见stm8s中文数据手册P251(图96主设备发送模式发送序列图)
  
  //S 起始条件
  I2C->CR2 |= 0x01;  //产生起始位            CR2 start位      
  //EV5:SB=1,读SR1 然后将地址写入DR寄存器将清除该标志。
  while(!(I2C->SR1 & 0x01));  //等待START发送完 E5
  
  //ADDRESS (发送模式)
  I2C->DR = 0x00;  //发送MLX90615器件地址(最后一位是0,表示发送)
  

  while(!(I2C->SR1 & 0x02));  //等特7位器件地址发送完并且收到ack,ADDR置1
  
//EV6:ADDR 在软件读取SR1后,对SR3寄存器读操作 将清除改位
I2C->SR1; //见P251 读SR1 (实验证明可以不要)
I2C->SR3; //然后读SR3 清  ADDR(等于库函数I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED))


  //DATA 发送寄存器地址
  I2C->DR = (u8)(index);
  
  //EV8_2 TxE=1 ,BTF=1,产生停止条件时由硬件清除。
  while(!(I2C->SR1 & 0x84));  //检测SR1 TXE1 BTF位置(只有当stm8收到ack,TxE才会置1,其实这句相当于判断收到ack没有?)
  
  
  
  //在发送地址和清除ADDR 之后,I2C接口进入主设备接收模式。以下见stm8s中文数据手册P252(图97主设备接收模式接收序列图)
  
  //S 重复起始条件
  I2C->CR2 |= 0x01;  //产生重复起始位
  //EV5:SB=1,读SR1 然后将地址写入DR寄存器将清除该标志。
  while(!(I2C->SR1 & 0x01));  //等待START发送完
  
  //ADDRESS (接收)
  I2C->DR = 0x01;  //发送MLX90615器件地址(最后一位是1,表示接收),发送完后自动发送ack(提前是CR2 ack位使能)

  
  //EV6:ADDR 在软件读取SR1后,对SR3寄存器读操作 将清除改位
  while(!(I2C->SR1 & 0x02));  //等特7位器件地址发送完并且收到ack,ADDR置1
I2C->SR1; //见P251 读SR1 (实验证明可以不要)
I2C->SR3; //然后读SR3 清  ADDR(等于库函数I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED))

//循环读取数据
  while(NumByteToRead)  
  {
      //EV7_1 :RxNE=1 ,读DR寄存器清除该标志。设置ACK=0和STOP 请求。(在接收最后一个字节前)
        if(NumByteToRead == 1) //实验证明在最后一个字节前后都一样
    {
      I2C->CR2 &= ~0x04; //ack使能
      
      I2C->CR2 |= 0x02;  //停止位产生stop
   
    }
      
   
      ///测试EV7 RxNE=1(收到一个字节后RxNE置1) ,判断DR寄存器有数据
    if(I2C->SR1 & 0x40)
    {   
   
      
       *pBuffer=I2C->DR;//在接收模式下,收到完整字节后,自动发送ack(提前是CR2 ack位使能,不需要专门CR2 ack位置1)
              //在风驰里面例子,在每次收到字节后加I2C_AcknowledgeConfig(I2C_ACK_CURR)无任何意义,
       pBuffer++;  
       NumByteToRead--;
           
              
         

      
    }
      
  }
   
I2C->CR2 |= 0x04;//为一下循环开始 设置 ack使能,上面 EV7_1设置ack=0发送stop后;需要手动设置ack=1使能,必要在接收数据之前

//切记!切记!很多例子都没有加上这句,包括风驰 的例子!! 不过 他没有加循环! 如果他在循环一次就会出现问题。CR2 ack位其实就是使能的意思!!很多人都理解成需要手动设置!
// 都是软件模拟I2C 搞太多!! 想当然啦!没有仔细看官方的文档!
}






stm8调试硬件I2C心得.pdf

169.74 KB

沙发
Startthejourn| | 2014-3-5 16:58 | 只看该作者
顶下  楼主有玩过STM8s103 IIC没  遇到问题了

使用特权

评论回复
板凳
FAQ| | 2014-3-5 17:03 | 只看该作者
直接复制STM32的程序,改改就行了。

使用特权

评论回复
地板
bigwudan|  楼主 | 2014-3-5 22:35 | 只看该作者
Startthejourn 发表于 2014-3-5 16:58
顶下  楼主有玩过STM8s103 IIC没  遇到问题了

啥子问题!

使用特权

评论回复
5
hubaixdl123| | 2015-5-1 19:56 | 只看该作者
本帖最后由 hubaixdl123 于 2015-5-1 22:32 编辑

LZ,请教你一个问题。
我用风驰的MMA745的程序,这个程序读写MA7455时没有问题,我将程序改成了MPU6050的读写程序,写MPU6050的寄存器的时候,没有问题,但是一进入读程序,BUSY一直为1,所以只能读一次,第二次的时候,由于BUSY为1,就无法再读下去了。我将库改到了IO口,还是一样,在用IO口的方式下,读寄存器,跟踪下去,到Soft_I2C_Stop()的时候,设SDA为输出,SDA=1时,在ODR中,SDA位变成了1,但是在IDR中,SDA位还是0,说明输出为0,所以BUSY=1不会改变。
以上的问题,1.可能是在读的过程序中,什么参数没有设置好?
                  2.SMT8的IO口驱动电流不够?我将IO口改为其它IO口也一样。
                  3.进入程序后,我多次读MPU6050的WHO MA I,第一次正确,后面有时会读出错误的数,如0,64等,4次可以正确读出一次正确的值,此时BUSY=0;可能是程序的延时不正确?                                                  4.在写模式下没有正确释放总线?



mpu60502.part1.rar

900 KB

mpu60502.part2.rar

392.97 KB

使用特权

评论回复
6
csust_omega| | 2015-5-1 23:27 | 只看该作者
hubaixdl123 发表于 2015-5-1 19:56
LZ,请教你一个问题。
我用风驰的MMA745的程序,这个程序读写MA7455时没有问题,我将程序改成了MPU6050的读 ...

只能读一次,说明读了一次后没有释I2C总线,导致I2C总线一直处于忙的状态,是不是读完后没有发停止位?

使用特权

评论回复
7
hubaixdl123| | 2015-5-2 00:49 | 只看该作者
本帖最后由 hubaixdl123 于 2015-5-2 00:51 编辑

有发停止位。停止位在WRITE时正常,但是到了READ时就不正常 了。一直读WHO MA I,四次正常一次。很有可能是程序有某个地方不正确。国弄了两天了,没有LPC+KEIL稳定。参考LZ的程序也是一样。(谢谢你的回复)。

使用特权

评论回复
8
maoyanf| | 2015-5-3 10:51 | 只看该作者
FAQ 发表于 2014-3-5 17:03
直接复制STM32的程序,改改就行了。

楼主stm8例程复制一般是不大好用的,官方例程有些问题,尤其是中断向量

使用特权

评论回复
9
hubaixdl123| | 2015-5-3 16:20 | 只看该作者
同一个I2C上挂了一下MA7455,拆了就好了。弄了几天,开发板出拆坏了。

使用特权

评论回复
10
小浣熊| | 2015-5-3 22:10 | 只看该作者
谢谢楼主分享自己的经验啊。。

使用特权

评论回复
11
HORSE7812| | 2015-5-4 09:08 | 只看该作者
mark

使用特权

评论回复
12
1316014468| | 2015-5-4 11:09 | 只看该作者
谢谢楼主分享。。。

使用特权

评论回复
13
aaa1125456| | 2015-5-14 17:20 | 只看该作者
mark

使用特权

评论回复
14
stvoe| | 2015-7-5 09:52 | 只看该作者
非常感谢楼主分享。
我在stm8s005k6上调试mpu6050的I2C处于一直检测忙状态,不知啥原因。
初始化代码:
#define I2C_DEFAULT_SPEED 100000

        CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
        I2C_DeInit();
        CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, ENABLE);
        I2C_Init(I2C_DEFAULT_SPEED, 0xA0, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, 16);

检测状态测试代码:

        while(I2C_GetFlagStatus( I2C_FLAG_BUSBUSY))
        {
                CP_TRACE("I2C_GetFlagStatus bus busy.");
        }

检测时一直处于busy状态,换了不同参数都不行,不知道什么原因导致的。我是菜鸟啊

使用特权

评论回复
15
lee1111211| | 2015-8-2 21:53 | 只看该作者
mark

使用特权

评论回复
16
eliswee| | 2015-9-26 11:08 | 只看该作者
一开始就卡在总线忙检测上了,啥原因呀??

使用特权

评论回复
17
734774645| | 2015-9-27 14:59 | 只看该作者
停止位在WRITE时正常,但是到了READ时就不正常 了

使用特权

评论回复
18
爱好学习者| | 2015-9-28 11:28 | 只看该作者
我的IIC也是出现了,只可以读一次的问题,在读第二次的时候,就无法读到数据了,我是使用两个STM8的MCU通信

使用特权

评论回复
19
dswkl11| | 2016-3-1 14:36 | 只看该作者
楼主,我把你的Read_8816() 函数 替换了风驰那个 I2C_EEPROM_ReadBuffer(),也不行啊,连读都读不出来。。。

使用特权

评论回复
20
土豆泥吃货| | 2016-3-9 17:16 | 只看该作者
楼主你好,我用的您上面的那个程序读数据,调试通过,但是没有读出数据,而且在第二次调用读函数时,就又会卡在检测busy那里,您知道是什么原因吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

7

帖子

0

粉丝