×
单片机 > 其他资讯 > 详情

STM32部分知识之I2C

发布时间:2020-06-19 发布时间:
|

I2C(IIC,Inter-Integrated Circuit),两线式串行总线,由PHILIPS公司开发用于连接微控制器及其外围设备。它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps以上。


多主机I2C总线系统结构:



因为STM32自带的I2C不稳定所以采用模拟I2C,所以首先的初始化I0口


void IIC_Init(void)

{

  GPIO_InitTypeDef  GPIO_InitStructure;

 

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟

 

  //GPIOB8,B9初始化设置

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

  GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化

IIC_SCL=1;

IIC_SDA=1;

}

 


II2C协议:

1)空闲状态


I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。


2)起始信号与停止信号


起始信号:当SCL为高期间,SDA由高到低的跳变;启动信号是一种电平跳变时序信号,而不是一个电平信号。

停止信号:当SCL为高期间,SDA由低到高的跳变;停止信号也是一种电平跳变时序信号,而不是一个电平信号。


void IIC_Start(void)

{

SDA_OUT();     //sda线输出

IIC_SDA=1;     

IIC_SCL=1;

delay_us(4);

  IIC_SDA=0;//START:when CLK is high,DATA change form high to low 

delay_us(4);

IIC_SCL=0;       //准备发送或者接收数据

}

void IIC_Stop(void)

{

SDA_OUT();//sda线输出

IIC_SCL=0;

IIC_SDA=0;//STOP:when CLK is high DATA change form low to high

  delay_us(4);

IIC_SCL=1; 

IIC_SDA=1;//发送I2C总线结束信号

delay_us(4);    

}

3)应答信号ACK


发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 


对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。


u8 IIC_Wait_Ack(void)

{

u8 ucErrTime=0;

SDA_IN();      //SDA设置为输入

IIC_SDA=1;delay_us(1);    

IIC_SCL=1;delay_us(1);  

while(READ_SDA)

{

ucErrTime++;

if(ucErrTime>250)

{

IIC_Stop();

return 1;

}

}

IIC_SCL=0;//时钟输出0

return 0;  

}

4)数据有效性


I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。


即:数据在SCL的上升沿到来之前就需准备好。并在在下降沿到来之前必须稳定。


 



//产生应答信号

void IIC_Ack(void)

{

IIC_SCL=0;

SDA_OUT();

IIC_SDA=0;

delay_us(2);

IIC_SCL=1;

delay_us(2);

IIC_SCL=0;

}

//不产生ACK应答     

void IIC_NAck(void)

{

IIC_SCL=0;

SDA_OUT();

IIC_SDA=1;

delay_us(2);

IIC_SCL=1;

delay_us(2);

IIC_SCL=0;

}

//I2C发送一个字节

//返回从机有无应答

//1,有应答

//0,无应答

void IIC_Send_Byte(u8 txd)

{                        

    u8 t;   

SDA_OUT();     

    IIC_SCL=0;//拉低时钟开始数据传输

    for(t=0;t<8;t++)

    {              

        IIC_SDA=(txd&0x80)>>7;

        txd<<=1;   

delay_us(2);   //对TEA5767这3个延时都是必须得

IIC_SCL=1;

delay_us(2); 

IIC_SCL=0;

delay_us(2);

    }  

}  

 


//读一个字节,ack=1,发送ACK,ack=0,发送nACK

u8 IIC_Read_Byte(unsigned char ack)

{

unsigned char i,receive=0;

SDA_IN();//SDA设置为输出

    for(i=0;i<8;i++ )

{

        IIC_SCL=0; 

        delay_us(2);

IIC_SCL=1;

        receive<<=1;

        if(READ_SDA)receive++;   

delay_us(1); 

    }  

    if (!ack)

        IIC_NAck();//发送nACK

    else

        IIC_Ack(); //发送ACK   

    return receive;

}

 

5)数据的传送


在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。数据位的传输是边沿触发。


附:


EEPROM(24C02)(总容量是256(2K/8)个字节。接口:IIC)


正点原子F4开发板上面A0=A1=A2=0;



如果A2=A1=A0=0;


那么:


读的时候


Device Address=0xA1


写的时候


Device Address=0xA0


24C02写时序:


再把程序列出来:


void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)

{            

    IIC_Start();  

if(EE_TYPE>AT24C16)

{

IIC_Send_Byte(0XA0);     //发送写命令

IIC_Wait_Ack();

IIC_Send_Byte(WriteAddr>>8);//发送高地址   

}else IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0,写数据  

IIC_Wait_Ack();    

    IIC_Send_Byte(WriteAddr%256);   //发送低地址

IIC_Wait_Ack();      

IIC_Send_Byte(DataToWrite);     //发送字节    

IIC_Wait_Ack();         

    IIC_Stop();//产生一个停止条件 

delay_ms(10);  

}

24C02读时序:


相关程序:


u8 AT24CXX_ReadOneByte(u16 ReadAddr)

{   

u8 temp=0;        

    IIC_Start();  

if(EE_TYPE>AT24C16)

{

IIC_Send_Byte(0XA0);    //发送写命令

IIC_Wait_Ack();

IIC_Send_Byte(ReadAddr>>8);//发送高地址     

}else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0xA0,写数据    

IIC_Wait_Ack(); 

    IIC_Send_Byte(ReadAddr%256);   //发送低地址

IIC_Wait_Ack();     

IIC_Start();     

IIC_Send_Byte(0XA1);           //进入接收模式    

IIC_Wait_Ack();  

    temp=IIC_Read_Byte(0);    

    IIC_Stop();//产生一个停止条件    

return temp;

}



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
输入偏置电流消除电阻――您真的需要它们吗?