目录

前言

辅助函数

相关信号函数

起始信号

停止信号

接收应答函数

发送应答信号

应答信号

非应答信号

发送/接收一个字节数据

发送一字节数据

接收一字节数据

应用

IIC级联

最后


前言

IIC为两线式串行总线,其用于主设备与从设备之间的通信,且任一时刻只能有一台主设备。网上关于IIC的详细说明很多,故本文不打算从介绍IIC入手,直接进行程序说明。

此外,由于不同的从设备的控制方法不同,鄙人不才,想不到一个比较完美的方法将不同的设备在程序上进行统一,因此,本文章仅介绍IIC的基本信号产生的函数,还望读者谅解。如对设备在程序上的统一,有好办法的读者,还请赐教!

文章中程序使用的单片机为STC15系列的单片机,所用的时钟频率为24MHz。但是它是适用51系列的单片机的,因其程序编写过程大同小异,故读者可在此基础上适当修改,以适用读者所用的芯片。

辅助函数

在IIC中,当SCL为高电平时,SDA上电平的变化将代表着相关的操作,为防止误触发,每个函数都以SCL为低电平收尾。

/************************************************************************本文件为IIC的基本信号集合(作为主机),就目前测试,适合在各个频率下工作,针对不同的频率,仅需适当调整IIC延时的循环次数即可每个信号中都以SCL低电平为结尾,这样一来可防止信号发送之后在SDA上的电平变化引起误触发
*************************************************************************/sbit SDA = P0^0;
sbit SCL = P0^1;

在IIC适用过程中会涉及到相应信号的延时,在此吾建立了一个专用于IIC延时的函数,如下:

/*仅作为IIC延时,故使其仅作为该文件可以调用的函数,可根据不同的时钟频率调节相应的延时时间*/
static void IIC_Delay()
{unsigned char i;for(i = 0;i < 2;i++) //根据不同的时钟频率调整不同的循环次数{_nop_();}
}

接下来的函数是配置所使用到的引脚的模式以及相关的初始化,如下:

/*IIC初始化,将端口设为准双向输入输出(不设置为推挽模式是因为还需要读取数据,推挽下输入的电平几乎是不变的)*/
void IIC_Init()
{P0M0 &= 0xfc; //根据需要调整参数P0M1 &= 0xfc;    //根据需要调整参数SCL = 0;     //将时钟线拉低后,数据线上的变化不会产生影响,防止误触发SDA = 1;      //释放数据线
}

相关信号函数

起始信号

起始信号即在SCL为高电平情况下,SDA由高电平变为低电平

/****IIC起始信号(SCL高电平下SDA的一个下降沿,后以SCL变为低电平收尾)****/
/*                         ____/     \4.7us___/       \___                                   */
void IIC_Start()
{SDA = 1;SCL = 1;SDA = 0;SCL = 0;
}

停止信号

停止信号即在SCL为高电平情况下,SDA由低电平变为高电平

/****IIC停止信号(SCL高电平下SDA一个上升沿,后以SCL变为低电平收尾)****/
/*                            _____________SCL ____/                    4us_____SDA ______/      \____                         */
void IIC_Stop()
{SDA = 0;SCL = 1;SDA = 1;SCL = 0;
}

接收应答函数

主设备释放SDA总线,将SCL总线置为高电平,接收SDA上的应答信号

/*接收应答信号,若接收到非应答信号,则发送停止信号(SDA低电平表示应答,高电平表示非应答)*/
bit IIC_ReceiveACK()
{bit state;SDA = 1;SCL = 1;state = SDA;SCL = 0;if(state)            //非应答{IIC_Stop();}return state;
}

发送应答信号

应答信号

SDA保持低电平,然后将SCL由低电平转为高电平

/*************************发送应答信号函数*************************/
/****应答(SDA保持为低电平)****/
/*                               ____SCL _______/    \_____             _____SDA         \____________                         */
void IIC_SendACK()
{SDA = 0;SCL = 1;IIC_Delay();     //必须延时SCL = 0;
}

非应答信号

SDA保持高电平,然后将SCL由低电平转为高电平

/****非应答(SDA保持为高电平)****/
/*                               ____SCL _______/    \_____             _____________SDA    ____/                                       */
void IIC_SendNACK()
{SDA = 1;SCL = 1;IIC_Delay();SCL = 0;
}

