找回密码
 立即注册
查看: 118|回复: 2

求教

[复制链接]

3

主题

2

回帖

33

积分

新手上路

积分
33
发表于 2026-8-16 22:59:41 | 显示全部楼层 |阅读模式
#include <AI8051U.H>
#include "LCD1602.h"
#include "Key.h"
#include "Delay.h"
#include "I2C.h"
#include "at24c02.h"
void main()
{
        unsigned char Data;
        P_SW2 |= 0x80;
        P0M0 |=0xff;
        P0M1 &=~0xff;
        P2M1 &= ~0x18;  
P2M0 &= ~0x18;;
P2M0 |=0xc0;
        P2M1 &=~0xc0;
        P2PU |=0x18;
        P3M0 |=0xff;
        P3M1 &=~0xff;

        LCD_Init();
AT24C02_WriteByte(1,5);
        Delay1ms(20);
Data=AT24C02_ReadByte(1);
        LCD_ShowNum(1,1,Data,4);
  while(1)
    {

     }
}


#include <AI8051U.H>

sbit I2C_SCL = P2^4;
sbit I2C_SDA = P2^3;
void Delay5us(void)        //@11.0592MHz
{
        unsigned long edata i;

        _nop_();
        _nop_();
        i = 12UL;
        while (i) i--;
}

void I2C_start()
{
        I2C_SDA=1;
        Delay5us();
        I2C_SCL=1;
        Delay5us();
        I2C_SDA=0;
        Delay5us();
        I2C_SCL=0;
}

void I2C_stop()
{
        I2C_SDA=0;
        Delay5us();
        I2C_SCL=1;
        Delay5us();
        I2C_SDA=1;
        Delay5us();

       
}

void I2C_sendbyte(unsigned char Byte)
{
        unsigned char i;
        for(i=0;i<8;i++)
        {
                I2C_SDA =Byte&(0x80>>i);
                Delay5us();
                I2C_SCL=1;
                Delay5us();
                I2C_SCL=0;
        }

}

unsigned char I2C_receivebyte(void)
{
        unsigned char i,Byte=0x00;
        I2C_SDA=1;
        for(i=0;i<8;i++)
        {
                I2C_SCL=1;
                Delay5us();
                if(I2C_SDA){Byte |=(0x80>>i);}
                I2C_SCL=0;
        }
        return Byte;
}

void I2C_SendAck(unsigned char Ackbit)
{
        I2C_SDA=Ackbit;
        I2C_SCL=1;
        Delay5us();
        I2C_SCL=0;
}

unsigned char I2C_Receivebit(void)
{
        unsigned char Ackbit;
        I2C_SDA=1;
        Delay5us();
        I2C_SCL=1;
         Ackbit=I2C_SDA;
        I2C_SCL=0;
        return Ackbit;
}


#include <AI8051U.H>
#include "I2C.h"

#define AT24C02_ADDRESS 0xa0

void AT24C02_WriteByte(unsigned char WordAddress,unsigned char Data)
{
        I2C_start();
        I2C_sendbyte(AT24C02_ADDRESS);
        I2C_Receivebit();
        I2C_sendbyte(WordAddress);
        I2C_Receivebit();
        I2C_sendbyte(Data);
        I2C_Receivebit();
        I2C_stop();
       

}

unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
        unsigned char Data;
        I2C_start();
        I2C_sendbyte(AT24C02_ADDRESS);
        I2C_Receivebit();
        I2C_sendbyte(WordAddress);
        I2C_Receivebit();
        I2C_start();
        I2C_sendbyte(AT24C02_ADDRESS | 0x01);
        I2C_Receivebit();
          Data=I2C_receivebyte();
        I2C_SendAck(1);
        I2C_stop();
        return Data;
}


对着江协科技 AT24C02板块的代码写的 ,就主函数由于使用的板子为AI 8051,进行了端口配置,为什么LCD1602显示为0127

回复

使用道具 举报 送花

53

主题

1467

回帖

3684

积分

超级版主

积分
3684
发表于 2026-8-17 10:21:55 | 显示全部楼层


截图202608171021104207.jpg

https://www.stcaimcu.com/thread-25008-1-1.html
​可以【贴图】问,也可以 【语音】问,最好是【文字】问;
还可以 用 www.STCAIMCU.com 论坛的帖子链接网址 问


STC官网:https://www.stcai.com/
QQ:2593903262
微信号:18106296598
回复

使用道具 举报 送花

53

主题

1467

回帖

3684

积分

超级版主

积分
3684
发表于 2026-8-17 10:23:01 | 显示全部楼层

我已经掌握了足够的信息。让我验证一下关键点:你的延时函数按11.0592MHz编写,但AI8051U实际可能运行在24MHz甚至更高。延时严重不足导致I2C时序错误。

让我给你一个完整的分析和修正方案。


问题诊断:为什么 LCD 显示 "0127"

你写的 AT24C02_WriteByte(1, 5) 期望写入地址1的值为5,但读回来 Data = 0x7F = 127,说明 I2C 读写时序错误,AT24C02 无法正确识别数据

