普通IO口模拟IIC时序,进行红外测温

IIC介绍和代码编写

I2C总线(Inter Integrated Circuit Bus):

是Philips公司推出的串行总线标准(为二线制)。总线上扩展的外围器件及外设接口通过总线寻址,是具备总线仲裁和高低速设备同步等功能的高性能多主机总线。

I2C总线工作原理:

串行数据线SDA和串行时钟线SCL构成的,可发送和接收数据。

所有挂接在I2C总线上的器件和接口电路都应具有I2C总线接口,且所有的SDA/SCL同名端相连。总线上所有器件要依靠SDA发送的地址信号寻址,不需要片选线。

特点:组成系统结构简单,占用空间小,芯片管脚的数量少,无需片选信号,价格低。允许若干兼容器件共享总线,应用比较广泛。总线的长度可达7.6m,传送速度可达400kbps,标准速率为100kbps。支持多个组件。支持多主控器件(某时刻只能有一个主控器件)。I2C总线上所有设备的SDA, SCL引脚必须外接上拉电阻。

典型的I2C总线系统结构,如图所示。I2C总线上可以挂接多个器件,其中每个器件必须都支持I2C总线通信协议。

I2C总线器件的寻址方式

由于所有器件都通过SCL和SDA连接在I2C总线上,因此,主器件在进行数据传输前需要通过寻址,选择需要通信的从器件。I2C总线上所有外围器件都需要有唯一的I2C位地址,由器件地址和引脚地址两部分组成。

器件地址是I2C器件固有的地址编码,器件出厂时就已经给定,不可更改。

引脚地址是由I2C总线外围器件的地址引脚(A2,A1,A0)决定,根据其在电路中接电源正极、接地或悬空的不同,形成不同的地址代码。

I2C总线接口 EEPROM存储器

目前,市场上I2C总线接口器件有多种,例如A/D转换器、D/A转换器(PCF8591)、时钟芯片和存储器(24C02)等。这里以典型的I2C总线接口的存储器为例进行介绍。

I2C总线接口EEPROM存储器是一种采用I2C总线接口的串行总线存储器,这类存储器具有体积小、引脚少、功耗低、工作电压范围宽等特点。目前,Atmel、MicroChip、National等公司均提供各种型号的I2C总线接口的串行EEPROM存储器。在单片机系统中使用较多的EEPROM存储器是24系列串行EEPROM。其具有型号多、容量大、支持I2C总线协议、占用单片机I/O端口少,芯片扩展方便、读写简单等优点。

 

 I2C总线概述

I2C总线采用两线制,由数据线SDA和时钟线SCL构成。I2C总线对数据通信时序进行了严格的定义。主要看虚线部分。  

I2C总线数据操作

在I2C总线上,数据是伴随着时钟脉冲,一位一位地传送的,数据位由低到高传送,每位数据占一个时钟脉冲。I2C总线上的在时钟线SCL高电平期间,数据线SDA的状态就表示要传送的数据,高电平为数据1,低电平为数据0。在数据传送时,SDA上数据的改变在时钟线为低电平时完成,而SCL为高电平时,SDA必须保持稳定,否则SDA上的变化会被当作起始或终止信号而致使数据传输停止。

 

I2C总线在传送数据过程中共有三种类型信号:开始信号、停止信号和应答信号。

开始信号:SCL保持高电平的状态下,SDA出现下降沿。出现开始信号以后,总线被认为“忙”。

停止信号:SCL保持高电平的状态下,SDA出现上升沿。停止信号过后,总线被认为“空闲”。

应答信号:接收数据的器件在接收到8位数据后,向发送数据的器件发出特定的低电平脉冲,表示已收到数据。           

总线空闲:SCL和SDA都保持高电平。

总线忙:在数据传送开始以后,SCL为高电平的时候,SDA的数据必须保持稳定,只有当SCL为低电平的时候才允许SDA上的数据改变。

I2C协议起始信号时序

    起始信号用于开始I2C总线通信。其中,起始信号是在时钟线SCL为高电平期间,数据SDA上高电平向低电平变化的下降沿信号。起始信号出现以后,才可以进行后续的I2C总线寻址或数据传输等。

