stm32——I2C,0.96寸oled屏

发布于:2025-09-11 ⋅ 阅读:(18) ⋅ 点赞:(0)

一、内部集成电路概述

基本概念

内部集成电路(Inter Integrated Circuit)的简称叫做IIC或者I2C,是一种简单的、半双工同步通信的串行通信接口,IIC总线是上世纪80年代(1982年)由飞利浦公司设计出来,当时的目的是为了给MCU和外围芯片提供更简单的交互方式。

引脚说明

IIC总线只需要两根引脚就可以实现通信,一根是数据线(SDA Serial Data),另一根是时钟线(SCL Serial Clock),所有通过IIC接口通信的外围器件都挂载在IIC总线上,通过这种机制就可以实现多机通信。
在这里插入图片描述

可以看到,外围器件的时钟线和数据线都是挂载在IIC总线(由主控芯片提供),并且在空闲状态下所有器件的时钟线(SCL)和数据线(SDA)都被总线的上拉电阻拉高,这样就可以把SDA引脚和SCL引脚设置为开漏模式即可,好处是防止短路。

思考:如果IIC总线上挂载了多个外围器件,如何与某一个器件进行单独通信? 器件地址

通信速率

可以看到IIC总线支持不同的通信速率,但是一般常用的标准速率100KHZ,但是有的外围器件可以支持高达400KHZ的通信速率,而由于IIC总线是半双工通信,所以同一时刻只能接收或者发送,也就是说IIC总线一般是为了控制,不适合作为大量数据传输的接口。

在这里插入图片描述

通信过程
在这里插入图片描述

(1)空闲状态
在这里插入图片描述

(2)开始信号

在这里插入图片描述

(3)数据传输

在这里插入图片描述

(4)应答信号

在这里插入图片描述

(5)停止信号

在这里插入图片描述

器件地址

在这里插入图片描述

程序设计

由于MCU内部只有3个IIC接口,所以想要使用IIC接口控制传感器,就必须使用IIC接口对应的引脚,把引脚复用为IIC功能,并且对硬件IIC进行配置和初始化,为了提高可移植性,用户也可以采用IO口模拟IIC时序的方案来控制传感器,该方案不受硬件的限制。

/************************************************************
	利用IO口模拟IIC时序,需要使用2个IO口(SDA和SCL)

	SCL时钟线只能由主器件进行控制,所以SCL引脚必须为输出模式
	SDA数据线,在主器件发送数据时,SDA引脚为输出模式
	SDA数据线,在主器件接收数据时,SDA引脚为输入模式

************************************************************/

#define  SDA_SET(n)  (n) ? GPIO_SetBits(GPIO?,GPIO_Pin_?) : GPIO_ResetBits(GPIO?,GPIO_Pin_?) 
#define  SCL_SET(n)  (n) ? GPIO_SetBits(GPIO?,GPIO_Pin_?) : GPIO_ResetBits(GPIO?,GPIO_Pin_?) 

#define  SDA_READ    GPIO_ReadInputDataBit(GPIO?,GPIO_Pin_?)


//SCL引脚设置
void IIC_SCLConfig(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	//打开GPIO端口的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIO?,ENABLE);

	//SCL
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode_OUT;					//输出模式
	GPIO_InitStructure.GPIO_Speed 	= GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType 	= GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd  	= GPIO_PuPd_DOWN;
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_?;
	GPIO_Init(GPIO?, &GPIO_InitStructure);
}

//SDA引脚设置
void IIC_SDAConfig(GPIOMode_TypeDef GPIO_Mode)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	//打开GPIO端口的时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIO?,ENABLE);

	//SCL
	GPIO_InitStructure.GPIO_Mode 	= GPIO_Mode;					
	GPIO_InitStructure.GPIO_Speed 	= GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType 	= GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd  	= GPIO_PuPd_DOWN;
	GPIO_InitStructure.GPIO_Pin 	= GPIO_Pin_?;
	GPIO_Init(GPIO?, &GPIO_InitStructure);
}

//IIC的初始化
void IIC_Config(void)
{
	//1.设置SDA和SCL为输出模式
	IIC_SCLConfig();
	IIC_SDAConfig(GPIO_Mode_OUT);

	//2.确保SDA和SCL处于空闲状态
	SDA_SET(1);
	SCL_SET(1);
	delay_us(5);
}



