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 的):

  1. 检查IO是否不忙

    while(I2C_GetFlagStatus(&I2Cx, I2C_FLAG_BUSY) == SET){
    if((timeout--) == 0) return -ETIMEDOUT;
    

    }

  2. 生成开始条件并设置写入条件(写入模式的地址)。

    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;
    }
    
  3. 现在你可以发送数据字节(这是你的IO状态),这个函数直接写入I2C TX(收发器)寄存器:

    I2C_SendData(&I2Cx, reg_addr);
    while(I2C_GetFlagStatus(&I2Cx, I2C_ISR_TC) == RESET){
        if((timeout--) == 0) return -EIO;
    }
    
  4. 生成读取条件,然后从 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);
    }
    
  5. 您可以继续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

this may help

Really nice guide!

希望这有助于理解和解决您的问题。:)

谢谢,布尔金

我发现了明显的错误。 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);