根本原因:延时函数与系统主时钟不匹配

看你的延时函数:

void Delay5us(void)        //@11.0592MHz
{
    unsigned long edata i;
    _nop_();
    _nop_();
    i = 12UL;
    while (i) i--;
}

这个延时是为 11.0592MHz 编写的。但 AI8051U 上电默认工作在内部高速IRC,出厂校准频率通常为 24MHz(或更高)。在 24MHz 下,这个 Delay5us 实际只有约 2.3us,比标称的5us少了一半以上

结果就是 I2C 的 SCL 高/低电平持续时间太短,AT24C02 无法稳定采样 SDA 数据,导致:

  • 写入时数据未正确锁存
  • 读取时 SDA 悬浮/noise 被读成高电平,得到 0x7F

这正是你看到 127 的原因。

次要因素

  1. I2C 引脚建议用「开漏」模式(你现在是准双向口,虽理论上也能用,但开漏+I2C规范更匹配)
  2. 写操作后等待时间不够:AT24C02 内部写周期约5ms,你的 Delay1ms(20) 若同样基于11.0592MHz,实际时间不足,可能读的是未写完的值。但读0x7F更偏向时序错误。

解决方案

我给你一个修正后的完整方案,主要做三件事:

  1. 在 main 开头明确配置系统主时钟(设为24MHz,或者把延时函数改成适配实际时钟)
  2. 把延时函数改成能精确保证I2C时序的版本
  3. I2C引脚改为开漏模式 + 内部/外部上拉

方案A:建议你直接使用 AI8051U 官方实验箱的软件模拟 I2C 例程(SDA=P3.3, SCL=P3.2)

官方例程(上面论坛 TID 24590)用的是 SDA=P3^3, SCL=P3^2。如果你板子上AT24C02接的是P2.3/P2.4,那你要用你自己的引脚,但要修好延时。

方案B:修正你的代码(推荐,思路清晰)

我基于你的代码,修正时钟和延时。关键是把 Delay5us 改成一个与系统时钟无关的、能保证至少几微秒的延时,或者直接改用 _nop_() 计数方式配合实际频率。

不过最稳妥、最推荐的还是把系统时钟明确设为 11.0592MHz,这样你的所有延时函数(Delay5us、Delay1ms 等)都和你原本写的一致。让我给你一个综合修正的 main.c:


修正后的参考代码

main.c(关键修改:时钟设置 + 开漏配置 + 写后等待):

#include 
#include "LCD1602.h"
#include "Key.h"
#include "Delay.h"
#include "I2C.h"
#include "at24c02.h"

void main()
{
    unsigned char Data;

    // ===== 1. 允许访问扩展寄存器 XFR =====
    P_SW2 |= 0x80;   // 8位模式访问XFR

    // ===== 2. 明确设置系统主时钟 =====
    // AI8051U 出厂校准频率可能是24MHz。
    // 如果你希望所有延时函数都按11.0592MHz工作,
    // 就显式把系统时钟切到 11.0592MHz 频段。
    // 但更简单的做法:这里不改时钟,而是把延时函数按实际时钟重写。
    // 这里假设你选择保持当前默认时钟(比如24MHz),延时函数按实际频率精度写。
    // 若你的Delay.h按11.0592MHz写,则强烈建议把主频设成11.0592MHz,见下面注释掉的代码。

    /*
    // --- 若要把系统时钟设为 11.0592MHz(可选)---
    CLKDIV = 0x04;
    IRTRIM = CHIPID11;      // 22.1184MHz 校准值
    // 注意:11.0592MHz 不是出厂校准的10个频率之一,
    // 出厂校准的是 22.1184MHz。建议用内部IRC自动,不手动改。
    */

    // ===== 3. I/O 配置 =====
    P0M0 |= 0xff;   P0M1 &= ~0xff;    // P0 推挽(接LCD,驱动能力强)

    // P2.3(SDA)、P2.4(SCL) 配置为 开漏模式 + 内部上拉
    P2M0 |= 0x18;   // P2.3、P2.4 M0=1
    P2M1 |= 0x18;   // P2.3、P2.4 M1=1  → 开漏模式
    P2PU |= 0x18;   // P2.3、P2.4 使能内部上拉

    // P2.7、P2.6 推挽(你原来配置)
    P2M0 |= 0xc0;   P2M1 &= ~0xc0;

    // P3 推挽(LCD数据等)
    P3M0 |= 0xff;   P3M1 &= ~0xff;

    LCD_Init();

    AT24C02_WriteByte(1, 5);
    Delay1ms(20);    // 等待写完成(AT24C02内部写周期约5ms,20ms足够)

    Data = AT24C02_ReadByte(1);
    LCD_ShowNum(1, 1, Data, 4);

    while(1)
    {
    }
}

I2C.c(关键修改:延时重新基于实际需求,把SCL高/低保持时间拉长):

#include 

sbit I2C_SCL = P2^4;
sbit I2C_SDA = P2^3;

