STM32F4之模拟I2C通信协议的实现

一,何为IIC?

I2C(IIC,InterIntegrated Circuit),两线式串行总线,PHILIPS公司开发用于连接微控制器及其外围设备。

它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、ICIC之间进行双向传送,高速IIC总线一般可达400kbps以上。

IIC是半双工通信方式。

二,IIC通信的6种状态

1.空闲状态

2.开始信号

3.停止信号

4.应答信号

5.数据的有效性

6.数据传输

三.用代码实现I2C协议的模拟

1.空闲状态:当SDA以及SCL两条总线都处于高电平状态时,处于空闲状态

void IIC_init()
{
    //声明一个GPIO的结构体变量
	GPIO_InitTypeDef GPIO_InitStructure;
	//使能GPIO外设时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	//定义该GPIO结构体
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8 |GPIO_Pin_9; //两个GPIO
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;         //输出模式
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;    //100MHz
	GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;		//推挽输出
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;			//上拉
	//初始化GPIOB
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	//初始化I2C总线,使之成为空闲状态
	IIC_SCL=1;
	IIC_SDA=1;
}

2.开始状态:当SCL为高电平时,SDA从高电平到低电平进行跳变,然后SCL跳变为低电平,时刻装备接收数据

                                     

按照上图实现如下代码 :(注意:SDA有输入,输出两种状态)

void IIC_start()
{
	//将SDA的IO设置为输出状态 
	SDA_OUT();
	IIC_SDA=1;
	IIC_SCL=1;
	delay_us(4);
	IIC_SDA=0;
	delay_us(4);
	IIC_SCL=0;    //拉低数据总线,时刻准备接收数据
}

 3.结束状态:当SCL总线为高时,SDA从低到高进行跳变

                            

按照上图实现代码如下 :(在SCL为高电平时,SDA进行跳变)

//产生停止信号
void IIC_stop()
{
	//数据输出
	SDA_OUT();
	IIC_SCL=0;
	IIC_SDA=0;
	delay_us(4);
	IIC_SCL=1;     //按照上图,在SCL为高电平时,SDA进行跳变
	IIC_SDA=1;
	delay_us(4);
}

 

4.应答信号

当发送器每发送一个字节,就会在第9周期释放数据总线(即SDA为高电平),等待接收器发送一个应答信号

该应答信号:(接收应答信号时,SDA需改变为输入状态)

当读到来自接收器的低电平,表明已经接收设备已经接收到数据。

当读到来自接收器的低电平,表明接收设备未能正常接收数据。

因此我们应该实现,应答信号,非应答信号,等待应答信号三个函数,以下为应答信号的实现

                                                   

根据上图以及数据的有效性(在SCL信号由低到高,再由高到低的过程中,高电平保持期间,SDA保持不变,SDA即发送的数据),可以写出以下代码:

//产生应答信号
void IIC_ack()
{
	IIC_SCL=0;  
	SDA_OUT();
	IIC_SDA=0;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;

}

5.非应答信号

                                      

上图中的not acknowledge 就是非应答信号。

根据上图以及数据的有效性(在SCL信号由低到高,再由高到低的过程中,高电平保持期间,SDA保持不变,SDA即发送的数据),可以写出以下代码:

//产生非应答信号
void IIC_nack()
{
	IIC_SCL=0;

	SDA_OUT();
	IIC_SDA=1;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;

}

6.等待应答的信号

在SCL的有效周期期间,读到SDA线上的数据

//将数据总线进行释放
//SDA为输入模式,进行应答信号的读取
//返回值: 1,无应答
//       0,有应答
u8 IIC_Wait_Ack()
{
	u8 ucErrTime=0;
	//SDA输入模式设置
	SDA_IN();
	IIC_SDA=1;
	delay_us(1);
	IIC_SCL=1;    
	delay_us(1);
	while(READ_SDA)//应答信号的读取
	{
			ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_stop();
			return 1;
		}
	
	}
	IIC_SCL=0;
	return 0;

}

7.数据的接收

在SCL有效周期内对数据进行接收(SCL=0  --->   SCL=1  读SDA    --->SCL=0  形成数据的有效性)

(注意:receive需将其初始化为0,否则会出现数据传输错误,因为局部变量的值为脏值,在栈上的值)

u8 IIC_Read_Byte(unsigned char ack)
{
		u8 receive=0,t;
		SDA_IN();
		for(t=0;t<8;t++)
		{
			IIC_SCL=0;      //SCL=0  -> SCL=1 读SDA ->SCL=0  形成数据的有效性
			delay_us(2);
			IIC_SCL=1;
	
			receive<<=1;    //接收一位数据为0
			if(READ_SDA)
			{
				receive++;  //接收一位数据为1
			}
			delay_us(1);
		}
		if(!ack)
		{
			IIC_nack();
		}else
		{
			IIC_ack();
		
		}
		return receive;
}

8.数据的发送(SCL=0  --->   SCL=1  发送SDA    --->SCL=0  形成数据的有效性)

void IIC_Send_Byte(u8 txd)
{
	  u8 t;	
	  SDA_OUT();
		IIC_SCL=0;
	  for(t=0;t<8;t++)
		{
			IIC_SDA=(txd&0x80)>>7;//将最高位的数据进行输出
			txd<<=1; //将最高位的数据溢出,准备发送次高位的数据
			delay_us(2);
			IIC_SCL=1;
			delay_us(2);
			IIC_SCL=0;
			delay_us(2);
		}
}

以上为I2C通信协议的实现(部分代码未给出),后续文章为I2C协议的使用

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_33974167

有价值,请赏瓶水喝

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值