当前位置:   article > 正文

<MCU进阶>GPIO模拟IIC

gpio模拟iic

一、初识IIC

IIC(Inter Interface Circuit,芯片间总线)是一种两线式串行总线,由PHILIPS公司开发,用于连接微控制器及其外围设备。多用于主机和从机在数据量不大传输距离短的场合下的主从通信。I2C总线由数据线SDA时钟线SCL构成通信线路,既可用于发送数据,也可接收数据,是一种半双工通信协议。总线上的主设备与从设备之间以字节(8位)为单位进行双向的数据传输。

(一)IIC的三种传输速率:

  • 标准速率:100K bit/s
  • 快速速率:400K bit/s
  • 高速速率:3.4M bit/s

(二)IIC的硬件特性:

​ IIC是一种一主多从的的硬件连接方式,具体连接可参照下图;
请添加图片描述

(三)IIC时序

起始信号:在SCL高电平的时候SDA线上有高到低的跳变

停止信号:在SCL高电平的时候SDA线上有低到高的跳变
在这里插入图片描述
应答信号:当从设备数据接收完成并且需要产生一个应答信号时,主设备需要主动产生一个时钟信号同时释放SDA,让从设备将SDA拉低则为一个应答信号、
在这里插入图片描述
数据传输:SDA线上的数据需要在SCL为高电平的时候保持不变,在SCL为低电平的时候发生数据翻转
在这里插入图片描述
IIC读写:IIC通讯的第一个字节用于确定主机选择的通讯的从机,最后一位代表的写入数据还是读取数据(0:写入;1:读取)
在这里插入图片描述
IIC数据写入:IIC数据写入流程(应答信号由从机产生)
在这里插入图片描述
IIC数据读取:IIC数据读取流程(灰色的数据由从设备产生)
在这里插入图片描述

二、MCU模拟IIC驱动代码

(一)通用部分

IIC延时:

void delay_us(unsigned char Time)
{
    unsigned char a;
    for (a = 0; a < Time; a++) {
        NOP();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

(二)GPIO初始化

当mcu模拟IIC通信时候需要将SDA以及SDL脚初始化为推挽输出(若无可初始化为上拉输出),以下以一个8位单片机初始化为例:

#define IIC_SCL_1()     {PB7 = 1;}
#define IIC_SCL_0()     {PB7 = 0;}

#define IIC_SDA_1()     {PC1 = 1;}
#define IIC_SDA_0()     {PC1 = 0;}

#define IIC_SDA_READ()  PC1

#define IIC_SDA_IN()    {TRISC1 = 1;}
#define IIC_SDA_OUT()   {TRISC1 = 0;}

void soc_iic_gpio_init(void)
{
    // SDA init 输出上拉
    TRISC1 = 0; // 设置PC1为输出
    WPDC1 = 0;
    WPUC1 = 1;

    // SCK init 输出上拉
    TRISB7 = 0; // 设置PB7为输出
    WPDB7 = 0;
    WPUB7 = 1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

(三)IIC起始信号

void soc_iic_start(void)
{
    // IIC 开始信号在SCL高电平的时候SDA下降沿
    IIC_SDA_OUT();
    IIC_SDA_1();
    IIC_SCL_1();
    delay_us(1);
    IIC_SDA_0();
    delay_us(1);
    IIC_SCL_0();
    delay_us(1);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

(四)IIC停止信号

void soc_iic_stop(void)
{
    // IIC 结束信号在SCL高电平的时候SDA上升沿
    IIC_SDA_OUT();
    IIC_SCL_0();
    IIC_SDA_0();
    delay_us(1);
    IIC_SCL_1();
    delay_us(1);
    IIC_SDA_1();
    delay_us(1);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

(五)IIC应答/无需应答

void soc_iic_ack(void)
{
    IIC_SDA_OUT();
    IIC_SDA_0(); /* CPU驱动SDA = 0 */
    delay_us(1);
    IIC_SCL_1(); /* CPU产生1个时钟 */
    delay_us(1);
    IIC_SCL_0();
    delay_us(1);
    IIC_SDA_1(); /* CPU释放SDA总线 */
}

void soc_iic_no_ack(void)
{
    IIC_SDA_1(); /* CPU驱动SDA = 1 */
    delay_us(1);
    IIC_SCL_1(); /* CPU产生1个时钟 */
    delay_us(1);
    IIC_SCL_0();
    delay_us(1);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

(六)IIC等待应答

unsigned char soc_iic_wait_ack(void)
{
    unsigned char re;

    IIC_SDA_1(); /* CPU释放SDA总线 */
    IIC_SDA_IN();
    delay_us(1);
    IIC_SCL_1(); /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
    delay_us(1);
    if (IIC_SDA_READ()) { /* CPU读取SDA口线状态 */
        re = 1;
    } else {
        re = 0;
    }

    IIC_SCL_0();
    delay_us(1);
    return re;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

(七)IIC发生一个字节数据

void soc_iic_send_byte(unsigned char _ucByte)
{
    unsigned char i;
    /* 先发送字节的高位bit7 */
    IIC_SDA_OUT();
    for (i = 0; i < 8; i++) {
        if (_ucByte & 0x80) {
            IIC_SDA_1();
        } else {
            IIC_SDA_0();
        }
        delay_us(1);
        IIC_SCL_1();
        delay_us(1);
        IIC_SCL_0();
        _ucByte <<= 1; /* 左移一个bit */
        delay_us(1);
    }
    IIC_SDA_1(); // 释放总线
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

(八)IIC读取一个字节数据

unsigned char soc_iic_read_byte(void)
{
    unsigned char i;
    unsigned char value;

    /* 读到第1个bit为数据的bit7 */
    value = 0;
    IIC_SDA_IN();
    for (i = 0; i < 8; i++) {
        value <<= 1;
        IIC_SCL_1();
        delay_us(1);
        if (IIC_SDA_READ()) {
            value++;
        }
        IIC_SCL_0();
        delay_us(1);
    }
    return value;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/713150
推荐阅读
相关标签
  

闽ICP备14008679号