×
单片机 > 单片机程序设计 > 详情

stm32_GPIO模拟I2c读写EEPROM

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

/*

下面给出STM32通过GPIO模拟I2C读写EEPROM程序

*/



#define SCL_H GPIOB->BSRR = GPIO_Pin_6

#define SLC_L GPOIB->BRR = GPIO_Pin_6

#define SDA_H GPIOB->BSRR = GPIO_Pin_7

#define SDA_L GPIOB->BRR = GPIO_Pin_7

#define SCL_read GPIOB-IDR & GPIO_Pin_6

#define SDA_read GPIOB->IDR & GPIO_Pin_7



#define I2C_PageSize 8



void I2C_GPIO_Config(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

/*Configure I2C1 Pins:SCL and SDA*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 |GPIO_Pin_7;

GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50Hz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;

GPOI_Init(GPIOB,&GPIO_InitStructure);

}



void I2C_delay(void)

{

u8 i=100; //设置通信速度


while(i)

{

i--;

}



bool I2C_Start(void)

{

SDA_H;

SCL_H;

I2C_delay();

if(!SDA_read) return FALSE;  //SDA线为低电平总线忙,退出


SDA_L;

I2C_delay();

if(SDA_read) return FALSE; //SDA线为高电平则总线出错,退出


SDA_L;

I2C_delay();

return TRUE;

}



void I2C_Stop(void)

{

SCL_L;

I2C_delay();

SDA_L;

I2C_delay();

SCL_H;

I2C_delay();

SDA_H;

I2C_delay(); 

}



void I2C_Ack(void)

{

SCL_L;

I2C_delay();

SDA_L;

I2C_delay();

SCL_H;

I2C_delay();

SCL_L;

I2C_delay(); 

}



void I2C_NoAck(void)

{

SCL_L;

I2C_delay();

SDA_H;

I2C_delay();

SCL_H;

I2C_delay();

SCL_L;

I2C_delay();

}



bool I2C_WaitAck(void)  //返回为:-1有ACK, =0 无ACK

{

SCL_L;

I2C_delay();

SDA_H;

I2C_delay();

SCL_H;

I2C_delay();

if(SDA_read)

{

SCL_L;

return FALSE;

}

SCL_L;

return TRUE;


}



void I2C_SendByte(u8 SendByte) //数据从高位到低位

{

u8 i=8;

while(i--)

{

SCL_L;

I2C_delay();

if(SendByte & 0x80)

SDA_H;

else

SDA_L;

SendByte <<= 1;

I2C_delay();

SCL_H;

I2C_delay();


}

SCL_L; 

}





void I2C_ReceiveByte(void) //数据从高位到低位

{

u8 i=8;

u8 ReceiveByte = 0;


SDA_H;

while(i--)

{

ReceiveByte <<= 1;

SCL_L;

I2C_delay();

SCL_H;

I2C_delay();

if(SDA_read)

{

ReceiveByte|=0x01;

}

SCL_L;

return ReceiveByte; 

}



//写入1字节数据 (代写入数据,待写入地址,器件类型)

bool I2C_WirteByte(u8 SendByte,u16 WriteAddress,u8 DeviceAddress)

{

if(!I2C_Start()) return FALSE;


I2C_SendByte(((WriteAddress & 0x0700)>>7)|DeviceAddress & 0xFFFE); //设置高起始地址 + 器件地址


if(!I2C_WaitAck())

I2C_Stop();

return FALSE;

}

I2C_SendByte((u8)(WriteAddress & 0x00FF)); //设置低起始地址

I2C_WaitAck();

I2C_SendByte(SendByte);

I2C_WaitAck();

I2C_Stop();

//注意:因为这里要等待EERPOM写完成,可以采用查询 或延时方式(10ms)

//Systick_Delay_1ms(10);

return TRUE;

}



//注意不能跨页写

//写入1串数据(待写入数组地址,待写入长度,待写入地址,器件类型)

bool I2C_BufferWrite(u8 *pBuffer,u8 length,u16 WriteAddress,u8 DeviceAddress)

{

if(!I2C_Start()) return FALSE;


I2C_SendByte(((WriteAddress & 0x0700)>>7)|DeviceAddress & 0xFFFE); //设置高起始地址 + 器件地址


if(!I2C_WaitAck())

I2C_Stop();

return FALSE;

}

I2C_SendByte((u8)(WriteAddress & 0x00FF)); //设置低起始地址

I2C_WaitAck();



while(length--)

{

I2C_SendByte(*pBuffer);

I2C_WaitAck();

pBuffer++; 

}

I2C_Stop();

//注意:因为这里要等待EERPOM写完成,可以采用查询 或延时方式(10ms)

//Systick_Delay_1ms(10);

return TRUE; 

}



//跨页写入1串数据(待写入数组地址,待写入长度,待写入地址,器件类型)

void I2C_PageWrite(u8 *pBuffer,u8 length,u16 WriteAddress,u8 DeviceAddress )

{

u8 NumOfPage=0,NumOfSingle=0,Addr=0,count=0;

Addr = WriteAddress%I2C_PageSize; //写入地址是开始页的第几页

count = I2C_PageSize - Addr; //在开始页要写入的个数

NumOfPage = length/I2C_PageSize; //要写入的页数

NumOfSingle = length%I2C_PageSize; //不足一页的个数

if(Addr == 0) //写入地址是页开始

{

if(NumOfPage == 0) //数据小于一页

{

I2C_BufferWrite(pBuffer,NumOfSingle,WriteAddress,DeviceAddress); //写少于一页的数据 

}

else //数据大于一页

{

while(NumOfPage) //要写入的页数

{

I2C_BufferWrite(pBuffer,I2C_PageSize,WriteAddress,DeviceAddress);//写一页的数据

WriteAddress += I2C_PageSize;

pBuffer += I2C_PageSize;

NumOfPage--;

Systick_Delay_1ms(10);

}

if(NumOfSingle!=0) //剩余数据小于一页

{

I2C_BufferWrite(pBuffer,NumOfSingle,WriteAddress,DeviceAddress); 

//写少于一页的数据

Systick_Delay_1ms(10);

}

}

}

else  //写入的数据不是页的开始

{

if(NumOfPage == 0) //数据小于一页

{

I2C_BufferWrite(pBuffer,NumOfSingle,WriteAddress,DeviceAddress);

//写少于一页的数据

}

else  //数据大于等于一页

{

length = count;

NumOfPage = length / I2C_PageSize; //重新计算要写入的页数

NumOfSingle = length % I2C_PageSize;

//重新计算不足一页的个数


if(count!=0)

{

I2C_BufferWrite(pBuffer,count,WriteAddress,DeviceAddress);

//将开始的空间写满一页


WriteAddress += count;

pBuffer +=count;

}


while(NumOfPage--) //要写入的页数

{

I2C_BufferWrite(pBuffer,I2C_PageSize,WriteAddress,DeviceAddress); //写一页的数据


WriteAddress += I2C_PageSize;

pBuffer += I2C_PageSize; 

}


if(NumOfSingle != 0) //剩余数据小于一页

{

I2C_BufferWrite(pBuffer,NumOfSingle,WriteAddress,DeviceAddress); 

//写少于一页的数据

}

}


}

}





//读出1串数据(存放读出数据,待读出长度,带读出地址,器件类型)

bool I2C_ReadByte(u8 *pBuffer,u8 length,u16 ReadAddress,u8 DeviceAddress)

{

if(!I2C_Start()) return FALSE;

I2C_SendByte(((ReadAddress&0x0700)>>7)|DeviceAddress&0xFFFE);//设置高起始地址+器件地址

if(!I2C_WaitAck())

{

I2C_Stop();

return FALSE;

}

I2C_SendByte((u8)(ReadAddress & 0x00FF));//设置低起始地址

I2C_WaitAck();

I2C_Start();

I2C_SendByte(((ReadAddress&0x0700)>>7)|DeviceAddress&0x0001);

I2C_WaitAck();

while(length)

{

*pBuffer = I2C_ReceiveByte();

if(length==1) I2C_NoAck();

else I2C_Ack();

pBuffer++;

length--;

}

I2C_Stop;

return TRUE;

}




/*

下面给出STM32通过GPIO模拟I2C读写EEPROM程序

*/

 

#define SCL_H GPIOB->BSRR = GPIO_Pin_6

#define SLC_L GPOIB->BRR = GPIO_Pin_6

#define SDA_H GPIOB->BSRR = GPIO_Pin_7

#define SDA_L GPIOB->BRR = GPIO_Pin_7

#define SCL_read GPIOB-IDR & GPIO_Pin_6

#define SDA_read GPIOB->IDR & GPIO_Pin_7

 

#define I2C_PageSize 8

 

void I2C_GPIO_Config(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

/*Configure I2C1 Pins:SCL and SDA*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 |GPIO_Pin_7;

GPIO_InitStructure.GPIO_Speed =GPIO_Speed_50Hz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;

GPOI_Init(GPIOB,&GPIO_InitStructure);

}

 

void I2C_delay(void)

{

u8 i=100; //设置通信速度

while(i)

{

i--;

}

}

 

bool I2C_Start(void)

{

SDA_H;

SCL_H;

I2C_delay();

if(!SDA_read) return FALSE;  //SDA线为低电平总线忙,退出

SDA_L;

I2C_delay();

if(SDA_read) return FALSE; //SDA线为高电平则总线出错,退出

SDA_L;

I2C_delay();

return TRUE;

}

 

void I2C_Stop(void)

{

SCL_L;

I2C_delay();

SDA_L;

I2C_delay();

SCL_H;

I2C_delay();

SDA_H;

I2C_delay();

}

 

void I2C_Ack(void)

{

SCL_L;

I2C_delay();

SDA_L;

I2C_delay();

SCL_H;

I2C_delay();

SCL_L;

I2C_delay();

}

 

void I2C_NoAck(void)

{

SCL_L;

I2C_delay();

SDA_H;

I2C_delay();

SCL_H;

I2C_delay();

SCL_L;

I2C_delay();

}

 

bool I2C_WaitAck(void)  //返回为:-1有ACK, =0 无ACK

{

SCL_L;

I2C_delay();

SDA_H;

I2C_delay();

SCL_H;

I2C_delay();

if(SDA_read)

{

SCL_L;

return FALSE;

}

SCL_L;

return TRUE;

}

 

void I2C_SendByte(u8 SendByte) //数据从高位到低位

{

u8 i=8;

while(i--)

{

SCL_L;

I2C_delay();

if(SendByte & 0x80)

SDA_H;

else

SDA_L;

SendByte <<= 1;

I2C_delay();

SCL_H;

I2C_delay();

}

SCL_L;

}

void I2C_ReceiveByte(void) //数据从高位到低位

{

u8 i=8;

u8 ReceiveByte = 0;

SDA_H;

while(i--)

{

ReceiveByte <<= 1;

SCL_L;

I2C_delay();

SCL_H;

I2C_delay();

if(SDA_read)

{

ReceiveByte|=0x01;

}

}

SCL_L;

return ReceiveByte;

}

//写入1字节数据 (代写入数据,待写入地址,器件类型)

bool I2C_WirteByte(u8 SendByte,u16 WriteAddress,u8 DeviceAddress)

{

if(!I2C_Start()) return FALSE;

I2C_SendByte(((WriteAddress & 0x0700)>>7)|DeviceAddress & 0xFFFE); //设置高起始地址 + 器件地址

if(!I2C_WaitAck())

{

I2C_Stop();

return FALSE;

}

I2C_SendByte((u8)(WriteAddress & 0x00FF)); //设置低起始地址

I2C_WaitAck();

I2C_SendByte(SendByte);

I2C_WaitAck();

I2C_Stop();

//注意:因为这里要等待EERPOM写完成,可以采用查询 或延时方式(10ms)

//Systick_Delay_1ms(10);

return TRUE;

}

 

//注意不能跨页写

//写入1串数据(待写入数组地址,待写入长度,待写入地址,器件类型)

bool I2C_BufferWrite(u8 *pBuffer,u8 length,u16 WriteAddress,u8 DeviceAddress)

{

if(!I2C_Start()) return FALSE;

I2C_SendByte(((WriteAddress & 0x0700)>>7)|DeviceAddress & 0xFFFE); //设置高起始地址 + 器件地址

if(!I2C_WaitAck())

{

I2C_Stop();

return FALSE;

}

I2C_SendByte((u8)(WriteAddress & 0x00FF)); //设置低起始地址

I2C_WaitAck();

 

while(length--)

{

I2C_SendByte(*pBuffer);

I2C_WaitAck();

pBuffer++;

}

I2C_Stop();

//注意:因为这里要等待EERPOM写完成,可以采用查询 或延时方式(10ms)

//Systick_Delay_1ms(10);

return TRUE;

}

 

//跨页写入1串数据(待写入数组地址,待写入长度,待写入地址,器件类型)

void I2C_PageWrite(u8 *pBuffer,u8 length,u16 WriteAddress,u8 DeviceAddress )

{

u8 NumOfPage=0,NumOfSingle=0,Addr=0,count=0;

Addr = WriteAddress%I2C_PageSize; //写入地址是开始页的第几页

count = I2C_PageSize - Addr; //在开始页要写入的个数

NumOfPage = length/I2C_PageSize; //要写入的页数

NumOfSingle = length%I2C_PageSize; //不足一页的个数

if(Addr == 0) //写入地址是页开始

{

if(NumOfPage == 0) //数据小于一页

{

I2C_BufferWrite(pBuffer,NumOfSingle,WriteAddress,DeviceAddress); //写少于一页的数据

}

else //数据大于一页

{

while(NumOfPage) //要写入的页数

{

I2C_BufferWrite(pBuffer,I2C_PageSize,WriteAddress,DeviceAddress);//写一页的数据

WriteAddress += I2C_PageSize;

pBuffer += I2C_PageSize;

NumOfPage--;

Systick_Delay_1ms(10);

}

if(NumOfSingle!=0) //剩余数据小于一页

{

I2C_BufferWrite(pBuffer,NumOfSingle,WriteAddress,DeviceAddress);

//写少于一页的数据

Systick_Delay_1ms(10);

}

}

}

else  //写入的数据不是页的开始

{

if(NumOfPage == 0) //数据小于一页

{

I2C_BufferWrite(pBuffer,NumOfSingle,WriteAddress,DeviceAddress);

//写少于一页的数据

}

else  //数据大于等于一页

{

length = count;

NumOfPage = length / I2C_PageSize; //重新计算要写入的页数

NumOfSingle = length % I2C_PageSize;

//重新计算不足一页的个数

if(count!=0)

{

I2C_BufferWrite(pBuffer,count,WriteAddress,DeviceAddress);

//将开始的空间写满一页

WriteAddress += count;

pBuffer +=count;

}

while(NumOfPage--) //要写入的页数

{

I2C_BufferWrite(pBuffer,I2C_PageSize,WriteAddress,DeviceAddress); //写一页的数据

WriteAddress += I2C_PageSize;

pBuffer += I2C_PageSize;

}

if(NumOfSingle != 0) //剩余数据小于一页

{

I2C_BufferWrite(pBuffer,NumOfSingle,WriteAddress,DeviceAddress); 

//写少于一页的数据

}

}

}

}

 

 

//读出1串数据(存放读出数据,待读出长度,带读出地址,器件类型)

bool I2C_ReadByte(u8 *pBuffer,u8 length,u16 ReadAddress,u8 DeviceAddress)

{

if(!I2C_Start()) return FALSE;

I2C_SendByte(((ReadAddress&0x0700)>>7)|DeviceAddress&0xFFFE);//设置高起始地址+器件地址

if(!I2C_WaitAck())

{

I2C_Stop();

return FALSE;

}

I2C_SendByte((u8)(ReadAddress & 0x00FF));//设置低起始地址

I2C_WaitAck();

I2C_Start();

I2C_SendByte(((ReadAddress&0x0700)>>7)|DeviceAddress&0x0001);

I2C_WaitAck();

while(length)

{

*pBuffer = I2C_ReceiveByte();

if(length==1) I2C_NoAck();

else I2C_Ack();

pBuffer++;

length--;

}

I2C_Stop;

return TRUE;

}

 


关键字:stm32  GPIO  模拟I2c  读写EEPROM 

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

热门文章 更多
C51 特殊功能寄存器SFR的名称和地址