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

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

[复制链接]
老牛洋车 提问时间:2019-9-18 15:32 /
    我使用的模块是包含了DS1307的AT24C32两个I2C通讯的芯片,开始准备启用硬件I2C,但测试了多天都没有成功,后来只要改为GPIO模拟I2C才成功驱动这两个芯片。现在我仍想继续尝试用硬件I2C,但一直不知道如何在操作前设定器件的地址,我使用的是HAL库,在此请各位指教,谢谢!
收藏 评论16 发布时间:2019-9-18 15:32

举报

16个回答
老牛洋车 回答时间:2019-9-19 14:42:23
下面是分别用HAL_I2C_Receive()和HAL_I2C_Transmit()函数,HAL_I2C_Mem_Read()和HAL_I2C_Mem_Write()函数对DS1307进行操作的函数:

  1. /******************************************************************************************
  2. * 函数名称: DS1307_I2C_Transmit(uint8_t size)
  3. * 功能说明: 写数据到DS1307
  4. * 输    入: size 数据个数(要写入数据在全局数组DS_Buff中)
  5. * 输    出: 0 = 成功写入  1 = 写数据过程中出现错误
  6. ******************************************************************************************/
  7. uint8_t DS1307_I2C_Transmit(uint8_t size)
  8. {
  9.    
  10.         DS1307_DataToBuff();      //将时间及日期数据转换到Buff数组中
  11.         if(HAL_I2C_Master_Transmit(&hi2c1,0xD0,(uint8_t*)DS_Buff ,size,10000) != HAL_OK)
  12.     {
  13.         return 1;
  14.     }
  15.         return 0;
  16. }

  17. /******************************************************************************************
  18. * 函数名称: DS1307_I2C_Receive(uint8_t size)
  19. * 功能说明: 从DS1307读出数据
  20. * 输    入: size 数据个数(读出的数据在全局数组DS_Buff中)
  21. * 输    出: 0 = 成功读出  1 = 读数据过程中出现错误
  22. ******************************************************************************************/
  23. uint8_t DS1307_I2C_Receive(uint8_t size)
  24. {
  25.     if(HAL_I2C_Master_Receive(&hi2c1,0xD0,DS_Buff,7,10000) != HAL_OK)
  26.     {
  27.         return 1;
  28.     }
  29.     if(size == 1){               //检查DS1307是否需要初始化
  30.                 if(DS_Buff[0]>127){
  31.             year = 2019;
  32.                     month = 9;
  33.                     day = 18;
  34.                     week = 3;
  35.                     hour = 9;
  36.                     minute = 1;
  37.                
  38.             DS1307_DataToBuff();
  39.                         DS1307_I2C_Transmit(8);
  40.                 }
  41.         }
  42.         else{
  43.             DS1307_BuffToData();
  44.     }
  45.         return 0;       
  46. }
  47.                  
  48. /******************************************************************************************
  49. * 函数名称: DS1307_I2C_Read()
  50. * 功能说明: 读DS1307的日历数据,并转换为各自的变量值
  51. * 输    入: 无
  52. * 输    出: 0 = 成功从DS1307获取数据  >0 = 从DS1307获取数据过程中出现错误
  53. ******************************************************************************************/
  54. void DS1307_I2C_Read(void)
  55. {

  56.     while (HAL_I2C_Mem_Read(&hi2c1,0x00D0,0,I2C_MEMADD_SIZE_8BIT,(uint8_t*)DS_Buff,7,10000) != HAL_OK)
  57. //        while (HAL_I2C_Master_Receive(&hi2c1, 0, (uint8_t *)DS_Buff, 7, 10000) != HAL_OK)
  58.     {
  59.         if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
  60.         {
  61.             LCD_write_ASCII(0,3,1,(uint8_t *)"DS_Read_Error!");
  62.         }
  63.     }

  64.         DS1307_BuffToData();
  65.        
  66. }

  67. /******************************************************************************************
  68. * 函数名称: DS1307_I2C_Write()
  69. * 功能说明: 将当前的日历数据写入DS1307
  70. * 输    入: 无
  71. * 输    出: 0 = 成功写入数据  >0 = DS1307写入数据过程中出现错误
  72. ******************************************************************************************/
  73. void DS1307_I2C_Write(void)
  74. {
  75.     DS1307_DataToBuff();           //时间日期数据转换存入Buff数组中
  76.        
  77.     while (HAL_I2C_Mem_Write(&hi2c1,0x00D0,0,I2C_MEMADD_SIZE_8BIT,(uint8_t*)DS_Buff,7,10000) != HAL_OK)
  78. //    while (HAL_I2C_Master_Transmit(&hi2c1, 0, (uint8_t *)DS_Buff, 7, 10000) != HAL_OK)
  79.     {
  80.         if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
  81.         {
  82.             LCD_write_ASCII(0,3,1,(uint8_t *)"DS_Write_Erro!");
  83. //                        return 2;
  84.         }
  85.     }
  86. //        return 0;
  87. }

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

  96. //        LCD_write_ASCII(0,3,1,(uint8_t *)"Check_Begin...");
  97.     while (HAL_I2C_Mem_Read(&hi2c1,0x00D0,0,I2C_MEMADD_SIZE_8BIT,(uint8_t*)DS_Buff,1,10000) != HAL_OK)
  98.     while (HAL_I2C_Master_Receive(&hi2c1, 0, (uint8_t *)DS_Buff, 1, 10000) != HAL_OK)
  99.     {
  100.         if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
  101.                 {
  102.                     LCD_write_ASCII(0,3,1,(uint8_t *)"CheckReadErro!");
  103.                 }
  104.         }
  105.         LCD_write_value(0,4,3,0,1,DS_Buff[0]);
  106.         if(DS_Buff[0]> 127){
  107.         year = 2019;
  108.                 month = 9;
  109.                 day = 18;
  110.                 week = 3;
  111.                 hour = 9;
  112.                 minute = 1;
  113.                
  114.         DS1307_DataToBuff();

  115.         while (HAL_I2C_Mem_Write(&hi2c1,0x00D0,0,I2C_MEMADD_SIZE_8BIT,(uint8_t*)DS_Buff,1,10000) != HAL_OK)
  116. //        while (HAL_I2C_Master_Transmit(&hi2c1, 0, (uint8_t *)DS_Buff, 8, 10000) != HAL_OK)
  117.         {
  118.             if (HAL_I2C_GetError(&hi2c1) != HAL_I2C_ERROR_AF)
  119.             {
  120.                 LCD_write_ASCII(0,3,1,(uint8_t *)"CheckWriteErr!");
  121.             }
  122.         }
  123.         }
  124. }

  125. /******************************************************************************************
  126. * 函数名称: DS1307_DataToBuff()
  127. * 功能说明: 将时间日期变量数据转换到数组Buff中
  128. * 输    入: 无
  129. * 输    出: 无
  130. ******************************************************************************************/
  131. void DS1307_DataToBuff(void)
  132. {
  133.     uint8_t temp;
  134.         DS_Buff[0] = 0;                  //秒
  135.     temp = ((minute/10)<<4|(minute%10));
  136.     DS_Buff[1] = temp;               //分
  137.     temp = ((hour/10)<<4|(hour%10));
  138.     DS_Buff[2] = temp;               //时

  139.     DS_Buff[3] = week;               //星期

  140.     temp = ((day/10)<<4|(day%10));
  141.     DS_Buff[4] = temp;               //日
  142.     temp = ((month/10)<<4|(month%10));
  143.     DS_Buff[5] = temp;               //月
  144.     temp = ((year%100)/10<<4|(year%10));
  145.     DS_Buff[6] = temp;               //年
  146.     DS_Buff[7] = 32;                 //0010 0000 = 允许按1Hz输出方波
  147. }


  148. /******************************************************************************************
  149. * 函数名称: DS1307_BuffToData()
  150. * 功能说明: 将数组Buff数据转换到时间日期变量中
  151. * 输    入: 无
  152. * 输    出: 无
  153. ******************************************************************************************/
  154. void DS1307_BuffToData(void)
  155. {
  156.     second = ((DS_Buff[0]&0x70)>>4)*10 + (DS_Buff[0]&0x0F);//秒,屏蔽秒的第7位的标志
  157.     minute = ((DS_Buff[1]&0x70)>>4)*10 + (DS_Buff[1]&0x0F);//分(取低7位)
  158.            hour = ((DS_Buff[2]&0x30)>>4)*10 + (DS_Buff[2]&0x0F);  //时(取低5位)
  159.            week = (DS_Buff[3]&0x07);                              //周(取低3位)
  160.     day = ((DS_Buff[4]&0x30)>>4)*10 + (DS_Buff[4]&0x0F);   //日(取低6位)
  161.     month = ((DS_Buff[5]&0x10)>>4)*10 + (DS_Buff[5]&0x0F); //月(取低5位)
  162.     year = 2000 + (DS_Buff[6]>>4)*10 + (DS_Buff[6]&0x0F);  //年
  163. }

