GPIO引脚 模拟 IIC(软件IIC)

GPIO引脚 模拟 IIC(软件IIC)

IIC总线在传输数据的过程中一共有三种类型信号,分别为:开始信号、结束信号和应答信号。
IIC总线的时序图:
在这里插入图片描述

空闲状态
当IIC总线的数据线SDA和时钟线SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。

起始信号与停止信号
起始信号:当时钟线SCL为高期间,数据线SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号;
停止信号:当时钟线SCL为高期间,数据线SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。
在这里插入图片描述

应答信号
发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。

应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;
应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。

对于反馈有效应答位ACK的要求是:接收器在第9个时钟脉冲之前的低电平期间将数据线SDA拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放数据线SDA,以便主控接收器发送一个停止信号P。

数据有效性
IIC总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定;只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。

即:数据在时钟线SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。
在这里插入图片描述

数据的传达
在IIC总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。

以下是具体的代码

static void sda_mode(uint8_t mode)   ///设置输入或者输出
{
	stc_gpio_cfg_t GPIO_Init;
	
	//使能gpio的时钟门
	Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE);
	
	//输入/输出
	GPIO_Init.enDir = mode;
	GPIO_Init.enOD = GpioOdEnable;                          ///< 开漏输出
	//上拉或者下拉
	GPIO_Init.enPu = GpioPuEnable;
	GPIO_Init.enPd = GpioPdDisable;
	
	Gpio_Init(GpioPortA,GpioPin12,&GPIO_Init);
	
}


void Iic_Start(void)
{
	sda_mode(GPIO_Mode_OUT);	//SDA设置为输出模式
	
	//空闲
	SCL=1;		//SCL脚拉高
	SDA_H;		//SDA脚拉低
	delay10us(1);
	
	SDA_L;		//SDA脚拉低
	delay10us(1);

	//钳住总线 
	SCL=0;		//SCL拉低
}

void Iic_Stop(void)
{
	sda_mode(GPIO_Mode_OUT);//SDA设置为输出模式
	SCL=0;
	SDA_L;
	
	delay10us(1);
	SCL=1;
	
	delay10us(1);
	
	SDA_H;  //总线空闲
}

//等待从机应答信号 1:无效应答 0:有效应答
uint8_t Iic_Wait_Ack(void)
{
	uint8_t ack = 0;
	sda_mode(GPIO_Mode_IN);		//SDA设置为输入模式
	
	SCL=0;
	delay10us(1);
	
	SCL=1;
	
	if(SDA_IN)
	{
		ack = 1;  //无效应答
	}
	else
	{
		ack = 0;  //有效应答
	}
	delay10us(1);
	SCL=0;

	return ack;
}

//编写代码主机发送一位数据 0 或 1
//发送应答信号 0有效应答  1无效应答
void Iic_Send_Ack(uint8_t ack)
{
	sda_mode(GPIO_Mode_OUT);
	
	SCL=0;
	
	if(ack == 1)
	{
		SDA_H;
	}
	if(ack == 0)
	{
		SDA_L;
	}
	
	delay10us(1);
	
	SCL=1;
	delay10us(1);
	SCL=0;
	

}

void Iic_Send_Byte(uint8_t txd)
{
	uint8_t i;
	sda_mode(GPIO_Mode_OUT);

	SCL=0;
	
	for(i=0; i<8; i++)
	{
		//从高往低取出每一位数据
		if(txd & (1<<(7-i)))
		{
			SDA_H;
		}
		else
		{
			SDA_L;
		}
	
		delay10us(1);
		SCL=1;
		delay10us(1);
		SCL=0;
	
	}
	
	
}

uint8_t Iic_Read_Byte()
{
	uint8_t i;
	uint8_t date=0;
	sda_mode(GPIO_Mode_IN);


	
	for(i=0; i<8; i++)
	{
		SCL=1;
		delay10us(1);
		
		
		if(SDA_IN==1)
		{
			date+=1;
		}
		if(i!=7)
			date=date << 1;
		

		
		SCL=0;
		delay10us(1);

	
	}
	return date;
	
	
}

void Write_Bytes(uint8_t addr, uint8_t data)
{
	uint8_t ack;
	//开始信号 
	Iic_Start();
	
	//发送写设备地址
	Iic_Send_Byte(I2C_WADDR);
	ack=Iic_Wait_Ack();
	if(ack == 1)
	{
		return ;
	}
	
	//发送写数据的地址
	Iic_Send_Byte(addr);
	ack=Iic_Wait_Ack();
	if(ack == 1)
	{
		return ;
	}	
	
	delay10us(1);
	Iic_Send_Byte(data);
	ack=Iic_Wait_Ack();
	if(ack == 1)
	{
		return ;
	}
	
	Iic_Stop();

}

void Read_Bytes(uint8_t addr, uint8_t *read_buff,uint8_t len)
{
	uint8_t ack;
	uint8_t i=0;
	
	//开始信号 
	Iic_Start();
	
	//发送写设备地址
	Iic_Send_Byte(I2C_WADDR);
	ack=Iic_Wait_Ack();
	if(ack == 1)
	{
		return ;
	}
	
	//发送读数据的地址
	Iic_Send_Byte(addr);
	ack=Iic_Wait_Ack();
	if(ack == 1)
	{
		return ;
	}

	//开始信号 
	Iic_Start();
	
	//发送读设备地址
	Iic_Send_Byte(I2C_RADDR);
	ack=Iic_Wait_Ack();
	if(ack == 1)
	{
		return ;
	}
	while(len--)
	{
		read_buff[i++]=Iic_Read_Byte();
		if(len==0)
		{
			Iic_Send_Ack(1);
		}
		else 
		{
			Iic_Send_Ack(0);
		}
	}

	Iic_Stop();
	
}
  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值