一、IIC时序

IIC(Inter-Integrated Circuit, 内部集成电路)总线是飞利浦公司开发的两线式串行总线,用于短距离传输,常用语微控制器及其外围设备。它是由数据线SDA和时钟线SCL构成的串行总线,可发送和接收数据。

I2C总线通过上拉电阻接正电源。即当总线空闲时,两根线均为高电平。如此,连在总线上的任一器件输出的低电平,都可以使得总线的信号变低,也就是说各器件的SDA和SCL都是线"与"关系。

I2C是同步串行总线,由SCL为所有设备提供统一的时钟信号。 即使多个节点发送时钟信号时,由于SCL"线与"的原因,SCL上为统一的时钟信号。

数据位(1\0)有效性规定:I2C总线进行数据传送时,时钟信号为高电平期间,SDA线上的数据必须保持稳定;只有在SCL线的信号为低电平器件,SDA线的才可进行高低电平状态变化。

起始信号、终止信号、应答信号

起始信号: SCL线为高电平期间,SDA线由高电平向低电平跳变(下降沿)----是一种电平跳变时序信号

终止信号:SCL线为高电平期间,SDA线由低电平向高电平跳变(上升沿)-----是一种电平跳变的时序信号

应答信号:在接收数据的IC(接收器)在接收到8bit数据后,向发送数据的IC(发送器)发出特定的低电平脉冲,表示已收到数据。即发送器在时钟脉冲9期间释放数据线,这样接收器就可以反馈一个应答信号。ACK(低电平)---规定为有效应答位,NACK(高电平),规定为非应答位,表示接收器接收该字节咩有成功。

为了时钟信号的统一,我们假定只有一个设备发出时钟信号,该设备称为主机。其他IIC设备作为从机存在。

二、从STM32出发 IO软件模拟I2C的驱动程序

步骤1、IO管脚初始化

假设使用的 IIC_SCL  IIC_SDA 输出  以及READ_SDA输入

#define SDA_IN()      宏定义设置管脚为输入模式

#define SDA_OUT()   宏定义设置管脚为输出模式

步骤2、发出起始信号

采用4us

void IIC_Starts(void)

{

SDA_OUT() ;

IIC_SCL  =  1;

IIC_SDA = 1;   //空闲态

dealy_us(4);

IIC_SCL = 1;

IIC_SDA = 0;   //当SCL线为高电平是, SDA线上由高到低电平跳变

delay_us(4);

IIC_SCL = 0;    //钳住,等待发送或接受

}

步骤3、发出终止信号

void IIC_Stop(void)

{

SDA_OUT() ;

IIC_SCL  =  0;

IIC_SDA  = 0;   //

dealy_us(4);

IIC_SCL = 1;

IIC_SDA = 1;   //当SCL线为高电平是, SDA线上由低到高电平跳变

delay_us(4);

}

步骤4 等待ACK应答

uint8_t IIC_Wait_ACK(void)

{

uint8_t ucTimeCnt= 0;

SDA_IN() ;       //SDA管脚设为输入模式

IIC_SDA = 1;

delay_us(1);

IIC_CLK = 1;

delay_us(1);

while(READ_SDA)

{

ucTimeCnt ++;

if(ucTimeCnt>250)

{

IIC_Stop();

return 1;

}

}

//等到应道地电平

IIC_CLK = 0; //钳住,等待发送或接受

}

步骤5 发送一字节数据

void  IIC_Send_Byte(uint8 byte)

{

uint8_t i = 0;

SDA_OUT() ;

IIC_SCL = 0;   // 只有在SCL线为低电平时,SDA线才可以改变

for(i=0;i<8;i++)

{

IIC_SDA = (byte&0x80)>>7;   //每次发最高位

byte<<1;    //更新最高位

delay_us(2);

IIC_CLK = 1;

delay_us(2);

IIC_CLK = 0;

delay_us(2);      //第三个2us是为什么???

}

}

步骤6 读取一个字节,并发送ACK或NACK,发送NACK即通知从机发送器结束数据发送,释放SDA线(SDA接口置1)。

uint8IIC_Read_Byte(uint8_t  ack)

