使用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复位这种。
附:
- 硬件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;
}
- 通讯过程中出现问题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
}