IIC工作模式时序分析

IIC工作模式时序分析

此处利用IO口模拟IIC通信过程中的时序,IIC由一条数据线进行收发数据,因此IIC是半双工的。
image

通信过程

在IIC通信过程SDA存在两种模式(接收模式和发送模式),发送或接受一个字节(器件的7个bit+1个bit方向(1 - 读方向,0 - 写方向)),以下面器件为例:
image

模式配置

  1. 当SDA为接入模式接收了1字节数据后在第九个时钟脉冲期间就要变成输出模式发送ask
  2. 当SDA为输出模式发送了1字节数据后在第九个时钟脉冲期间就要变成输入模式检测是否收到ask
  3. 因此SDA需配置两个模式而SCL模拟时序只需配置输出模式
#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_?)

IIC的SCL配置

/**
  * @name:	IIC_SCLConfig
  * @brief  	IIC的SCL配置
  * @param  	void
  * @retval 	void
  * @date 	2024/09/10
  * @note   	补充 注意 说明
  */
void IIC_SCLConfig()
{
    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);
}

IIC的SDA配置

/**
  * @name:	IIC_SDAConfig
  * @brief  	IIC的SCL配置
  * @param  	
		@GPIO_Mode
  * @retval 	void
  * @date 	2024/09/10
  * @note   	补充 注意 说明
  */
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的空闲状态

image

/**
  * @name:	IIC_Config
  * @brief  	IIC的初始化
  * @param  	
		@GPIO_Mode
  * @retval 	void
  * @date 	2024/09/10
  * @note   	补充 注意 说明
  */
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的开始信号

image

/**
  * @name:	IIC_Start
  * @brief  	IIC的开始信号
  * @param  	void
  * @retval 	void
  * @date 	2024/09/10
  * @note   	补充 注意 说明
  */
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);
}

IIC的发送字节

image

/**
  * @name:	IIC_SendByte
  * @brief  	IIC的发送字节
  * @param  	
		@Byte
  * @retval 	void
  * @date 	2024/09/10
  * @note   	补充 注意 说明
  */
void IIC_SendByte(uint8_t Byte)   //1011 0110
{
     //1.设置SDA为输出模式
    IIC_SDAConfig(GPIO_Mode_OUT);

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

    //2.循环发送8次,每次发送一个bit  遵循MSB 高位先出
    for(int i=0;i<8;i++)
    {
        SDA_SET(1);
        delay_us(5);
        //3.判断待发送的字节的最高位  ???? ???? & 1000 0000
        if( Byte & 0x80 )
        {
            SDA_SET(1);
        }
        else
            SDA_SET(0);

        Byte <<= 1;
        delay_us(5);

        SDA_SET(0);
        delay_us(5);
    }
}

IIC的接收字节

image

/**
  * @name:	IIC_RecvByte
  * @brief  	IIC的接受字节
  * @param  	void
  * @retval 	uint8_t 
  * @date 	2024/09/10
  * @note   	补充 注意 说明
  */
uint8_t IIC_RecvByte(void)
{
	uint8_t i=0;
	uint8_t data =0;

	//保证SDA引脚为输入模式
	IIC_SDAConfig(GPIO_Mode_IN);

	SCL_SET(0);
	delay_us(5);


	for(i=0;i<8;i++)
	{
		//时钟线拉高,数据有效
		SCL_SET(1);
		delay_us(5);

		data <<=1;
		data |= SDA_READ;
		delay_us(5);


		//时钟线拉低,保持占用总线,总线是忙状态
		SCL_SET(0);
		delay_us(5);

	}
}

IIC的判断从机是否应答

image

/**
  * @name:	IIC_IsSlaveACK
  * @brief  	IIC的判断从机是否应答
  * @param  	void
  * @retval 	bool
  * @date 	2024/09/10
  * @note   	补充 注意 说明
  */
bool  IIC_IsSlaveACK(void)
{
	bool ack;

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

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

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

	//5.把SCL引脚电平拉低
	SCL_SET(0);
	delay_us(5);

	return ack;
}

IIC的收到从机数据发送应答

image

/**
  * @name:	IIC_MasterACK
  * @brief  	IIC的收到从机数据发送应答
  * @param  	void
  * @retval 	void
  * @date 	2024/09/10
  * @note   	补充 注意 说明
  */
void IIC_MasterACK(void) 
{
   	 // 1.设置SDA引脚为输出模式
    	IIC_SDAConfig(GPIO_Mode_OUT);

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

	// 3.设置SDA为高电平,表示应答
       	SDA_SET(1);
       	delay_us(5);

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

IIC的停止信号

image

/**
  * @name:	IIC_Stop
  * @brief  	IIC的停止信号
  * @param  	void
  * @retval 	void
  * @date 	2024/09/10
  * @note   	补充 注意 说明
  */
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);

}
posted @ 2024-09-10 19:47  luxiaolim  阅读(509)  评论(0)    收藏  举报