2.IIC通信标准固件库解析

1.IIC的开始

  • I2C0与I2C2的使用
#define I2C0_SPEED              100000
#define I2C0_SLAVE_ADDRESS7     0xA0
#define I2C_PAGE_SIZE           8

#define I2C2_SPEED              100000
#define I2C2_SLAVE_ADDRESS7     0xA0

1.1.IIC初始化

rcu_periph_clock_enable(RCU_GPIOB);
//GPIOB的RCU外设时钟使能
gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_8);
gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_9);
//GPIO复用设置
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_8);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_9);
//GPIO模式设置复用上拉
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,GPIO_PIN_8);
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,GPIO_PIN_9);
//GPIO输出设置开漏输出

rcu_periph_clock_enable(RCU_GPIOF);

gpio_af_set(GPIOF, GPIO_AF_4, GPIO_PIN_1);
gpio_af_set(GPIOF, GPIO_AF_4, GPIO_PIN_0);

gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_0);
gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_1);
gpio_output_options_set(GPIOD, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,GPIO_PIN_0);
gpio_output_options_set(GPIOF, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,GPIO_PIN_1);

1.2.IIC设置

rcu_periph_clock_enable(RCU_I2C0);
//使能I2C0的RCU外设时钟
i2c_clock_config(I2C0,I2C0_SPEED,I2C_DTCY_2);
//I2C0时钟设置
i2c_mode_addr_config(I2C0,I2C_I2CMODE_ENABLE,I2C_ADDFORMAT_7BITS,I2C0_SLAVE_ADDRESS7);
//I2C0地址设置
i2c_enable(I2C0);
//I2C0使能
i2c_ack_config(I2C0,I2C_ACK_ENABLE);
//I2C0应答帧设置开启

/* enable I2C clock */
rcu_periph_clock_enable(RCU_I2C2);
/* configure I2C clock */
i2c_clock_config(I2C2,I2C2_SPEED,I2C_DTCY_2);
/* configure I2C address */
i2c_mode_addr_config(I2C2,I2C_I2CMODE_ENABLE,I2C_ADDFORMAT_7BITS,I2C2_SLAVE_ADDRESS7);
/* enable I2C2 */
i2c_enable(I2C2);
/* enable acknowledge */
i2c_ack_config(I2C2,I2C_ACK_ENABLE);

2.IIC通信简要概述

2.1.轮询流程

IIC轮询确认从机地址是否有效
从机地址有效则使用该从机地址进行通信
uint8_t i2c_addr_poll(uint32_t i2c_periph,uint8_t poll_addr)
{
	uint16_t i = 0;
	uint8_t result;
	  /* wait until I2C bus is idle */
	  while(i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY));
	//等待I2C总线忙碌结束
	  i2c_start_on_bus(i2c_periph);
	  while(!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND));
	  //等待起始位置0
	  /* send slave address to I2C bus */
	i2c_master_addressing(i2c_periph, poll_addr, I2C_TRANSMITTER);
	//主机发送从机地址
	  /* wait until ADDSEND bit is set */
	  while(!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND))
	//从机地址是否发送(没有发送则停留在该循环中等待发送完成)
	{
		i++ ;
		if(i > 60000)
		{
			break;
		}
	}
	  
	if(i > 60000)
	{
		result = 0;
	}
	else
	{
		result = 1;
	}		
	
	  i2c_stop_on_bus(i2c_periph);
	  //发送结束位给IIC总线
	  while(I2C_CTL0(i2c_periph)&0x0200);
	//等待I2C0下I2C_CTL0中的硬件清零结束
	return result;
}

2.2. 单字节发送流程

  • BSY位判断 --> 发送START信号 --> SBSEND位判断 --> 从机地址发送 --> ADDSEND位判断 --> 清除ADDSEND位 --> 满足TBE位置1进入下一步 --> transmit发送字节 --> 满足BTC位置1进入下一步 --> 发送STOP信号
  • 添加内容:超时则发送STOP信号
