hujjj 发表于 2019-9-18 15:32:10

使用HAL库硬件I2C时如何设置器件地址?

    我使用的模块是包含了DS1307的AT24C32两个I2C通讯的芯片,开始准备启用硬件I2C,但测试了多天都没有成功,后来只要改为GPIO模拟I2C才成功驱动这两个芯片。现在我仍想继续尝试用硬件I2C,但一直不知道如何在操作前设定器件的地址,我使用的是HAL库,在此请各位指教,谢谢!

ldptest 发表于 2019-9-18 17:20:23

是指设置从地址码?
/* I2C1 init function */
void MX_I2C1_Init(void)
{

hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
    Error_Handler();
}

}



还是访问器件的地址?
HAL_I2C_Mem_Write(&hi2c1,ADDRESS,DC,I2C_MEMADD_SIZE_8BIT,&Byte,1,I2C_TIMEOUT);

hujjj 发表于 2019-9-18 17:39:52

谢谢回复!是从器件的地址。
那是不是每次读写不同的器件之前都要调用I2C_Init()函数?

morphlings2014 发表于 2019-9-19 09:30:35

使用库函数读写的时候就能设置地址,不需要初始化那里设置,HAL_I2C_Mem_Read(i2c_handler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length, 1000);可以看到第二哥参数是设备地址,第三个就是寄存器地址。

hujjj 发表于 2019-9-19 09:57:35

