使用51单片机模拟IIC从机,实现主机(51单片机)对模拟从机的读写操作

1.思路

IIC大部分都是MCU对EEPROM进行读写数据,今天我们用一块51单片机模拟iic_slaver,另外一块mcu当主机,实现主机对iic_slaver的读写。主机向从机读写数据。

1.1写数据

(1)主机发送开始信号,从机检测开始信号(while(IPIN_SCL);while(PIN_SDA)😉.
(2)主机发送器件地址,从机检测器件地址是否正确,若正确从机应答,不正确从机不作回应。
(3)主机发送寄存器地址,从机收到并回应ack。
(4)主机发送8bit数据,从机接收8bit数据,并将数据保存。从机应答主机发送的8bit数据
(5)主机发送结束信号,从机检测结束信号。

1.2读数据

(1)开始信号,主机向从机发送start,从机等待start。
(2)主机发送器件地址,从机判断主机发送的器件地址是否匹配。
(3)主机发送奇存器地址,从机收到并回应ack
(4)知己再次发送开始信号。
(5)主机发送设备地址和读操作,从机判断地址是否匹配,若是则回应。
(6)从机在检测到SCL的情况下,向主机发送8bit数据
(7)等待并判断主机发送的应答
(8)主机发送结束信号,从机检测结束信号。

2.从机IIC协议

2.1起始信号和结束信号

主机发送的起始信号是在SCL线高电平期间,SDA从高电平跳转到低电平。所以从机的代码应该是等带SCL高电平,在SCL高电平期间,等待SDA从高电平跳转到低电平。

void slaver_wait_start()
{
	while(!PIN_SCL);	//等待高电平
	while(PIN_SDA);
	while(PIN_SCL);
}

void slaver_wait_stop()
{
	while(!PIN_SCL);
	while(!PIN_SDA);
}

2.2从机读取和写数据

void slaver_read_data()
{
	u8 i;
	g_u8_data = 0x00;	//全局变量
	for(i=0;i<8;i++)
	{
		while(!PIN_SCL);
		if(PIN_SDA)
		{
			g_u8_data |= (0x80>>i);
		}
		while(PIN_SCL);
	}
}

void slaver_write_data(u8 u8_byte)
{
	u8 i;
	for(i=0;i<8;i++)
	{
		while(PIN_SCL);		//等待时钟线低电平
		PIN_SDA = u8_byte & (0x80>>i);
		while(!PIN_SCL);	
		while(PIN_SCL);	
	}
	PIN_SDA = 1;		//释放SDA信号线
}

2.3从机发送和接收ACK

void slaver_send_ack(u8 u8_ack)
{
	PIN_SDA = u8_ack;
	while(!PIN_SCL);	
	while(PIN_SCL);	
	PIN_SDA = 1;
}

int slaver_receive_ack()
{
	while(!PIN_SCL);
	if(PIN_SDA)
	{
		while(PIN_SCL);
		return 1;
	}
	else
	{
		while(PIN_SCL);
		return 0;
	}
}

2.4判断主机发送读操作还是写操作

int slaver_device_addr()
{
	slaver_wait_start();
	slaver_read_data();
	if(g_u8_data == g_u8_device_w_addr)
	{
		slaver_send_ack(0);
		return 1;
	}
	else if(g_u8_data == g_u8_device_r_addr)
	{
		slaver_send_ack(0);
		return 2;
	}
	else
	{
		return 0;
	}
}

2.5寄存器地址

void slaver_reg_addr()
{
	slaver_read_data();
	g_u8_reg_addr = g_u8_data;
	slaver_send_ack(0);
}

2.6主函数

主机在发送完器件地址、寄存器地址后,主机读数据比写数据要多发送个起始位和器件地址,所以我就判断是否有起始位,有起始位就读,没有就写,这样代码就不会卡死,抓取的波形也是正确的。主机的SCL接从机的SCL,主机的SDA接从机的SDA,接地。

sbit PIN_SCL = P1^4;
sbit PIN_SDA = P1^5;

u8 g_u8_device_w_addr = 0xa8;
u8 g_u8_device_r_addr = 0xa9;
u8 g_u8_data = 0x00;
u8 g_u8_reg_addr = 0x01;
u8 g_u8_buf[10];

void main()
{
	while(1)
	{
		if(slaver_device_addr() == 1)
		{
			slaver_reg_addr();
			while(!PIN_SCL);
			if(PIN_SDA == 1)								//主机读
			{
				if(slaver_device_addr() == 2)
				{
					slaver_write_data(g_u8_buf[0]);
					if(slaver_receive_ack() == 1)
					{
						slaver_wait_stop();
					}
				}
			}
			else											//主机写,从机读
			{
				slaver_read_data();
				g_u8_buf[0] = g_u8_data;
				slaver_send_ack(0);
				slaver_wait_stop();
			}
		}
	}
}

3.主机IIC协议

3.1起始信号和结束信号

在这里插入图片描述

void master_start()
{
	PIN_SDA = 1;
	PIN_SCL = 1;
	PIN_SDA = 0;
	PIN_SCL = 0;
}

void master_stop()
{
	PIN_SDA = 0;
	PIN_SCL = 1;
	PIN_SDA = 1;
}

3.2主机写数据和读数据

void master_writedata(u8 u8_data)
{
	u8 i;
	for(i=0;i<8;i++)
	{
		PIN_SDA = u8_data(0x80>>i);
		PIN_SCL = 1;
		PIN_SCL = 0;
	}
	PIN_SCL = 0;
}

u8 master_readdata()
{
	u8 i;
	u8 u8_word = 0x00;
	PIN_SDA = 1;
	for(i=0;i<8;i++)
	{
		PIN_SCL = 1;
		if(PIN_SDA)
		{
			u8_word |= (0x80 >>i);
		}
		PIN_SCL = 0;
	}
	return u8_word;
}

3.3主机发送和接收ACK

void master_write_ack(u8 u8_ackbit)
{
	PIN_SCL = 0;
	PIN_SDA = u8_ackbit;
	PIN_SCL = 1;
	PIN_SCL = 0;
}

BOOL master_check_ack()
{
	BOOL result  = FALSE;
	u8 u8_ackbit = 0;
	u16 u16_wait = 0;
	
	PIN_SDA = 1;				//释放总线,让从机发送ack
	PIN_SCL = 1;
	
	while(_i2c_read_data() && (u16_wait < Timeout))
	{
		u16_wait++;
	}
	
	if(!_i2c_read_data())
	{
		result = TRUE;
	}
	
	PIN_SCL = 0;
	return result;
}

3.4主机写

BOOL master_write_byte(u8 * u8_buf,u8_num)
{
	BOOL result = FALSE;
	master_start();
	master_writedata(0xa8);
	if(!master_check_ack())
		goto STOP;
	
	master_writedata(0x00);
	if(!master_check_ack())
		goto STOP;
	
	while(u8_num--)
	{
		master_writedata(*u8_buf--);
		if(!master_check_ack())
			goto STOP;
	}
	result = TRUE;

STOP:
	master_stop();
	return result;
}

3.5主机读

void master_read_byte(u8 * u8_byte,u8 num)
{
	master_start();
	master_writedata(0xa8);
	if(!master_check_ack())
		goto STOP;
	
	master_writedata(0x00);
	if(!master_check_ack())
		goto STOP;
		
	master_start();
	master_writedata(0xa9);
	if(!master_check_ack())
		goto STOP;
	
	while(u8_num--)
	{
		*u8_byte++ == master_readdata();
		if(u8_num)
		{
			master_write_ack(0);
		}
		else
		{
			master_write_ack(1);
		}
	}
STOP:
	master_stop();
}

4.使用逻辑分析仪抓取波形

4.1主机写数据波形图

在这里插入图片描述

4.2 主机读数据波形图

在这里插入图片描述

  • 11
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值