/*
下面给出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 8void 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;elseSDA_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相关推荐

  1. STM32F10x_模拟I2C读写EEPROM(2)(切换SDA方向 + 读ACK位 + 完整代码)

    文章目录 前言 一.宏定义 二.I2C延时函数 1. 注意 三.起始 / 停止信号 1. 时序图 2. 起始信号 3. 停止信号 四.切换SDA方向 1. SDA配置为输入模式 2. SDA配置为输出 ...

  2. STM32F10x_硬件I2C读写EEPROM(标准外设库版本)

    Ⅰ.写在前面 上一篇文章是"STM32F10x_模拟I2C读写EEPROM",讲述使用IO口模拟I2C总线通信,对EEPROM(AT24Xxx)进行读写操作的过程. 上一篇文章主要 ...

  3. I2C—读写EEPROM

    1 I2C协议简介 I2C通讯协议(Inter-IntegratedCircuit)是由Phiilps公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要USART.CAN等通讯协议的外部收发设 ...

  4. 51单片机模拟I2C读写M24LR04

    目录 一. 有关M24LR04的介绍 二. I2C的读写时序 三. 参考代码 四. 调试中遇到的问题 一. 有关M24LR04的介绍 M24LR04是ST公司的一款NFC芯片,支持ISO15693和I ...

  5. 再造STM32---第十九部分:I2C—读写 EEPROM

    本章参考资料:<STM32F4xx 参考手册>.<STM32F4xx 规格书>.库帮助文档<stm32f4xx_dsp_stdperiph_lib_um.chm>及 ...

  6. I2C读写EEPROM

    前言 1.I2C 通讯协议(Inter-Integrated Circuit)是由Phiilps公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要USART.CAN等通讯协议的外部收发设备,现 ...

  7. STM32F103RC引脚模拟I2C操作EEPROM(24C16)的方法总结

    要使用24C16,首先了解一下它. 1.24C16的总容量是16K bit,转换成字节除以8,即为 2K byte. 2.DEVICE ADDRESS的前四位固定为1010,紧跟着的三位,范围是 00 ...

  8. STM32CubeMX学习笔记(9)——I2C接口使用(读写EEPROM AT24C02)

    一.I2C简介 I2C(Inter-Integrated Circuit ,内部集成电路) 总线是一种由飞利浦 Philip 公司开发的串行总线.是两条串行的总线,它由一根数据线(SDA)和一根 时钟 ...

  9. STM32硬件IIC读写EEPROM

    前面一篇写了软件模拟IIC读写EEPROM. 本篇介绍硬件IIC读写EEPROM.平台是STM32F103+AT24C04N.SDA和SCL接5K上拉电阻到3.3v. 首先介绍AT24C04N的基本特 ...

最新文章

  1. 在vs2008中配置OpenCV2.2
  2. GitHub发福利:30多万元资源,学生可以免费用
  3. c++ svd实例整理
  4. jquery导入数据_Web技术——简单的数据库编程
  5. ISO C99中的一些扩展(草稿)
  6. LeetCode 1701. 平均等待时间(模拟)
  7. CREO 6.0 - 基础 - 01 - 零件 - 零件的装配 - 零件的移动、偏转、角度角度设定
  8. 中国内窥镜仪器固定臂市场趋势报告、技术动态创新及市场预测
  9. 沃兹批评苹果避税:纳税还不如我积极
  10. 硅谷战争:苹果、Google和微软上演三国演义
  11. Linux 网卡配置eth1修改为eth0
  12. Java实现生成并下载Excel文件
  13. 打开mysql 的时候报错_关于mysql的启动报错处理
  14. Outlook无法启动一直显示“正在启动”的解决方法
  15. javascript 动态设置样式style
  16. 通过宏代码自动解除excel工作表格保护
  17. 2021湖南省地区高考成绩排名查询,湖南高考排名查询方法,2021年湖南高考成绩位次全省排名查询...
  18. 服务器sas卡的作用,英特尔IOP34x处理器介绍
  19. ROS【IMU】姿态检测与解算
  20. MobileNet实战:tensorflow2.X版本,MobileNetV3图像分类任务(小数据集)

热门文章

  1. python循环代码优化技巧_记一次优化python循环代码逻辑的过程
  2. DP\记忆化搜索-牛客寒假集训营3-牛牛的DRB迷宫I
  3. Flutter中如何选择StatelessWidget和StatefulWidget
  4. 女神异闻录5(p5)系统拆解
  5. redhat linux 禁用网卡,RedHat Linux下防火墙配置技巧
  6. 聊聊旷厂黑科技 | 手机多摄的终极奥义是“多”吗?
  7. 详解APP应用分发平台的榜单推荐和搜索排名规则
  8. c语言中的结构体定义和常见用法
  9. 用友通T3联不上服务器
  10. mysql图形查询操作 点找面及面找点 Polygon获取中心点坐标 空间地理位置计算