你的浏览器版本过低,可能导致网站不能正常访问!为了你能正常使用网站功能,请使用这些浏览器。
举报
morphlings2014 发表于 2019-9-19 09:30 使用库函数读写的时候就能设置地址,不需要初始化那里设置,HAL_I2C_Mem_Read(i2c_handler, Addr, (uint16_ ...
安 发表于 2019-9-19 11:19 参考代码如下,我测试没有问题的。DS1307 uint8_t data1[7],data[8]; uint8_t c ...
安 发表于 2019-9-19 15:37 可以选择地址的。第一次先写入硬件地址和读取地址。第二次直接读取数据长度即可。MEM这个函数我没有仔细的 ...
发出器件地址和内存地址的时序是正确的
连续读入了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[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;
}
这是用HAL_I2C_Mem_Read()函数读取的日历数据(年份和时间):
/* 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);
那是不是每次读写不同的器件之前都要调用I2C_Init()函数?
谢谢指教,在再试试看。
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;
}
你看一下你的写时序逻辑是什么要样的吧
按照您的代码示例,确实能够对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字节开始读写操作,不能对某个指定的字节进行操作?
我再测试看看。