现在的位置: 首页 > 综合 > 正文

FSL-KL46_I2C模块编程

2018年10月27日 ⁄ 综合 ⁄ 共 5151字 ⁄ 字号 评论关闭
文章目录

FSL-KL46_I2C模块编程

饕餮的阿周
986914265@qq.com

此处不具体介绍I2C模块,不介绍I2C硬件的实现原理,不分析其通信协议,仅介绍与编程有关的寄存器和驱动构件的实现。

一、I2C总线上的信号类型

I2C总线在传送数据过程中共有四种类型信号,分别是开始信号、停止信号、重新开始信号和应答信号。

二、主机向从机读/写1个字节数据的过程

1.主机向从机写1个字节数据的过程

首先主机产生START信号,然后发送一个7位从机地址,第8位是数据方向位(R/W),0表示主机发送数据,这时候主机等待从机的应答信号(ACK),收到应答信号,发送要访问的地址,等待从机的响应信号,收到响应信号时,发送1个字节的数据,等待从机的响应信号,当收到响应信号时,产生停止信号,结束发送信号。

2.主机从从机读1个字节数据的过程

首先主机产生START信号,然后发送一个从机地址,此时该地址的第8位为0,表明是向从机写命令,主机等待从机的应答信号(ACK),收到应答信号时,发送要访问的地址,继续等待从机的应答信号,当主机收到应答信号后,主机要改变通信模式(主机将由发送变为接收,从机将由接收变为发送),所以主机发送重新开始信号,然后发送一个从机地址,此时该地址的第8位为1,表明将主机设置成接收模式(读),这时主机等待从机的应答信号,当收到应答信号时,就可以接收1个字节的数据,当接收完成后,主机发送非应答信号,不再接收数据,主机进而产生停止信号,结束传送过程。

三、I2C寄存器

I2C的两个模块,所有的终端用户可以访问的I2C寄存器共有22个,每个模块各有11个8位寄存器,但每个模块常用的只有5个,这些寄存器复位为0。下表给出了I2C的模块0和模块1常用的10个寄存器,每个寄存器均可“读/写”。


1.I2C地址寄存器1(I2Cx_A1)

D7~D1(AD[7:1])当作为从机被寻址时,此字段包含I2C模块所使用的初始从机地址。此字段用于7位地址方案和10位地址方案中的低7位。
D0(0)—保留位。这个只读字段是保留的,读取值为0。

2.I2C分频寄存器(I2Cx_F)

D7~D6(MULT)—定义倍频因子MUL。此因子与SCL分频一起使用,以产生I2C波特率。
D5~D0(ICR)—时钟频率。此字段和MULT字段确定I2C波特率、SDA保持时间、SCL开始保持时间和SCL停止保持时间。

3.I2C控制寄存器1(I2Cx_C1)

D7(ICEN)—I2C使能。使能I2C模块的操作。0 禁用, 1使能。
D6(IICEN I2C)—I2C中断使能。使能I2C中断请求。0 禁用,1使能。
D5(MST)—主机模式选择。
D4(TX)—传送模式选择。
D3(TXAK)—传送应答使能。
D2(RSTA)—重复开始。
D1(WUEN)—唤醒使能。
D0(DMAEN)—DMA使能。

4.I2C状态寄存器(I2Cx_S)

D7(TCF)—传输完成标志。该位在一个字节和应答信号传输完成时被置位。
D6(IAAS)—作为从机被寻址。
D5(BUSY)—总线忙。
D4(ARBL)—仲裁丢失。
D3(RAM)—扩展地址匹配。
D2(SRW)—从机读/写。
D1(IICIF)—中断标志。
D0(RXAK)—接收应答。

5.I2C数据I / O寄存器(I2Cx_D)
在主机传送模式,当数据被写入到这个寄存器后,数据传输开始。首先发送最高位。在主机接收模式下,读取该寄存器开始接收下一个字节的数据。在从机模式下,同样的功能都可以在地址匹配后发生后获得。在主模式和从模式下的传输开始时,C1 [TX]位必须正确地反映所需的传输方向。

四、I2C驱动构件封装

