STM32 通用GPIO模拟I2C实现

2023-05-16

STM32 通用GPIO模拟I2C实现

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

#ifdef HW_I2C1	//硬件I2C初始化
    //PA8-I2C1_SCL
    GPIO_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_SDA
    GPIO_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();   //zyboy
    SCL1_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;
        else
            SDA1_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); //写少于一页的数据
            }
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32 通用GPIO模拟I2C实现 的相关文章

  • STM32F103概要

    The STM32F103x4 STM32F103x6 STM32F103xC STM32F103xD and STM32F103xE are a drop in replacement for STM32F103x8 B medium d
  • STM32 GPIO工作原理详解

    STM32 GPIO介绍 1 STM32引脚说明 GPIO是通用输入 输出端口的简称 是STM32可控制的引脚 GPIO的引脚与外部硬件设备连接 可实现与外部通讯 控制外部硬件或者采集外部硬件数据的功能 以STM32F103ZET6芯片为例
  • linux GPIO C API

    我有一个 powerpc 板 上面运行着 3 2 内核 使用 sysfs 访问 GPIO 按预期工作 例如 gt echo 242 gt sys class gpio export gt cat sys class gpio gpio242
  • 擦除后无法写入闪存

    所以我不能在擦除后直接写入内部闪存 如果写操作之前没有擦除操作 那么我可以 有什么想法吗 编程函数返回 成功写入 值 但查看内存时 没有写入任何数据 这是代码 uint32 t pageAddress 0x08008000 uint16 t
  • mmap 比 ioremap 慢

    我正在为运行 Linux 2 6 37 的 ARM 设备进行开发 我正在尝试尽快切换 IO 引脚 我制作了一个小内核模块和一个用户空间应用程序 我尝试了两件事 使用以下命令直接从内核空间操作 GPIO 控制寄存器ioremap mmap G
  • 1.69寸SPI接口240*280TFT液晶显示模块使用中碰到的问题

    1 69寸SPI接口240 280TFT液晶显示模块使用中碰到的问题说明并记录一下 在网上买了1 69寸液晶显示模块 使用spi接口 分辨率240 280 给的参考程序是GPIO模拟的SPI接口 打算先移植到FreeRtos测试 再慢慢使用
  • STM32 暂停调试器时冻结外设

    当到达断点或用户暂停代码执行时 调试器可以停止 Cortex 中代码的执行 但是 当皮质停止在暂停状态下执行代码时 调试器是否会冻结其他外设 例如 DMA UART 和定时器 您只能保留时间 r 取决于外围设备 我在进入主函数时调用以下代码
  • 在 U-Boot 中使用 I2C 读取多个字节

    我的 Freescale p1022tw 板的 I2C 驱动程序有问题 U Boot 的控制台上有一个从 I2C 设备读取的命令 i2c md chip address 0 1 2 of objects 当我从 id 为 0x60 地址为
  • STM32F207 I2C 测试失败

    我正在使用 STM32F207 微控制器在 STM3220G EVAL 板上学习嵌入式开发 我尝试通过连接同一芯片上的两个 I2C2 和 I2C3 模块并发送 接收字符来测试 I2C 接口 这是我当前编写的代码 使用 mdk arm 5 i
  • 无法使用 OpenOCD 找到脚本文件

    我正在尝试按照本教程将 OpenOCD 与我的 ST 发现板一起使用 https japaric github io discovery README html https japaric github io discovery READM
  • 毕设开题分享 单片机智能教室系统(智能照明+人数统计)

    1 简介 Hi 大家好 今天向大家介绍一个学长做的单片机项目 单片机智能教室系统 智能照明 人数统计 大家可用于 课程设计 或 毕业设计 项目分享 https gitee com feifei1122 simulation project
  • Arm:objcopy 如何知道 elf 中的哪些部分要包含在二进制或 ihex 中?

    我正在开发一个项目 其中涉及解析arm elf 文件并从中提取部分 显然 elf 文件中有很多部分没有加载到闪存中 但我想知道 objcopy 到底如何知道要在二进制文件中包含哪些部分以直接闪存到闪存中 以arm elf文件的以下reade
  • systick定时器

    systick定时器 文章目录 前言 一 前期疑惑 二 解答 1 关于systick是阻塞的吗 2 非阻塞 三 软件编写 总结 前言 这边记录systick相关知识点 一 前期疑惑 在学习systick志气啊 其实对于systick还是一脸
  • 核心耦合内存在 STM32F4xx 上可执行吗?

    尝试从 STM32F429s CCM 运行代码 但每当我命中 CCM 中的第一条指令时 我总是会遇到硬故障 并且 IBUSERR 标志被设置 该指令有效且一致 STM32F4xx 是否可能不允许从 CCM 执行 数据访问效果良好 alios
  • 是什么让 SPI 比 I2C 协议更快 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我了解 I2C 和 SPI 通信的基础知识 因为两者都是同步协议 我想知道是什么让 SPI 比 I2C 更快 如果我没记错的话 使用 I2
  • 按下按钮时 GPIO 事件检测不给出输出

    以下 python 脚本应该等待按钮按下 打印按钮按下消息 然后退出 但是 当我按下按钮时 什么也没有打印 然后 当我按回车键时 脚本会打印 检测到按钮按下 然后停止 我如何修复此代码 以便在按下按钮时打印 检测到按钮按下 我按照教程制作了
  • 从内核模块向用户空间通知 GPIO 中断[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我有一段代码可以检测内核模块中的 GPIO 中断 现在 我正在寻找一种机制 在检测到来自内核模块的 gpio 中断时通知用户空间 任何与不同选项
  • STM32内部时钟

    我对 STM32F7 设备 意法半导体的 Cortex M7 微控制器 上的时钟系统感到困惑 参考手册没有充分阐明这些时钟之间的差异 SYSCLK HCLK FCLK 参考手册中阅读章节 gt RCC 为 Cortex 系统定时器 SysT
  • HAL_Delay() 陷入无限循环

    我被 HAL Delay 函数困住了 当我调用此函数 HAL Delay 时 控制陷入无限循环 在寻找问题的过程中 我发现了这个 http www openstm32 org forumthread2145 threadId2146 htt
  • 哪些变量类型/大小在 STM32 微控制器上是原子的?

    以下是 STM32 微控制器上的数据类型 http www keil com support man docs armcc armcc chr1359125009502 htm http www keil com support man d

随机推荐

  • LayoutLM——文本与布局的预训练用于文档图像理解

    摘要 xff1a 预训练技术近年来在多种NPL任务中取得了广泛的成功 尽管广泛的NPL应用的预训练模型 xff0c 其大多聚焦于文本级别的操作 xff0c 而忽略了布局与风格信息 xff0c 这对文档图像的理解至关重要 该篇论文提出了Lay
  • 初识hash

    1 哈希表 哈希表 xff08 Hash Table xff09 是一种根据关键字直接访问内存存储位置的数据结构 通过哈希表 xff0c 数据元素的存放位置和数据元素的关键字之间建立起某种对应关系 xff0c 建立这种对应关系的函数称为哈希
  • 程序员们,AI来了,机会来了,危机也来了

    程序员们 xff0c AI来了 xff0c 机会来了 xff0c 危机也来了 1 人工智能真的来了 纵观古今 xff0c 很少有计算机技术能有较长的发展寿命 xff0c 大部分昙花一现 xff0c 比如 xff1a 昔日的DOS windo
  • 11.FreeRTOS学习笔记-内存管理

    几种内存分配算法的比较 heap 1 c 管理方案是 FreeRTOS 提供所有内存管理方案中最简单的一个 它只能申请内存而不能进行内存释放 并且申请内存的时间是一个常量 heap 2 c方案支持释放申请的内存 但是它不能把相邻的两个小的内
  • C#(Csharp)基础教程(上)(菜鸟教程笔记)

    C 及其开发环境简介 参考视频 c 教程 1 1 C 概述 C 是一个现代的 通用的 面向对象的编程语言 xff0c 它是由微软 xff08 Microsoft xff09 开发的 xff0c 由 Ecma 和 ISO 核准认可的 C 是由
  • Python 语法糖

    class person def init self func self f 61 func print 34 init 34 def call self args kwargs print 34 call 34 self f 第一种使用装
  • Makefile经典教程(掌握这些足够)

    makefile很重要 什么是makefile xff1f 或许很多Winodws的程序员都不知道这个东西 xff0c 因为那些Windows的IDE都为你做了这个工作 xff0c 但我觉得要作一个好的和professional的程序员 x
  • C语言 mkdir 创建多级目录

    通过例子来说明 xff1a 我要在当前目录下创建 head follow end 目录 C语言中mkdir原型为int mkdir const char pathname mode t mode mkdir 函数以mode方式创建一个以pa
  • pip3 install paramiko 安装失败

    running build ext generating cffi module build temp linux x86 64 cpython 37 cryptography hazmat bindings openssl c creat
  • PX4 的 ECL EKF 公式推导及代码解析

    如有谬误 xff0c 请联系指正 转载请注明出处 联系方式 xff1a e mail ericzzj 64 163 com github https github com ericzzj1989 matlab px4 msf
  • 基于K-近邻算法的手写数字识别研究

    摘要 xff1a 基于K 近邻算法研究手写数字 xff08 0 9 xff09 的识别问题 xff0c 本文通过对手写数字的图像进行处理 xff0c 提取特征向量 xff0c 使用Python实现了K 近邻算法 xff0c 并在此基础上开发
  • MySQL数据库学习体系笔记

    一 数据库系统概论 学习知识点 1 数据管理计算的产生和发展 2 关系型数据库中常用概念 3 结构化查询语音SQL简介 1 数据管理计算的产生和发展 应用程序通过数据库管理系统与数据库进行数据交互 xff08 插入 更新 删除数据 检索数据
  • "NetVLAD"场景识别模型解读

    c论文 xff1a NetVLAD CNN architecture for weakly supervised place recognition 来源 xff1a CVPR 2016 应用 xff1a NetVLAD是一种场景识别算法
  • 装饰器-带参数的装饰器动态传值

    带参数的装饰器动态传值 文章目录 带参数的装饰器动态传值装饰器实现的简单实现装饰器参数动态传入值把装饰器实例方法 改成静态方法装饰器函数写类的外面总结一下 有一个函数 xff0c 返回字符串类型 xff0c 现在需要在这个 字符串上添加链接
  • C#的实现FTP传送文件

    简介 xff1a 接上文实现对FTP的传送文件 xff0c 此文和上文可以说是如出一辙 xff0c 不过此文是通过cmd进行建立连接的 xff0c 建立连接后也是通过以下几个步骤实现操作 建立文件的层级结构如上文 xff0c 这里就不啰嗦了
  • x210v3开发板u-boot-2012.10移植之六---系统时钟初始化

    疯雨 版权所有 xff0c 转载请注明 http blog csdn net u010346967 欢迎加入 朱老师物联网大课堂qq群 一起学习进步 群号 xff1a 397164505 此系列的文章前提 xff1a 熟悉uboot启动流程
  • 安卓手机投屏到win10电脑

    PC端操作 手机端操作 xff08 Mi6为例 xff09 pc端弹出提示 xff0c 选择是
  • 一种解决按键开关电平毛刺问题的算法

    一种解决按键开关电平毛刺问题的算法 通过检测按键开关的相应管脚电平状态来判断按键是否按下 xff0c 按键未按下时 xff0c 对应管脚电平的为高 xff0c 按下之后对应管脚电平变为低电平 xff0c 松开之后 xff0c 回复高电平 x
  • 华为鸿蒙系统:基于微内核的全场景分布式OS

    华为鸿蒙系统 xff1a 基于微内核的全场景分布式OS 1 分布式架构首次用于终端OS xff0c 实现跨终端无缝协同体验 2 确定时延引擎和高性能IPC技术实现系统天生流畅 3 基于微内核架构重塑终端设备可信安全 4 通过统一IDE支撑一
  • STM32 通用GPIO模拟I2C实现

    STM32 通用GPIO模拟I2C实现 通用GPIO模拟I2C通信实现样例 1 GPIO初始化 ifdef HW I2C1 硬件I2C初始化 PA8 I2C1 SCL GPIO StructInit amp GPIO InitStructu