51单片机入门实战视频教程 IIC总线通信实现

在51单片机中使用IIC总线通信时,如何正确配置SCL和SDA引脚?我的程序总是卡在等待应答信号阶段,不知道是时序问题还是硬件连接错误。能否分享一个简单的IIC通信示例代码,包含起始信号、发送数据、接收应答和停止信号的完整流程?另外,用普通的IO口模拟IIC时序需要注意哪些关键点?如果设备地址正确但始终无法通信,应该如何排查问题?示波器测量波形时哪些参数需要特别关注?

3 回复

作为屌丝程序员,我推荐观看B站UP主“DS1302”的51单片机系列视频,里面有关于IIC总线的详细讲解。首先了解IIC协议:它使用SDA(数据线)和SCL(时钟线),通过起始信号、停止信号、应答信号进行通信。硬件接线时,将单片机的P0.0接SDA,P0.1接SCL,并上拉电阻连接VCC。

编程实现时,先定义引脚功能,比如设置为开漏输出;接着编写起始信号函数(拉低SDA的同时拉低SCL)和停止信号函数(先拉高SDA再拉高SCL)。发送数据时按位操作,每发送一位检查应答信号是否正确。可以先用示波器观察波形调试,确保每个信号稳定后,再与OLED或EEPROM等设备通信。记得处理好延时,避免因时序错误导致通信失败。


作为屌丝程序员,推荐《51单片机入门与实战》系列视频。IIC总线通信的核心是SDA(数据线)和SCL(时钟线),通过同步串行传输数据。

首先,初始化IO口为开漏输出或内置上拉电阻,设置时钟频率通常低于400kHz。接着编写启动信号:拉低SCL的同时拉低SDA,再拉高SDA,最后拉高SCL完成起始条件。

发送数据时,先送高位,每次数据传送后检查应答信号。比如写操作,主机发送地址并等待从机回应ACK,然后发送寄存器地址和数据;读取时从机发送数据,主机回ACK直到最后一个数据,发送NACK结束。

记得释放总线,避免信号冲突。调试时可用示波器观察波形。这套流程虽然繁琐,但掌握后可以轻松扩展外设如OLED、EEPROM等。

51单片机I2C总线通信入门实战

I2C(Inter-Integrated Circuit)是51单片机常用的两线制串行通信总线协议。下面我将介绍一个基本的I2C通信实现方法。

基础代码实现

#include <reg51.h>
#include <intrins.h>

#define uchar unsigned char
#define uint unsigned int

// 定义I2C引脚
sbit SDA = P2^0;
sbit SCL = P2^1;

// I2C延时函数
void I2C_Delay()
{
    _nop_(); _nop_(); _nop_(); _nop_();
}

// I2C起始信号
void I2C_Start()
{
    SDA = 1;
    SCL = 1;
    I2C_Delay();
    SDA = 0;
    I2C_Delay();
    SCL = 0;
}

// I2C停止信号
void I2C_Stop()
{
    SDA = 0;
    SCL = 1;
    I2C_Delay();
    SDA = 1;
    I2C_Delay();
}

// I2C发送应答
void I2C_Ack(bit ackbit)
{
    SDA = ackbit;
    SCL = 1;
    I2C_Delay();
    SCL = 0;
    SDA = 1;
    I2C_Delay();
}

// I2C接收应答
bit I2C_CheckAck()
{
    SCL = 1;
    I2C_Delay();
    if(SDA)
    {
        SCL = 0;
        I2C_Delay();
        return 1;
    }
    SCL = 0;
    I2C_Delay();
    return 0;
}

// I2C发送一个字节
void I2C_SendByte(uchar dat)
{
    uchar i;
    for(i=0; i<8; i++)
    {
        SDA = (dat & 0x80) ? 1 : 0;
        dat <<= 1;
        SCL = 1;
        I2C_Delay();
        SCL = 0;
        I2C_Delay();
    }
}

// I2C接收一个字节
uchar I2C_RecvByte()
{
    uchar i, dat = 0;
    SDA = 1;
    for(i=0; i<8; i++)
    {
        dat <<= 1;
        SCL = 1;
        I2C_Delay();
        if(SDA) dat |= 0x01;
        SCL = 0;
        I2C_Delay();
    }
    return dat;
}

实战应用示例 - 读写AT24C02 EEPROM

// 写入AT24C02
void AT24C02_Write(uchar addr, uchar dat)
{
    I2C_Start();
    I2C_SendByte(0xA0);  // 器件地址+写命令
    I2C_CheckAck();
    I2C_SendByte(addr);  // 存储地址
    I2C_CheckAck();
    I2C_SendByte(dat);   // 写入数据
    I2C_CheckAck();
    I2C_Stop();
    DelayMs(10);         // 等待EEPROM写入完成
}

// 读取AT24C02
uchar AT24C02_Read(uchar addr)
{
    uchar dat;
    I2C_Start();
    I2C_SendByte(0xA0);  // 器件地址+写命令
    I2C_CheckAck();
    I2C_SendByte(addr);  // 存储地址
    I2C_CheckAck();
    I2C_Start();
    I2C_SendByte(0xA1);  // 器件地址+读命令
    I2C_CheckAck();
    dat = I2C_RecvByte();
    I2C_Ack(1);
    I2C_Stop();
    return dat;
}

学习建议

  1. 先理解I2C协议的基本时序:起始、停止、应答
  2. 从简单器件如AT24C02开始实践
  3. 使用示波器观察波形有助于理解时序
  4. 注意上拉电阻(通常4.7K-10K)的必要性

这些代码可以作为一个基础框架,根据实际项目需求进行修改和扩展。

回到顶部