打印
[资料分享与下载]

FSL-KL46_I2C模块编程

[复制链接]
648|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
quray1985|  楼主 | 2015-7-7 14:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
此处不具体介绍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;        }}

相关帖子

沙发
FSL_TICS_ZJJ| | 2015-7-7 16:05 | 只看该作者
楼主你好!
分享帖就不要以未结帖形式发了,否则和问题贴就混淆了。

使用特权

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

本版积分规则

156

主题

1488

帖子

5

粉丝