void i2c_byte_write(uint32_t i2c_periph,uint8_t i2c_addr,uint8_t write_address,uint8_t buffer)
{
		uint16_t i;
    while(i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY));
    i2c_start_on_bus(i2c_periph);
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND));
    i2c_master_addressing(i2c_periph, i2c_addr, I2C_TRANSMITTER);
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND))
		{
			i++ ;
			if(i > 60000)
			{
				i2c_stop_on_bus(i2c_periph);
				return;
			}
		}   
    i2c_flag_clear(i2c_periph,I2C_FLAG_ADDSEND);
    while(SET != i2c_flag_get(i2c_periph, I2C_FLAG_TBE));
    i2c_data_transmit(i2c_periph, write_address);
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
    i2c_data_transmit(i2c_periph, buffer); 
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
    i2c_stop_on_bus(i2c_periph);
    while(I2C_CTL0(i2c_periph)&0x0200);
}
//发送单字节命令
void i2c_cmd_write(uint32_t i2c_periph,uint8_t i2c_addr,uint8_t cmd)
{
		uint16_t i;

    while(i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY));
		//等待BUS总线占用结束

    i2c_start_on_bus(i2c_periph);
    //发送起始位给IIC总线
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND));
    //等待起始位发送标志位置1
		i2c_master_addressing(i2c_periph, i2c_addr, I2C_TRANSMITTER);
    //主机发送从机地址
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND))
		//主机模式等待发送完成
		{
			i++ ;
			if(i > 60000)
			{
				i2c_stop_on_bus(i2c_periph);
				//发送结束位给IIC总线
				return;
			}
		}    
    i2c_flag_clear(i2c_periph,I2C_FLAG_ADDSEND);
    //清除ADDSEND标志位的值
    while(SET != i2c_flag_get(i2c_periph, I2C_FLAG_TBE));
    //等待传输数据缓冲为空
    i2c_data_transmit(i2c_periph, cmd);
    //发送cmd(一个字节)
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));    
		//等待(缓冲区发送完成标志位置1)字节发送结束
    i2c_stop_on_bus(i2c_periph);
    //发送结束位给IIC总线
    while(I2C_CTL0(i2c_periph)&0x0200);
		//等待I2C0下I2C_CTL0中的硬件清零结束	
}

2.3.多字节发送流程

BSY位判断 --> 发送START信号 --> SBSEND位判断 --> 从机地址发送 --> ADDSEND位判断 --> 清除ADDSEND位 --> 满足TBE位置1进入下一步 --> while循环字符串索引更迭自减构建完整的字符串发送结构 --> 满足BTC位置1进入下一步 --> 发送STOP信号

void i2c_write(uint32_t i2c_periph,uint8_t i2c_addr,uint8_t write_address,uint8_t* p_buffer,  uint8_t number_of_byte)
{
		uint16_t i;
    /* wait until I2C bus is idle */
    while(i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY));
    
    /* send a start condition to I2C bus */
    i2c_start_on_bus(i2c_periph);
    
    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND));
    
    /* send slave address to I2C bus */
    i2c_master_addressing(i2c_periph, i2c_addr, I2C_TRANSMITTER);
    
    /* wait until ADDSEND bit is set */
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND))
		{
			i++ ;
			if(i > 60000)
			{
				/* send a stop condition to I2C bus */
				i2c_stop_on_bus(i2c_periph);
				return;
			}
		}   
    
    /* clear the ADDSEND bit */
    i2c_flag_clear(i2c_periph,I2C_FLAG_ADDSEND);
    
    /* wait until the transmit data buffer is empty */
    while( SET != i2c_flag_get(i2c_periph, I2C_FLAG_TBE));
    
    /* send the EEPROM's internal address to write to : only one byte address */
    i2c_data_transmit(i2c_periph, write_address);
    
    /* wait until BTC bit is set */
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
    
    /* while there is data to be written */
    while(number_of_byte--){  
        i2c_data_transmit(i2c_periph, *p_buffer);
        
        /* point to the next byte to be written */
        p_buffer++; 
        
        /* wait until BTC bit is set */
        while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
    }
    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(i2c_periph);
    
    /* wait until the stop condition is finished */
    while(I2C_CTL0(i2c_periph)&0x0200);
}

2.4. 在目标从机的寄存器地址中多字节接收流程