// 延时函数:不管系统主频多少,保证足够的I2C时序。
// 这里用_nop_()计数,为了在不同主频下都够用,
// 建议延时偏大一些(稳妥)。下面这个约等于 24MHz 下 ~10us。
void I2C_Delay(void)
{
    unsigned char i;
    for(i=0; i<20; i++)
    {
        _nop_();
    }
}

void I2C_start(void)
{
    I2C_SDA = 1;
    I2C_Delay();
    I2C_SCL = 1;
    I2C_Delay();
    I2C_SDA = 0;
    I2C_Delay();
    I2C_SCL = 0;
    I2C_Delay();
}

void I2C_stop(void)
{
    I2C_SDA = 0;
    I2C_Delay();
    I2C_SCL = 1;
    I2C_Delay();
    I2C_SDA = 1;
    I2C_Delay();
}

void I2C_sendbyte(unsigned char Byte)
{
    unsigned char i;
    for(i=0; i<8; i++)
    {
        I2C_SDA = (Byte & (0x80 >> i)) ? 1 : 0;
        I2C_Delay();
        I2C_SCL = 1;
        I2C_Delay();
        I2C_SCL = 0;
        I2C_Delay();
    }
}

unsigned char I2C_receivebyte(void)
{
    unsigned char i, Byte = 0x00;
    I2C_SDA = 1;               // 释放SDA,准备读
    for(i=0; i<8; i++)
    {
        I2C_SCL = 1;
        I2C_Delay();
        if(I2C_SDA) { Byte |= (0x80 >> i); }
        I2C_SCL = 0;
        I2C_Delay();
    }
    return Byte;
}

void I2C_SendAck(unsigned char Ackbit)
{
    I2C_SDA = Ackbit;
    I2C_Delay();
    I2C_SCL = 1;
    I2C_Delay();
    I2C_SCL = 0;
    I2C_Delay();
}

unsigned char I2C_Receivebit(void)
{
    unsigned char Ackbit;
    I2C_SDA = 1;
    I2C_Delay();
    I2C_SCL = 1;
    I2C_Delay();
    Ackbit = I2C_SDA;
    I2C_SCL = 0;
    I2C_Delay();
    return Ackbit;
}

at24c02.c(建议读操作时也加入ACK检查和适当时序):

#include 
#include "I2C.h"

#define AT24C02_ADDRESS 0xa0

void AT24C02_WriteByte(unsigned char WordAddress, unsigned char Data)
{
    I2C_start();
    I2C_sendbyte(AT24C02_ADDRESS);
    I2C_Receivebit();      // 应答
    I2C_sendbyte(WordAddress);
    I2C_Receivebit();
    I2C_sendbyte(Data);
    I2C_Receivebit();
    I2C_stop();
}

unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
    unsigned char Data;
    I2C_start();
    I2C_sendbyte(AT24C02_ADDRESS);
    I2C_Receivebit();      // 应答
    I2C_sendbyte(WordAddress);
    I2C_Receivebit();      // 应答
    I2C_start();           // 重复起始
    I2C_sendbyte(AT24C02_ADDRESS | 0x01);  // 读命令
    I2C_Receivebit();      // 应答
    Data = I2C_receivebyte();
    I2C_SendAck(1);        // 主机发送非应答(结束)
    I2C_stop();
    return Data;
}

重点提醒

  1. 最关键的修改是延时:你原来的 Delay5us 是按11.0592MHz算的,AI8051U实际主频高得多,导致时序不足。我把延时改成了一个对主频不那么敏感、且偏大更稳妥的版本。如果你的 Delay.h 里的 Delay1ms 也是按11.0592MHz写的,在24MHz下也会偏快——建议要么统一把主频设成11.0592MHz,要么把所有延时函数都改成根据实际主频计算。

  2. 如果改了延时还不行,请检查:

    • AT24C02 的 VCC、GND、A0/A1/A2 是否接对(地址应为 0xA0)
    • SCL/SDA 是否有 上拉电阻(虽然你使能了内部上拉,但如果板上有外部上拉更好)
    • 确认你的板子 AT24C02 是接在 P2.3/P2.4,还是 P3.2/P3.3(如果是后者,请把 sbit 引脚和I2C脚切换改对)
  3. 如果方便,建议直接参考AI8051U官方实验箱例程(论坛TID 24590),它用的是 SDA=P3.3, SCL=P3.2,并配好了正确的主频(24MHz)和延时。


需要我帮你把完整的 Delay.h/.c 也按24MHz改好吗?或者你告诉我你板子上 AT24C02 实际接在哪些引脚,我帮你把引脚配置也一起调对。


🔍 搜索 "#include ai805…"<

📌 相关论坛讨论

  1. 求教
  2. 12-1 AT24C02数据存储,江协科技讲普中51单片机开发板 STC89C52学习板 配套程序, A2标
  3. 不断电下载疑问

⏱️ 查找用时 31.9s | 总回答用时 54.7s

STC官网:https://www.stcai.com/
QQ:2593903262
微信号:18106296598
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-9-23 16:10 , Processed in 0.070047 second(s), 55 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表