我有stm32f4-discovery工具包,我想尝试用于hd44870 LCD的i / o扩展器。我有一个PCF8574AT link to io example like mine 8位扩展器,其中i2c地址是hi2c3硬件上的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扩展器的任何想法都被打破了?
答案 0 :(得分: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(8位)只提供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);
此步骤将写入和读取数据。无论如何,这个芯片在那里有一些棘手的逻辑,它比看起来更简单。实际上它的工作原理就像输出一样简单。外部输入只触发PCF8574引脚,仅此而已,输入模式无特殊配置。对于确保使用PCF8574 INT引脚的输入监视器,PCF8574将触发INT引脚。
例如:
如果您需要输入引脚,只需将引脚设置为逻辑0即可。并监视INT引脚,如果输入发生变化,INT引脚将被触发,您应该通过I2C读取数据。
对于OUTPUT low,只需写入零。
对于OUTPUT高设置逻辑是真的。
您正在使用HAL,因此您必须阅读 HAL_I2C_Master_Transmit 功能中发生的事情。不要忘记地址是7位,地址的第一个字节也包括R / W条件。第一个字节bit0是R / W位。所以你应该处理它。
例如,使用define:#define PCF8574_WRITE_ADRESS (0x40) /*for writing to chip*/
#define PCF8574_READ_ADRESS ((0x40)|0x01) /*for reading chip*/
以下是一些链接: i2c explanations
希望这有助于理解您的问题并解决它。:)
答案 1 :(得分:0)
谢谢,Bulkin
我发现了明显的错误。 HAL库不是i2c_address&lt;&lt; 1。 我/你必须在代码中加入相同的结果!
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);