起始信号用于开始I2C总线通信。其中,起始信号是在时钟线SCL为高电平期间,数据SDA上高电平向低电平变化的下降沿信号。起始信号出现以后,才可以进行后续的I2C总线寻址或数据传输等

void IIC_Start(void)
{
    IIC_OUTPUT_MODE_SET();
    SCL=1;//SDA初始化为高电平“1”
    SDA_out=1;//开始数据传送时,要求SCL为高电平“1”
    delay_us(5);
    SDA_out=0;//SDA的下降沿被认为是开始信号
    delay_us(5);
    SCL=0;//SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)
    delay_us(5);  
}

I2C协议终止信号时序

终止信号用于终止I2C总线通信。其中,终止信号是在时钟线SCL为高电平期间,数据线SDA上低电平到高电平变化的上升沿信号。终止信号一出现,所有I2C总线操作都结束,并释放总线控制权。终止信号的时序,

终止信号用于终止I2C总线通信。其中,终止信号是在时钟线SCL为高电平期间,数据线SDA上低电平到高电平变化的上升沿信号。终止信号一出现,所有I2C总线操作都结束,并释放总线控制权。终止信号的时序

void IIC_Stop(void)
{
    IIC_OUTPUT_MODE_SET();
    SCL=0;
    SDA_out=0;//拉低,为产生上升沿做准备
    delay_us(5);
    SCL=1;
    delay_us(5);
    SDA_out=1;
    delay_us(5);
}

I2C协议应答信号时序

发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 

对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。 如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号,以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。

SDA两条线交叉,表示数据允许跳变。

//应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节
void IIC_ACK_NACK(u8 ack) 
{
    IIC_OUTPUT_MODE_SET();
    SCL=0;//SCL为低电平时才能改变SDA的状态
    delay_us(5);
    if(ack==0)  SDA_out=0;//读到低电平有效ACK
    else  SDA_out=1;//读到高电平无效NACK
    delay_us(5);    
    SCL=1;
    delay_us(5);
    SCL=0;
}

u8 IIC_WaitACK(void) //等待应答
{
    u8 t = 0;
    IIC_OUTPUT_MODE_SET();
    SDA_out=1;//8位发送完后释放数据线,准备接收应答位 
    delay_us(5);
    SCL=0;
    delay_us(5); 
    IIC_INPUT_MODE_SET();
    delay_us(5); 
    while(SDA_in) //当数据线输入为高电平时,进入等待,看是否会变成低电平
    {
        t++;
        if(t>250) //当等待到一定时刻依然是高电平,则停止发送
        {
            IIC_Stop();
            return 1;
        }
        delay_us(5);//为增加的时刻进行延时
    }
    delay_us(5);      
    SCL=1;
    delay_us(5);
    SCL=0;             
    delay_us(5);    
    return 0;    
}

IIC输入输出模式设置

void IIC_OUTPUT_MODE_SET(void)
{
    GPIO_InitTypeDef SHT31;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); 
    
    SHT31.GPIO_Mode=GPIO_Mode_OUT; //输出模式
    SHT31.GPIO_OType=GPIO_OType_PP; //推挽
    SHT31.GPIO_Pin=GPIO_Pin_7;
    SHT31.GPIO_PuPd=GPIO_PuPd_NOPULL; //下拉
    SHT31.GPIO_Speed=GPIO_Speed_100MHz;
    GPIO_Init(GPIOB,&SHT31);
}
void IIC_INPUT_MODE_SET(void)
{
    GPIO_InitTypeDef SHT31;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); 
    
    SHT31.GPIO_Mode=GPIO_Mode_IN; //输出模式
    SHT31.GPIO_OType=GPIO_OType_PP; //推挽
    SHT31.GPIO_Pin=GPIO_Pin_7;
    SHT31.GPIO_PuPd=GPIO_PuPd_NOPULL; //下拉
    SHT31.GPIO_Speed=GPIO_Speed_100MHz;
    GPIO_Init(GPIOB,&SHT31);
}

I2C总线的传送格式