<span style="font-size:12px;">//选择为发送模式
void i2c_set_tx_mode(uint_8 I2C_No)
{
	if(I2C_No<0||I2C_No>1) //如果模块号写错则强制其为0
	{
	    I2C_No = 0;
	}
	if(0 == I2C_No)
    {
    	BSET(I2C_C1_TX_SHIFT,I2C0_C1); //置位i2c0 TXAK
    }
	else
	{
		BSET(I2C_C1_TX_SHIFT,I2C1_C1); //置位i2c0 TXAK
	}
}</span>

//选择为接受模式
void i2c_set_rx_mode(uint_8 I2C_No)
{
	if(I2C_No<0||I2C_No>1) //如果模块号写错则强制其为0
	{
	    I2C_No = 0;
	}
	if(0 == I2C_No)
    {
		BCLR(I2C_C1_TX_SHIFT,I2C0_C1); //置位i2c0 TXAK
    }
	else
	{
		BCLR(I2C_C1_TX_SHIFT,I2C1_C1); //置位i2c0 TXAK
	}
}
//设置为从机模式
void i2c_set_slave_mode(uint_8 I2C_No)
{
	if(I2C_No<0||I2C_No>1) //如果模块号写错则强制其为0
	{
	    I2C_No = 0;
	}
	if(0 == I2C_No)
    {
		BCLR(I2C_C1_MST_SHIFT,I2C0_C1); //清i2c0 MST
    }
	else
	{
		BCLR(I2C_C1_MST_SHIFT,I2C1_C1); //清i2c0 MST
	}
}
//设置为主机模式
void i2c_set_master_mode(uint_8 I2C_No)
{
	if(I2C_No<0||I2C_No>1) //如果模块号写错则强制其为0
	{
	    I2C_No = 0;
	}
	if(0 == I2C_No)
    {
		BSET(I2C_C1_MST_SHIFT,I2C0_C1); //置位i2c0 MST
    }
	else
	{
		BSET(I2C_C1_MST_SHIFT,I2C1_C1); //置位i2c0 MST
	}
}
//发送非应答信号
void i2c_give_nack(uint_8 I2C_No)
{
	if(I2C_No<0||I2C_No>1) //如果模块号写错则强制其为0
	{
	    I2C_No = 0;
	}
	if(0 == I2C_No)
    {
    	BSET(I2C_C1_TXAK_SHIFT,I2C0_C1); //置位i2c0 TXAK
    }
	else
	{
		BSET(I2C_C1_TXAK_SHIFT,I2C1_C1); //置位i2c0 TXAK
	}
}
//发送应答信号
void i2c_give_ack(uint_8 I2C_No)
{
	if(I2C_No<0||I2C_No>1) //如果模块号写错则强制其为0
	{
	    I2C_No = 0;
	}
	if(0 == I2C_No)
    {
		BCLR(I2C_C1_TXAK_SHIFT,I2C0_C1); //清i2c0 TXAK
    }
	else
	{
		BCLR(I2C_C1_TXAK_SHIFT,I2C1_C1); //清i2c0 TXAK
	}
}
//重新开始信号
void i2c_repeated_start(uint_8 I2C_No)
{
	if(I2C_No<0||I2C_No>1) //如果模块号写错则强制其为0
	{
	    I2C_No = 0;
	}
	if(0 == I2C_No)
    {
		BSET(I2C_C1_RSTA_SHIFT,I2C0_C1); //置位i2c0 RSTA
    }
	else
	{
		BSET(I2C_C1_RSTA_SHIFT,I2C1_C1); //置位i2c0 RSTA
	}
}
//写
void i2c_write_byte(uint_8 I2C_No, uint_8 Data)
{
	if(I2C_No<0||I2C_No>1) //如果模块号写错则强制其为0
	{
	    I2C_No = 0;
	}
	if(0 == I2C_No)
    {
		I2C0_D = Data;
    }
	else
	{
		I2C1_D = Data;
	}
}
//读
uint_8 i2c_read_byte(uint_8 I2C_No)
{
	if(I2C_No<0||I2C_No>1) //如果模块号写错则强制其为0
	{
	    I2C_No = 0;
	}
	if(0 == I2C_No)
    {
		return I2C0_D;
    }
	else
	{
		return I2C1_D;
	}
}
//开始信号
void i2c_start(uint_8 I2C_No)
{
    i2c_set_master_mode(I2C_No);
    i2c_set_tx_mode(I2C_No);
}
//停止信号
void i2c_stop(uint_8 I2C_No)
{
    i2c_set_slave_mode(I2C_No);
    i2c_set_rx_mode(I2C_No);
}
//等待
void i2c_wait(uint_8 I2C_No)
{
	if(I2C_No<0||I2C_No>1) //如果模块号写错则强制其为0
	{
	    I2C_No = 0;
	}
	if(0 == I2C_No)
    {
	    // wait flag
	    while(BGET(I2C_S_IICIF_SHIFT,I2C0_S) == 0);
	    //写1清零
	    BSET(I2C_S_IICIF_SHIFT,I2C0_S);
    }
	else
	{
	    // wait flag
	    while(BGET(I2C_S_IICIF_SHIFT,I2C1_S) == 0);
	    //写1清零
	    BSET(I2C_S_IICIF_SHIFT,I2C1_S);
	}
}<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">  </span>
//获取应答信号
uint_16 i2c_get_ack(uint_8 I2C_No)
{
	if(I2C_No<0||I2C_No>1) //如果模块号写错则强制其为0
	{
	    I2C_No = 0;
	}
	if(0 == I2C_No)
    {
		if(BGET(I2C_S_RXAK_SHIFT,I2C0_S) == 0)
		    return TRUE;
	    else
	        return FALSE;
    }
	else
	{
		if(BGET(I2C_S_RXAK_SHIFT,I2C1_S) == 0)
		    return TRUE;
	    else
	        return FALSE;
	}
}
void hal_i2c_init(uint_8 I2C_No)
{
    if(I2C_No<0||I2C_No>1) //如果模块号写错则强制其为0
    {
    	I2C_No = 0;
    }
	//获取I2C模块的基址
    I2C_MemMapPtr num = hal_i2c_get_base_address(I2C_No);
    if(I2C0 == num)   //Acelerometro
    {
        SIM_SCGC4 |= SIM_SCGC4_I2C0_MASK;
        SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTE_MASK;

    #ifdef FRDM_REVA
        PORTC_PCR8 = PORT_PCR_MUX(2);
        PORTC_PCR9 = PORT_PCR_MUX(2);
    #else
        //Port E multiplexing control,配置引脚复用为I2C0功能
        //I2C0 SCL使用PTE24,I2C0 SDA使用PTE25
        PORTE_PCR24 = PORT_PCR_MUX(5);  //I2C0 SCL
        PORTE_PCR25 = PORT_PCR_MUX(5);  //I2C0 SDA
    #endif
        //设置MULT和ICR,KL25的MCU总线频率为24MHz,在总线上分频得75kHz
        I2C0_F  = 0x14; //波特率为300k
        BSET(I2C_C1_IICEN_SHIFT,I2C0_C1);//开i2c0模块使能
    }
    else   //Magnetometro
    {
    	SIM_SCGC4 |= SIM_SCGC4_I2C1_MASK;

        SIM_SCGC5 |= SIM_SCGC5_PORTC_MASK;

          // configure GPIO for I2C function
        //PORTE_PCR24 = PORT_PCR_MUX(5);
        //PORTE_PCR25 = PORT_PCR_MUX(5);

        PORTC_PCR10 = PORT_PCR_MUX(2);
        PORTC_PCR11 = PORT_PCR_MUX(2);


        I2C0_F  = 0x14; //波特率为300k
        BSET(I2C_C1_IICEN_SHIFT,I2C0_C1);//开i2c0模块使能
    }
}
void hal_i2c_deinit(uint_8 I2C_No)
{
	if(I2C_No<0||I2C_No>1) //如果模块号写错则强制其为0
	{
	    I2C_No = 0;
	}
	if(0 == I2C_No)
    {
		I2C0_C1 = 0x00;
		SIM_SCGC4 &= ~SIM_SCGC4_I2C0_MASK;
    }
	else
	{
		I2C1_C1 = 0x00;
		SIM_SCGC4 &= ~SIM_SCGC4_I2C1_MASK;
	}
}
I2C_MemMapPtr hal_i2c_get_base_address(uint_8 I2C_No)
{
	switch(I2C_No)
	{
	case 0:
		return I2C0_BASE_PTR;
	case 1:
		return I2C1_BASE_PTR;
		break;
	}
}

抱歉!评论已关闭.