硬件IIC使用问题汇总
使用stm32f4硬件IIC与外置商用触控芯片进行通讯,当有触控数据时,将触控数据读出来。
-
使用IIC进行通讯要注意从机地址,发送的地址是左移后加上读写位的地址还是原来的单纯的7位地址
-
stm32硬件IIC关于100K与400K的配置不同点主要是在I2C_TRISE与I2C_CCR两个寄存器的配置上
//400K 的I2C时序配置I2C1->CR2 = 42; // 42MHz时钟 (根据实际时钟调整) I2C1->TRISE = 13; // 300nsI2C1->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;//复位IIC1I2C1->CR1&=~(1<<15);
- MCU作为主机时,不开启禁止时钟延长
// I2C1->CR1 |= I2C_CR1_NOSTRETCH; // 禁止时钟延长
- 硬件IIC很注重通讯时序,如果通讯过程中被打断容易造成卡死等问题,所以通讯过程中要加处理措施,硬件IIC复位这种。
附:
- 硬件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==1RCC->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;//复位IIC1I2C1->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; // 300nsI2C1->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==1I2C1->CR2|=1<<11; //开启I2C发送DMAI2C1->CR2|=1<<12; //设置DMA传输最后一位关闭应答#endif// 5. 清除所有标志I2C1->SR1 = 0;// 6. 使能I2CI2C1->CR1 |= I2C_CR1_PE;
}
- 通讯过程中出现问题I2C复位代码
/*
当出现错误或锁定状态后,可使用此位重新初始化外设。例如,如果 BUSY 位已置 1 但
因母线干扰而不能复位,则可使用 SWRST 位退出此状态。
*/
void i2c_software_reset(void)
{// 1. 禁用I2CI2C1->CR1 &= ~(1<<0);// 2. 强制复位I2C(清除所有寄存器状态)I2C1->CR1 |= 1<<15; // SWRST:软件复位 (Software reset) delay_ms(10);I2C1->CR1 &= ~(1<<15); // 清除复位// 3. 重新初始化I2Cinit_i2c();// 4. 重新初始化DMA#if I2C_DMA_TX_EN||I2C_DMA_RX_ENreinit_DMA1_S5C1(touch_data1, 66);#endif
}