STM32 通用GPIO模拟I2C实现

通用GPIO模拟I2C通信实现样例
1 GPIO初始化

#ifdef HW_I2C1   //硬件I2C初始化//PA8-I2C1_SCLGPIO_StructInit(&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_I2C1);
#else   //模拟I2C初始化GPIO_StructInit(&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET);GPIO_Init(GPIOA, &GPIO_InitStructure);
#endif#ifdef HW_I2C1 //硬件I2C初始化//PC9-I2C1_SDAGPIO_StructInit(&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_I2C1);
#else  //模拟I2C初始化GPIO_StructInit(&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;GPIO_WriteBit(GPIOC, GPIO_Pin_9, Bit_SET);GPIO_Init(GPIOC, &GPIO_InitStructure);
#endif

2 模拟I2C实例代码

#define M24LC256_ADDR 0xAE
#define M24LC256_PAGESIZE 64
#define M24LC256_WRITE_DELAY delay_ms(15)
static const u32 I2C_CLK_STRETCHING_TIMEOUT = 60000;
static const u32 I2C_WAIT_ACK_TIMEOUT = 30000;
static u32 i2c_clk_stretching_timer = 0;
static u32 i2c_wait_ack_timer = 0;
#define SCL1_H GPIO_SetBits(GPIOA, GPIO_Pin_8)
#define SCL1_L GPIO_ResetBits(GPIOA, GPIO_Pin_8)
#define SDA1_H GPIO_SetBits(GPIOC, GPIO_Pin_9)
#define SDA1_L GPIO_ResetBits(GPIOC, GPIO_Pin_9)
#define SDA1_READ (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_9))
#define SCL1_READ (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8))
static u8 I2C_Start(void)
{SDA1_H;I2C_delay();   //zyboySCL1_H;I2C_delay();i2c_clk_stretching_timer = 0;while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);  if(!SDA1_READ)return 0; //SDA线为低电平则总线忙,退出SDA1_L;I2C_delay();if(SDA1_READ)return 0; //SDA线为高电平则总线出错,退出SCL1_L;I2C_delay();return 1;
}
static void I2C_Stop(void)
{SCL1_L;I2C_delay();SDA1_L;I2C_delay();SCL1_H;i2c_clk_stretching_timer = 0;while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT); I2C_delay();SDA1_H;I2C_delay();
}
static void I2C_Ack(void)
{SCL1_L;I2C_delay();SDA1_L;I2C_delay();SCL1_H;i2c_clk_stretching_timer = 0;while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT); I2C_delay();SCL1_L;I2C_delay();
}
static void I2C_NoAck(void)
{SCL1_L;I2C_delay();SDA1_H;I2C_delay();SCL1_H;i2c_clk_stretching_timer = 0;while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);   I2C_delay();SCL1_L;I2C_delay();
}
static u8 I2C_WaitAck(void) //返回为:=1有ACK,=0无ACK
{delay_us(10);SCL1_L;I2C_delay();SDA1_H;I2C_delay(); i2c_wait_ack_timer = 0;while((SDA1_READ) && i2c_wait_ack_timer++<=I2C_WAIT_ACK_TIMEOUT);  if(!SDA1_READ){SCL1_H;i2c_clk_stretching_timer = 0;while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);  I2C_delay();SCL1_L;return 1;}return 0;
}
static void I2C_SendByte(u8 SendByte) //数据从高位到低位
{u8 i = 8;while(i--){SCL1_L;I2C_delay();if(SendByte&0x80)SDA1_H;elseSDA1_L;SendByte<<=1;I2C_delay();SCL1_H;i2c_clk_stretching_timer = 0;while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);  I2C_delay();}SCL1_L;
}
static u8 I2C_ReceiveByte(void) //数据从高位到低位
{u8 i = 8;u8 ReceiveByte = 0;SDA1_H;while(i--){ReceiveByte <<= 1;SCL1_L;I2C_delay();SCL1_H;i2c_clk_stretching_timer = 0;while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT); I2C_delay();if(SDA1_READ){ReceiveByte |= 0x01;}}SCL1_L;return ReceiveByte;
}
static u8 Deal_IIC_Data(u8 slave_addr, u8 *sdata, u16 slen, u8 *rdata, u16 rlen)
{u16 i = 0;if(slen > 0){if(!I2C_Start())return 0;I2C_SendByte(slave_addr);if(!I2C_WaitAck()){I2C_Stop();return 0;}        for(i = 0; i < slen; i++){I2C_SendByte(sdata[i]);if(!I2C_WaitAck()){I2C_Stop();return 0;}}}if(rlen > 0){if(!I2C_Start())return 0;I2C_SendByte(slave_addr | 0x01);if(!I2C_WaitAck()){I2C_Stop();return 0;}for(i = 0; i < rlen; i++){rdata[i] = I2C_ReceiveByte();if(i == (rlen-1)){I2C_NoAck();}else{I2C_Ack();}}}I2C_Stop();return 1;
}
void M24LC256_Program_Page(u16 addr, u8 *data, u16 len)
{u16 i = 0;u8 *sdata;sdata = (u8 *)malloc(len+2);sdata[0] = addr / 0x100;sdata[1] = addr % 0x100;for(i = 0; i < len; i++){sdata[2+i] = data[i];}Deal_IIC_Data(M24LC256_ADDR, sdata, len+2, NULL, 0);M24LC256_WRITE_DELAY;free(sdata);
}
void M24LC256_Program_Byte(u16 addr, u8 data)
{u8 sdata[3];sdata[0] = addr / 0x100;sdata[1] = addr % 0x100;sdata[2] = data;Deal_IIC_Data(M24LC256_ADDR, sdata, 3, NULL, 0);M24LC256_WRITE_DELAY;
}void M24LC256_Read_Bytes(u16 addr, u8 *data, u16 len)
{u8 sdata[2];sdata[0] = addr / 0x100;sdata[1] = addr % 0x100;Deal_IIC_Data(M24LC256_ADDR, sdata, 2, data, len);
}
void M24LC256_Program(u16 addr, u8 *data, u16 len)  //此接口存在bug,需优化
{u8 page_num = 0, single_num = 0, current_addr = 0, first_page_num = 0;current_addr = addr % M24LC256_PAGESIZE; //写入地址是开始页的第几位first_page_num = M24LC256_PAGESIZE - current_addr; //在开始页要写入的个数page_num = len / M24LC256_PAGESIZE; //要写入的页数single_num = len % M24LC256_PAGESIZE; //不足一页的个数if(current_addr == 0) //写入地址是页的开始{if(page_num == 0) //数据小于一页{M24LC256_Program_Page(addr, data, single_num); //写少于一页的数据}else //数据大于等于一页{while(page_num) //要写入的页数{M24LC256_Program_Page(addr, data, M24LC256_PAGESIZE); //写一页的数据addr += M24LC256_PAGESIZE;data += M24LC256_PAGESIZE;page_num--;}if(single_num != 0) //剩余数据小于一页{M24LC256_Program_Page(addr, data, single_num); //写少于一页的数据}}}else //写入地址不是页的开始{if(page_num == 0) //数据小于一页{M24LC256_Program_Page(addr, data, single_num); //写少于一页的数据}else //数据大于等于一页{len -= first_page_num;page_num = len / M24LC256_PAGESIZE; //重新计算要写入的页数single_num = len % M24LC256_PAGESIZE; //重新计算不足一页的个数if(first_page_num != 0){M24LC256_Program_Page(addr, data, first_page_num); //将开始的空间写满一页addr += first_page_num;data += first_page_num;}while(page_num--) //要写入的页数{M24LC256_Program_Page(addr, data, M24LC256_PAGESIZE); //写一页的数据addr += M24LC256_PAGESIZE;data += M24LC256_PAGESIZE;}if(single_num != 0) //剩余数据小于一页{M24LC256_Program_Page(addr, data, single_num); //写少于一页的数据}}}
}

