硬件IIC使用问题汇总

发布于:2025-08-30 ⋅ 阅读:(12) ⋅ 点赞:(0)

使用stm32f4硬件IIC与外置商用触控芯片进行通讯,当有触控数据时,将触控数据读出来。

  • 使用IIC进行通讯要注意从机地址,发送的地址是左移后加上读写位的地址还是原来的单纯的7位地址

  • stm32硬件IIC关于100K与400K的配置不同点主要是在I2C_TRISE与I2C_CCR两个寄存器的配置上

    //400K 的I2C时序配置
        I2C1->CR2 = 42;           // 42MHz时钟 (根据实际时钟调整)   
        I2C1->TRISE = 13;         // 300ns
    	I2C1->CCR = (1 << 15) // F/S=1 (Fast mode)     400KHz
    	  | (0 << 14) // DUTY=0 (Standard fast mode duty)
    	  | (ccr_value & 0x0FFF); // CCR value = 35
    
    //100K 的I2C时序配置
        I2C1->CR2 = 42;           // 42MHz时钟 (根据实际时钟调整)
        I2C1->TRISE = 43;         // 1000ns (42MHz时)
        I2C1->CCR = 0xD2;         // 100kHz标准模式
    
  • 硬件IIC用到的IO口需要配置为复用开漏输出(按规定不能额外配置下拉了,要不容易实现电平问题)

  • 很重要的一个点是:在配置硬件IIC时,设置完复用开漏输出要配置I2C时序之前记得要复位一下IIC。(有的设备不用复位也能与其进行通讯,有的必须复位否则不好用。)

	I2C1->CR1|=1<<15;//复位IIC1
	I2C1->CR1&=~(1<<15);
  • MCU作为主机时,不开启禁止时钟延长
//    I2C1->CR1 |= I2C_CR1_NOSTRETCH;  // 禁止时钟延长
  • 硬件IIC很注重通讯时序,如果通讯过程中被打断容易造成卡死等问题,所以通讯过程中要加处理措施,硬件IIC复位这种。

附:

  1. 硬件IIC(使用的PB6、PB7)初始化配置代码
void init_i2c(void)
{
    uint16_t ccr_value = 35;
	// 1. 使能时钟
    RCC->APB1ENR |= 1 << 21;  // I2C1时钟
    RCC->AHB1ENR |= 1 << 1;   // GPIOB时钟
	#if I2C_DMA_TX_EN==1||I2C_DMA_RX_EN==1
    RCC->AHB1ENR |= 1 << 21;    // DMA1时钟
	#endif
    // 2. 配置PB6(SCL)/PB7(SDA)为I2C
    // 复位GPIO配置
    GPIOB->MODER &= ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7);
    GPIOB->OTYPER &= ~(GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7);
    GPIOB->AFR[0] &= ~(4 << (6 * 4));
    GPIOB->AFR[0] &= ~(4 << (7 * 4));
	
    // 设置复用功能模式
    GPIOB->MODER |= (2 << (6 * 2)) | (2 << (7 * 2));  // 复用模式
    
    // 高速模式
    GPIOB->OSPEEDR |= (3 << (6 * 2)) | (3 << (7 * 2));  // 高速
    
//	GPIOB->PUPDR |= (2<<(7*2));
	
    // 开漏输出模式
    GPIOB->OTYPER |= (1 << 6) | (1 << 7);
    
    // AF4 (I2C1)
    GPIOB->AFR[0] |= (4 << (6 * 4)) | (4 << (7 * 4));
    
	
	RCC->APB1RSTR|=1<<21; //复位IIC1时钟
	RCC->APB1RSTR&=~(1<<21);//停止复位IIC1时钟

	I2C1->CR1|=1<<15;//复位IIC1
	I2C1->CR1&=~(1<<15);
	delay_us(5);
//	PBout(6) = 1;
//	PBout(7) = 1;
	
    // 3. 配置I2C时序
    I2C1->CR2 = 42;           // 42MHz时钟 (根据实际时钟调整)
//    I2C1->TRISE = 43;         // 1000ns (42MHz时)
    I2C1->TRISE = 13;         // 300ns
	I2C1->CCR = (1 << 15) // F/S=1 (Fast mode)     400KHz
	  | (0 << 14) // DUTY=0 (Standard fast mode duty)
	  | (ccr_value & 0x0FFF); // CCR value = 35

//	I2C1->CCR = 0xD2;         // 100kHz标准模式
    
	// 4. 配置控制寄存器
    I2C1->CR1 = 0;
    I2C1->CR1 &= ~I2C_CR1_POS;  // I2C模式
//    I2C1->CR1 |= I2C_CR1_NOSTRETCH;  // 禁止时钟延长
    
	
	#if I2C_DMA_TX_EN==1||I2C_DMA_RX_EN==1
	I2C1->CR2|=1<<11;	//开启I2C发送DMA
	I2C1->CR2|=1<<12;	//设置DMA传输最后一位关闭应答
	#endif
	
    // 5. 清除所有标志
    I2C1->SR1 = 0;
    
    // 6. 使能I2C
    I2C1->CR1 |= I2C_CR1_PE;
}
  1. 通讯过程中出现问题I2C复位代码
/*
当出现错误或锁定状态后,可使用此位重新初始化外设。例如,如果 BUSY 位已置 1 但    
因母线干扰而不能复位,则可使用 SWRST 位退出此状态。
*/
void i2c_software_reset(void)
{
    // 1. 禁用I2C
    I2C1->CR1 &= ~(1<<0);
    
    // 2. 强制复位I2C(清除所有寄存器状态)
    I2C1->CR1 |= 1<<15;  // SWRST:软件复位 (Software reset)  
	delay_ms(10);
    I2C1->CR1 &= ~(1<<15); // 清除复位
    
    // 3. 重新初始化I2C
    init_i2c();
    
    // 4. 重新初始化DMA
    #if I2C_DMA_TX_EN||I2C_DMA_RX_EN
    reinit_DMA1_S5C1(touch_data1, 66);
    #endif
}

网站公告

今日签到

点亮在社区的每一天
去签到