51单片机之模拟IIC总线
目录
前言
辅助函数
相关信号函数
起始信号
停止信号
接收应答函数
发送应答信号
应答信号
非应答信号
发送/接收一个字节数据
发送一字节数据
接收一字节数据
应用
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总线相关推荐
- 基于51单片机实现模拟IIC总线时序
最近用到测量光线的模块BH1750FVI时需要用到IIC总线操作, 于是就又费功夫学习了下, 基本上算是了解了, 所以呢, 就用51的IO口, 模拟出了总线时序, 并能正确操纵需要用IIC总线访问地一 ...
- 用Proteus学习51单片机之I2C(IIC)总线
最近刚做好一个站,基于rails 3,教程为主,大家捧场看看,谢谢!www.yo945.com 在学习单片机的过程中,我常有这样的烦恼:随随便便一个芯片,少则占用三五个IO口,一般的就占用8个,稍微想 ...
- 51单片机(IO模拟IIC通信)
单片机作为主机 sbit SDA = P1^0; sbit SCL = P1^1; IIC数据操作:在iic总线上,数据伴随时钟脉冲,一位一位的传送的,数据位由高到低传送,每位数据占一个时钟脉冲.在时 ...
- “MPX4115型压力传感器+PCF8591型AD+模拟IIC总线”的Proteus仿真
一.MPX4115型压力传感器介绍 1.1 引脚说明 即:1引脚为模拟量输出,2引脚接地,三引脚接电源,4.5.6引脚空 1.2 输出特性图 选择典型曲线,我们可以得知转换公式:压力值=(电压值/5. ...
- 基于stm32单片机的模拟IIC时序(附源码)
我下面要说的是基于stm32单片机的模拟IIC时序,以及是一些要注意的事项:结合自己所做的MMA7455加速度传感器,我把模拟IIC的源代码贴了出来,大家可以参考一下. 1.因为在IIC协议中,当总线 ...
- 51单片机LED模拟交通灯
51单片机LED模拟交通灯 文章目录 51单片机LED模拟交通灯 实验环境 仿真图 代码解析 效果演示 实验环境 实验软件: Keil5 + Proteus7 实验元件: AT89C51 * 1, L ...
- 基于高速51单片机的模拟USB接口设计
基于高速51单片机的模拟USB接口设计 作者:廖颂文 摘要:参照AVRUSB技术给出了51单片机通过模拟USB通信的实现方法.用VC编写了上位机软件,通过libusb驱动实现了PC与ST12LE560 ...
- 使用51单片机+lcd1602转接板-iic接口进行显示
使用51单片机+lcd1602转接板-iic接口进行显示 某宝上有卖lcd1602与iic芯片pcf8574的整合,虽然lcd1602能直接用51单片机使用,不过经过整合之后只需要对SCL和SDA两个 ...
- 【Proteus仿真】51单片机洗衣机模拟控制程序
[Proteus仿真]51单片机洗衣机模拟控制程序 Proteus仿真 Proteus仿真说明 1. 启动洗衣仿真后,首先选择洗衣模式, 2. 调节液位传感器的可调电阻,模拟洗衣前的进水过程. 3. ...
- 基于51单片机的软件IIC详细讲解
单片机软件仿真IIC信号 IIC属于两线式总线串口协议,主要包含有串行时钟线(SCL),和串行数据线(SDA)组成 /**************************IIC的一般通讯写数据过程为: ...
最新文章
- Sql Server插入数据并返回自增ID,@@IDENTITY,SCOPE_IDENTITY和IDENT_CURRENT的区别
- linux下载tomcat7命令,linux下安装tomcat7.0
- python程序编程千分符号怎么输入_教你用Python来玩“微信跳一跳”瞬间千分……已开源...
- 2018android旗舰手机,2018 年发布的 Android 手机,哪一部是你心目中的最佳手机?理由是什么?...
- java里面运行js_在java中利用rhino执行javascript
- oracle bbed 使用,Oracle BBED使用 四步快速启动Oracle BBED
- php 删除字符串中链接_python面试——删除字符串中的“b”和“ac”,删除后无b和ac(CloudIn(云英)面经)...
- 最课程学员启示录:一份有诚意的检讨书
- C++基础知识面试精选100题系列(11-20题)[C++ basics]
- java内网环境使用代理访问外网api
- 节奏大师闪退android,游戏动态:《节奏大师》闪退问题解决方法汇总
- 在html中 创建超链接使用的标记是,建立超链接标记是什么
- YOLOV7改进--添加CBAM注意力机制
- php 正则格式化图片,php利用正则表达式格式化电话号码的方法
- php上传文件时报错:only variables should be passed by reference
- 英语音标 什么是音素
- HDU 6148 Valley Numer(数位DP)
- Win2003系统部署SSL证书(部署https教程)
- php命令执行后门,php后门木马常用命令
- demon算法 matlab,Ncut图像分割算法MATLAB实现