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

51单片机、IIC从机模拟、IIC协议、iiC读写

  • 1.思路
  • 1.1写数据
  • 1.2读数据
  • 2.从机IIC协议
  • 2.1起始信号和结束信号
  • 2.2从机读取和写数据
  • 2.3从机发送和接收ACK
  • 2.4判断主机发送读操作还是写操作
  • 2.5寄存器地址
  • 2.6主函数
  • 3.主机IIC协议
  • 3.1起始信号和结束信号
  • 3.2主机写数据和读数据
  • 3.3主机发送和接收ACK
  • 3.4主机写
  • 3.5主机读
  • 4.使用逻辑分析仪抓取波形
  • 4.1主机写数据波形图
  • 4.2 主机读数据波形图
  • 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 主机读数据波形图

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用51单片机实现IIC从机模拟,实现主机读写操作

    发表评论