STM32 I2C(hal库) I2C:I2C和串口不同只有一条线可以用来传递数据SDA另一条用于提供同步时钟脉冲的时钟线SCL并且为半双工通信同一时刻只能进行一个方向的通信因此采用主从模式一台为主机另一台多台为从机IC2读取OLED屏幕数据具体原理可以看我的标准库中的I2C接下来我们就直接配置CubeMX先到Connectivity点击I2C然后选择I2C模式参数配置默认就好然后就可以看到右边PB6和PB7配置为I2C_SLC和I2C_SDA随后按照这个参数进行配置I2C不过初始化配置默认就是这个所以也不用改这是OLED屏幕指令0x00 是命令流0x8d,0x14 使能电荷泵0xaf 打开屏幕的开关0xa5 使屏幕全亮先从机也就是OLED屏幕发送这些指令就能开启对应的操作这是I2C的发送数据和读写数据的函数最后是配置函数uint8_tCommands[]{0x00,0x8d,0x14,0xaf,0xa5};HAL_I2C_Master_Transmit(hi2c1,0x78,Commands,sizeof(Commands),HAL_MAX_DELAY);uint8_tDataOled;HAL_I2C_Master_Receive(hi2c1,0x78,DataOled,1,HAL_MAX_DELAY);if((DataOled(0x016))0){HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_RESET);}else{HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_SET);}I2C中断模式和DMA模式简单状态机其实I2C中断模式和DMA模式与串口中断模式和DMA模式本质是一样的所以不做过多赘述直接开始CubeMX配置首先打开NVIC中断向量一个是I2C事件中断一个是I2C错误中断本节主要讲事件中断随后就是发送和接收函数HAL_I2C_Master_Transmit_IT(hi2c1,0x78,Commands,sizeof(Commands));HAL_I2C_Master_Receive_IT(hi2c1,0x78,DataOled,1);从串口小节我们就了解到这个中断和DMA模式是非阻塞模式所以这些操作一瞬间就完成了不需要等待所以就不需要等待时间参数HAL_I2C_Master_Transmit_IT(hi2c1,0x78,Commands,sizeof(Commands));uint8_tDataOled;HAL_I2C_Master_Receive_IT(hi2c1,0x78,DataOled,1);if((DataOled(0x016))0){HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_RESET);}else{HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_SET);}因为这个中断和DMA模式是非阻塞模式它们将任务交给外设后就会接着向下执行并不会等到数据的接收和发送完成整个通信流程都交给外设和中断控制通信完成后再通过中断来通知我们所以上面的发送和接受函数只是CPU通知外设进行发起和接受它们并没有完成CUO就会跳到处理判断函数这里这时我们就需要一个简单的状态机来不同的状态下做不同的事这是我们的状态机现在我们就开始配置代码吧main主函数if(OLED_State0){OLED_Start();OLED_State1;}elseif(OLED_State2){OLED_ReceiveData();OLED_State3;}elseif(OLED_State4){LED_Open();}OLED.C函数#includemain.h#includei2c.hvoidOLED_Start(void){staticuint8_tCommands[]{0x00,0x8d,0x14,0xaf,0xae};HAL_I2C_Master_Transmit_IT(hi2c1,0x78,Commands,sizeof(Commands));}uint8_tDataOled;volatileuint8_tOLED_State0;// 0空闲, 1发送中, 2发送完成, 3接收中, 4接收完成volatilevoidOLED_ReceiveData(void){HAL_I2C_Master_Receive_IT(hi2c1,0x78,DataOled,1);}voidLED_Open(void){if((DataOled(0x016))0){HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_RESET);}else{HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_SET);}}//I2C主机发送完成回调函数voidHAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef*hi2c){if(hi2chi2c1){OLED_State2;}}//I2C主机接收完成回调函数voidHAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef*hi2c){if(hi2chi2c1){OLED_State4;}}**这里注意**要在OLED.h中加入extern volatile uint8_t OLED_State; 定义为全局变量最后是DMA模式其实就是在原代码基础上将IT改成DMA就ok了回调函数用的也是同一个这里就不多写了最后总结I2C的相关函数/* 普通I2C接收函数 * 第一个参数是I2C句柄 * 第二个参数是从机地址,8位地址,最后一位为0,函数内部会自动处理最后一位 * 第三个参数是要发送的数据的指针 * 第四个参数是要发送的字节数 * 第五个参数是超时时间 */HAL_I2C_Master_Receive(I2C_HandleTypeDef*hi2c,uint16_tDevAddress,uint8_t*pData,uint16_tSize,uint32_tTimeout);/*参数同上*/HAL_I2C_Master_Transmit(I2C_HandleTypeDef*hi2c,uint16_tDevAddress,uint8_t*pData,uint16_tSize,uint32_tTimeout);//I2C中断模式发送函数HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef*hi2c,uint16_tDevAddress,uint8_t*pData,uint16_tSize);//I2C中断模式接收函数HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef*hi2c,uint16_tDevAddress,uint8_t*pData,uint16_tSize);//I2C主机发送完成回调函数voidHAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef*hi2c);//I2C主机接收完成回调函数voidHAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef*hi2c);