{

uint8_t i, recvVal=0;

SDA_IN();

for(i=0; i<8; i++)

{

IIC_CLK = 0;

delay_us(2);  //等待输出

IIC_CLK = 1;  //可读取

recvVal<<1;  //将最低位空出

if(IIC_SDA()) recvVal++;   //高电平,则最低位为1

delay_us(1);

}

if(ack)

{

IIC_ACK();

}

else

{

IIC_NACK();

}

retrun recvVal;

}

步骤7   发出应答ACk

void IIC_ACK(void)

{

SDA_OUT() ;

IIC_CLK = 0;

IIC_SDA = 0;

delay_us(2);

IIC_CLK = 1;

delay_us(2);

IIC_CLK = 0;

}

步骤8 发出应答NACK

void IIC_NACK(void)

{

SDA_OUT() ;

IIC_CLK = 0;

IIC_SDA = 1;

delay_us(2);

IIC_CLK = 1;

delay_us(2);

IIC_CLK = 0;

}

三、从具体I2C器件中读写数据

1、主器件先从器件写数据

上图所说的就是I2C向从机特定地址写数据。

2、主器件接收从机数据

注意 从写完地址后,要重新发起地址+接收。

3、DEVICEADDRESS

DECVICEADDR地址的8位地址信息组成如下所示,以24C02 EEPROM为例说明

对于24C02而言,最高位的4bit为1010(0xA), A2 A1 A0为管脚地址位,必须与硬件输入引脚一致,假设接地,LSB为读/写操作选择位,高为读操作,低位写操作。  0xA0---写  0xA1-----读

对于EEPROM而言,比较器件地址一致后,输出应答为"0"。如果不一致,则返回到待机状态。

章节2 完成了GPIO口模拟IIC的驱动,现在就是落实到实际应用。AT24C02 EEPROM和MPU6050,这两个器件都是作为IIC从机。

这里对从机和主机 以及发送器和接收器再次说明

主机: 发出时钟脉冲的IIC器件,这里是软件模拟的IIC 处于主动控制地位

从机: 目标的IIC器件 挂在IIC总线上的器件

发送器:在数据传输中处于发送地位

接收器:在数据传输中处于接收地址

若接收器是主机时,他在接收到最后一个自节后,发送一个NACK信号,以通知被控(从机)发送器结束数据发送,并释放SDA线,以便主控接收器发送一个终止信号P。

四 以AT24C02 EEPROM操作为例说明

1、字节写操作

写操作要求AT24C02在接收器件地址后和ACK应答后,在接收8位的字地址,AT24C02接收到地址后应答"0",然后接收一个8位数据,在接收8位数据后,AT24C02应答"0”。最后必须由主器件发送终止信号P在终止写序列。  这之后AT24C02进入内部写周期twr,数据写入非易失性存储器中。在这期间所有输入都是无效的,直到写周期完成,AT24C02才有应答。

//WriteAddr :写入数据的AT24C02目的存储地址   DataToWrite 待写入的值

void   AT24CXX_WriteOneByte(u16 WriteAddr, u8 DataToWrite)

{

IIC_Starts();   //发出起始信号

IIC_Send_Byte(0xA0);   //写器件地址+写操作

IIC_Wait_Ack();

IIC_Send_Byte(WriteAddr>>8); //发送高地址

IIC_Wait_Ack();

IIC_Send_Byte(WriteAddr%256);    //发送低地址

IIC_Wait_Ack();

IIC_Send_Byte(DataToWrite);

IIC_Wait_Ack();

IIC_Stop();

delay_ms(10);// 等AT24C02写数据

}

2、片写操作

即在发送一个8位数据后,在发7个数据(对于AT24C02而言)。每个数据都要有ACK,最后再由主器件发出终止信号P。

AT24C02器件按照8字节/页执行页写;AT24C04/08/16器件按16字节/页执行页写。AT24C02在接收到每个数据后,字地址的低3位内部自动加1,高位地址不变,维持在当前页内,注意当内部产生的自地址达到该页边界地址时,随后的数据将写入该页的页首。  如写入的字节数超过8个,字地址将回转到该页的首字节,先前的字节将会被覆盖。

接口函数待定

