什么是IIC(I2C)?

  IIC 即Inter-Integrated Circuit(集成电路总线),这种总线类型是由飞利浦半导体公司设计出来的一种简单、双向、二线制、同步串行总线。它是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。这种方式简化了信号传输总线接口。

  那么也就是说,只要收发双方同时接入SDA(双向数据线)、SCL(同步时钟线)便可以进行通信。

  I2C总线的工作速度分为 3 种模式(实际上,IIC的通信速率由SCL决定):

    S(标准模式),测量与控制场合;

    F(快速模式),速率为 400kb/s;(默认)

    Hs(高速模式),速率为 3.4Mb/s。

IIC接线框图

  一般情况下,SCL与SDA默认由上拉电阻拉高。这也是为了方便通信协议。

  多机连接时,为了区分不同的从机,我们会使用自定义的地址码进行区分。

   

IIC的通信状态

  IIC的通信要注意以下6个知识点:

    1.空闲状态

    2.开始信号

    3.停止信号

    4.应答信号

    5.数据的有效性

    6.数据传输

空闲状态:

  在IIC中规定,当SDA、SCL同时为高电平时,视为空闲状态。

  注意,这个规定是通信设备通信前的判断条件。

开始信号 & 停止信号:

  在IIC中规定,当SCL为高电平,且SDA从高到低的跳变时,视为数据开始传输;

  在IIC中规定,当SCL为高电平,且SDA从低到高的跳变时,视为数据停止传输;

  

数据有效性 & 数据传送 & 应答信号(ACK)

  数据有效性:

    在传输数据时,应保证数据在SCL的上升沿到来之前准备好,并在下降沿到来之前必须稳定。

    (由于在电路中,电平的跳变往往伴随着毛刺。)

  数据传送:

    在I2C总线上传送的每一位数据都有一个时钟脉冲相对应(或同步控制),即在SCL串行时钟的配合下,在SDA上逐位地串行传送每一位数据。

    在一般情况下,传输数据时,从数据的最高有效位开始发送。

  应答信号:

    在IIC中规定,发送方每发送1个字节(8位)后需要接收接收方发送的应答信号。

    ACK为0时,视为有效应答;ACK为1时,视为无效响应。

    总结:谁发了数据,谁就要接收一个应答信号

 STM32 模拟IIC完整代码

