正点原子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. mobile频段要查找、设置并获取相关参数,该怎么破?

    ​ 今天我们一起来学习查找和设置mobile频段,并获取相关参数. 一.mobile概述 1.1 简介 "4G mobile"指的是第四代移动通信技术,常用于描述通过4G网络进行的 ...

  2. Cisco Packet Tracer 交换机代码

    二层交换机S1代码: >en #conf  t #vlan 10 #vlan 20 #int r f 0/1-5 #sw a v 10 #int r f 0/6-10 #sw a v 20 #i ...

  3. swoole的安装

    因为换了一台工作电脑 需要重新安装各种环境,这里简单记录一下swoole的安装步骤. 首先去下载它的git仓库: $ git clone https://gitee.com/swoole/swoole ...

  4. 万字长文带你深入Redis底层数据结构

    Redis数据库的数据结构 Redis 的键值对中的 key 就是字符串对象,而 value 就是指Redis的数据类型,可以是String,也可以是List.Hash.Set. Zset 的数据类型 ...

  5. 读书笔记-C#8.0本质论-02

    10. 接口 10.1 显式与隐式接口实现的比较 10.1.1 隐式接口 namespace ConsoleApp1; internal static class Program { internal ...

  6. 在C#中调用EVAL函数方法,通过字符串计算

    一.用 MSScriptControl 在 C# 中执行 JavaScript 代码   javascript 中有个eval方法,用过的人都知道他的方便和强大之处. 在C#中,我们也可以通过Com组 ...

  7. 某开源ERP最新版SQL与RCE的审计过程

    文章首发于 https://forum.butian.net/share/134 前言 代码路径 https://gitee.com/jishenghua/JSH_ERP 软件版本 华夏ERP_v2. ...

  8. 【Mybatis】学习笔记01:连接数据库,实现增删改

    需要数据库SQL的请跳转到文末 哔哩哔哩 萌狼蓝天 [转载资料][尚硅谷][MyBatis]2022版Mybatis配套MD文档 [Mybatis]学习笔记01:连接数据库,实现增删改 [Mybati ...

  9. grpc与http2的关系

    https://nullget.sourceforge.io/?q=node/895 grpc与http2的关系 grpc client 发送包到原生的http2 server client收到报错: ...

  10. mybatis-plus多表联合分页查询

    1.entity层要写个Vo实体类 2.controller @AutoLog(value = "员工CURD-分页列表查询")@ApiOperation(value=" ...