morphlings2014 发表于 2019-9-19 09:30
使用库函数读写的时候就能设置地址,不需要初始化那里设置,HAL_I2C_Mem_Read(i2c_handler, Addr, (uint16_ ...

谢谢指教,在再试试看。

发表于 2019-9-19 11:19:12

参考代码如下,我测试没有问题的。DS1307
         uint8_t data1,data;      
         uint8_t ch;

         ch = 0x00;

         if(HAL_I2C_Master_Transmit(&hi2c1,0xD0,(uint8_t*)&ch,1,10000) != HAL_OK)
         {
                   return;
         }

         if(HAL_I2C_Master_Receive(&hi2c1,0xD0,data1,7,10000) != HAL_OK)
         {
                   return;
         }      

hujjj 发表于 2019-9-19 11:55:18

    按照四楼老师的提示使用HAL_I2C_Mem_Read()函数似乎可以读出数据了,但不知为何,读出的第一个数据没有问题,而后面的数据则不正确,还在继续测试中。下面是读数据时的时序图:
    发出器件地址和内存地址的时序是正确的



    连续读入了7个字节的数据


    但读入的数据却不同于DS1307内存数据,DS1307中有时间和日期数据,而读出的却只是1或0.


    这是读连续7个字节的时序图



    读写DS1307的函数如下:
/******************************************************************************************
* 函数名称: DS1307_I2C_Read()
* 功能说明: 读DS1307的日历数据,并转换为各自的变量值
* 输    入: 无
* 输    出: 0 = 成功从DS1307获取数据>0 = 从DS1307获取数据过程中出现错误
******************************************************************************************/
void DS1307_I2C_Read(void)
{
    while (HAL_I2C_Mem_Read(&hi2c1,0x00D0,0,I2C_MEMADD_SIZE_8BIT,(uint8_t*)DS_Buff,7,10000) != HAL_OK)
// while (HAL_I2C_Master_Receive(&hi2c1, 0, (uint8_t *)DS_Buff, 7, 10000) != HAL_OK)
    {
      if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
      {
            LCD_write_ASCII(0,3,1,(uint8_t *)"DS_Read_Error!");
      }
    }
    second = ((DS_Buff&0x70)>>4)*10 + (DS_Buff&0x0F);//秒,屏蔽秒的第7位的标志
minute = ((DS_Buff&0x70)>>4)*10 + (DS_Buff&0x0F);//分(取低7位)
hour = ((DS_Buff&0x30)>>4)*10 + (DS_Buff&0x0F);//时(取低5位)
week = (DS_Buff&0x07);                              //周(取低3位)
    day = ((DS_Buff&0x30)>>4)*10 + (DS_Buff&0x0F);   //日(取低6位)
    month = ((DS_Buff&0x10)>>4)*10 + (DS_Buff&0x0F); //月(取低5位)
year = 2000 + (DS_Buff>>4)*10 + (DS_Buff&0x0F);//年
}
/******************************************************************************************
* 函数名称: DS1307_I2C_Write()
* 功能说明: 将当前的日历数据写入DS1307
* 输    入: 无
* 输    出: 0 = 成功写入数据>0 = DS1307写入数据过程中出现错误
******************************************************************************************/
void DS1307_I2C_Write(void)
{
    uint8_t temp;
    DS_Buff = 0;                      //秒
    temp = ((minute/10)<<4|(minute%10));
    DS_Buff = temp;                   //分
    temp = ((hour/10)<<4|(hour%10));
    DS_Buff = temp;                   //时
    DS_Buff = week;                   //星期
    temp = ((day/10)<<4|(day%10));
    DS_Buff = temp;                   //日
    temp = ((month/10)<<4|(month%10));
    DS_Buff = temp;                   //月
    temp = ((year%100)/10<<4|(year%10));
    DS_Buff = temp;                   //年
    while (HAL_I2C_Mem_Write(&hi2c1,0x00D0,0,I2C_MEMADD_SIZE_8BIT,(uint8_t*)DS_Buff,7,10000) != HAL_OK)
//    while (HAL_I2C_Master_Transmit(&hi2c1, 0, (uint8_t *)DS_Buff, 7, 10000) != HAL_OK)
    {
      if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
      {
            LCD_write_ASCII(0,3,1,(uint8_t *)"DS_Write_Erro!");
//   return 2;
      }
    }
// return 0;
}


toofree 发表于 2019-9-19 12:50:07

从图上看,读时序似乎没有问题。
你看一下你的写时序逻辑是什么要样的吧

hujjj 发表于 2019-9-19 14:31:43

安 发表于 2019-9-19 11:19
参考代码如下,我测试没有问题的。DS1307
         uint8_t data1,data;      
         uint8_t c ...

    按照您的代码示例,确实能够对DS1307进行读写操作,不知为何我原来用这个函数时,这个参数却出现在第2个字节,第1个字节是0xF0(见下图):

    第一个字节是0xF0,第二个字节才是地址参数0xD0,以至于我以为这个地址参数是要读取的内存地址呢。



    下面是一个完整的读出7个字节内容的时序:



    这是放大后的时序:



    这是读出的内容:



    从目前测试的情况看,用HAL_I2C_Receive()和HAL_I2C_Transmit()函数对DS1307进行操作是没有问题了,但用HAL_I2C_Mem_Read()和HAL_I2C_Mem_Write()函数对DS1307进行操作却还存在问题,还需要继续测试排错。
    另外有个疑问:用HAL_I2C_Receive()和HAL_I2C_Transmit()函数是不是只能从0字节开始读写操作,不能对某个指定的字节进行操作?


hujjj 发表于 2019-9-19 14:42:23

下面是分别用HAL_I2C_Receive()和HAL_I2C_Transmit()函数,HAL_I2C_Mem_Read()和HAL_I2C_Mem_Write()函数对DS1307进行操作的函数:

/******************************************************************************************
* 函数名称: DS1307_I2C_Transmit(uint8_t size)
* 功能说明: 写数据到DS1307
* 输    入: size 数据个数(要写入数据在全局数组DS_Buff中)
* 输    出: 0 = 成功写入1 = 写数据过程中出现错误
******************************************************************************************/
uint8_t DS1307_I2C_Transmit(uint8_t size)
{
   
        DS1307_DataToBuff();      //将时间及日期数据转换到Buff数组中
        if(HAL_I2C_Master_Transmit(&hi2c1,0xD0,(uint8_t*)DS_Buff ,size,10000) != HAL_OK)
    {
      return 1;
    }
        return 0;
}

/******************************************************************************************
* 函数名称: DS1307_I2C_Receive(uint8_t size)
* 功能说明: 从DS1307读出数据
* 输    入: size 数据个数(读出的数据在全局数组DS_Buff中)
* 输    出: 0 = 成功读出1 = 读数据过程中出现错误
******************************************************************************************/
uint8_t DS1307_I2C_Receive(uint8_t size)
{
    if(HAL_I2C_Master_Receive(&hi2c1,0xD0,DS_Buff,7,10000) != HAL_OK)
    {
      return 1;
    }
    if(size == 1){               //检查DS1307是否需要初始化
                if(DS_Buff>127){
            year = 2019;
                  month = 9;
                  day = 18;
                  week = 3;
                  hour = 9;
                  minute = 1;
               
            DS1307_DataToBuff();
                        DS1307_I2C_Transmit(8);
                }
        }
        else{
          DS1307_BuffToData();
    }
        return 0;       
}
               
/******************************************************************************************
* 函数名称: DS1307_I2C_Read()
* 功能说明: 读DS1307的日历数据,并转换为各自的变量值
* 输    入: 无
* 输    出: 0 = 成功从DS1307获取数据>0 = 从DS1307获取数据过程中出现错误
******************************************************************************************/
void DS1307_I2C_Read(void)
{

    while (HAL_I2C_Mem_Read(&hi2c1,0x00D0,0,I2C_MEMADD_SIZE_8BIT,(uint8_t*)DS_Buff,7,10000) != HAL_OK)
//        while (HAL_I2C_Master_Receive(&hi2c1, 0, (uint8_t *)DS_Buff, 7, 10000) != HAL_OK)
    {
      if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
      {
            LCD_write_ASCII(0,3,1,(uint8_t *)"DS_Read_Error!");
      }
    }

        DS1307_BuffToData();
       
}

/******************************************************************************************
* 函数名称: DS1307_I2C_Write()
* 功能说明: 将当前的日历数据写入DS1307
* 输    入: 无
* 输    出: 0 = 成功写入数据>0 = DS1307写入数据过程中出现错误
******************************************************************************************/
void DS1307_I2C_Write(void)
{
    DS1307_DataToBuff();         //时间日期数据转换存入Buff数组中
       
    while (HAL_I2C_Mem_Write(&hi2c1,0x00D0,0,I2C_MEMADD_SIZE_8BIT,(uint8_t*)DS_Buff,7,10000) != HAL_OK)
//    while (HAL_I2C_Master_Transmit(&hi2c1, 0, (uint8_t *)DS_Buff, 7, 10000) != HAL_OK)
    {
      if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
      {
            LCD_write_ASCII(0,3,1,(uint8_t *)"DS_Write_Erro!");
//                        return 2;
      }
    }
//        return 0;
}

/******************************************************************************************
* 函数名称: DS1307_Chick()
* 功能说明: 检查DS1307是否已经初始化,若未初始化则用特写日期进行初始化
* 输    入: 无
* 输    出: 无
******************************************************************************************/
void DS1307_Check(void)
{

//        LCD_write_ASCII(0,3,1,(uint8_t *)"Check_Begin...");
    while (HAL_I2C_Mem_Read(&hi2c1,0x00D0,0,I2C_MEMADD_SIZE_8BIT,(uint8_t*)DS_Buff,1,10000) != HAL_OK)
    while (HAL_I2C_Master_Receive(&hi2c1, 0, (uint8_t *)DS_Buff, 1, 10000) != HAL_OK)
    {
      if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
                {
                  LCD_write_ASCII(0,3,1,(uint8_t *)"CheckReadErro!");
                }
        }
        LCD_write_value(0,4,3,0,1,DS_Buff);
        if(DS_Buff> 127){
      year = 2019;
                month = 9;
                day = 18;
                week = 3;
                hour = 9;
                minute = 1;
               
      DS1307_DataToBuff();

      while (HAL_I2C_Mem_Write(&hi2c1,0x00D0,0,I2C_MEMADD_SIZE_8BIT,(uint8_t*)DS_Buff,1,10000) != HAL_OK)
//      while (HAL_I2C_Master_Transmit(&hi2c1, 0, (uint8_t *)DS_Buff, 8, 10000) != HAL_OK)
      {
            if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
            {
                LCD_write_ASCII(0,3,1,(uint8_t *)"CheckWriteErr!");
            }
      }
        }
}

/******************************************************************************************
* 函数名称: DS1307_DataToBuff()
* 功能说明: 将时间日期变量数据转换到数组Buff中
* 输    入: 无
* 输    出: 无
******************************************************************************************/
void DS1307_DataToBuff(void)
{
    uint8_t temp;
        DS_Buff = 0;                  //秒
    temp = ((minute/10)<<4|(minute%10));
    DS_Buff = temp;               //分
    temp = ((hour/10)<<4|(hour%10));
    DS_Buff = temp;               //时

    DS_Buff = week;               //星期

    temp = ((day/10)<<4|(day%10));
    DS_Buff = temp;               //日
    temp = ((month/10)<<4|(month%10));
    DS_Buff = temp;               //月
    temp = ((year%100)/10<<4|(year%10));
    DS_Buff = temp;               //年
    DS_Buff = 32;               //0010 0000 = 允许按1Hz输出方波
}


/******************************************************************************************
* 函数名称: DS1307_BuffToData()
* 功能说明: 将数组Buff数据转换到时间日期变量中
* 输    入: 无
* 输    出: 无
******************************************************************************************/
void DS1307_BuffToData(void)
{
    second = ((DS_Buff&0x70)>>4)*10 + (DS_Buff&0x0F);//秒,屏蔽秒的第7位的标志
    minute = ((DS_Buff&0x70)>>4)*10 + (DS_Buff&0x0F);//分(取低7位)
           hour = ((DS_Buff&0x30)>>4)*10 + (DS_Buff&0x0F);//时(取低5位)
           week = (DS_Buff&0x07);                              //周(取低3位)
    day = ((DS_Buff&0x30)>>4)*10 + (DS_Buff&0x0F);   //日(取低6位)
    month = ((DS_Buff&0x10)>>4)*10 + (DS_Buff&0x0F); //月(取低5位)
    year = 2000 + (DS_Buff>>4)*10 + (DS_Buff&0x0F);//年
}

页: [1] 2
查看完整版本: 使用HAL库硬件I2C时如何设置器件地址?