void  AT24CXX_WritePage(u16 PageAdd, u8 * pBuffer,u16 NumToWrite)

{

}

3、连续写入任意字节数目---不超过全地址

//WriteAddr:开始写入的地址 对于24C02 为0~255    pBuffer:数据数组首地址     NumToWrite:要写入数据的个数

void AT24CXX_Write(u16 WriteAddr, u8 *pBuffer, u16 NumToWrite)

{

while(NumToWrite--)

{

AT24CXX_WriteOneByte(WriteAddr, *pBuffer);

WriteAddr ++;   //地址加1

pBuffer++;       //数组地址+1

}

}

4、当前地址读

读操作和写操作初始化相同,只是器件地址中的读/写选择位应为"1"。

AT24C02内部地址计数器只要芯片有电,就会保存着上次访问时最后一个地址加1的值。此时直接读,可读到该地址的值。当读到最后页的最后字节,地址会回转到0。

5、随机读

随机读需要先写一个目标字地址,一旦AT24C02 接收了器件地址和字地址 并应答了ACK,主器件就产生一个重复的起始信号。接着主器件发送器件地址|读操作,EEPROM应答ACK,并随时钟送出数据,主器件NACK,但是发送终止信号。

//ReadAddr   读目标地址

u8 AT24CXX_ReadOneByte(u16 ReadAddr)

{

u8  tempVal = 0;

IIC_Starts();   //发出起始信号

IIC_WriteOneByte(0xA0);  //写器件地址+写操作

IIC_Wait_Ack();    //等待应答

IIC_WriteOneByte(ReadAddr>>8);//高字节地址

IIC_Wait_Ack();

IIC_WriteOneByte(ReadAddr%256); //低字节地址

IIC_Wait_Ack();

IIC_Starts();  //重新发出起始信息

IIC_WriteOneByte(0xA1);   //读操作

IIC_Wait_Ack();

tempVal = IIC_ReadOneByte(0);  //读取一个字节,发出NACK

IIC_Stop();     //发出终止信号

return tempVal;

}

6、顺序读

顺序读可以通过"当前地址读‘’或“随机读”启动,主器件接收到一个数据后,应答ACK。只要AT24C02接收到ACK后,将自动增加字地址并继续随时钟发送后面的数据。若达到存储器地址末尾,地址自动回转到0,仍可继续顺序读取数据。

主器件NACK+终止条件,即可结束顺序读操作。

void AT24CXX_Read(u16 ReadAddr, u8 *pBuffer, u16 NumToRead)

{

while(NumToRead--)

{

*pBuffer++ = AT24CXX_ReadOneByte(ReadAddr++);

}

}

7、设备检查是否存在,首次在末尾字节写入0x55, 其他读末尾字节看是否是0x55

void AT24CXX_Check(void)

{

u8 tmpVal;

tmpVal = AT24CXX_ReadOneByte(255);

if(tmpVal == 0x55) retrun 0;

else{

AT24CXX_WriteOneByte(0x55);

tmpVal = AT24CXX_ReadOneByte(255);

if(tmpVal == 0x55) retrun 0;

}

return 1;

}