/*
https://blog.csdn.net/return_oops/article/details/80965437
*/
//使用IIC1 挂载M24C02,OLED,LM75AD,HT1382 PB6,PB7 #define SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;} //IO操作函数
#define IIC_SCL PBout(6) //SCL
#define IIC_SDA PBout(7) //SDA
#define READ_SDA PBin(7) //输入SDA //IIC所有操作函数
void IIC_Init(void); //初始化IIC的IO口
void IIC_Start(void); //发送IIC开始信号
void IIC_Stop(void); //发送IIC停止信号
void IIC_Send_Byte(u8 txd); //IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); //IIC等待ACK信号
void IIC_Ack(void); //IIC发送ACK信号
void IIC_NAck(void); //IIC不发送ACK信号 void I2C_WriteByte(uint16_t addr,uint8_t data,uint8_t device_addr);
uint16_t I2C_ReadByte(uint16_t addr,uint8_t device_addr,uint8_t ByteNumToRead);//寄存器地址,器件地址,要读的字节数 void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); IIC_SCL=;
IIC_SDA=; }
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=;
IIC_SCL=;
delay_us();
IIC_SDA=;//START:when CLK is high,DATA change form high to low
delay_us();
IIC_SCL=;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=;
IIC_SDA=;//STOP:when CLK is high DATA change form low to high
delay_us();
IIC_SCL=;
IIC_SDA=;//发送I2C总线结束信号
delay_us();
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=;
SDA_IN(); //SDA设置为输入
IIC_SDA=;delay_us();
IIC_SCL=;delay_us();
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>)
{
IIC_Stop();
return ;
}
}
IIC_SCL=;//时钟输出0
return ;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL=;
SDA_OUT();
IIC_SDA=;
delay_us();
IIC_SCL=;
delay_us();
IIC_SCL=;
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL=;
SDA_OUT();
IIC_SDA=;
delay_us();
IIC_SCL=;
delay_us();
IIC_SCL=;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=;//拉低时钟开始数据传输
for(t=;t<;t++)
{
IIC_SDA=(txd&0x80)>>;
txd<<=;
delay_us(); //对TEA5767这三个延时都是必须的
IIC_SCL=;
delay_us();
IIC_SCL=;
delay_us();
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=;
SDA_IN();//SDA设置为输入
for(i=;i<;i++ )
{
IIC_SCL=;
delay_us();
IIC_SCL=;
receive<<=;
if(READ_SDA)receive++;
delay_us();
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
} void I2C_WriteByte(uint16_t addr,uint8_t data,uint8_t device_addr)
{
IIC_Start(); if(device_addr==0xA0) //eeprom地址大于1字节
IIC_Send_Byte(0xA0 + ((addr/)<<));//发送高地址
else
IIC_Send_Byte(device_addr); //发器件地址
IIC_Wait_Ack();
IIC_Send_Byte(addr&0xFF); //发送低地址
IIC_Wait_Ack();
IIC_Send_Byte(data); //发送字节
IIC_Wait_Ack();
IIC_Stop();//产生一个停止条件
if(device_addr==0xA0) //
delay_ms();
else
delay_us();
} uint16_t I2C_ReadByte(uint16_t addr,uint8_t device_addr,uint8_t ByteNumToRead) //读寄存器或读数据
{
uint16_t data;
IIC_Start();
if(device_addr==0xA0)
IIC_Send_Byte(0xA0 + ((addr/)<<));
else
IIC_Send_Byte(device_addr);
IIC_Wait_Ack();
IIC_Send_Byte(addr&0xFF); //发送低地址
IIC_Wait_Ack(); IIC_Start();
IIC_Send_Byte(device_addr+); //发器件地址
IIC_Wait_Ack();
if(ByteNumToRead == )//LM75温度数据为11bit
{
data=IIC_Read_Byte();
}
else
{
data=IIC_Read_Byte();
data=(data<<)+IIC_Read_Byte();
}
IIC_Stop();//产生一个停止条件
return data;
}

STM32学习笔记:IIC通信协议详解(附带软件模拟源码)的更多相关文章

  1. expect学习笔记及实例详解【转】

    1. expect是基于tcl演变而来的,所以很多语法和tcl类似,基本的语法如下所示:1.1 首行加上/usr/bin/expect1.2 spawn: 后面加上需要执行的shell命令,比如说sp ...

  2. OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

    http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...

  3. spring事务详解(三)源码详解

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  4. IIC通信协议详解

    IIC通信详解 IIC概述 IIC:两线式串行总线,它是由数据线SDA和时钟线SCL构成的串行总线,可发送和接收数据. 在CPU与被控IC之间.IC与IC之间进行双向传送,高速IIC总线一般可达400 ...

  5. Hadoop源码学习笔记之NameNode启动场景流程一:源码环境搭建和项目模块及NameNode结构简单介绍

    最近在跟着一个大佬学习Hadoop底层源码及架构等知识点,觉得有必要记录下来这个学习过程.想到了这个废弃已久的blog账号,决定重新开始更新. 主要分以下几步来进行源码学习: 一.搭建源码阅读环境二. ...

  6. Docker技术入门与实战 第二版-学习笔记-3-Dockerfile 指令详解

    前面已经讲解了FROM.RUN指令,还提及了COPY.ADD,接下来学习其他的指令 5.Dockerfile 指令详解 1> COPY 复制文件 格式: COPY  <源路径> .. ...

  7. Redis学习笔记4-Redis配置详解

    在Redis中直接启动redis-server服务时, 采用的是默认的配置文件.采用redis-server   xxx.conf 这样的方式可以按照指定的配置文件来运行Redis服务.按照本Redi ...

  8. Struts2学习笔记(二)——配置详解

    1.Struts2配置文件加载顺序: default.properties(默认常量配置) struts-default.xml(默认配置文件,主要配置bean和拦截器) struts-plugin. ...

  9. Struts2学习笔记二 配置详解

    Struts2执行流程 1.简单执行流程,如下所示: 在浏览器输入请求地址,首先会被过滤器处理,然后查找主配置文件,然后根据地址栏中输入的/hello去每个package中查找为/hello的name ...

随机推荐

  1. 解Bug之路-记一次调用外网服务概率性失败问题的排查

    前言 和外部联调一直是令人困扰的问题,尤其是一些基础环境配置导致的问题.笔者在一次偶然情况下解决了一个调用外网服务概率性失败的问题.在此将排查过程发出来,希望读者遇到此问题的时候,能够知道如何入手. ...

  2. 虚拟机与ubuntu系统的安装与基础操作

    1.虚拟机的下载: 常见的虚拟机软件有:VMware  VirtuaIBOX  Virtual PC  等. 这里主要介绍VMware ,VMware目前已经有很多个版本,可以根据个人情况进行选择.安 ...

  3. 知乎模拟登录,支持验证码和保存 Cookies

    import requests import time import re import base64 import hmac import hashlib import json import ma ...

  4. 3.ORM框架一对多的关系及使用

    一对多就是主键与外键的关系,通过一个用户表,角色表进行举例子 角色表role:有外键,对应的是user表的主键 用户表users: from flask import Flask, render_te ...

  5. UICollectionViewCell点击高亮效果(附带效果GIF)

    首先效果如下: 背景是这样的:UI上使用的是UICollectionView,所以后面会使用它的协议方法完成. 实现思路是这样的:高亮状态+点击后短时间内保持颜色变化 实现的代码参考如下: // Ce ...

  6. 2020新春公益赛 writeup

    简单的招聘系统 无需注册账号,admin'or 1#登陆,到blank page页面,在输入key处发现有注入点: /pages-blank.php?key=1%27+union+select+1%2 ...

  7. scrapy 中 shell 出现 403 Forbiidden 解决方案

    版权声明本文来自:https://blog.csdn.net/qq_37462361/article/details/87860025 进入正题: 出现 403,表示网站拒绝提供服务 (因为很多网站都 ...

  8. development tool

    Eclipse :        https://www.eclipse.org/downloads/ WebStorm:   http://www.jetbrains.com/webstorm/do ...

  9. LeetCode 24. Swap Nodes in Pairs(交换链表中每两个相邻节点)

    题意:交换链表中每两个相邻节点,不能修改节点的val值. 分析:递归.如果以第三个结点为头结点的链表已经两两交换完毕(这一步递归实现---swapPairs(head -> next -> ...

  10. va_list、va_start、va_arg、va_end

    转载:https://www.cnblogs.com/bwangel23/p/4700496.html 这几个函数和变量是针对可变参数函数的,什么是可变参数函数呢,最经典的莫过于printf和scan ...