正点原子IIC讲解:https://www.bilibili.com/video/BV1o8411n7o9/?spm_id_from=333.337.search-card.all.click&vd_source=e35b16eeaf19ae2b23ff9587a735ee20

一、IIC总线

1. 物理层

(1)支持多设备,一个IIC通讯总线中可以连接多个IIC设备,支持多个通讯主机及多个通讯从机;

(2)两条线:双向串行数据线SDA,串行时钟线SCL,数据线用于传输数据,时钟线用于数据收发同步;

(3)每个连接到总线的设备都有一个独立的地址,主机通过这个地址对不同从机进行访问;

(4)总线通过上拉电阻接到电源,当IIC设备空闲时会输出高阻态。

(5)三种传输模式:标准模式(100kbit/s)、快速模式(400kbit/s)、高速模式(3.4Mbit/s)。

(6)连接相同总线的IC数量受总线最大电容400pf的限制。

2. 协议层

(1)起始信号:主机的IIC接口产生的传输,连接到IIC总线上的从机都会接收到这个信号。

(2)从机地址:起始信号产生后,所有从机开始等待主机广播从机地址信号,当广播地址与某个设备地址相同时,该设备就被选中,没有选择的设备会忽略之后的数据信号。IIC协议规定从机地址可以是7位或10位。

(3)传输方向位:地址位之后是传输方向选择位,该位为0时,表示后面数据传输方向是主机写数据到从机;该位为1时,主机读取从机数据。

(4)应答信号:

第一种,从机接收到匹配的地址,从机返回应答信号(ACK),表示找到对应的从设备;

第二种,当从机被寻址后,主机写数据到从机时,从机每收到一个字节的数据都需要给主机一个应答信号(ACK),主机只有接收到应答信号后才能继续发送数据。

(5)停止信号:发送停止信号结束通信。

S:起始信号

SLAVE ADDRESS:从机地址

R/W:传输方向,1读 0写

A:ACK表示应答信号

A非:NACK非应答信号,表示本次通信结束

P:停止信号

阴影部分为主机给从机发的,空白部分为从机给主机发的。

1、IIC主机写数据到从机

2、IIC主机由从机读取数据

3、IIC复合通信

4、IIC通信时序图

(1)起始信号、停止信号

起始信号:SDA、SCL均为高电平,首先处理器让SCL时钟保持高电平,然后让SDA数据信号由高变低就表示一个开始信号。同时IIC总线上的设备检测到这个开始信号就知道处理器要发送数据了,此时总线处于占用状态。

停止信号:处理器让SCL时钟保持高电平,然后让SDA数据信号由低变高就表示一个停止信号。同时IIC总线上的设备检测到这个停止信号就知道处理器已经结束了数据传输,此时总线处于空闲状态。

(2)数据格式/应答

字节从高位到低位传输。发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。

应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字

节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。

(3)通信

开始标志(S)发出后,主设备会传送一个7 位的从机地址,并且后面跟着一个第8位,称为Read/Write 位。R/W 位表示主设备是在接收从设备的数据还是在向从设备写数据。然后,主设备释放SDA线,等待从设备的应答信号(ACK)。每个字节的传输都要跟随有一个应答位,应答产生时(把SDA拉低)。从设备将SDA 线拉低并且在SCL 为高电平时保持低。数据传输总是以停止信号标志结束,然后释放通信线路。然而,主设备也可以产生重复的开始信号去操作另一台从设备,而不发出结束标志。综上可知,所有的SDA 信号变化都要在SCL 时钟为低电平时进行,除了开始和结束标志。

二、软件模拟IIC通信

iic.h


#ifndef __MYIIC_H
#define __MYIIC_H
#include "sys.h" //IO方向设置
#define SDA_IN() {GPIOA->CRL&=0X0FFFFFFF;GPIOA->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOA->CRL&=0X0FFFFFFF;GPIOA->CRL|=(u32)3<<28;} #define IIC_SCL PAout(4) //SCL
#define IIC_SDA PAout(5) //输出SDA
#define READ_SDA PAin(5) //输入SDA //IIC所有操作函数
void IIC_Init(void); //初始化IIC的IO口
void IIC_Start(void); //发送IIC开始信号
void IIC_Stop(void); //发送IIC停止信号
void IIC_Send_Byte(u8 TX_DATA); //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 IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr); #endif