复制代码
老牛洋车 回答时间:2019-9-19 11:55:18
    按照四楼老师的提示使用HAL_I2C_Mem_Read()函数似乎可以读出数据了,但不知为何,读出的第一个数据没有问题,而后面的数据则不正确,还在继续测试中。下面是读数据时的时序图:
    发出器件地址和内存地址的时序是正确的
I2C_MEM_Read_00.jpg


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

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

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


    读写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[0]&0x70)>>4)*10 + (DS_Buff[0]&0x0F);//秒,屏蔽秒的第7位的标志
minute = ((DS_Buff[1]&0x70)>>4)*10 + (DS_Buff[1]&0x0F);//分(取低7位)
hour = ((DS_Buff[2]&0x30)>>4)*10 + (DS_Buff[2]&0x0F);  //时(取低5位)
week = (DS_Buff[3]&0x07);                              //周(取低3位)
    day = ((DS_Buff[4]&0x30)>>4)*10 + (DS_Buff[4]&0x0F);   //日(取低6位)
    month = ((DS_Buff[5]&0x10)>>4)*10 + (DS_Buff[5]&0x0F); //月(取低5位)
year = 2000 + (DS_Buff[6]>>4)*10 + (DS_Buff[6]&0x0F);  //年
}
/******************************************************************************************
* 函数名称: DS1307_I2C_Write()
* 功能说明: 将当前的日历数据写入DS1307
* 输    入: 无
* 输    出: 0 = 成功写入数据  >0 = DS1307写入数据过程中出现错误
******************************************************************************************/
void DS1307_I2C_Write(void)
{
    uint8_t temp;
    DS_Buff[0] = 0;                      //秒
    temp = ((minute/10)<<4|(minute%10));
    DS_Buff[1] = temp;                   //分
    temp = ((hour/10)<<4|(hour%10));
    DS_Buff[2] = temp;                   //时
    DS_Buff[3] = week;                   //星期
    temp = ((day/10)<<4|(day%10));
    DS_Buff[4] = temp;                   //日
    temp = ((month/10)<<4|(month%10));
    DS_Buff[5] = temp;                   //月
    temp = ((year%100)/10<<4|(year%10));
    DS_Buff[6] = 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;
}


