大不列颠呆毛狼184 2024-03-01 15:36 采纳率: 66.7%
浏览 16

STM32F4硬件IIC无法正常使用

在使用STM32F4单片机的硬件iic时,无法发送数据帧,在调试追踪中发现发送函数一直卡在等待START信号发送的while循环中,是因为我的配置代码有遗漏没写的东西吗?请问有人可以指导一下吗?

void I2C_SendData7(I2C_TypeDef* I2Cx, uint8_t deviceAddress, uint8_t registerAddress, uint8_t* data, uint8_t dataSize) {
    u8 i;
    // 等待直到I2C空闲
    while (I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));

    // 生成START信号
    I2C_GenerateSTART(I2Cx, ENABLE);

    // 等待直到START信号被发送
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));

    // 发送设备地址和写入位
    I2C_Send7bitAddress(I2Cx, deviceAddress, I2C_Direction_Transmitter);

    // 等待直到设备地址被发送,并且被ACK
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));

    // 发送寄存器地址
    I2C_SendData(I2Cx, registerAddress);

    // 等待直到寄存器地址被发送,并且被ACK
    while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));

    // 发送数据
    for ( i = 0; i < dataSize; i++) {
        I2C_SendData(I2Cx, data[i]);
        // 等待直到数据被发送,并且被ACK
        while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
    }

    // 生成STOP信号
    I2C_GenerateSTOP(I2Cx, ENABLE);
}
    
    

//初始化IIC
void I2C3_Init(void)
{
      GPIO_InitTypeDef GPIO_InitStruct;
        I2C_InitTypeDef I2C_InitStruct;
        NVIC_InitTypeDef NVIC_InitStructure;

// 使能GPIOA和GPIOC时钟
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOC, ENABLE);

        // 配置PA8引脚
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
        GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // 复用功能模式
        GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; // 开漏输出
        GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // 上拉
        GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStruct);

        // 配置PC9引脚
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
        GPIO_Init(GPIOC, &GPIO_InitStruct);
    
        // 配置PA8引脚的复用功能为I2C功能
        GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_I2C3);

        // 配置PC9引脚的复用功能为I2C功能
        GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_I2C3);

         

        // 使能I2C3时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C3, ENABLE);

        // 配置I2C外设
        I2C_InitStruct.I2C_ClockSpeed = 100000; // 设置通信速率为100kHz
        I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; // I2C模式
        I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50%占空比
        I2C_InitStruct.I2C_OwnAddress1 = 0x00; // 主机地址,这里设置为0x00
        I2C_InitStruct.I2C_Ack = I2C_Ack_Enable; // 使能应答
        I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // 7位地址模式
        I2C_Init(I2C3, &I2C_InitStruct);
      I2C_ITConfig(I2C3, I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF, ENABLE);   
        // 使能I2C外设
        I2C_Cmd(I2C3, ENABLE);
  
        // Configure the I2C event priority
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
        NVIC_InitStructure.NVIC_IRQChannel                   = I2C3_EV_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;       //抢占优先级1
        NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;       //响应优先级0 不行换1试试
        NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
        NVIC_Init(&NVIC_InitStructure);

  }

  • 写回答

3条回答 默认 最新

  • Kwan的解忧杂货铺 Java领域优质创作者 2024-03-01 15:36
    关注

    大不列颠呆毛狼184 下午好🌅🌅🌅
    本答案参考通义千问

    看起来你的代码中I2C初始化和发送数据的逻辑基本正确,但确实存在一些可能的问题。这里有几个可能需要检查的地方:

    1. 确认时钟配置:确保I2C3的时钟已正确配置。检查RCC_APB1PeriphClockCmd函数是否正确设置了I2C3时钟(RCC_APB1Periph_I2C3)。

    2. 复用功能配置:确认PA8和PC9引脚是否已经配置为I2C3的SCL和SDA线。检查GPIO_PinAFConfig函数是否正确设置了GPIOA和GPIOC的引脚功能。

    3. 中断优先级设置NVIC_InitStructure.NVIC_IRQChannelSubPriority可能需要调整。有些设备或板子可能需要不同的优先级才能正确接收中断。尝试将它设置为1(最高优先级)看看是否有改变。

    4. 硬件问题:确认你的硬件连接没有问题,包括电源、地线、SCL和SDA线是否正确连接,以及I2C设备是否正确上电并且地址设置正确。

    5. 调试中断:检查I2C_IT_EVT中断是否启用,如果未启用,设备可能不会响应START信号。在I2C_Init函数中添加这一行:

      I2C_ITConfig(I2C3, I2C_IT_EVT | I2C_IT_BUF, ENABLE);
      
    6. 错误处理:在发送数据时,添加一个超时机制,以防无限等待。例如,可以增加一个计数器并在一定次数后强制停止等待。

    根据以上建议,修改你的代码如下:

    void I2C3_Init(void)
    {
        ... // 其他代码保持不变
    
        // 增加超时处理
        uint16_t timeout = 100; // 设置一个合理的超时计数
        while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT) && timeout-- > 0) {}
    
        // 其他代码...
    }
    
    void I2C_SendData7(...)
    {
        ... // 其他代码保持不变
    
        // 在发送数据时增加超时处理
        for (i = 0; i < dataSize; i++) {
            if (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED) && timeout-- > 0) {
                // 如果超时,强制停止等待
                break;
            }
            I2C_SendData(I2Cx, data[i]);
        }
    
        ... // 其他代码...
    }
    

    这样,如果在等待期间没有接收到预期的中断事件,函数会跳出并继续执行。如果问题仍然存在,可能需要进一步检查硬件或者使用示波器检查I2C信号是否正确。

    评论

报告相同问题?

问题事件

  • 创建了问题 3月1日

悬赏问题

  • ¥15 在不同的执行界面调用同一个页面
  • ¥20 基于51单片机的数字频率计
  • ¥50 M3T长焦相机如何标定以及正射影像拼接问题
  • ¥15 keepalived的虚拟VIP地址 ping -s 发包测试,只能通过1472字节以下的数据包(相关搜索:静态路由)
  • ¥20 关于#stm32#的问题:STM32串口发送问题,偶校验(even),发送5A 41 FB 20.烧录程序后发现串口助手读到的是5A 41 7B A0
  • ¥15 C++map释放不掉
  • ¥15 Mabatis查询数据
  • ¥15 想知道lingo目标函数中求和公式上标是变量情况如何求解
  • ¥15 关于E22-400T22S的LORA模块的通信问题
  • ¥15 求用二阶有源低通滤波将3khz方波转为正弦波的电路