iic.c

#include "myiic.h"
#include "delay.h" /*
*@Function :IIC_Init()
*@brief :初始化IIC GPIO
*@param :void
*@retval : void
*/
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE ); //使能GPIOA时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;//PA4---SCL PA5---SDA
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_4 | GPIO_Pin_5); //PA4,PA5 输出高
} /*
*@Function :IIC_Start()
*@brief :产生IIC起始信号
*@param :void
*@retval : void
*/
void IIC_Start(void)
{
SDA_OUT(); //sda线输出 IIC_SDA=1; //处于空闲状态
IIC_SCL=1; //处于空闲状态
delay_us(4);//延时时间看从机设备
IIC_SDA=0;//时钟线为高时数据线由高变低
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
} /*
*@Function :IIC_Stop()
*@brief :产生IIC停止信号
*@param :void
*@retval : void
*/
void IIC_Stop(void)
{
SDA_OUT();//sda线输出 IIC_SCL=0;
IIC_SDA=0;
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//时钟线为高,数据线由低变高
delay_us(4);
} /*
*@Function :IIC_Ack()
*@brief :产生ACK应答
*@param :void
*@retval : void
*/
void IIC_Ack(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//数据线为低电平表示应答
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
} /*
*@Function :IIC_NAck()
*@brief :不产生ACK应答
*@param :void
*@retval : void
*/
void IIC_NAck(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
} /*
*@Function :IIC_Wait_Ack()
*@brief :等待应答信号
*@param :1,接收应答失败 0,接收应答成功
*@retval : void
*/
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
SDA_IN(); //SDA设置为输入
IIC_SDA=1;//释放sda线
delay_us(1);
IIC_SCL=1;//从机返回ack
delay_us(1);
while(READ_SDA) //scl为高电平时读取sda
{
ucErrTime++;
if(ucErrTime>250) //超时判断
{
IIC_Stop();//sda高电平表示从机无应答
return 1;//接收应答失败
}
}
IIC_SCL=0;//时钟输出0,结束ack检查
return 0;
} /*
*@Function :IIC_Send_Byte()
*@brief :IIC发送一个字节
*@param :TX_DATA 要发送的数据
*@retval : void
*/
void IIC_Send_Byte(u8 TX_DATA)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
//IIC_SDA=(TX_DATA&0x80)>>7;//先发高位,与运算取出最高位,移到最后一位
if((TX_DATA&0x80)>>7)
IIC_SDA=1;
else
IIC_SDA=0;
TX_DATA <<=1; //左移一位用于下一位发送,最高位已经发送出去
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
} /*
*@Function :IIC_Read_Byte()
*@brief :IIC读1个字节
*@param :ack=1时,发送ACK,ack=0,发送nACK
*@retval : 读取的数据
*/
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;//先接收的高位,需要将接收的数据左移一位
if(READ_SDA) receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}

