<MCU进阶>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();
    }
}

(二)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;
}

(三)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);
}

(四)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);
}

(五)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);
}

(六)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;
}

(七)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(); // 释放总线
}

(八)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;
}
  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坚持学习的小王同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值