打印
[应用方案]

单片机 IIC 软模拟

[复制链接]
1147|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
minzisc|  楼主 | 2024-6-17 05:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、IIC概述

IIC(Inter-IntegratedCircuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器以及其外围设备,IIC也被成为I2C,其实两者是完全相同的,只是名词不一样而已。
它是由数据线SDA和时钟线SCL构成的串行总线,可发送和接收数据。

二、IIC特点
  • 数据线SDA:数据线用来传输数据;时钟线SCL:时钟线用来同步数据收发

  • 总线上每一个器件都有一个唯一的地址识别,所以我们只需要知道器件的地址,根据时序就可以实现微控制器与器件之间的通信。

  • 数据线SDA和时钟线SCL都是双向线路,都通过一个电流源或上拉电阻连接到正的电压,所以当总线空闲的时候,这两条线路都是高电平。

  • 总线上数据的传输速率在标准模式下可达100kbit/s在快速模式下可达400kbit/s在高速模式下可达3.4Mbit/s。

  • 总线支持设备连接个数:同时支持多个主机和多个从机,连接到总线的接口数量只由总线电容是400pF的限制决定,如以下图所示:





注意:注意起始和终止信号都是由主机发出的,总线在起始条件之后,视为忙状态,在停止条件之后被视为空闲状态。

应答:每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据。

注意:从机应答主机所需要的时钟仍是主机提供的,应答出现在每一次主机完成8个数据位传输后紧跟着的时钟周期,低电平0表示应答,1表示非应答

三、示例代码/* -----------------------------------------头文件-----------------------------------------*/#include "iic.h"/* -----------------------------------------宏定义-----------------------------------------*/#define IIC_SDA(N) IIC_SDA = N#define IIC_SCL(N) IIC_SCL = N/*选择SDA的数据方向*/#define IIC_SDA_Input()     {P13_PushPull_Mode;P14_Input_Mode;}#define IIC_SDA_Output()    {P13_PushPull_Mode;P14_PushPull_Mode;}/* -----------------------------------------结构体定义-------------------------------------*//* -----------------------------------------全局变量定义-----------------------------------*/sbit IIC_SDA = P1 ^ 4;sbit IIC_SCL = P1 ^ 3;/* -----------------------------------------应用程序---------------------------------------*/void Delayus(uint16_t i){    while (i--);}void Delayms(uint16_t i){    i = i * 1000;    Delayus(i);}/*********************************************函数名:IIC_Init功  能:IIC引脚初始化作  者:薛建强时  间:2019/06/11**********************************************/void IIC_Init(void){    IIC_SDA_Output();    IIC_SDA(1);    IIC_SCL(1);}/*********************************************函数名:IIC_Start功  能:IIC通讯开始作  者:薛建强时  间:2019/06/11**********************************************/void IIC_Start(void){    IIC_SDA_Output();  // 设置为输出模式    IIC_SCL(1);    IIC_SDA(1);    Delayus(1);    IIC_SDA(0);    IIC_SCL(0);    Delayus(2);}/*********************************************函数名:IIC_Stop功  能:IIC通讯结束作  者:薛建强时  间:2019/06/11**********************************************/void IIC_Stop(void){    IIC_SDA_Output();  // 设置为输出模式    IIC_SCL(0);    IIC_SDA(0);    Delayus(2);    IIC_SCL(1);    IIC_SDA(1);    Delayus(2);}/*********************************************函数名:IIC_Wait_ACK功  能:IIC从设备应答作  者:薛建强时  间:2019/06/11**********************************************/void IIC_Wait_ACK(void){    uint8_t i = 0;    IIC_SDA_Input();            //   SDA 设置为输入    IIC_SCL(1);    Delayus(1);    while (IIC_SDA == 1 && i < 250)        i++;    IIC_SCL(0);    IIC_SDA_Output();           //   设置成输出    Delayus(2);}/*********************************************函数名:IIC_NACK功  能:主设备非应答作  者:薛建强时  间:2019/06/11**********************************************/void IIC_NACK(void){    IIC_SCL(1);    Delayus(1);    IIC_SDA(1);    IIC_SCL(0);    Delayus(2);}/*********************************************函数名:IIC_WriteByte功  能:发送一个字节形  参:byte--待发送字节作  者:薛建强时  间:2019/06/11**********************************************/void IIC_WriteByte(uint8_t byte){    uint8_t len = 0;    IIC_SCL(0);    Delayus(2);    for (len = 0; len < 8; len++)    {        if (byte & 0x80)        {            IIC_SDA(1);        }        else        {            IIC_SDA(0);        }        Delayus(1);        IIC_SCL(1);        byte <<= 1;        Delayus(1);        IIC_SCL(0);        Delayus(2);    }    IIC_SDA(1);    IIC_SCL(0);    Delayus(2);}/*********************************************函数名:IIC_ReadByte功  能:向从设备接收一个字节返回值:Byte--读取到的字节作  者:薛建强时  间:2019/06/11**********************************************/uint8_t IIC_ReadByte(void){    uint8_t len = 0, Byte = 0;    IIC_SDA(1);    IIC_SDA_Input();            // SDA 设置为输入    for (len = 0; len < 8; len++)    {        IIC_SCL(0);        Delayus(1);        IIC_SCL(1);        Delayus(1);        Byte <<= 1;        Byte |= IIC_SDA;        Delayus(1);        IIC_SCL(0);        Delayus(1);    }    return Byte;}/*********************************************函数名:IIC_ReceiveData功  能:向从设备接收一个字节,并带应答作  者:薛建强时  间:2019/06/11**********************************************/uint8_t IIC_ReceiveData(uint8_t Ack){    uint8_t i = 0, ReadValue = 0;    IIC_SDA_Output();   //   设置成输出模式    IIC_SDA(1);    IIC_SDA_Input();    //   设置为输入模式    IIC_SCL(0);    for (i = 0; i < 8; i++)    {        IIC_SCL(1);        Delayus(1);        ReadValue <<= 1;        if (IIC_SDA != 0)        {            ReadValue |= 0x01;        }        Delayus(1);        IIC_SCL(0);        Delayus(2);    }    if (Ack)    {        IIC_SCL(0);        IIC_SDA_Output();   //   设置成输出模式        IIC_SDA(0);        Delayus(2);        IIC_SCL(1);        Delayus(1);        IIC_SCL(0);    }    else    {        IIC_SCL(0);        IIC_SDA_Output();   //   设置成输出模式        IIC_SDA(1);        Delayus(2);        IIC_SCL(1);        Delayus(1);        IIC_SCL(0);    }    return ReadValue;}#ifndef __IIC_H#define __IIC_H/* -----------------------------------------头文件-----------------------------------------*/#include "main.h"/* -----------------------------------------宏定义-----------------------------------------*//* -----------------------------------------结构体定义-------------------------------------*/typedef struct{  uint8_t                DelayTick;             //定义延时,以适应不同器件对速率的不同要求,具体值要在调试中确定  uint8_t                        ADDR;         //器件地址}IIC_TYPE;/* -----------------------------------------全局变量定义-----------------------------------*//* -----------------------------------------应用程序---------------------------------------*/void    IIC_Init(void);                // IIC端口void    IIC_Start(void);               // 启动信号void    IIC_Stop(void);                // 停止信号void    IIC_Wait_ACK(void);            // 应答信号void    IIC_NACK(void);void    IIC_WriteByte(uint8_t txd);uint8_t IIC_ReadByte(void);            // 读取数据uint8_t IIC_ReceiveData(uint8_t Ack);  // 读取数据#endif四、应用

i2C总线是各种总线中使用信号线最少,并具有自动寻址、多主机时钟同步和仲裁等功能的总线。因此,使用I2C总线设计计算机系统十分方便灵活,体积也小,因而在各类实际应用中得到广泛应用。下面举二个应用示例。

I2C的运用比如在铁电存储器中,用铁电存储数据就是用的I2C总线协议。
伺服控制系统用I2C扩展LCD显示器

它用8XC752单片机的PWM输出经放大后来驱动电机,电机的转速由测速机测取并直接送到8XC752片内的A/D电路。处理后的有关信息经I2C总线送到LCD驱动芯片PCF8577以驱动64段LCD显示板。
通用I/O端口作为I2C总线接口

目前,51、96系列的单片机应用很广,但是由于它们都没有I2C总线接口,从而限制了在这些系统中使用具有I2C总线接口的器件。通过对I2C总线时序的分析,可以用51单片机的两根I/O线来实现I2C总线的功能。接I2C总线规定:SCL线和SDA线是各设备对应输出状态相“与”的结果,任一设备都可以用输出低电平的方法来延长SCL的低电平时间,以迫使高速设备进入等待状态,从而实现不同速度设备间的时钟同步。因此,即使时钟脉冲的高、低电平时间长短不一,也能实现数据的可靠传送,可以用软件控制I/O口做I2C接口。下面就是用GMS97C2051的通用I/O口来作为I2C总线接口,并由软件控制实现数据传送的例子。

在单主控器的系统中,时钟线仅由主控器驱动,因此可以用51系列的一根I/O线作为SCL的信号线,将其设置为输出方式,并由软件控制来产生串行时钟信号。在实际系统中使用了P1.3。另一根I/O线P1.2作为I2C总线的串行数据线,可在软件控制下在时钟的低电平期间读取或输出数据。

系统传输数据的过程如下:先由单片机发出一个启始数据信号,接着送出要访问器件的7位地址数据,并等待被控器件的应答信号。当收到应答信号后,根据访问要求进行相应的操作。

如果是读入数据,则数据线可一直设为输入方式,中间不需要改变SDA线的工作方式,每读入一个字节均应依次检测应答信号;如果是输出数据,则首先将SDA设置为输出方式,当发送完一个字节后,需要改变SDA线为输入方式,此时读入被控器件的应答信号就完成了一个字节的传送。当所有数据传输完毕后,应向SDA发出一个停止信号,以结束该次数据传输


使用特权

评论回复
沙发
huquanz711| | 2024-6-17 08:01 | 只看该作者
IIC好多都是用的IO模拟方式

使用特权

评论回复
板凳
呐咯密密| | 2024-6-17 14:05 | 只看该作者
软件模拟很好用,但是你这太乱了,没法看

使用特权

评论回复
地板
yangxiaor520| | 2024-6-19 07:59 | 只看该作者
软件模拟IIC有时候比硬件IIC好用

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

55

主题

5241

帖子

4

粉丝