STM32上进行I2C通讯

STM32上进行I2C通讯

起始信号:当SCL为高期间,SDA由高到低的跳变。

void I2C_Start(void)
{
	MPU_SDA_OUT();//设置SDA为输出模式
	I2C_SDA=1;
	I2C_SCL=1;
	I2C_Delay();
	I2C_SDA=0;
	I2C_Delay();
	I2C_SCL=0;
}

停止信号:当SCL为高期间,SDA由低到高的跳变。

void I2C_Stop(void)
{
	MPU_SDA_OUT();
	I2C_SDA=0;
	I2C_SCL=0;
	I2C_Delay();
	I2C_SCL=1;
	I2C_Delay();
	I2C_SDA=1;
}

应答信号ACK与非应答信号NACK: 发送器发送完一个字节的时候,就在时钟脉冲第9个周期的时候释放数据线,由接收器反馈到SDA一个应答信号。应答信号为低电平时,规定为有效应答位。规定高电平为非应答位(NACK)。

void I2C_Ack(void)
{
	I2C_SCL=0;
	MPU_SDA_OUT();
	I2C_SDA=0;
	I2C_Delay();
	I2C_SCL=1;
	I2C_Delay();
	I2C_SCL=0;
}
void I2C_NAck(void)
{
	I2C_SCL=0;
	MPU_SDA_OUT();
	I2C_SDA=1;
	I2C_Delay();
	I2C_SCL=1;
	I2C_Delay();
	I2C_SCL=0;
}

等待ACK信号:

u8 I2C_Wait_Ack(void)
{
	u8 ucErrTime=0;
	MPU_SDA_IN();      
	I2C_SDA=1;I2C_Delay();	   
	I2C_SCL=1;I2C_Delay();	 
	while(MPU_READ_SDA)  //nack时sda为1,一直循环。ack时sda为0,停止循环。
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			I2C_Stop();
			return 1;
		}
	}
	I2C_SCL=0;
	return 0;
}

发送一个字节:

void I2C_Send_Byte(u8 txd)
{                        
    u8 t;   
	MPU_SDA_OUT(); 	    
    I2C_SCL=0;
    for(t=0;t<8;t++)
    {              
        I2C_SDA=(txd & 0x80)>>7; //发送txd里面的最高位,赋值到I2C_SDA
        txd<<=1; 	             //将txd的次高位放到最高位
		I2C_SCL=1;               //在SCL为高时数据有效,所以先准备好数据
		I2C_Delay(); 
		I2C_SCL=0;	
		I2C_Delay();
    }	 
} 

读取一个字节:

//ack=1时,发送ACK,ack=0,发送nACK
u8 I2C_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	MPU_SDA_IN();
    for(i=0;i<8;i++ )
    {
        I2C_SCL=0; 
        I2C_Delay();
        I2C_SCL=1;
        receive<<=1;//将先前接收到的最低位的数据往高位方向移一位
        if(MPU_READ_SDA)receive++;//数据始终保存在receive的最低位
        I2C_Delay(); 
    }					 
   if (!ack)I2C_NAck();
   else I2C_Ack();
   return receive;
}

单字节写入、读取:

u8 Single_Write(unsigned char SlaveAddress,unsigned char REG_Address,unsigned char REG_data)		    
{
  	I2C_Start();
    I2C_Send_Byte((SlaveAddress<<1) | 0);//发送器件地址,0代表写操作
    I2C_Wait_Ack();
    I2C_Send_Byte(REG_Address );//发送寄存器(Register,简写REG)地址
    I2C_Wait_Ack();	
    I2C_Send_Byte(REG_data);//发送数据
    I2C_Wait_Ack();
    I2C_Stop(); 
    return 0;
}

u8 Single_Read(unsigned char SlaveAddress,unsigned char REG_Address)
{  
	u8 REG_data;
	I2C_Start();
	I2C_Send_Byte((SlaveAddress<<1)|0);
	I2C_Wait_Ack();
	I2C_Send_Byte(REG_Address); 
	I2C_Wait_Ack();
	I2C_Start();
	I2C_Send_Byte((SlaveAddress<<1)|1);//发送器件地址,0代表读操作
	I2C_Wait_Ack();
	REG_data= I2C_Read_Byte(0);//读取数据发送nack,并把该8位数据赋值到数据寄存器中
	I2C_Stop();
	return REG_data;
}	

连续写入、读取:

u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
    //addr器件地址,reg寄存器地址,len数据长度,*buf数据起始地址
	u8 i; 
    I2C_Start(); 
	I2C_Send_Byte((addr<<1)|0);//0代表写入
	I2C_Wait_Ack();
    I2C_Send_Byte(reg);
    I2C_Wait_Ack();		
	for(i=0;i<len;i++)
	{
		I2C_Send_Byte(buf[i]);	
		I2C_Wait_Ack();
	}
    I2C_Stop();	 
	return 0;	
} 

u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{ 
 	I2C_Start();
	I2C_Send_Byte((addr<<1)|0);
	I2C_Wait_Ack();
    I2C_Send_Byte(reg);	
    I2C_Wait_Ack();
    I2C_Start();
	I2C_Send_Byte((addr<<1)|1);
    I2C_Wait_Ack();		
	while(len)
	{
		if(len==1)*buf=I2C_Read_Byte(0);
		else *buf=I2C_Read_Byte(1);		
		len--;
		buf++; 
	}    
    I2C_Stop();
	return 0;	
}
posted @ 2022-02-08 21:33  slyuan  阅读(212)  评论(0编辑  收藏  举报