i2c基本读写过程(每日小结5.I2C部分程序)
//EEPROM 24C02 通过IIC 总线与外部连接//硬件上24C02的SCL线和SDA线接在PC12和PC11上,接下来我们就来聊聊关于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