IO口软件模拟IIC相关推荐

  1. 软件模拟IIC主从机

    软件模拟IIC 从机部分 从机接收部分 从机发送部分 主机部分 阻塞式发送 定时器中断方式发送 从机部分 因为项目简单,就只有数据接收,数据命令处理,显示.显示部分使用定时器中断动态扫描方式,主函数用 ...

  2. STM32 软件模拟 IIC 代码,标准库、HAL库可用

    1 #ifndef _IIC_H 2 #define _IIC_H 3 4 #include "stdio.h" 5 #include "stm32f1xx_hal.h& ...

  3. STM32基于软件模拟IIC进行AHT21B温湿度采集

    STM32基于软件模拟IIC进行AHT21B温湿度采集 一. IIC简介 1.1 IIC简介 1.2 实现方式 1.3 实现方式对比 二. AHT21B简介 2.1 简介 2.2 产品特点 2.3 外 ...

  4. STM32 软件模拟IIC

    0.系列目录 STM32 软件模拟IIC STM32 使用DMP库处理MPU6050数据 STM32 MPU6050与匿名上位机通讯(V2.6版) 1.IIC通讯过程 SCL和SDA在空闲时候均为高电 ...

  5. STM32 Cube MX 之hal库软件模拟IIC 可直接移植使用

    此为软件模拟IIC,可以直接移植到HAL库使用..h文件需要自己做函数声明这里就不再放出,如有问题大家可以讨论. 使用的时候只需要更改SDA 和SCL引脚的宏定义就可以移植使用,当然IIC协议其实就是 ...

  6. STM32F103单片机软件模拟IIC并读取TMP112数字温度传感器

    本文利用STM32F103系列单片机读取TMP112数字温度传感器的温度信息,TMP112数字传感器采用IIC总线协议通信.STM32自身含有硬件IIC资源,分别是PB6-->SCL.PB7-- ...

  7. 【蓝桥杯嵌入式】【STM32】5_IICEEPROM之软件模拟IIC

    文章目录 1.原理图 2.源代码   下载工程文件:   https://gitee.com/Joseph_Cooper/blue-bridge-embedded 1.原理图 顺便指出了该器件的地址. ...

  8. 一种基于IO口的模拟串口(LOG)实现方法

    一.使用背景 当MCU的串口不够用时,可以通过IO模拟的方式将任意一个具有输出功能的管脚配置为串口输出,从而方便开发和调试. 二.实现原理 通过IO口模拟串口发送波形,配置对应的波特率等信息,然后映射 ...

  9. 2021-11-3 软件模拟IIC时序,并和EEPROM存储芯片24C02双向通信以及显示功能

    IIC(Inter-Integrated Circuit(集成电路总线)) 2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL.所有接到I2C总线设备上的串行数据SDA都接到 ...

最新文章

  1. 支付宝接口调用问题快速通道
  2. python真的那么强大嘛-这些 Python 库真的很“冷”,但是却很强大
  3. 企业需要建设网站该如何咨询价格呢?
  4. red hat 4.1.2_安装Red Hat Container Development Kit 2.2版本
  5. 移动端导出excel_连载系列【4】Excel开发移动端quot;APPquot;
  6. qt设置路径为应用程序启动路径
  7. loading窗口动画 web_在页面未加载完之前显示loading动画
  8. pyqt与mysql例子_PyQt 连接MySql数据库,C++代码转Python3代码
  9. PHP性能调优,PHP慢日志---善用php-fpm的慢执行日志slow log,分析php性能问题
  10. 手把手教你搭建pytorch深度学习网络
  11. Python被誉为神奇的“胶水语言”,到底神奇在哪?
  12. [Python] Python学习笔记之常用模块总结[持续更新...]
  13. stm32的HAL库uart的注意点
  14. 中国移动计算机二面笔试题,中国移动笔试面试经验
  15. sodp软件如何导入多个工作面信息_平方英尺和面积计算软件:Metes and Bounds for Mac...
  16. 2019年5款你必须知道的顶级ASO优化工具
  17. 数据结构创建有向图(C++语言)
  18. 【大数据技术应用实战】【大数据与人工智能视角下数字孪生和元宇宙】二、新一轮大数据与人工智能变革
  19. 华为交换机RRPP单环配置
  20. 自学html4,HTML4

热门文章

  1. Robotstudio软件二次开发:基于C#语言的Smart组件开发基础
  2. mysql插入数据返回主键值_Mysql插入记录后返回该记录ID
  3. 百望股份获阿里腾讯系5.17亿元A轮融资
  4. c语言接口测试方法,如何做API接口测试?
  5. 计算机加硬盘后速度变慢,ssd硬盘win10系统加上机械硬盘后启动很慢怎么修复
  6. 10.07 WZZX Day2总结
  7. The bean ‘xxImpl‘ could not be injected as a ‘xxx‘ because it is a JDK dynamic proxy that implements
  8. a律13折线pcm编码例题_a律13折线编码段内码怎么确定
  9. 国稻种芯百团计划行动 丰收节贸促会·袁隆平:水稻国际竞争
  10. 使用链表(LinkedList) 二叉搜索树(BST) 实现不重复元素集合(Set)