IO口软件模拟IIC
一、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相关推荐
- 软件模拟IIC主从机
软件模拟IIC 从机部分 从机接收部分 从机发送部分 主机部分 阻塞式发送 定时器中断方式发送 从机部分 因为项目简单,就只有数据接收,数据命令处理,显示.显示部分使用定时器中断动态扫描方式,主函数用 ...
- STM32 软件模拟 IIC 代码,标准库、HAL库可用
1 #ifndef _IIC_H 2 #define _IIC_H 3 4 #include "stdio.h" 5 #include "stm32f1xx_hal.h& ...
- STM32基于软件模拟IIC进行AHT21B温湿度采集
STM32基于软件模拟IIC进行AHT21B温湿度采集 一. IIC简介 1.1 IIC简介 1.2 实现方式 1.3 实现方式对比 二. AHT21B简介 2.1 简介 2.2 产品特点 2.3 外 ...
- STM32 软件模拟IIC
0.系列目录 STM32 软件模拟IIC STM32 使用DMP库处理MPU6050数据 STM32 MPU6050与匿名上位机通讯(V2.6版) 1.IIC通讯过程 SCL和SDA在空闲时候均为高电 ...
- STM32 Cube MX 之hal库软件模拟IIC 可直接移植使用
此为软件模拟IIC,可以直接移植到HAL库使用..h文件需要自己做函数声明这里就不再放出,如有问题大家可以讨论. 使用的时候只需要更改SDA 和SCL引脚的宏定义就可以移植使用,当然IIC协议其实就是 ...
- STM32F103单片机软件模拟IIC并读取TMP112数字温度传感器
本文利用STM32F103系列单片机读取TMP112数字温度传感器的温度信息,TMP112数字传感器采用IIC总线协议通信.STM32自身含有硬件IIC资源,分别是PB6-->SCL.PB7-- ...
- 【蓝桥杯嵌入式】【STM32】5_IICEEPROM之软件模拟IIC
文章目录 1.原理图 2.源代码 下载工程文件: https://gitee.com/Joseph_Cooper/blue-bridge-embedded 1.原理图 顺便指出了该器件的地址. ...
- 一种基于IO口的模拟串口(LOG)实现方法
一.使用背景 当MCU的串口不够用时,可以通过IO模拟的方式将任意一个具有输出功能的管脚配置为串口输出,从而方便开发和调试. 二.实现原理 通过IO口模拟串口发送波形,配置对应的波特率等信息,然后映射 ...
- 2021-11-3 软件模拟IIC时序,并和EEPROM存储芯片24C02双向通信以及显示功能
IIC(Inter-Integrated Circuit(集成电路总线)) 2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL.所有接到I2C总线设备上的串行数据SDA都接到 ...
最新文章
- 支付宝接口调用问题快速通道
- python真的那么强大嘛-这些 Python 库真的很“冷”,但是却很强大
- 企业需要建设网站该如何咨询价格呢?
- red hat 4.1.2_安装Red Hat Container Development Kit 2.2版本
- 移动端导出excel_连载系列【4】Excel开发移动端quot;APPquot;
- qt设置路径为应用程序启动路径
- loading窗口动画 web_在页面未加载完之前显示loading动画
- pyqt与mysql例子_PyQt 连接MySql数据库,C++代码转Python3代码
- PHP性能调优,PHP慢日志---善用php-fpm的慢执行日志slow log,分析php性能问题
- 手把手教你搭建pytorch深度学习网络
- Python被誉为神奇的“胶水语言”,到底神奇在哪?
- [Python] Python学习笔记之常用模块总结[持续更新...]
- stm32的HAL库uart的注意点
- 中国移动计算机二面笔试题,中国移动笔试面试经验
- sodp软件如何导入多个工作面信息_平方英尺和面积计算软件:Metes and Bounds for Mac...
- 2019年5款你必须知道的顶级ASO优化工具
- 数据结构创建有向图(C++语言)
- 【大数据技术应用实战】【大数据与人工智能视角下数字孪生和元宇宙】二、新一轮大数据与人工智能变革
- 华为交换机RRPP单环配置
- 自学html4,HTML4
热门文章
- Robotstudio软件二次开发:基于C#语言的Smart组件开发基础
- mysql插入数据返回主键值_Mysql插入记录后返回该记录ID
- 百望股份获阿里腾讯系5.17亿元A轮融资
- c语言接口测试方法,如何做API接口测试?
- 计算机加硬盘后速度变慢,ssd硬盘win10系统加上机械硬盘后启动很慢怎么修复
- 10.07 WZZX Day2总结
- The bean ‘xxImpl‘ could not be injected as a ‘xxx‘ because it is a JDK dynamic proxy that implements
- a律13折线pcm编码例题_a律13折线编码段内码怎么确定
- 国稻种芯百团计划行动 丰收节贸促会·袁隆平:水稻国际竞争
- 使用链表(LinkedList) 二叉搜索树(BST) 实现不重复元素集合(Set)