zoukankan      html  css  js  c++  java
  • 使用STM8S i2c对TPS65987寄存器进行读写

    上图是TPS65987的i2c读写协议,和标准i2c协议有点出入,不过也不难理解,在读的时候i2c slave在发送数据过来之前会先发送1byte数据表示后面会有几个字节数据过来,在写的时候i2c host要先写1byte数据告诉i2c slave接下来会写几个bytes数据。

     Talk is cheap. Show me the code.

    以下代码是基于STM8S。

    /*******************************************************************************
    **函数名称:void IIC_Read(unsigned char subaddr , unsigned char Byte_addr , unsigned char *buffer)
    **功能描述:向IIC器件读数据
    **入口参数:
              subaddr :  从器件地址
              Byte_addr : 确定从器件写地址的起始地址
              *buffer   : 读数据的缓冲区起始地址
    **输出:无
    *******************************************************************************/
    void TPS65987_IIC_Read(unsigned char subaddr , unsigned char Byte_addr , unsigned char *buffer)
    {
      unsigned char i2csr1;
      unsigned char DataLen;
      
      I2C_CR2_bit.ACK = 1;            //产生应答信号
      
      I2C_CR2_bit.START = 1;    //发送起始信号
      while(I2C_SR1_bit.SB == 0);    //等待起始信号产生
      i2csr1 = I2C_SR1;        //SR1.AF??
      I2C_DR = subaddr;        //发送器件地地址,并清除SB标志位
      while(I2C_SR1_bit.ADDR == 0);    //等待器件地址发送完成
      i2csr1 = I2C_SR1;
      i2csr1 = I2C_SR3;        //读状态寄存器1和状态寄存器3清除发送器件地址标志位
      I2C_DR = Byte_addr;
      while(I2C_SR1_bit.BTF == 0);//等待移位发送器发送完成
      i2csr1 = I2C_SR1;    //清除BIT标志位
      
      //重新发送起始信号
      I2C_CR2_bit.START = 1;//I2C1->CR1 |= I2C_CR1_START;
      while(I2C_SR1_bit.SB == 0);//等待起始信号产生
    
      i2csr1 = I2C_SR1;//SR1.AF??
      I2C_DR = (char)(subaddr | 0x01);    //发送器件地地址,并清除SB标志位
      while(I2C_SR1_bit.ADDR == 0);         //等待器件地址发送完成
      i2csr1 = I2C_SR1;
      i2csr1 = I2C_SR3;            //读状态寄存器1和状态寄存器2清除发送器件地址标志位
      
      while (I2C_SR1_bit.RXNE == 0); //先读取Byte Count到DataLen
      i2csr1 = I2C_SR1;
      DataLen = I2C_DR;
      
      while(DataLen)
      {
        if(DataLen == 1)
        {
            I2C_CR2_bit.ACK = 0;          //最后一个字节不产生应答信号
            I2C_CR2_bit.STOP = 1;         //发送停止信号结束数据传输
        }
    
        while(I2C_SR1_bit.RXNE == 0);
        i2csr1 = I2C_SR1;
    
        *buffer = I2C_DR;    
        buffer++;
        DataLen--;
      }
    }
    /*******************************************************************************
    **函数名称:void IIC_Write(unsigned char subaddr , unsigned char Byte_addr , unsigned char *buffer , unsigned short num)
    **功能描述:向IIC器件写数据
    **入口参数:
              subaddr :  从器件地址
              Byte_addr : 确定器件写地址的起始地址
              *buffer   : 写数据的起址地址
              num                : 要写数据的个数
    **输出:无
    *******************************************************************************/
    void TPS65987_IIC_Write(unsigned char subaddr , unsigned char Byte_addr , unsigned char *buffer , unsigned short num)
    {
        unsigned char i2csr1;
        
        
        //while(I2C1->SR2 & I2C_SR2_BUSY);          //判断I2C模块是否忙
        
        //发送起始信号
        I2C_CR2_bit.START = 1;    
        while(I2C_SR1_bit.SB == 0);    //等待起始信号产生
        i2csr1 = I2C_SR1; //SR1.AF
        I2C_DR = (subaddr);        //发送从器件地址,并清除SB标志位
        while(I2C_SR1_bit.ADDR == 0);    //等待器件地址发送完成
        i2csr1 = I2C_SR1;
        i2csr1 = I2C_SR3;        //读状态寄存器1和状态寄存器3清除发送器件地址标志位
        
    
        I2C_DR = Byte_addr;             //发送从器件存储首地址
    #if 1
        while(I2C_SR1_bit.BTF == 0);  //等待移位发送器发送完成
        i2csr1 = I2C_SR1;          //清除BIT标志位
    #else
        while((I2C_SR1_bit.TXE) == 0);//数据寄存器为空,跳出循环继续运行
        i2csr1 = I2C_SR1;
    #endif
            I2C_DR = (unsigned char)num; //把Byte Count先告诉给TPS65987
            while(I2C_SR1_bit.BTF == 0);//等待移位发送器发送完成
            i2csr1 = I2C_SR1;        //清除BIT标志位
            i2csr1 = I2C_DR;
            
        while(num > 0)
        {
                I2C_DR = *buffer;        //发送器件存储首地址
    
                while(I2C_SR1_bit.BTF == 0);//等待移位发送器发送完成
                i2csr1 = I2C_SR1;        //清除BIT标志位
                i2csr1 = I2C_DR;
                buffer++;
                num--;
        }
        I2C_CR2_bit.STOP = 1;       //发送停止信号结束数据传输
    }

    这样就可以对TPS65987进行读写了。

    上面的i2c读写函数没有加上timeout功能,如果不想在i2c通信不成功时一直阻塞的话,可以在while循环里面加上,例如:

    unsigned int count = 0;
    
    while(I2C_SR1_bit.ADDR == 0)    //等待器件地址发送完成
    {
         if (++count > 6000) { //count大于6000立即返回
             I2C_CR2_bit.STOP = 1;
             return;
         }   
    }    

    注意:

    从Windows下上位机工具也可以进行TPS65987的register读写,TPS65981_2_6_7_8 Application Customization 6.1.1上显示的i2c1地址为0x20, i2c2的地址为0x38;注意0x20/0x38是七位地址位的值,进行i2c读写时的地址要左移一位,即0x20/0x38 << 1等于0x40/0x70。

    如果直接用地址0x20/0x38进行读写会怎么样呢,结果就是地址发过去没收到ACK。下图是用0x38地址去读寄存器值的时候示波器抓到的波形(黄色波形是SCL,粉红色波形是SDA)。

     从波形上看0x38地址发过去是没有ACK的,所以slave地址0x38肯定是错误的了。

    后面用示波器量了一下TPS65981_2_6_7_8 Application Customization 6.1.1上位机软件和TPS65987 EVM进行i2c读写时的波形,发现i2c2的地址发过去的确实是0x70。

  • 相关阅读:
    linux学习17 运维核心技能-Linux系统下用户权限管理
    linux学习16 Linux用户和组管理命令演练和实战应用
    linux学习15 Linux系统用户和组全面讲解
    linux学习14 Linux运维高级系统应用-glob通配及IO重定向
    linux学习13 Linux运维常用文件管理命令及系统变量基础
    linux学习12 bash的常见特性及文本查看命令实战
    linux学习11 Linux基础命令及命令历史
    linux学习10 Linux目录结构和根文件系统全面讲解
    【Hadoop离线基础总结】Hive调优手段
    【Hadoop离线基础总结】Hive的基本操作
  • 原文地址:https://www.cnblogs.com/wanglouxiaozi/p/12419928.html
Copyright © 2011-2022 走看看