i2c总线与51单片机(附时序配置代码)

将I2C总线与51单片机结合使用,通常需要通过软件模拟I2C协议(因传统51单片机无硬件I2C模块),实现与外部I2C设备(如EEPROM、传感器等)的通信。以下是具体实现方法和示例:

### **一、硬件连接**

1. **电路设计**:

   - **SDA**和**SCL**引脚:连接到51单片机的任意两个IO口(如P2.0和P2.1)。

   - **上拉电阻**:在SDA和SCL线上各接一个4.7kΩ电阻到VCC,确保总线空闲时为高电平。

   - **I2C设备**:例如AT24C02(EEPROM)、MPU6050(加速度计)等。

 

   ```plaintext

   51单片机 I2C设备

   P2.0 (SDA) ------> SDA

   P2.1 (SCL) ------> SCL

   VCC ------> VCC

   GND ------> GND

   ### **二、软件模拟I2C协议**

#### **1. GPIO配置**

将SDA和SCL引脚配置为**准双向模式**(51单片机默认模式),支持输出和输入功能:

```c

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

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

```

#### **2. 基本时序函数**

需实现以下关键时序函数:

**起始条件**:SCL高电平时,SDA从高→低。

**停止条件**:SCL高电平时,SDA从低→高。

**发送ACK/NACK**:接收方在第9个时钟周期拉低SDA(ACK)或保持高电平(NACK)。

**读写字节**:逐位发送或接收8位数据。

**示例代码**:

```c

// 起始条件

void I2C_Start() {

    SDA = 1;

    SCL = 1;

    Delay_us(5); // 延时保证稳定性

    SDA = 0;

    Delay_us(5);

    SCL = 0;

}

 

// 停止条件

void I2C_Stop() {

    SDA = 0;

    SCL = 1;

    Delay_us(5);

    SDA = 1;

    Delay_us(5);

}

 

// 发送ACK

void I2C_Ack() {

    SDA = 0; // ACK:拉低SDA

    SCL = 1;

    Delay_us(2);

    SCL = 0;

    SDA = 1; // 释放SDA

}

 

// 发送NACK

void I2C_Nack() {

    SDA = 1; // NACK:保持SDA高电平

    SCL = 1;

    Delay_us(2);

    SCL = 0;

}

 

// 发送一个字节(MSB优先)

void I2C_SendByte(unsigned char dat) {

    unsigned char i;

    for (i = 0; i < 8; i++) {

        SDA = (dat & 0x80) ? 1 : 0; // 发送最高位

        dat <<= 1;

        SCL = 1;

        Delay_us(2);

        SCL = 0;

        Delay_us(2);

    }

    // 等待从机ACK

    SDA = 1; // 释放SDA,准备接收ACK

    SCL = 1;

    Delay_us(2);

    if (SDA == 0) { /* ACK成功 */ }

    SCL = 0;

}

 

// 接收一个字节

unsigned char I2C_ReadByte() {

    unsigned char i, dat = 0;

    SDA = 1; // 释放SDA,切换为输入模式

    for (i = 0; i < 8; i++) {

        SCL = 1;

        Delay_us(2);

        dat <<= 1;

        dat |= SDA; // 读取当前位

        SCL = 0;

        Delay_us(2);

    }

    return dat;

}

### **三、实际应用示例:读写AT24C02 EEPROM**

#### **1. 写入数据到EEPROM**

```c

void EEPROM_Write(unsigned char addr, unsigned char dat) {

    I2C_Start();

    I2C_SendByte(0xA0); // 发送器件地址(写模式)

    I2C_SendByte(addr); // 发送存储地址

    I2C_SendByte(dat); // 发送数据

    I2C_Stop();

    Delay_ms(10); // 等待EEPROM写入完成

}

#### **2. 从EEPROM读取数据**

```c

unsigned char EEPROM_Read(unsigned char addr) {

    unsigned char dat;

    I2C_Start();

    I2C_SendByte(0xA0); // 发送器件地址(写模式)

    I2C_SendByte(addr); // 发送存储地址

    I2C_Start(); // 重启总线

    I2C_SendByte(0xA1); // 发送器件地址(读模式)

    dat = I2C_ReadByte(); // 读取数据

    I2C_Nack(); // 发送NACK结束读取

    I2C_Stop();

    return dat;

}

### **四、关键注意事项**

1. **时序精度**:  

   51单片机时钟频率较低(如12MHz),需调整延时函数以满足I2C速率(如100kHz标准模式)。

   延时函数可通过循环空操作或定时器实现。

2. **总线冲突处理**:  

多主模式下需实现仲裁机制,但51单片机资源有限,通常设计为单主模式。

3. **抗干扰设计**:  

   总线长度尽量短(<1米),避免信号反射。

   若环境干扰大,可降低速率或使用屏蔽线。

4. **上拉电阻选择**:  

    根据总线上设备数量调整阻值,设备越多,阻值应越小(如3.3kΩ)。

### **五、调试技巧**

1. **逻辑分析仪**:观察SDA和SCL波形,检查起始/停止条件、ACK/NACK是否正常。

2. **串口打印**:在读写过程中通过串口输出调试信息(如发送的地址、数据)。

3. **简化代码**:先实现单字节读写,再扩展为多字节操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值