本帖最后由 tinnu 于 2021-2-15 23:55 编辑
使用的是轮询的例程例程修改的IIC读写程序。
(一)引脚
arduino引脚上的IIC是PB8、PB9,属于复用功能。
例程使用的PB6、PB7是默认的IIC1,复用映射需要额外使能复用功能:
RCC_APB2PeriphClockCmd( RCC_APB2PERIPH_AFIO , ENABLE);
GPIO_PinsRemapConfig(GPIO_Remap_I2C1,ENABLE);
(二)使能IIC功能
/* I2C configuration */
I2C_InitStructure.I2C_Mode = I2C_Mode_I2CDevice;
I2C_InitStructure.I2C_FmDutyCycle = I2C_FmDutyCycle_2_1;
I2C_InitStructure.I2C_OwnAddr1 = I2C_SLAVE_ADDRESS7;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AddrMode = I2C_AddrMode_7bit;
I2C_InitStructure.I2C_BitRate = I2C_SPEED;
/* I2C Peripheral Enable */
I2C_Cmd(I2C_PORT, ENABLE);
/* Apply I2C configuration after enabling it */
I2C_Init(I2C_PORT, &I2C_InitStructure);
对着例程照搬就行。
(三)器件
IIC器件采用MPU9250,一个九轴传感器,八位器件地址0xD0,WHO AM I位 0x75,数据为0x71.
(四)写IIC
写的方法很简单,例程照搬即可:
I2C_StatusType I2C_Master_Transmit(I2C_Type* I2Cx, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
/* Wait until BUSY flag is reset */
if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_BUSYF, SET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
{
return I2C_ERROR_STEP_1;
}
/* Disable Pos */
I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Current);
/* Send START condition */
I2C_GenerateSTART(I2Cx, ENABLE);
/* Wait until SB flag is set */
if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_STARTF, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_2;
}
/* Send slave address for write */
I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Transmit);
/* Wait until ADDR flag is set */
if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_ADDRF, RESET, I2C_EVT_CHECK_ACKFAIL, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_3;
}
/* Clear ADDR flag */
I2C_ClearADDRFlag(I2Cx);
while(Size > 0)
{
/* Wait until TDE flag is set */
if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_TDE, RESET, I2C_EVT_CHECK_ACKFAIL, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_4;
}
/* Write data to DR */
I2C_SendData(I2Cx, (*pData++));
Size--;
}
/* Wait until BTF flag is set */
if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_BTFF, RESET, I2C_EVT_CHECK_ACKFAIL, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_5;
}
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_OK;
}
写入效果:
(五)读效果
雅特力的IIC在读IIC方面有一个比较特殊的处理,会预先读两位,可以通过配置CTL1寄存器第11位阻止预读取。
这里先不处理预读取的问题。
I2C_StatusType I2C_Master_Rec2(I2C_Type* I2Cx, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
/* Wait until BUSY flag is reset */
if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_BUSYF, SET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
{
return I2C_ERROR_STEP_1;
}
/* Disable Pos */
I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Current);
/* Send START condition */
I2C_GenerateSTART(I2Cx, ENABLE);
/* Wait until SB flag is set */
if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_STARTF, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_2;
}
/* Send slave address for write */
I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Receive);
/* Wait until ADDR flag is set */
if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_ADDRF, RESET, I2C_EVT_CHECK_ACKFAIL, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_3;
}
/* Clear ADDR flag */
I2C_ClearADDRFlag(I2Cx);
while(Size > 0)
{
/* Wait until TDE flag is set */
if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_RDNE, RESET, I2C_EVT_CHECK_ACKFAIL, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_4;
}
/* Write data to DR */
(*pData++) = I2C_ReceiveData(I2Cx);
Size--;
}
if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_BTFF, RESET, I2C_EVT_CHECK_ACKFAIL, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_5;
}
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
/* Disable Address Acknowledge */
I2C_AcknowledgeConfig(I2Cx, DISABLE);
return I2C_OK;
}
读取一个位的效果:
I2C_Master_Rec2(I2C_PORT, I2C_SLAVE_ADDRESS7, tx_buf, 1, 1000);
但是读取多个位的时候,则会出现把总线钳住不释放的现象:
I2C_Master_Rec2(I2C_PORT, I2C_SLAVE_ADDRESS7, tx_buf, 2, 1000);
并且总线被钳住之后,硬件复位是无法释放总线的,也就是第一次出错后,在不断电的情况下,即便复位,下一次程序重新运行,重新初始化,依旧是总线忙的状态,无法写也无法读。
main.zip
(2.24 KB)
|
|