1.I2C总线由SCL和SDA组成
SCL:串行时钟线,负责传送时钟信号
SDA:串行数据线,负责传送数据
连接:将主机与从机的SCL和SDA分别对应连接,并且还要将SCL和SDA分别接一个上拉电阻(阻值一般位4.7K)
注意:SCL和SDA都应该是开漏输出(实现逻辑线与)
2.开漏输出与推挽输出的区别
开漏输出:P-MOS保持断开,只控制N-MOS的通断(输出1为高阻抗,0为低电压)
推挽输出:均可控制P-MOS和N-MOS通过控制P-MOS和N-MOS来输出高电压和低电压(输出1为高电压,0为低电压)
3.逻辑线与
线与1:开漏模式下,向所有IO引脚写,输出高阻抗,相当于开路,I2C(SCL,SDA相同)总线悬空,但由于上拉电阻,总线电压会被拉高,则输出高电压1
线与0:当其中任意一个引脚写0,其他引脚保持1,写1的引脚输出高阻抗,写0的引脚输出低电压,总线通过写0的引脚接地,则上拉电阻无效,此时总线输出低电压0
4.通信过程
I2C是总线结构其主机与从机会共用SCL与SDA这两条线
过程:
<1>起始位:在SCL高电压时,向SDA发送下降沿
在数据传送开始前,,总线处与空闲状态,由于上拉电阻的存在,SCL和SDA处于高电压,此时主机只要把SDA拉低,就可以发送一个起始位.
<2>寻址:主机向总线上发送从机地址(从机地址有7位和10位)
当SCL为高电平时读取SDA上的数据,读取7个周期即为从机地址(7位从机地址),并在发送地址后发送一位读/位(0-写,1-读),发送从机地址后主机释放SDA线,等待从机应答,从机通过将SDA拉低来发送一个应答信号(这个应答信号称位ACK),表示应答从机发送ADK来告诉主机寻址成功,反之无应答称位NAK(主要原因有:1.地址填错,要寻址的从机不存在 2.要寻址从机正忙,来不及回复ACK 3.从机故障)
<3>数据传输:通过主机发送读写位不同,数据传输方向不同
I2C以字节为单位传输数据,每次可以传输多个字节
写:主机向从机发送8个比特也就是一个字节,然后释放SDA,等待从机确认接收,从机通过把SDA拉低来发送ACK,来表示收到.
读:与写相同,从机向主机发送数据,主机回复ACK每读一个字节.
<4>停止位:在SCL高电压时,向SDA发送上升沿
在数据传输接收后,主机需要向总线上发送一个停止位
5.OLED I2C通信
<1>I2C接口配置
<2>接线
<3>代码部分
向从机写数据:HAL_I2C_Master_Transmit(&hi2c1,0x78,conmmads,sizeof(conmmads),HAL_MAX_DELAY);
&hi2c1:I2C句柄指针
0x78:从机地址
conmmads:发送数组
sizeof(conmmads):发送数据数量,以字节为单位
HAL_MAX_DELAY:超时时间,单位ms
返回值:HAL_OK-成功
向从机读数据:HAL_I2C_Master_Receive(&hi2c1,0x78,&dataRcvd,1,HAL_MAX_DELAY); 参数与上面相同
6.C语言移位判断操作
通过判断接受的数据第6位是否为0,表示屏幕是否开启成功
(dataRcvd&(0x01<<6)) == 0
因为接收数据为uiint8_t,所以我只需要判断第位是否为0.对此我们需要按位与判断的方法来判断第6为是否为0
移位操作
首先,移位操作是一种位操作,可以将数字的二进制表示向左或向右移动。在C语言中,左移操作用 << 表示。例如:
0x01 << 6 的意思是把数 0x01(二进制表示为 00000001)向左移动6位,变成 01000000,十六进制表示为 0x40。
按位与操作
按位与操作用符号 & 表示,它将两个数的二进制表示进行比较,只有当两个相应的位都为1时,结果位才为1,否则为0。比如:
假设 dataRcvd 的值是 0x42,二进制表示为 01000010。
使用掩码 0x40(01000000)来与 dataRcvd 进行按位与操作:
01000010 (dataRcvd)
& 01000000 (0x40)
----------
01000000
判断特定位
在这个操作后,我们得到的结果是 0x40。这意味着:
如果特定位(在这个例子中是第7位)为1,那么与操作后的结果将是掩码本身(0x40),因为只有这一位在两个操作数中都是1。
如果这一位为0,那么无论 dataRcvd 的其他位如何,与操作后的结果将是 0x00,因为掩码在该位是1,而 dataRcvd 在该位是0,1和0的与操作结果是0。
因此,检查 dataRcvd & 0x40 的结果是否等于0,实际上是在检查 dataRcvd 的第7位是否为0。如果是0,结果就是0;如果不是0,结果就不是0。
7.完整代码
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
uint8_t conmmads[] = {0x00,0x8d,0x14,0xaf,0xa5}; //0xa5让屏幕全亮
uint8_t dataRcvd;
HAL_I2C_Master_Transmit(&hi2c1,0x78,conmmads,sizeof(conmmads),HAL_MAX_DELAY); //向从机写数据
HAL_I2C_Master_Receive(&hi2c1,0x78,&dataRcvd,1,HAL_MAX_DELAY); //向从机读数据
if((dataRcvd&(0x01<<6)) == 0){
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
}
else{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
8.总结
I2C总线结构可实现单片机与多个从机实现通信,通过SCL与SDA高低电平的变化来获取数据,极大提高单片机交换数据的效率.
I2C在单片机上的优势:
简化的硬件接口:I2C协议仅使用两条线——串行数据线(SDA)和串行时钟线(SCL)进行通信。这种简化的接口降低了硬件设计的复杂性,尤其是在连接多个设备时,可以显著减少系统内的连线数量。
支持多主机和多从机:I2C允许多个主设备和多个从设备共存在同一总线上。这提供了灵活的设计选择,使得多个控制器可以管理或访问同一总线上的多个设备。
内置错误检测功能:I2C通信包括应答机制,该机制允许主设备检测到数据是否已被从设备成功接收。此外,总线的物理层设计支持冲突检测和仲裁,保证即使在多主机环境下也能可靠通信。
可扩展和灵活的通信速度:I2C支持多种通信速度,如标准模式(100 kHz)、快速模式(400 kHz)、快速模式+(1 MHz)和高速模式(3.4 MHz)。这使得设计者可以根据需要选择合适的速度,以优化性能和功耗。
地址编码简单:每个I2C设备都有一个唯一的地址。在多设备系统中,可以通过简单的硬件配置(例如,通过设定引脚状态)来设置这些地址,使得设备识别和数据路由变得容易。
功耗较低:由于其简洁的总线活动和有效的数据传输机制,I2C在低功耗应用中表现出色,这对于电池供电的或追求能效的系统尤其重要。
适用于短距离通信:虽然I2C主要适用于板级通信,但它非常适合在单片机和各种传感器、存储器之间的近距离通信.
学习教程:b站up铁头山羊