stm32f4xx HAL lib & PCF8457AT - 写入无响应
stm32f4xx HAL lib & PCF8457AT - no response to write
我有 stm32f4-discovery 套件,我想尝试 i/o hd44870 LCD 扩展器。我在 hi2c3 硬件上有 PCF8574AT link to io example like mine 8 位扩展器,其中 i2c 地址为 0x3f(由 i2c 扫描仪检查)。对于 c/c++,请在 Eclipse 环境中使用 HAL 库。好的,看看代码。
首先我初始化 i2c3 - 就像 SCL 上的数据表 100kHz:
static void MX_I2C3_Init(void)
{
hi2c3.Instance = I2C3;
hi2c3.Init.ClockSpeed = 100000;
hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c3.Init.OwnAddress1 = 0;
hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c3.Init.OwnAddress2 = 0;
hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
然后尝试将数据发送到 I/O 扩展器。但在此之前,我检查 i/o 是否可以使用:
result = HAL_I2C_IsDeviceReady(&hi2c3,0x3f , 2, 2);
if (result == HAL_BUSY)
{
HD44780_Puts(6, 1, "busy");
}else{
HD44780_Puts(6, 1, "ready");
uint8_t data_io = 0xff;
HAL_I2C_Master_Transmit(&hi2c3, 0x3f, data_io, 1, 100);
}
在同一个扩展器上没有任何变化。有什么想法是错的还是 i/0 扩展器坏了?
我对HAL驱动不太了解,真的没用过HAL。但是我接触过pcf8574 IO扩展器。 正如你所说,你已经用扫描仪检查过了,如果你得到地址,线路和设备都没有问题。由于我不是 I2C 和 HAL 库方面的专家,我将展示我的 I2C 驱动程序,它依赖于 STM32 标准外设驱动程序,并且适用于 PCF8574 和各种 I2C 设备。有一个例子,片段(阻塞模式,不是基于 irq 的):
检查IO是否不忙
while(I2C_GetFlagStatus(&I2Cx, I2C_FLAG_BUSY) == SET){
if((timeout--) == 0) return -ETIMEDOUT;
}
生成开始条件并设置写入条件(写入模式的地址)。
I2C_TransferHandling(&I2Cx, dev_addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Write);
while(I2C_GetFlagStatus(&I2Cx, I2C_ISR_TXIS) == RESET){
if((timeout--) == 0) return -ENODEV;
}
现在你可以发送数据字节(这是你的IO状态),这个函数直接写入I2C TX(收发器)寄存器:
I2C_SendData(&I2Cx, reg_addr);
while(I2C_GetFlagStatus(&I2Cx, I2C_ISR_TC) == RESET){
if((timeout--) == 0) return -EIO;
}
生成读取条件,然后从 PCF8574 读取数据,数据应该与刚写入的数据相同(如果没有切换 IO 扩展器)。基本上你可以读取字节或更多字节(取决于设备)。在您的情况下,PCF8574(8bit) 仅提供 1 个字节。
I2C_TransferHandling(dev->channel,dev_addr, len, I2C_AutoEnd_Mode,I2C_Generate_Start_Read);
size_t i;
for(i=0;i<len;i++){
timeout = I2C_TIMEOUT;
while(I2C_GetFlagStatus(dev->channel, I2C_ISR_RXNE) == RESET){
if((timeout--) == 0) return -EIO;
}
data[i] = I2C_ReceiveData(dev->channel);
}
您可以继续RW操作,或者等到设备自动停止在线转换:
while(I2C_GetFlagStatus(&I2Cx, I2C_FLAG_STOPF) == RESET){
if((timeout--) == 0) return -EIO;
}
I2C_ClearFlag(&I2Cx, I2C_ICR_STOPCF);
此步骤将写入和读取数据。不管怎样,这个芯片有一些棘手的逻辑,它比看起来更简单 like.Actually 它的工作原理就像简单的输出一样。外部输入仅触发 PCF8574 引脚,仅此而已,输入模式无需特殊配置。对于输入监视器肯定使用 PCF8574 INT 引脚,PCF8574 将触发 INT 引脚。
例如:
如果你想要输入引脚,而不是简单地将引脚设置为逻辑零。并监控 INT 引脚,如果输入发生变化,INT 引脚将被触发,您应该通过 I2C 读取数据。
对于输出低只写零。
并且对于 OUTPUT 高设置逻辑真。
您正在使用 HAL,因此您必须阅读 HAL_I2C_Master_Transmit 函数内部发生的情况。不要忘记地址是 7 位,地址的第一个字节还包括 R/W condition.First 字节 bit0 是 R/W 位。所以你应该处理它。
例如定义:
#define PCF8574_WRITE_ADRESS (0x40) /*for writing to chip*/
#define PCF8574_READ_ADRESS ((0x40)|0x01) /*for reading chip*/
以下是一些链接:
i2c explanations
希望这有助于理解和解决您的问题。:)
谢谢,布尔金
我发现了明显的错误。 HAL 库不 i2c_address << 1 。 I/YOU 必须在代码中输入不相同的结果!
HAL_I2C_Master_Transmit(&hi2c3, (0x3f<<1), data_io, 1, 100);
或
$define i2c_address_write (0x3f <<1 )
HAL_I2C_Master_Transmit(&hi2c3, i2c_address_write , data_io, 1, 100);
阅读:
$define i2c_address_read ((0x3f <<1) | 0x01)
HAL_I2C_Master_Transmit(&hi2c3, i2c_address_read , data_io, 1, 100);
我有 stm32f4-discovery 套件,我想尝试 i/o hd44870 LCD 扩展器。我在 hi2c3 硬件上有 PCF8574AT link to io example like mine 8 位扩展器,其中 i2c 地址为 0x3f(由 i2c 扫描仪检查)。对于 c/c++,请在 Eclipse 环境中使用 HAL 库。好的,看看代码。
首先我初始化 i2c3 - 就像 SCL 上的数据表 100kHz:
static void MX_I2C3_Init(void)
{
hi2c3.Instance = I2C3;
hi2c3.Init.ClockSpeed = 100000;
hi2c3.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c3.Init.OwnAddress1 = 0;
hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c3.Init.OwnAddress2 = 0;
hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c3) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
然后尝试将数据发送到 I/O 扩展器。但在此之前,我检查 i/o 是否可以使用:
result = HAL_I2C_IsDeviceReady(&hi2c3,0x3f , 2, 2);
if (result == HAL_BUSY)
{
HD44780_Puts(6, 1, "busy");
}else{
HD44780_Puts(6, 1, "ready");
uint8_t data_io = 0xff;
HAL_I2C_Master_Transmit(&hi2c3, 0x3f, data_io, 1, 100);
}
在同一个扩展器上没有任何变化。有什么想法是错的还是 i/0 扩展器坏了?
我对HAL驱动不太了解,真的没用过HAL。但是我接触过pcf8574 IO扩展器。 正如你所说,你已经用扫描仪检查过了,如果你得到地址,线路和设备都没有问题。由于我不是 I2C 和 HAL 库方面的专家,我将展示我的 I2C 驱动程序,它依赖于 STM32 标准外设驱动程序,并且适用于 PCF8574 和各种 I2C 设备。有一个例子,片段(阻塞模式,不是基于 irq 的):
检查IO是否不忙
while(I2C_GetFlagStatus(&I2Cx, I2C_FLAG_BUSY) == SET){ if((timeout--) == 0) return -ETIMEDOUT;
}
生成开始条件并设置写入条件(写入模式的地址)。
I2C_TransferHandling(&I2Cx, dev_addr, 1, I2C_SoftEnd_Mode, I2C_Generate_Start_Write); while(I2C_GetFlagStatus(&I2Cx, I2C_ISR_TXIS) == RESET){ if((timeout--) == 0) return -ENODEV; }
现在你可以发送数据字节(这是你的IO状态),这个函数直接写入I2C TX(收发器)寄存器:
I2C_SendData(&I2Cx, reg_addr); while(I2C_GetFlagStatus(&I2Cx, I2C_ISR_TC) == RESET){ if((timeout--) == 0) return -EIO; }
生成读取条件,然后从 PCF8574 读取数据,数据应该与刚写入的数据相同(如果没有切换 IO 扩展器)。基本上你可以读取字节或更多字节(取决于设备)。在您的情况下,PCF8574(8bit) 仅提供 1 个字节。
I2C_TransferHandling(dev->channel,dev_addr, len, I2C_AutoEnd_Mode,I2C_Generate_Start_Read); size_t i; for(i=0;i<len;i++){ timeout = I2C_TIMEOUT; while(I2C_GetFlagStatus(dev->channel, I2C_ISR_RXNE) == RESET){ if((timeout--) == 0) return -EIO; } data[i] = I2C_ReceiveData(dev->channel); }
您可以继续RW操作,或者等到设备自动停止在线转换:
while(I2C_GetFlagStatus(&I2Cx, I2C_FLAG_STOPF) == RESET){ if((timeout--) == 0) return -EIO; } I2C_ClearFlag(&I2Cx, I2C_ICR_STOPCF);
此步骤将写入和读取数据。不管怎样,这个芯片有一些棘手的逻辑,它比看起来更简单 like.Actually 它的工作原理就像简单的输出一样。外部输入仅触发 PCF8574 引脚,仅此而已,输入模式无需特殊配置。对于输入监视器肯定使用 PCF8574 INT 引脚,PCF8574 将触发 INT 引脚。
例如:
如果你想要输入引脚,而不是简单地将引脚设置为逻辑零。并监控 INT 引脚,如果输入发生变化,INT 引脚将被触发,您应该通过 I2C 读取数据。
对于输出低只写零。
并且对于 OUTPUT 高设置逻辑真。
您正在使用 HAL,因此您必须阅读 HAL_I2C_Master_Transmit 函数内部发生的情况。不要忘记地址是 7 位,地址的第一个字节还包括 R/W condition.First 字节 bit0 是 R/W 位。所以你应该处理它。
例如定义:
#define PCF8574_WRITE_ADRESS (0x40) /*for writing to chip*/
#define PCF8574_READ_ADRESS ((0x40)|0x01) /*for reading chip*/
以下是一些链接: i2c explanations
希望这有助于理解和解决您的问题。:)
谢谢,布尔金
我发现了明显的错误。 HAL 库不 i2c_address << 1 。 I/YOU 必须在代码中输入不相同的结果!
HAL_I2C_Master_Transmit(&hi2c3, (0x3f<<1), data_io, 1, 100);
或
$define i2c_address_write (0x3f <<1 )
HAL_I2C_Master_Transmit(&hi2c3, i2c_address_write , data_io, 1, 100);
阅读:
$define i2c_address_read ((0x3f <<1) | 0x01)
HAL_I2C_Master_Transmit(&hi2c3, i2c_address_read , data_io, 1, 100);