STM32 通用GPIO模拟I2C实现相关推荐

  1. 【STM32】GPIO模拟I2C程序示例

    00. 目录 文章目录 00. 目录 01. IIC简介 02. 功能描述 03. 硬件模块 04. 软件设计 05. 结果验证 06. 附录 07. 声明 01. IIC简介 IIC(Inter-I ...

  2. 外设驱动库开发笔记8:GPIO模拟I2C驱动

    I2C总线简单方便,是我们经常使用的一种总线.但有时候我们的MCU没有足够多的I2C控制器来实现我们的应用,所幸我可以使用普通的GPIO引脚来模拟低速的I2C总线通信.这一节我们就来实现使用软件通过普 ...

  3. linux源码gpio模拟i2c,linux内核gpio模拟i2c实例.doc

    linux内核gpio模拟i2c实例.doc linux内核GPIO模拟I2C实例2010-10-11作者:cvip302814来源:cvip302814的blog前言:在许多情况下,我们并没有足够的 ...

  4. GPIO模拟I2C程序实现

    GPIO模拟I2C程序实现. I2C是由Philips公司发明的一种串行数据通信协议,仅使用两根信号线:SerialClock(简称SCL)和SerialData(简称SDA).I2C是总线结构,1个 ...

  5. Linux I2C子系统分析之(一) ----- 用GPIO模拟I2C总线

    在drivers/i2c/busses下包含各种I2C总线驱动,如S3C2440的I2C总线驱动i2c-s3c2410.c,使用GPIO模拟I2C总线的驱动i2c-gpio.c,这里只分析i2c-gp ...

  6. S5PV210之GPIO模拟I2c时序之pcf8591与at24xx linux3.0.8驱动

    目录:一. 说明 二. 驱动程序说明及问题 三. 案例一       四. 案例二 一. 说明 mini210开发板上带了at24c08, 看了linux内核自带的at24.c的驱动程序,编译下载到看 ...

  7. i2c 驱动五:gpio模拟i2c

    有关linux的i2c相关文章有一下几篇,他们互相关联,应该一同看: - i2c 驱动一:简介 - i2c 驱动二:devfs文件系统 - i2c 驱动三:自己实现设备和驱动分离 - i2c 驱动四: ...

  8. MTK6592 GPIO模拟I2C

    虽然Linux内核支持该功能,但是MTK并不支持I2C-GPIO功能,官方说法是硬件I2C接口已经够多,不需要软件模拟,并且用GPIO模拟I2C会影响系统性能... 所以,要做的,就是将被MTK阉割的 ...

  9. GPIO模拟I2C通信协议(二)

    GPIO模拟2C读写E2PROM 1 E2PROM简介 2 AT24C28的读写逻辑 2.1 单字节写入 (BYTE WRITE) 2.2 页写入 (PAGE WRITE) 2.3 读取当前地址 (C ...

最新文章

  1. 系统登录界面的验证码
  2. Nginx 负载均衡配置和策略
  3. 个人总结------高级知识点必会
  4. 记一次node+react项目发布过程(一)--webpack生产环境打包优化
  5. java双缓冲绘图_Java双缓冲技术-绘图应用
  6. 在互联网行业呆了这么多年
  7. windows之bat之批处理复制文件
  8. android gdbserver
  9. echarts怎么保存图片到剪切板上_Mac上微信、QQ的聊天图片和记录保存在哪?如何清理或导出?...
  10. noip2013解题报告
  11. RANSAC算法思想与实现点云粗配准
  12. win10 IDE改AHCI,无需重装系统
  13. 词法分析(三):有限自动机DFA与NFA
  14. 微信自动发卡机器人说明
  15. 给计算机图片文件夹加密码,文件夹加密软件如何给照片文件夹加密
  16. 切披萨n块需要几刀原理c语言,别再问我披萨要切几块了
  17. dos下的for命令详解(zz)
  18. 【Java】认识Sring、String的常见操作和StringBuffer 和StringBuilder的区别【字符串详解】
  19. 10首现代诗歌欣赏:什么是孤独
  20. 现货黄金赚吗:黄金实战技巧

热门文章

  1. Asciinema - 终端日志记录神器,机器学习开发者的福音
  2. ubuntu下使用netplan配置网络
  3. 小白怎么学习云计算?2020最新云计算学习路线图
  4. Kubernetes K8S之资源控制器Job和CronJob详解
  5. [深入研究4G/5G/6G专题-40]: URLLC-11-《3GPP URLLC相关协议、规范、技术原理深度解读》-5-5G Qos原理与架构: 切片、PDU会话、QosFlow、5QI、DRB
  6. 第39级台阶 小明刚刚看完电影《第39级台阶》,离开电影院的时候,他数了数礼堂前的台阶数,恰好是39级!
  7. 墙外干货:如何通过风格指南驱动模块化交互设计
  8. 华为的全闪存存储之路
  9. 超简单的位运算---再也不用担心看不懂题解了
  10. mac mtu测试_从Mac OS X的命令行设置MTU大小