发送/接收一个字节数据

发送一字节数据

/****IIC发送一个字节数据(每发送一个字节接收一次应答)****/
void IIC_SendByte(unsigned char dat)
{unsigned char i;for(i = 0;i < 8;i++){SDA = (dat >> 7);SCL = 1;IIC_Delay();SCL = 0;dat <<= 1;IIC_Delay();     //必须延时}
}

接收一字节数据

/****IIC接收一个字节(每接收一个字节发送一次应答/非应答)****/
unsigned char IIC_ReadByte()
{unsigned char i,receive;SDA = 1;              //释放数据线for(i = 0;i < 8;i++){SCL = 1;receive <<= 1;receive |= SDA;SCL = 0;IIC_Delay();       //必须延时}return receive;
}

应用

在使用IIC对设备进行读写操作时,需要先往IIC总线上发送7位从机地址和一位读写标志位,7位从机地址由模块厂商生产时确定,发送后与该地址一致的从机根据最后一位进入读或者写状态。当最后一位为0时,往从机写入数据;当最后一位为1时,往从机读出数据。以下假设从机的7位地址为0x68,为读者演示其读写操作:

写入数据:

IIC_SendByte((0x68 << 1) & 0xfe);      //direction is write

读出数据:

IIC_SendByte((0x68 << 1) | 0x01);      //direction is read

IIC级联

IIC级联即将不同模块的IIC时钟引脚和数据引脚分别连接在一起,然后连接到单片机的IO口上,可实现单片机的一对IIC的IO口控制多个模块。例如模块1的SCL引脚与模块2的SCL引脚连接在一起然后接到单片机定义的SCL引脚上;再将模块1的SDA引脚与模块2的SDA引脚连接在一起然后接到单片机的SDA引脚上,即级联。

在级联中如何区分不同的模块呢?此时前面提到的从机地址发挥了关键作用。由于每次对模块进行控制时都需要先发送从机地址和读写位,其中读写位说明了数据的传输方向,而从机地址则说明了此时所控制的模块。

在从机地址由7位数据组成的模块中,理论上可级联的IIC模块个数为127个。

在实际的级联操作中,由于每个模块多少会有漏电流,所以还要根据实际情况决定是否需要为单片机的IO口添加上拉电阻,增强其驱动能力。

假设此时有两个IIC模块进行级联,模块1的从机地址为0x68,模块2的从机地址为0x38。当对模块1进行读写时,操作如下:

IIC_SendByte((0x68 << 1) & 0xfe);      //direction is write
IIC_SendByte((0x68 << 1) | 0x01);     //direction is read

当对模块2进行读写时,操作如下:

IIC_SendByte((0x38 << 1) & 0xfe);      //direction is write
IIC_SendByte((0x38 << 1) | 0x01);     //direction is read

级联更多模块的操作与此类似,不作过多赘述。

最后

以上即IIC的基本函数,程序中有些地方必须有一定的延时,否则将造成通信异常,这些地方我在后面都有注释。这些延时仅适用于24MHz及一下的频率使用模拟IIC,其他频率下的其他地方是否需要延时鄙人未知;还有,在其他频率下,延时函数也需要进行一定的调整,这些问题本身难度不大,留给读者探索。

51单片机之模拟IIC总线相关推荐

  1. 基于51单片机实现模拟IIC总线时序

    最近用到测量光线的模块BH1750FVI时需要用到IIC总线操作, 于是就又费功夫学习了下, 基本上算是了解了, 所以呢, 就用51的IO口, 模拟出了总线时序, 并能正确操纵需要用IIC总线访问地一 ...

  2. 用Proteus学习51单片机之I2C(IIC)总线

    最近刚做好一个站,基于rails 3,教程为主,大家捧场看看,谢谢!www.yo945.com 在学习单片机的过程中,我常有这样的烦恼:随随便便一个芯片,少则占用三五个IO口,一般的就占用8个,稍微想 ...

  3. 51单片机(IO模拟IIC通信)

    单片机作为主机 sbit SDA = P1^0; sbit SCL = P1^1; IIC数据操作:在iic总线上,数据伴随时钟脉冲,一位一位的传送的,数据位由高到低传送,每位数据占一个时钟脉冲.在时 ...

  4. “MPX4115型压力传感器+PCF8591型AD+模拟IIC总线”的Proteus仿真

    一.MPX4115型压力传感器介绍 1.1 引脚说明 即:1引脚为模拟量输出,2引脚接地,三引脚接电源,4.5.6引脚空 1.2 输出特性图 选择典型曲线,我们可以得知转换公式:压力值=(电压值/5. ...

  5. 基于stm32单片机的模拟IIC时序(附源码)

    我下面要说的是基于stm32单片机的模拟IIC时序,以及是一些要注意的事项:结合自己所做的MMA7455加速度传感器,我把模拟IIC的源代码贴了出来,大家可以参考一下. 1.因为在IIC协议中,当总线 ...

  6. 51单片机LED模拟交通灯

    51单片机LED模拟交通灯 文章目录 51单片机LED模拟交通灯 实验环境 仿真图 代码解析 效果演示 实验环境 实验软件: Keil5 + Proteus7 实验元件: AT89C51 * 1, L ...

  7. 基于高速51单片机的模拟USB接口设计

    基于高速51单片机的模拟USB接口设计 作者:廖颂文 摘要:参照AVRUSB技术给出了51单片机通过模拟USB通信的实现方法.用VC编写了上位机软件,通过libusb驱动实现了PC与ST12LE560 ...

  8. 使用51单片机+lcd1602转接板-iic接口进行显示

    使用51单片机+lcd1602转接板-iic接口进行显示 某宝上有卖lcd1602与iic芯片pcf8574的整合,虽然lcd1602能直接用51单片机使用,不过经过整合之后只需要对SCL和SDA两个 ...

  9. 【Proteus仿真】51单片机洗衣机模拟控制程序

    [Proteus仿真]51单片机洗衣机模拟控制程序 Proteus仿真 Proteus仿真说明 1. 启动洗衣仿真后,首先选择洗衣模式, 2. 调节液位传感器的可调电阻,模拟洗衣前的进水过程. 3. ...

  10. 基于51单片机的软件IIC详细讲解

    单片机软件仿真IIC信号 IIC属于两线式总线串口协议,主要包含有串行时钟线(SCL),和串行数据线(SDA)组成 /**************************IIC的一般通讯写数据过程为: ...

最新文章

  1. Sql Server插入数据并返回自增ID,@@IDENTITY,SCOPE_IDENTITY和IDENT_CURRENT的区别
  2. linux下载tomcat7命令,linux下安装tomcat7.0
  3. python程序编程千分符号怎么输入_教你用Python来玩“微信跳一跳”瞬间千分……已开源...
  4. 2018android旗舰手机,2018 年发布的 Android 手机,哪一部是你心目中的最佳手机?理由是什么?...
  5. java里面运行js_在java中利用rhino执行javascript
  6. oracle bbed 使用,Oracle BBED使用 四步快速启动Oracle BBED
  7. php 删除字符串中链接_python面试——删除字符串中的“b”和“ac”,删除后无b和ac(CloudIn(云英)面经)...
  8. 最课程学员启示录:一份有诚意的检讨书
  9. C++基础知识面试精选100题系列(11-20题)[C++ basics]
  10. java内网环境使用代理访问外网api
  11. 节奏大师闪退android,游戏动态:《节奏大师》闪退问题解决方法汇总
  12. 在html中 创建超链接使用的标记是,建立超链接标记是什么
  13. YOLOV7改进--添加CBAM注意力机制
  14. php 正则格式化图片,php利用正则表达式格式化电话号码的方法
  15. php上传文件时报错:only variables should be passed by reference
  16. 英语音标 什么是音素
  17. HDU 6148 Valley Numer(数位DP)
  18. Win2003系统部署SSL证书(部署https教程)
  19. php命令执行后门,php后门木马常用命令
  20. demon算法 matlab,Ncut图像分割算法MATLAB实现

热门文章

  1. vue配置代理服务器proxy
  2. Groundhog Looking Dowdy(尺取大法)
  3. python中def main是什么意思_浅析Python中的main函数
  4. 2017年华东师范大学网络赛 A
  5. 如何用 Telemetry 测试移动 APP H5性能?
  6. 利用Vue制作一个简单的走马灯
  7. RecyclerView报错:Scrapped or attached views may not be recycled
  8. linux中bash是什么命令,linux中bash是什么意思?
  9. NPR——卡通渲染(二)
  10. 策略模式Java实现