14 STM32 - IIC (时序图+软件源码)

news2024/12/28 21:59:16

14.1 IIC简介

IIC(Inter-Integrated Circuit),中文集成电路总线,是一种串行通信总线,使用多主从架构。I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。主设备通过两个IO口便可以访问许多设备,因此可以节约IO口。IIC主从之间只有一根数据线,可以收数据,也可以发数据,但是不能同时收发,因此IIC属于半双工的通信模式。IIC硬件电路通常两根线接4.7K-10K电阻上拉到3.3V。结构如下图所示。
在这里插入图片描述

14.2 IIC时序

IIC两根线传输数据的信号分为开始信号,传输信号,应答信号,结束信号。
开始信号:SCL为高电平时,SDA由高向低跳变。
传输信号:SCL为高电平时,SDA的电平信号(整个SCL为高时,要确保SDA信号保持不变,只有SCL低电平时,SDA电平才能改变)。
应答信号:传输信号完成后,SDA在SCL低电平时输出高电平,然后修改为输入模式,待SCL为高时读取SDA电平,为高是否定应答信号,为低是肯定应答信号。
结束信号:SCL为高电平时,SDA由低向高跳变。
如下图,即完成一次8字节数据传输,发送的数据为:0xB2,(二进制: 10110110)
在这里插入图片描述

1: 开始信号;
2:数据改变,只有SCL为低时才能修改;
3-10:数据传输,数据为0xB2,(二进制: 10110110)
11:应答信号:高为从机确定收到数据,低为从机不确定收到数据
12: 结束信号

14.3 软件模拟源码:

#include "soft_iic.h"
#include "delay.h"

//IO操作函数     
#define IIC_SCL    PBout(6) //SCL
#define IIC_SDA    PBout(7) //SDA     
#define READ_SDA   PBin(7)  //输入SDA 

//IO方向设置
#define SDA_IN()  { GPIOB->MODER&=~(3<<(7*2));GPIOB->MODER|=0<<7*2; }  //PB7输入模式
#define SDA_OUT() { GPIOB->MODER&=~(3<<(7*2));GPIOB->MODER|=1<<7*2; }  //PB7输出模式



//初始化IIC
void IICInit(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    
    //GPIOB8,B9初始化设置
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;   //普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;  //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;    //上拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);          //初始化
    IIC_SCL=1;
    IIC_SDA=1;
}

//产生IIC起始信号
static void IIC_Start(void)
{
    SDA_OUT();     //sda线输出
    IIC_SDA=1;
    IIC_SCL=1;
    DelayUs(4);
    IIC_SDA=0;    //START:when CLK is high,DATA change form high to low 
    DelayUs(4);
    IIC_SCL=0;    //钳住I2C总线,准备发送或接收数据 
}

//产生IIC停止信号
static void IIC_Stop(void)
{
    SDA_OUT();  //sda线输出
    IIC_SCL=0;
    IIC_SDA=0;  //STOP:when CLK is high DATA change form low to high
    DelayUs(4);
    IIC_SCL=1; 
    IIC_SDA=1;  //发送I2C总线结束信号
    DelayUs(4);                                   
}

//等待应答信号到来
//返回值:1,接收应答失败    0,接收应答成功
static u8 IIC_Wait_Ack(void)
{
    u8 ucErrTime=0;
    SDA_IN();      //SDA设置为输入  
    IIC_SDA=1;DelayUs(1);       
    IIC_SCL=1;DelayUs(1);     
    while(READ_SDA)
    {
        ucErrTime++;
        if(ucErrTime>250) // 超时错误
        {
            IIC_Stop();
            return 1;
        }
    }
    IIC_SCL=0; //时钟输出0        
    return 0; // 有应答返回0
}

//产生ACK应答
static void IIC_Ack(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=0;
    DelayUs(2);
    IIC_SCL=1;
    DelayUs(2);
    IIC_SCL=0;
}