BSY位判断 --> 发送START信号 --> SBSEND位判断 --> 从机地址发送 --> ADDSEND位判断 --> 清除ADDSEND位 --> 满足TBE位置1进入下一步 --> IIC使能 --> transmit发送地址 --> 满足BTC位置1进入下一步 --> 发送START信号 --> SBSEND位判断 --> 从机地址发送 --> ADDSEND位判断 --> 清除ADDSEND位 --> 进入复合阶段

uint8_t i2c_read(uint32_t i2c_periph,uint8_t i2c_addr,uint8_t read_address,uint8_t* p_buffer, uint16_t number_of_byte)
{  
		uint8_t	rt = 1;
		uint16_t i;
    /* wait until I2C bus is idle */
    while(i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY));

    if(2 == number_of_byte){
        i2c_ackpos_config(i2c_periph,I2C_ACKPOS_NEXT);
    }
    
    /* send a start condition to I2C bus */
    i2c_start_on_bus(i2c_periph);
    
    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND));
    
    /* send slave address to I2C bus */
    i2c_master_addressing(i2c_periph, i2c_addr, I2C_TRANSMITTER);
    
    /* wait until ADDSEND bit is set */
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND))
		{
			i++ ;
			if(i > 60000)
			{
				/* send a stop condition to I2C bus */
				i2c_stop_on_bus(i2c_periph);
				rt = 0;
				return rt;
			}
		}   
    
    /* clear the ADDSEND bit */
    i2c_flag_clear(i2c_periph,I2C_FLAG_ADDSEND);
    
    /* wait until the transmit data buffer is empty */
    while(SET != i2c_flag_get( i2c_periph , I2C_FLAG_TBE ));

    /* enable i2c_periph*/
    i2c_enable(i2c_periph);
    
    /* send the slave internal address to write to */
    i2c_data_transmit(i2c_periph, read_address);  
    
    /* wait until BTC bit is set */
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
    
    /* send a start condition to I2C bus */
    i2c_start_on_bus(i2c_periph);
    
    /* wait until SBSEND bit is set */
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND));
    
    /* send slave address to I2C bus */
    i2c_master_addressing(i2c_periph, i2c_addr, I2C_RECEIVER);

    if(number_of_byte < 3){
        /* disable acknowledge */
        i2c_ack_config(i2c_periph,I2C_ACK_DISABLE);
    }
    
    /* wait until ADDSEND bit is set */
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND));
    
    /* clear the ADDSEND bit */
    i2c_flag_clear(i2c_periph,I2C_FLAG_ADDSEND);
    
    if(1 == number_of_byte){
        /* send a stop condition to I2C bus */
        i2c_stop_on_bus(i2c_periph);
    }
    
    /* while there is data to be read */
    while(number_of_byte){
        if(3 == number_of_byte){
            /* wait until BTC bit is set */
            while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));

            /* disable acknowledge */
            i2c_ack_config(i2c_periph,I2C_ACK_DISABLE);
        }
        if(2 == number_of_byte){
            /* wait until BTC bit is set */
            while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
            
            /* send a stop condition to I2C bus */
            i2c_stop_on_bus(i2c_periph);
        }
        
        /* wait until the RBNE bit is set and clear it */
        if(i2c_flag_get(i2c_periph, I2C_FLAG_RBNE)){
            /* read a byte from the EEPROM */
            *p_buffer = i2c_data_receive(i2c_periph);
            
            /* point to the next location where the byte read will be saved */
            p_buffer++; 
            
            /* decrement the read bytes counter */
            number_of_byte--;
        } 
    }
    
    /* wait until the stop condition is finished */
    while(I2C_CTL0(i2c_periph)&0x0200);
    
    /* enable acknowledge */
    i2c_ack_config(i2c_periph,I2C_ACK_ENABLE);

    i2c_ackpos_config(i2c_periph,I2C_ACKPOS_CURRENT);
		
		return rt;
}

2.4.1.复合阶段描述

字节数321
信号发送和应答控制BTC位判断然后设置关闭应答帧BTC位判断然后发送STOP信号
索引更迭自加接收p_buffer + 1p_buffer + 2p_buffer + 3

复合阶段是上下两者在同一个while循环中依次进行的。

2.5. 在目标从机的寄存器地址中写入多字节流程

  • BSY位判断 --> 发送START信号 --> SBSEND位判断 --> 从机地址发送 --> ADDSEND位判断 --> 清除ADDSEND位 --> transmit发送地址 --> 满足BTC位置1进入下一步 --> while循环字符串索引更迭自减构建完整的字符串发送结构 --> 满足BTC位置1进入下一步 --> 发送STOP信号
  • 添加内容:添加i2c_delay、judge_i2c_over_time