STM32IO口模拟IIC时序的更多相关文章

  1. 【STM32】IIC的基本原理(实例:普通IO口模拟IIC时序读取24C02)(转载)

     版权声明:本文为博主原创文章,允许转载,但希望标注转载来源. https://blog.csdn.net/qq_38410730/article/details/80312357 IIC的基本介绍 ...

  2. 用I/O口模拟IIC总线协议遇到的一些问题

    最近做的一个项目,是基于IIC总线通信的传感器系统.由于另外一个传感器使用的是类IIC协议,而不是标准IIC,所以MCU不能与其通信,最后没有办法,只有通过I/O口模拟的方式实现IIC的总线通信.具体 ...

  3. lpc1788IO口模拟IIC

    #ifndef __MYIIC_H_ #define __MYIIC_H_ #include "common.h" #include "delay.h" #in ...

  4. 用I/O口模拟总线时序

    在做总线通信过程中,我们很少会用到这样方法,一般在我们选择MCU的时候都会带有你所需要的通信接口.但是,对于一些简单的通信应该用的场合,一般在一些传感器的数据通信过程中,传感器厂商会将通信协议做一些改 ...

  5. GPIO软件模拟IIC时序

    一.MPU6050中的IIC时序 1.1 START和STOP SDA和SCL在高电平时,SDA拉低表示START.SCL拉低,表示可以传输数据. SDA和SCL在低电平时,SDA拉高表示STOP. ...

  6. 模拟IIC协议时序

    IIC是飞利浦公司开发的两线式串行总线,主要应用在单片机和外围电子器件之间的数据通讯. IIC总线优点是节约总线数,稳定,快速,是目前芯片制造上非常流行的一种总线,大多数单片机已经片内集成了IIC总线 ...

  7. C51—模拟IIC总线实现EEPROM存取数据

    a - 什么是IIC总线 -什么是EEPROM -IIC总线的通信格式 模块化设计注解 整体代码 - 什么是IIC总线 IIC总线是同步通信的一种特殊形式,具有接线口少.控制简单.器件封装形式小.通信 ...

  8. stm32软件模拟IIC读取PX4FLOW光流传感器数据

    这段时间在做全国光电设计大赛,用到了px4的px4flow光流传感器,用软件模拟iic读取数据不定期会导致px4flow死机,查了资料和光流的源码,发现这个光流用了stm32的硬件iic,所以对软件模 ...

  9. GPIO模拟IIC接口信号质量分析

    信号质量有问题的波形001: 信号质量有问题的波形002: 从上图可以看出,GPIO口模拟的I2C接口,电平都存在半高的情况. 因为I2C的接口是通过GPIO模拟实现的,该时钟信号线SCL内部默认为下 ...

  10. MSP430的IO口模拟I2C总线对AT24C25进行读写程序

    功能: 实现MSP430口线模拟I2C总线协议与24C04通信.                                           ** 描述: 主系统工作时钟为12MHz,I2C工 ...

随机推荐

  1. Codeforces Round 891 (div.3) D题解析

    CodeForces Round 898 (div 4) D题.Strong Vertices 大致思路 对于题目的给的式子,au-av>=bu-bv,我们可以通过移项得到au-bu>=a ...

  2. Pylon C++ Programmer's Guide

    移步至Pylon C++ Programmer's Guide观看效果更佳 Getting Started pylon编程指南是一个关于如何使用Basler pylon C++ API进行编程的快速指 ...

  3. 使用 LLVM 框架创建一个工作编译器,第 1 部分

    使用 LLVM 及其中间表示构建一个自定义编译器 LLVM 编译器基础架构提供了一种强大的方法来优化您使用任何编程语言编写的应用程序.了解本系列文章(由两部分组成)第一部分中有关 LLVM 的基础知识 ...

  4. YOLOv8-PyQT5可视化界面

    使用PyQT5实现YOLOv8图形化界面 准备工作: 1.首先在YOLOv8环境中安装pyqt5 pip install pyqt5 pip install pyqt5-tools 然后再你的anac ...

  5. elasticsearch之python操作

    总结使用python对于elasticsearch的常用操作 安装 pip install elasticsearch 2. 连接 from elasticsearch import Elastics ...

  6. canvas(八)绘制图片和坐标转换

    1.绘制图片 相关api及其参数:ctx.drawImage() 参数 说明 参数一 图片对象 参数二,三 可选,图片裁剪的基点(原图左上角为原点) 参数四,五 可选,图片裁剪区域的宽高(基于原图大小 ...

  7. 《JavaScript 模式》读书笔记(7)— 设计模式1

    这些模式已经出现了相当长的一段时间,并被证明在许多情况下都非常有用.这也是为什么需要自己熟悉并谈论这些模式的原因. 虽然这些设计模式是与语言和实现方式无关的,并且人们已经对此研究了多年,但都主要是从强 ...

  8. 升级到 .NET Core 3.1

    微软升级的频率有点快,转眼 .NET Core 升级到 3.1 版了,这是一个长期支持版本,意味着 .NET Core 正式进入成熟期. 不过,对于开发人员来说,你的项目又需要迁移了. 升级项目文件 ...

  9. 鸿蒙(HarmonyOS)原生AI能力之文本识别

    鸿蒙(HarmonyOS)原生AI能力之文本识别 原生智能介绍 在之前开发中,很多场景我们是通过调用云端的智能能力进行开发.例如文本识别.人脸识别等. 原生即指将一些能力直接集成在本地鸿蒙系统中,通过 ...

  10. [SpringBoot]浏览器输出中文乱码问题解决

    问题情境: IDEA.Springboot.浏览器访问接口查看返回的JSON数据,发现中文乱码 解决方案: server: servlet: encoding: charset: UTF-8 enab ...