//不产生ACK应答            
static void IIC_NAck(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=1;
    DelayUs(2);
    IIC_SCL=1;
    DelayUs(2);
    IIC_SCL=0;
}

static void IIC_Send_Byte(u8 txd)
{                        
    u8 t;
    SDA_OUT();
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1;
        DelayUs(2);   //对TEA5767这三个延时都是必须的
        IIC_SCL=1;
        DelayUs(2);
        IIC_SCL=0;
        DelayUs(2);
    }
}

static u8 IIC_Read_Byte(unsigned char ack)
{
    unsigned char i,receive=0;
    SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
    {
        IIC_SCL=0; 
        DelayUs(2);
        IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;
        DelayUs(1); 
    }
    if (ack)
        IIC_Ack(); //发送ACK   
    else
        IIC_NAck(); //发送nACK
    return receive;
}

直接调用以上API函数,可以读写24C02(EEPROM)。

// 读1字节内容
u8 W24C_ReadOneByte(u16 addr, u8* data)
{
    IIC_Start();
    IIC_Send_Byte(0xA0);
    if(1 == IIC_Wait_Ack())
    {
        return 1; // err
    }
    IIC_Send_Byte(addr>>8);
    if(1 == IIC_Wait_Ack())
    {
        return 2; // err
    }
    IIC_Send_Byte(addr&0x0FF);
    if(1 == IIC_Wait_Ack())
    {
        return 3; // err
    }
    IIC_Start();
    IIC_Send_Byte(0xA1);
    if(1 == IIC_Wait_Ack())
    {
        return 4; // err
    }
    data[0] = IIC_Read_Byte(0);
    IIC_Stop();
    return 0;
}


// 读n字节内容
u8 W24C_ReadByte(u16 addr, u8* buf, u16 len)
{
    u16 i;
    IIC_Start();
    IIC_Send_Byte(0xA0);
    if(1 == IIC_Wait_Ack())
    {
        return 1; // err
    }
    IIC_Send_Byte(addr>>8);
    if(1 == IIC_Wait_Ack())
    {
        return 2; // err
    }
    IIC_Send_Byte(addr&0x0FF);
    if(1 == IIC_Wait_Ack())
    {
        return 3; // err
    }
    IIC_Start();
    IIC_Send_Byte(0xA1);
    if(1 == IIC_Wait_Ack())
    {
        return 4; // err
    }
    for(i=0; i<len; i++)
    {
        buf[i] = IIC_Read_Byte(1);
    }
    IIC_Stop();
    return 0;
}

u8 W24C_WriteOneByte(u16 addr, u8 data)
{
    IIC_Start();
    IIC_Send_Byte(0xA0);
    if(1 == IIC_Wait_Ack())
    {
        return 1; // err
    }
    IIC_Send_Byte(addr>>8);
    if(1 == IIC_Wait_Ack())
    {
        return 2; // err
    }
    IIC_Send_Byte(addr&0x0FF);
    if(1 == IIC_Wait_Ack())
    {
        return 3; // err
    }
    IIC_Send_Byte(data);
    if(1 == IIC_Wait_Ack())
    {
        return 4; // err
    }
    IIC_Stop();
    DelayMs(5);
    return 0;
}


u8 W24C_WriteByteHighSpeed(u16 addr, u8* data, u8 len)
{
    u8 i;
    
    IIC_Start();
    IIC_Send_Byte(0xA0);
    if(1 == IIC_Wait_Ack())
    {
        return 1; // err
    }
    IIC_Send_Byte(addr>>8);
    if(1 == IIC_Wait_Ack())
    {
        return 2; // err
    }
    IIC_Send_Byte(addr&0x0FF);
    if(1 == IIC_Wait_Ack())
    {
        return 3; // err
    }
    for(i=0; i<len; i++)
    {
        IIC_Send_Byte(data[i]);
        IIC_Wait_Ack();
    }
    IIC_Stop();
    DelayMs(5);
    return 0;            
}