//IIC的开始信号
void IIC_Start(void)
{
	//1.设置SDA引脚为输出模式
	IIC_SDAConfig(GPIO_Mode_OUT);

	//2.确保SDA和SCL处于空闲状态
	SDA_SET(1);
	SCL_SET(1);
	delay_us(5);

	//3.把SDA引脚电平拉低
	SDA_SET(0);
	delay_us(5);

	//4.把SCL引脚电平拉低,此时准备数据
	SCL_SET(0);
	delay_us(5);
	
}

//IIC的发送字节
void IIC_SendByte(uint8_t Byte)   //1011 0110
{
	//1.设置SDA引脚为输出模式
	IIC_SDAConfig(GPIO_Mode_OUT);

	//2.把SCL引脚电平拉低,此时主机准备数据
	SCL_SET(0);
	delay_us(5);

	//3.循环发送8bit,遵循MSB高位先出
	for(i=0;i<8;i++)
	{
		//4.判断待发送的字节的最高位
		if( Byte & 0x80 )
		{
			SDA_SET(1);
		}
		else
			SDA_SET(0);

		Byte <<= 1;
		delay_us(5);

		//5.把SCL电平拉高,此时从机读取bit
		SCL_SET(1);
		delay_us(5);

		//6.把SCL引脚电平拉低,此时主机准备下一个bit
		SCL_SET(0);
		delay_us(5);
	}
}

//判断从机是否应答
bool  IIC_IsSlaveACK(void)
{
	//1.设置SDA引脚为输入模式
	IIC_SDAConfig(GPIO_Mode_IN);

	//2.把SCL引脚电平拉低,此时为第9个脉冲的低电平,从机准备bit
	SCL_SET(0);
	delay_us(5);

	//3.把SCL引脚电平拉高,此时为第9个脉冲的高电平,主机读取状态
	SCL_SET(1);
	delay_us(5);

	//4.主机读取状态  1 表示未应答  0  表示已应答
	if(SDA_READ)
		return false;
	else
		return true;

}


//IIC读取字节
uint8_t IIC_ReadByte(void)
{
	uint8_t i = 0,data = 0;

	//1.设置SDA引脚为输入模式
	IIC_SDAConfig(GPIO_Mode_IN);

	//2.把SCL引脚电平拉低,此时从机准备数据
	SCL_SET(0);
	delay_us(5);

	//3.循环读取8bit,遵循MSB高位先出
	for (i = 0; i < 8; ++i)
	{
		//4.把SCL电平拉高,此时主机读取bit
		SCL_SET(1);
		delay_us(5);

		//5.主机读取bit
		data <<= 1;
		data |= SDA_READ;
		delay_us(5);

		//6.把SCL引脚电平拉低,此时从机准备下一个bit数据
		SCL_SET(0);
		delay_us(5);
	}

	//7.返回结果
	return data;
}

//ack=1 表示不应答  ack=0 表示要应答
void IIC_MasterACK(uint8_t ack)
{
	//1.设置SDA引脚为输出模式
	IIC_SDAConfig(GPIO_Mode_OUT);

	//2.把SCL引脚电平拉低,此时主机准备
	SCL_SET(0);
	delay_us(5);

	//3.判断ack的状态,从而对SDA操作
	if(ack)
		SDA_SET(1);
	else
		SDA_SET(0);

	delay_us(5);

	//4.把SCL电平拉高,此时从机读取bit
	SCL_SET(1);
	delay_us(5);
}

//IIC的停止信号
void IIC_Stop(void)
{
	//1.设置SDA引脚为输出模式
	IIC_SDAConfig(GPIO_Mode_OUT);

	//2.设置SDA和SCL均为低电平
	SDA_SET(0);
	SCL_SET(0);
	delay_us(5);

	//3.把SCL电平拉高
	SCL_SET(1);
	delay_us(5);

	//4.把SDA电平拉高
	SDA_SET(1);
	delay_us(5);
}

int main()
{
	IIC_Config();

}

二、IC接口的0.96寸OLED屏

驱动芯片

在这里插入图片描述

器件地址

在这里插入图片描述


网站公告

今日签到

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