void i2c_delay_write(uint32_t i2c_periph,uint8_t i2c_addr,uint8_t write_address,uint8_t* p_buffer,  uint8_t number_of_byte)
{
		uint16_t i = 0;
	  uint32_t time = 10000;
	
    /* wait until I2C bus is idle */
	  i2c_over_time = 0;
    while(i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY))
		{
			  if(judge_i2c_over_time() == 1)
				{
						return; 	 
				}
    } 			
    i2c_delay(time);
	
    /* send a start condition to I2C bus */
    i2c_start_on_bus(i2c_periph);
    i2c_delay(time);
	
    /* wait until SBSEND bit is set */
		i2c_over_time = 0;
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND))
		{
			  if(judge_i2c_over_time() == 1)
				{
						i2c_stop_on_bus(i2c_periph);
						return; 	 
				}
    } 			
    i2c_delay(time);
	
    /* send slave address to I2C bus */
    i2c_master_addressing(i2c_periph, i2c_addr, I2C_TRANSMITTER);
    i2c_delay(time);  
	
    /* wait until ADDSEND bit is set */
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND))
		{
			i++ ;
			if(i > 60000)
			{
				/* send a stop condition to I2C bus */
				i2c_stop_on_bus(i2c_periph);
				return;
			}
		}   
    i2c_delay(time);
		
    /* clear the ADDSEND bit */
    i2c_flag_clear(i2c_periph,I2C_FLAG_ADDSEND);
		i2c_delay(time); 
    
    /* wait until the transmit data buffer is empty */
		i2c_over_time = 0;
    while( SET != i2c_flag_get(i2c_periph, I2C_FLAG_TBE))
		{
			  if(judge_i2c_over_time() == 1)
				{
						i2c_stop_on_bus(i2c_periph);
						return; 	 
				}
    }			
		i2c_delay(time);
    
    /* send the EEPROM's internal address to write to : only one byte address */
    i2c_data_transmit(i2c_periph, write_address);
		i2c_delay(time);
    
    /* wait until BTC bit is set */
		i2c_over_time = 0;
    while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC))
		{
			  if(judge_i2c_over_time() == 1)
				{
						i2c_stop_on_bus(i2c_periph);
						return; 	 
				}
    } 			
		i2c_delay(time);
    
    /* while there is data to be written */
    while(number_of_byte--){  
        i2c_data_transmit(i2c_periph, *p_buffer);
        
        /* point to the next byte to be written */
        p_buffer++; 
        
        /* wait until BTC bit is set */
			  i2c_over_time = 0;
        while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC))
				{
					  if(judge_i2c_over_time() == 1)
						{
								i2c_stop_on_bus(i2c_periph);
								return; 	 
						} 
        }					
    }
		i2c_delay(time);
		
    /* send a stop condition to I2C bus */
    i2c_stop_on_bus(i2c_periph);
    i2c_delay(time);
		
    /* wait until the stop condition is finished */
		i2c_over_time = 0;
    while(I2C_CTL0(i2c_periph)&0x0200)
		{
			  if(judge_i2c_over_time() == 1)
				{
						break; 	 
				}
    }			
		i2c_delay(time);
}

uint16_t i2c_over_time = 0;
/*!
    \brief  judge over time    
*/
uint8_t judge_i2c_over_time(void)
{
		i2c_over_time++;
    if(i2c_over_time > 60000)
    return 1;
    else
    return 0;			
}

void i2c_delay(uint32_t time)
{
     uint32_t i;
     
	   for(i=0;i<time;i++)
	   {
		 }	 
}

3.通用开发经验总结

3.1.对应IIC通信芯片,查找对应手册,找寻ADDR Input确认从机地址格式。
3.2.找寻所需要的工作模式寄存器以及控制引脚输出等寄存器,随后加入IIC单字节或多字节发送的函数封装对应功能即可。
3.3.遭遇一主机多从机类似通信风暴情形时,加入定时器控制或者delay使IIC指令错开发送即可简单解决。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AzusaFighting

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值