u8 W24C_WriteBytes(u16 addr, u8* data, u8 len)
{
    while(len--)
    {
        W24C_WriteOneByte(addr,*data);
        addr++;
        data++;
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1402394.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

目标检测 - 绘制bounding box

工具类 from PIL.Image import Image, fromarray import PIL.ImageDraw as ImageDraw import PIL.ImageFont as ImageFont from PIL import ImageColor import numpy as npSTANDARD_COLORS [AliceBlue, Chartreuse, Aqua, Aquamarine, Azure, Beige, Bisque,BlanchedAlmond, …

C++提高编程---模板---类模板

目录 一、类模板 1.模板 2.类模板的作用 3.语法 4.声明 二、类模板和函数模板的区别 三、类模板中成员函数的创建时机 四、类模板对象做函数参数 五、类模板与继承 六、类模板成员函数类外实现 七、类模板分文件编写 八、类模板与友元 九、类模板案例 一、类模板 …

SpringBoot - SpringBoot手写模拟SpringBoot启动过程

依赖 建一个工程&#xff0c;两个Module: 1. springboot模块&#xff0c;表示springboot框架的源码实现 2. user包&#xff0c;表示用户业务系统&#xff0c;用来写业务代码来测试我们所模拟出来的SpringBoot 首先&#xff0c;SpringBoot是基于的Spring&#xff0c;所以我…

3DMAX初级小白班第一课:菜单栏介绍

基本介绍 这里不可能一个一个选项全部教给大家&#xff08;毕竟之后靠实操慢慢就记住了&#xff09;&#xff0c;只说一些相对需要注意的设置。 自定义-热键编辑器-热键设置 这里有你所需要的全部快捷键 自定义-自定义UI启动布局 将UI布局还原到启动的位置 自定义-通用单…

使用Go发送HTTP GET请求

在Go语言中&#xff0c;我们可以使用net/http包来发送HTTP GET请求。以下是一个简单的示例&#xff0c;展示了如何使用Go发送HTTP GET请求并获取响应。 go复制代码 package main import ( "fmt" "io/ioutil" "net/http" …

HCIP网络的类型

一.网络类型&#xff1a; 点到点 BMA&#xff1a;广播型多路访问 -- 在一个MA网络中同时存在广播&#xff08;泛洪&#xff09;机制 NBMA&#xff1a;非广播型多路访问 -- 在一个MA网络中&#xff0c;没有泛洪机制-----不怎么使用了 MA&#xff1a;多路访问 -- 在一个…

03-常用编程概念

上一篇&#xff1a;02-编程猜谜游戏 本章介绍几乎所有编程语言中都会出现的概念&#xff0c;以及它们在 Rust 中的工作原理。许多编程语言的核心都有许多共同点。本章介绍的概念都不是 Rust 独有的&#xff0c;但我们会在 Rust 的上下文中讨论这些概念&#xff0c;并解释使用这…

课堂教学内容分为哪几类

作为一名老师&#xff0c;每天都要面对各种类型的学生&#xff0c;而学生们最关心的问题之一就是&#xff1a;老师&#xff0c;你到底要教我们什么&#xff1f;这个问题看似简单&#xff0c;实则深奥。那么&#xff0c;课堂教学内容究竟分为哪几类呢&#xff1f;今天&#xff0…

【webrtc】GCC 7: call模块创建的ReceiveSideCongestionController

webrtc 代码学习&#xff08;三十二&#xff09; video RTT 作用笔记 从call模块说起 call模块创建的时候&#xff0c;会创建 src\call\call.h 线程&#xff1a; 统计 const std::unique_ptr<CallStats> call_stats_;SendDelayStats &#xff1a; 发送延迟统计 const…

【书生·浦语大模型实战营05】《(5)LMDeploy 大模型量化部署实践》学习笔记

《(5)LMDeploy 大模型量化部署实践》 课程文档&#xff1a;《LMDeploy 的量化和部署》 1、大模型部署背景 1.1 模型部署 定义 将训练好的模型在特定软硬件环境中启动的过程&#xff0c;使模型能够接收输入并返回预测结果为了满足性能和效率的需求&#xff0c;常常需要对模型…

CLion调试Nodejs源码

【环境】 macOS node-v20.11.0源码 CLion 2023.3.2 【1】下载源码 https://nodejs.org/en/download/ 【2】编译源码 解压后的目录如下 进入解压后的目录进行编译 ./configure --debug make -C out BUILDTYPEDebug -j 4需要好久… 编译成功之后在node-v20.11.0目录下会有一个…

DNS是什么?为什么需要DNS?常用的DNS记录类型有哪些?

在互联网时代&#xff0c;基本上人人都要上网&#xff0c;网络已与人们日常生活息息相关。而DNS就在我们上网的过程中扮演着重要的角色—“将网址/域名解析成 IP 地址”。那么DNS是什么&#xff1f;为什么需要DNS&#xff1f;常用的DNS类型有哪些呢&#xff1f;别着急&#xff…

[数据结构 - C++] 红黑树RBTree

文章目录 1、前言2、红黑树的概念3、红黑树的性质4、红黑树节点的定义5、红黑树的插入Insert6、红黑树的验证7、红黑树与AVL树的比较附录&#xff1a; 1、前言 我们在学习了二叉搜索树后&#xff0c;在它的基础上又学习了AVL树&#xff0c;知道了AVL树是靠平衡因子来调节左右高…

springboot+mysql马拉松赛事志愿者管理系统-计算机毕业设计源码93439

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对马拉松赛事志愿者管理等问题&#xff0c;对…

司铭宇老师: 房地产中介销售顾问培训:房产中介经纪人提升销售业绩的法宝

房地产中介销售顾问培训&#xff1a;房产中介经纪人提升销售业绩的法宝 一、了解客户需求 成功的沟通始于深入了解客户的需求和期望。房地产经纪人应该通过提问和倾听来收集信息&#xff0c;比如客户对房产的地理位置、价格范围、户型设计等的偏好。此外&#xff0c;了解客户的…

【算法专栏学习】成贤学院,程序员的福利站到了,判断子序列,经典算法实战。

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

优思学院|怎样制作优秀的标准作业流程(SOP)?

我相信你一定去过众所周知的麦当劳。它在世界各地都有许多分店。不知道你是否曾在不同地方的麦当劳尝试过他们的美食&#xff0c;但你可能会好奇&#xff0c;为什么无论在世界哪个角落&#xff0c;麦当劳的食物口味都如此一致&#xff1f;它们是如何确保全球各地分店都能提供同…

中断——外部中断EXIT

终端可以分成外部中断和内部中断吗 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 野火中断章节有这样一句话 【F103在内核水平上搭载了一个异常响应系统&#xff0c; 支持为数众多的系统异常和外部中断。 其中系统异常有8个&#xff…

「 网络安全常用术语解读 」网络攻击者的战术、技术和常识知识库ATTCK详解

引言&#xff1a;随着网络攻击手段的不断升级和多样化&#xff0c;网络安全领域面临着越来越严峻的挑战。为了帮助网络安全专业人员更好地识别和防御网络攻击&#xff0c;MITRE公司创建了ATT&CK框架&#xff0c;以提供一个统一且结构化的方法来描述网络攻击者的行为和技巧。…

Git与GitHub零基础教学

大家好&#xff0c;我是星恒&#xff0c;这个帖子给大家分享的是git和github的全套教程&#xff0c;包含github初始&#xff0c;git常用命令以及基本使用&#xff0c;git的ssh链接github&#xff0c;github使用token登录&#xff0c;github和idea的配合&#xff0c;一些平时常用…