I2C总线的传送格式为主从式,对系统中的某一器件来说有四种工作方式:主发送方式、从发送方式、主接收方式、从接收方式。
只讲主发送从接收(单片机发送 24C08接收)

 主器件产生开始信号以后,发送的第一个字节为控制字节。前七位为从器件的地址片选信号。最低位为数据传送方向位(高电平表示读从器件,低电平表示写从器件),然后发送一个选择从器件片内地址的字节,来决定开始读写数据的起始地址。接着再发送数据字节,可以是单字节数据,也可以是一组数据,由主器件来决定。从器件每接收到一个字节以后,都要返回一个应答信号(ASK=0)。主器件在应答时钟周期高电平期间释放SDA线,转由从器件控制,从器件在这个时钟周期的高电平期间必须拉低SDA线,并使之为稳定的低电平,作为有效的应答信号。

写操作

写操作分为字节写和页面写两种操作,

在字节写模式下 ,主器件发送起始命令和从器件地址信息 R/W位置零 给从器件 在从器件产生。

应答信号后 ,主器件发送16的字节地址 主器件在收到从器件的另一个应答信号后 再发送数据到被寻址的存储单元 再次应答 并在主器件产生停止信号后。

开始内部数据的擦写 ,在内部擦写过程中 从器件不再应答主器件的任何请求 。

void IIC_Write(u8 data)
{
    u8 i;
    IIC_OUTPUT_MODE_SET();
    for(i=0;i<8;i++) 
    {
        SCL=0;
        if(data&0x80) SDA_out=1;
        else SDA_out=0;
        
        delay_us(5);
        SCL=1;
        delay_us(5);
        data =data<<1;
    }
    SCL=0;
    delay_us(5);   

读操作

读操作有三种基本操作:当前地址读、随机读和顺序读。下图给出的是顺序读的时序图。应当注意的是,为了结束读操作,主机必须在第9个周期间发出停止条件或者在第9个时钟周期内保持SDA为高电平,然后发出停止条件。

 

u8 IIC_Read(void)
{
    u8 data=0,i;
    SDA_out=1;
    IIC_INPUT_MODE_SET();
    for(i=0;i<8;i++) 
    {
        SCL=0;
        delay_us(5);//产生一个上升沿,再读数据
        SCL=1;
        delay_us(5);
        if(SDA_in) data|=1<<(7-i);        
        SCL=0;
        delay_us(5);
    }
    SCL=0;
    delay_us(5);
    return data;
}

MLX90615介绍和代码编写

红外测温MLX90615原理图

 

 温度转换 

 

//红外测温MLX90615
void MLX90615_Init(void) 
{
    GPIO_InitTypeDef mlx90615;  
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); 
    
    mlx90615.GPIO_Mode=GPIO_Mode_OUT; //输出模式
    mlx90615.GPIO_OType=GPIO_OType_OD; //在SMbus模式里,SDA为开漏NMOS I/O口
    mlx90615.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7; 
    mlx90615.GPIO_PuPd=GPIO_PuPd_UP; 
    mlx90615.GPIO_Speed=GPIO_Speed_100MHz;
    GPIO_Init(GPIOB,&mlx90615);
}

u8 SMBus_temp(float *temp)
{
    float Te=0;
    u8 h=0,l=0,pec=0;
    IIC_Start();
    IIC_Write((MLX9061X_ADDR<<1)|WRITE);//发送RAM地址+物体温度地址
    if(IIC_WaitACK()==0)
    {
        IIC_Write(MLX9061X_RAM_ACCESS|MLX9061X_RAM_TOBJ1);
        if(IIC_WaitACK()==0)//读到应答信号0
        {
            IIC_Start();
            IIC_Write(MLX9061X_ADDR<<1|READ);//发送读数据命令
            if(IIC_WaitACK()==0)
            {
                l=IIC_Read();//读低字节
                IIC_ACK_NACK(0);
                h=IIC_Read();
                IIC_ACK_NACK(0);            
                pec=IIC_Read();
                IIC_ACK_NACK(1);//从机非应答信号,停止接收数据
                IIC_Stop();
            }
            else return 3;//发送读数据命令,得到非应答
        }
        else return 2; //发送RAM地址+物体温度地址,得到非应答
    }
    else return 1;
    Te=h<<8|l;
    *temp=Te*0.02-273.15; //计算温度值
    return 0;//写入数据、读数据成功
}
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值