STM32硬件I2C双机通信

STM32硬件I2C双机通信

I2C的接口模式可以选择4种

  • 主发送器模式
  • 主接收器模式
  • 从发送器模式
  • 从接收器模式

在本次实验中需要用到两块STM32单片机,其中一块的I2C1做主机,另一块的I2C2做从机,分别进行I2C1写I2C2实验、I2C1读I2C2实验,两次实验I2C1均为主机。

1、主发送、从接收模式

在I2C1写I2C2实验中,先检测总线占用情况,确定在总线空闲的情况下,由主机发送起始信号然后发送从机地址,选择写命令,从机接收到地址与自身匹配后回应ACK信号,主机接收到ACK信号后开始发送数据,从机收到数据后回应ACK,当主机发送到最后一个字节并且收到ACK后,主机发出停止信号结束本次通信并且释放总线,从机收到停止信号后也退出与主机的通信。

注意:在从机I2C初始化的时候要设置从机地址,在主机发送从机地址的时候,一般最后一位是读写位,0写1读,假设从机地址为0x30,则发送0x30|0x00为写,0x30|0x01为读。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-49ofWtFi-1631685456411)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210915092054068.png)]

/**
  * @brief  主机I2C1写数据
  * @param  None
  * @retval None
  */
static void I2C1_Write_Byte(uint32_t ReadAddr)
{
	uint32_t i;
	uint32_t tbuf[10] = {0X01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a};
	
	while(I2C1->SR2&((u16)0x1<<1));		//等待总线空闲
	I2C1->CR1|=(u16)0x1<<8;				//置位START,产生起始条件
	
	/*  SB = 1: EV5 */
	while(!(I2C1->SR1&(u16)0x1<<0));	//等待SB置位,当发送出起始条件时该位被置1	
	I2C1->SR1;							//读SR1
	I2C1->DR = ReadAddr;				//发送写指令,写DR寄存器清除SB事件
	
	/*  ADDR = 1: EV6 */
	while(!(I2C1->SR1&(u16)0x1<<1));	//等待从设备应答
	
	/*  TxE = 1: EV8-1 */
	while(!(I2C1->SR1&(u16)0x1<<7));	//等待TxE为1,数据寄存器空
	for(i=0;i<SIZE;i++)
	{
		/*  TxE = 1: EV8 */
		I2C1->DR = tbuf[i];
		
		/*  TxE = 1, BTF = 1: EV8-2 */
		while(!(I2C1->SR1&(u16)0x1<<2));//BTF为1,字节发送结束
	}	
	I2C1->CR1|=(u16)0x1<<9;				//产生停止条件
	while(!(I2C1->CR1&(u16)0x1<<9));
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kfIpor5R-1631685456412)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210915092022348.png)]

/**
  * @brief  从机I2C2 读数据
  * @param  None
  * @retval None
  */
static void I2C2_Read_Byte(void)
{
	uint32_t i;
	uint32_t rbuf[SIZE];
	
    while(!(I2C2->SR2&(u16)0x1<<1));	//1:BUSY忙
    while(I2C2->SR2&(u16)0x1);			//0:从模式
    /*  ADDR = 1: EV1 */
    while(!(I2C2->SR1&(u16)0x1<<1));	//接收到地址
    I2C2->SR1;
    I2C2->SR2;							//清除ADDR
    for(i=0; i<10; i++)
    {
        /*  RxNE = 1: EV2 */
        while(!(I2C2->SR1&(u16)0x1<<6));//接收到数据
        rbuf[i] = I2C2->DR;
    }
    /*  STOPF = 1: EV4 */
    while(!(I2C2->SR1&(u16)0x1<<4));	//等待STOPF为1
}
2、主接收、从发送模式

在I2C1读I2C2实验中,先检测总线占用情况,确定在总线空闲的情况下,由主机发送起始信号然后发送从机地址,选择读命令,从机接收到地址与自身匹配后回应ACK信号,接着由从机开始发送数据,主机接收到数据后回应ACK信号,当主机完成所有数据接收后发送一个NACK信号,从机收到NACK后停止发送数据,主机发送完NACK后再发出停止信号,释放总线结束本次通信。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-078MQRlv-1631685456414)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210915095040285.png)]

/**
  * @brief  主机I2C1读数据
  * @param  ReadAddr  :开始读数的地址
  * @retval None
  */
static void I2C1_Read_Byte(uint32_t ReadAddr)
{
	uint32_t i;
	uint32_t rbuf[SIZE];
	
	while(I2C1->SR2&((u16)0x1<<1));		//等待总线空闲
	I2C1->CR1|=(u16)0x1<<8;				//置位START,产生起始条件
	
	/*  SB = 1: EV5 */
	while(!(I2C1->SR1&(u16)0x1<<0));	//等待SB置位,当发送出起始条件时该位被置1	
	I2C1->SR1;							//读SR1
	I2C1->DR = ReadAddr|0x01;			//发送读指令,写DR寄存器清除SB事件
	
	/*  ADDR = 1: EV6 */
	while(!(I2C1->SR1&(u16)0x1<<1));	//等待从设备应答
	I2C1->SR1;
	I2C1->SR2;							//清除ADDR		
	
	for(i=0;i<SIZE;i++)
	{
		/*  RxNE = 1: EV7 */
		while(!(I2C1->SR1&(u16)0x1<<6));//等待RXNE=1,接收到数据	
		rbuf[i] = I2C1->DR;
	}
	
	/*  STOP = 1: EV7-1 */
	I2C1->CR1&=~((u16)0x1<<10);			//ACK=0
	I2C1->CR1|=(u16)0x1<<9;				//产生停止条件
}	

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z6hZBPbH-1631685456416)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210915095057236.png)]

/**
  * @brief  从机I2C2 写数据
  * @param  None
  * @retval None
  */
static void I2C2_Write_Byte(void)
{
	uint32_t i;
	uint32_t tbuf[10] = {0X01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a};
	
    while(!(I2C2->SR2&(u16)0x1<<1));	//1:BUSY忙
    while(I2C2->SR2&(u16)0x1);			//0:从模式
    /*  ADDR = 1: EV1 */
    while(!(I2C2->SR1&(u16)0x1<<1));	//接收到地址
    I2C2->SR1;
    I2C2->SR2;
    /*  TxE = 1: EV3-1 */
    while(!(I2C2->SR1&(u16)0x1<<7));	//1:TXE 数据寄存器空
    for(i=0; i<10; i++)
    {
        /*  TxE = 1: EV3 */
        I2C2->DR = tbuf[i];
        while(!(I2C2->SR2&(u16)0x1<<2));//1:TRA 数据已发送
        while(!(I2C2->SR1&(u16)0x1<<2));//1:BTF 字节发送结束
    }
    /*  AF = 1: EV3-2 */
    while(!(I2C2->SR1&(u16)0x1<<10));	//1:AF 应答失败,发送结束
}
上一篇:php – 如何使用星号获取Web应用程序中任何调用的调用持续时间?


下一篇:如何使用PHP建立与Asterisk管理器的持久连接?