老牛洋车 回答时间:2019-9-20 10:08:09
    经过测试,使用HAL_I2C_Mem_Write()和HAL_I2C_Mem_Read()函数对DS1307进行读写操作没有问题,而使用HAL_I2C_Transmit()和HAL_I2C_Master_Receive()函数对DS1307进行读写操作却不成功,似乎操作的数据地址不正确。我在测试时按照每分钟读取一次,分别使用不同的函数对同一DS1307器件读取日历数据,用HAL_I2C_Mem_Read()函数能读出正确的日期和时间,而用HAL_I2C_Master_Receive()函数读出的内容却是错误的,应该是读入了其他地址的数据。
    这是用HAL_I2C_Mem_Read()函数读取的日历数据(年份和时间):
I2C_ReadDS1307_0.jpg



    这是月日和时间:

I2C_ReadDS1307_1.jpg



    这是用HAL_I2C_Master_Receive()函数读出年份和时间:

I2C_ReadDS1307_2.jpg



    这是月日和时间:

I2C_ReadDS1307_3.jpg



    我按照版主的提示在读写操作前先写入要读写的地址,然后再进行读写操作,结果仍是不行,看来对用HAL_I2C_Master_Receive()和用HAL_I2C_Master_Transmit()这两个函数还尚未理解和掌握。下面是我测试时的代码:

  1. /******************************************************************************************
  2. * 函数名称: DS1307_I2C_Transmit(uint8_t size)
  3. * 功能说明: 写数据到DS1307
  4. * 输    入: size 数据个数(要写入数据在全局数组DS_Buff中)
  5. * 输    出: 0 = 成功写入  1 = 写数据过程中出现错误
  6. ******************************************************************************************/
  7. uint8_t DS1307_I2C_Transmit(uint8_t size)
  8. {
  9.    
  10.         DS1307_DataToBuff();      //将时间及日期数据转换到Buff数组中
  11.         HAL_I2C_Master_Transmit(&hi2c1,0xD0,0,1,10000);//发送起始地址
  12.        
  13.         if(HAL_I2C_Master_Transmit(&hi2c1,0xD0,(uint8_t*)DS_Buff ,size,10000) != HAL_OK)
  14.     {
  15.         return 1;
  16.     }
  17.         return 0;
  18. }

  19. /******************************************************************************************
  20. * 函数名称: DS1307_I2C_Receive(uint8_t size)
  21. * 功能说明: 从DS1307读出数据
  22. * 输    入: size 数据个数(读出的数据在全局数组DS_Buff中)
  23. * 输    出: 0 = 成功读出  1 = 读数据过程中出现错误
  24. ******************************************************************************************/
  25. uint8_t DS1307_I2C_Receive(uint8_t size)
  26. {
  27.         HAL_I2C_Master_Transmit(&hi2c1,0xD0,0,1,10000);//发送起始地址
  28.        
  29.     if(HAL_I2C_Master_Receive(&hi2c1,0xD0,DS_Buff,7,10000) != HAL_OK)
  30.     {
  31.         return 1;
  32.     }
  33.     if(size == 1){               //检查DS1307是否需要初始化
  34.                 if(DS_Buff[0]>127){
  35.             year = 2019;
  36.                     month = 9;
  37.                     day = 18;
  38.                     week = 3;
  39.                     hour = 9;
  40.                     minute = 1;
  41.                
  42.             DS1307_DataToBuff();
  43.                         DS1307_I2C_Transmit(8);
  44.                 }
  45.         }
  46.         else{
  47.             DS1307_BuffToData();
  48.     }
  49.         return 0;       
  50. }
