i2c基本读写过程(每日小结5.I2C部分程序)

//EEPROM 24C02 通过IIC 总线与外部连接//硬件上24C02的SCL线和SDA线接在PC12和PC11上,接下来我们就来聊聊关于i2c基本读写过程?以下内容大家不妨参考一二希望能帮到您!

i2c基本读写过程(每日小结5.I2C部分程序)

i2c基本读写过程

//EEPROM 24C02 通过IIC 总线与外部连接。

//硬件上24C02的SCL线和SDA线接在PC12和PC11上。

参考资料:原子哥stm32 mini开发板

https://blog.csdn.net/shaguahaha/article/details/70766665

1.I2C初始化

void I2C_Init()

{

GPIO_InitTypeDef GPIO_InitStruct;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//使能GPIOC外设 时钟

GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;

GPIO_InitStruct.GPIO_Pin=GPIO_Pin_11;

GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(GPIOC,&GPIO_InitStruct);//外设初始化,PC.11---SDA数据线,发数据,收数据,在这是先初始化为输出模式,但其既要配置成输入,又要配置成输出。怎么办呢?

//1.可以使用宏定义直接操作寄存器。

#define SDA_IN() {GPIOC->CRH &=0xFFFF0FFFF;GPIOC->CRH |= 0xFFFF8FFF; }

#define SDA_OUT() {GPIOC->CRH &=0xFFFF0FFFF;GPIOC->CRH |= 0xFFFF3FFF;}

2.可以写2个函数,SDA_Out()和SDA_In(),函数里就是配置GPIO_Init;

GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;

GPIO_InitStruct.GPIO_Pin=GPIO_Pin_12;

GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(GPIOC,&GPIO_InitStruct);//外设初始化,PC.12,作为SCL时钟线,推挽输出

//I2C初始化时设为空闲状态,SDA、SCL均拉高

SCL=1;

SDA=1;//宏定义为引脚PC11

}

2.开始信号---SCL为高,SDA由高变低

//参考https://blog.csdn.net/shaguahaha/article/details/70766665

//在SCL高电平,SDA由高到低,在此之前,SDA的高电平必须保持>4.7us,起始信号变成低电平之后,还要延时>4us

void start()

{

SDA_IN();

SDA=1;

delay_us(5);//延时5us,使其稳定,记得在郭天祥的51单片机中有详细讲过,参考博客中也有说明。

SCL=1;

delay_us(5);

SDA=0;

delay_us(5);

SCL=0;//拉低SCL,原子哥说的是钳住I2C总线,准备发送或接收。钳住是什么意思?

//搜索后理解了:数据只允许在SCL为低时变化,SCL为高时,数据锁存;此时拉低SCL是准备开始写数据。

}

3.停止信号---SCL为高,SDA由低变高

void stop()

{

SDA_IN();

SCL=0;//如果SCL为高,且这时SDA为高,则下一步的拉低SDA则会被看成是一个开始信号。

delay_us(5);

SDA=0;

delay_us(5);

SCL=1;

delay_us(5);

SDA=1;

delay_us(5);

}

4.等待应答信号到来

//返回值:1,接收应答失败

// 0,接收应答成功

unsigned char WaitAck(void)

{

u8 ucErrTime=0;

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

SDA=1;

delay_us(1);

SCL=1;

delay_us(1);//SDA、SCL拉高,总线处于空闲状态。

while(RECEIVESDA)

{

ucErrTime ;

if(ucErrTime>250)

{

IIC_Stop();

return 1;

}

}

IIC_SCL=0;//时钟输出0

return 0;

}

5.应答信号---接收器在第9个时钟脉冲之前(前8个脉冲传输8bit数据)的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。

//应答-答复,SDA线,要设置为输出

void ACK()

{

SDA_OUT();

SCL=0;

delay_us(5);

SDA=0;//拉低

delay_us(5);

SCL=1;//高电平期间,保持SDA为低

delay_us(5);

SCL=0;

delay_us(5);

}

6.非应答信号,SDA与应答相反

void NACK()

{

SDA_OUT();

SCL=0;

delay_us(5);

SDA=1;

delay_us(5);

SCL=1;//高电平期间,保持SDA为低

delay_us(5);

SCL=0;

delay_us(5);

}

7.发送一个数据(1Byte=8bit),从高位开始

void SendData(unsigned char data)

{

int i;

SDA_OUT();

SCL=0;//拉低SCL---数据有效性:时钟信号(SCL)为高电平期间,数据线(SDA)上的数据必须保持稳定。

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

SDA=(data & 0x80)>>7;//当数据的最高位值0、1,赋给SDA

data=data<<1; //数据左移一位,第7位变成了最高位

SCL=1;//发数据

delay_us(2);

SCL=0;//发送完毕,拉低SCL,准备发送一个数据

delay_us(2);

}

}

8.接收数据

unsigned char ReadData(unsigned char ack)

{

u8 RevData; //接收到的数据

SDA_IN();

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

{

//数据准备

SCL=0;

delay_us(2);

SCL=1; //主机开始读数据

if(RECEIVESDA) RevData ; //接收到的是1,宏定义的SDA输入引脚

RevData<<=1;

delay_us(1);

}

if(ack) { //说明主机需要给从机应答

NACK();

}else{ //主机不需要给应答

ACK();

}

return RevData;

}

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页