复制代码



网络孤客 回答时间:2019-9-18 17:20:23
是指设置从地址码? 无标题.jpg
/* 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);
老牛洋车 回答时间:2019-9-18 17:39:52
谢谢回复!是从器件的地址。
那是不是每次读写不同的器件之前都要调用I2C_Init()函数?
chrome777 回答时间:2019-9-19 09:30:35
使用库函数读写的时候就能设置地址,不需要初始化那里设置,HAL_I2C_Mem_Read(i2c_handler, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, Buffer, Length, 1000);可以看到第二哥参数是设备地址,第三个就是寄存器地址。
老牛洋车 回答时间: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[7],data[8];        
         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;
         }      
七哥 回答时间:2019-9-19 12:50:07
从图上看,读时序似乎没有问题。
你看一下你的写时序逻辑是什么要样的吧
老牛洋车 回答时间:2019-9-19 14:31:43
安 发表于 2019-9-19 11:19
参考代码如下,我测试没有问题的。DS1307
         uint8_t data1[7],data[8];        
         uint8_t c ...

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

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


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


    这是放大后的时序:
DS1307_I2C_20.jpg


    这是读出的内容:
DS1307_I2C_21.jpg


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


废鱼 回答时间:2019-9-19 15:37:31
可以选择地址的。第一次先写入硬件地址和读取地址。第二次直接读取数据长度即可。MEM这个函数我没有仔细的研究,我使用的函数操作过程有I2C开始、停止操作。
老牛洋车 回答时间:2019-9-19 17:25:57
安 发表于 2019-9-19 15:37
可以选择地址的。第一次先写入硬件地址和读取地址。第二次直接读取数据长度即可。MEM这个函数我没有仔细的 ...

我再测试看看。
废鱼 回答时间:2019-9-20 10:20:58
我用到的时I2C1,楼主用的和我一样吗?楼主看一下你用的RTC的硬件地址是多少,是否和我的一致。1307读取出来的是BCD码,需要进行数据转换的。I2C操作入口时指针类型,需要注意一下。
老牛洋车 回答时间:2019-9-20 11:09:22
我的DS1307器件地址是0xD0,数据格式是BCD码,数组是定义为uint8_t,目前用HAL_I2C_Mem..函数能够正常读写,而且对AT24C32也能正常读写。但用HAL_I2C_Master..函数则读写出错,很可能是没有操控好读写的地址。
12下一页

所属标签

相似问题

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版