z9051638 发表于 2022-11-26 15:33:43

I2C求助贴,改的官网范例,读出的都是ff

网上买的8a8k64s4a12,和ds3231的模块,上面还有一个24c32,P14接的SDA,P15接SCL,VCC和GND都是在U8W连过来的,我想读写24c32成功了再学3231,可是读出来都是0xff,我知道看别人的原代码很乱,但有人能指点一下吗?



#include <STC8.h>
#include <stdio.h>
#include <intrins.h>
unsigned char flag,Dat24c32H,Dat24c32L;
bit busy;
sbit SDA=P1^4;
sbit SCL=P1^5;
void UartInit(void)                //9600bps@24.000MHz
{
       
        SCON = 0x50;                                //8位数据,可变波特率
        AUXR |= 0x01;                                //串口1选择定时器2为波特率发生器
        AUXR &= 0xFB;                                //定时器时钟12T模式
        T2L = 0xE8;                                        //设置定时初始值
        T2H = 0xFF;                                        //设置定时初始值
        AUXR |= 0x10;                                //定时器2开始计时

        EA=1;                                                                //打开总中断
}

void delayxms(unsigned int xms)                //延时
        {
                unsigned int i,j;
                for(i=xms;i>0;i--)
                        for(j=1350;j>0;j--);
        }

void I2C_Isr() interrupt 24
{
    _push_(P_SW2);
    P_SW2|=0x80;
    if (I2CMSST&0x40)
    {
      I2CMSST&=~0x40;                     //清中断标志
      busy = 0;
    }
    _pop_(P_SW2);
}

void Start()
{
    busy=1;
    I2CMSCR=0x81;                           //发送START命令
    while(busy);
}

void SendData(char dat)
{
    I2CTXD=dat;                               //写数据到数据缓冲区
    busy=1;
    I2CMSCR=0x82;                           //发送SEND命令
    while(busy);
}

void RecvACK()
{
    busy=1;
    I2CMSCR=0x83;                           //发送读ACK命令
    while(busy);
}

char RecvData()
{
    busy=1;
    I2CMSCR=0x84;                           //发送RECV命令
    while(busy);
    return I2CRXD;
}

void SendACK()
{
    I2CMSST=0x00;                           //设置ACK信号
    busy = 1;
    I2CMSCR=0x85;                           //发送ACK命令
    while(busy);
}

void SendNAK()
{
    I2CMSST=0x01;                           //设置NAK信号
    busy=1;
    I2CMSCR=0x85;                           //发送ACK命令
    while(busy);
}

void Stop()
{
    busy=1;
    I2CMSCR=0x86;                           //发送STOP命令
    while(busy);
}

void Delay()
{
    int i;

    for (i=0; i<3000; i++)
    {
      _nop_();_nop_();
      _nop_();_nop_();
      _nop_();_nop_();
      _nop_();_nop_();
    }
}

void main()
{
    P_SW2 = 0x80;
                UartInit();
    I2CCFG = 0xe0;                              //使能I2C主机模式
    I2CMSST = 0x00;

    Start();                                    //发送起始命令
    SendData(0xa0);                           //发送设备地址+写命令
    RecvACK();
    SendData(0x00);                           //发送存储地址高字节
    RecvACK();
    SendData(0x01);                           //发送存储地址低字节
    RecvACK();
    SendData(0x12);                           //写测试数据1
    RecvACK();
    SendData(0x78);                           //写测试数据2
    RecvACK();
    Stop();                                     //发送停止命令

    Delay();                                    //等待设备写数据

    Start();                                    //发送起始命令
    SendData(0xa0);                           //发送设备地址+写命令
    RecvACK();
    SendData(0x00);                           //发送存储地址高字节
    RecvACK();
    SendData(0x01);                           //发送存储地址低字节
    RecvACK();
    Start();                                    //发送起始命令
    SendData(0xa1);                           //发送设备地址+读命令
    RecvACK();
    Dat24c32H=RecvData();                            //读取数据1
    SendACK();
    Dat24c32L=RecvData();                            //读取数据2
    SendNAK();
    Stop();                                     //发送停止命令

    P_SW2 = 0x00;

    while (1)
                                {
                           TI=1;
                                printf("READ Dat24C32H=%bx   Dat24C32L=%bx \n",Dat24c32H,Dat24c32L);
               
                                while(!TI);
                                delayxms(2000);
                       }
}








zhp 发表于 2022-11-26 20:15:18

你需要确认你测试板上AT24C32的A0、A1、A2这3个脚的连接方法
是接GND还是接VCC,然后对程序中的设备地址进行相应的修改

(范例程序默认这3个脚接地)

z9051638 发表于 2022-11-26 22:00:55

zhp 发表于 2022-11-26 20:15
你需要确认你测试板上AT24C32的A0、A1、A2这3个脚的连接方法
是接GND还是接VCC,然后对程序中的设备地址进 ...

A0A1A2都是悬空的,我在程序里加上读3231的秒位和分位的语句,3231数据读出来了,难道是我24C32写的不对吗?

zhp 发表于 2022-11-26 22:22:59

z9051638 发表于 2022-11-26 22:00
A0A1A2都是悬空的,我在程序里加上读3231的秒位和分位的语句,3231数据读出来了,难道是我24C32写的不对 ...

DS3231能正确读写,说明I2C控制程序没问题
读写AT24C32失败,很大可能是设备地址不匹配
A0、A1、A2悬空,那要看芯片内部是否在这3脚有上拉或者下拉
你可以用万用表测量一下这3个教悬空时的电平
如果是高电平,则需要修改代码中的设备地址

不过一般设计电路时,这3个脚一定是外部接GND或者VCC,
进行地址选择,悬空设计倒是很少见

z9051638 发表于 2022-11-27 12:06:39

是的,如你所说,悬空不行,人家设计的本意可能是让自己焊硬件地址,先谢谢指点,我的程序中我还有点不明白的地方,上图,望帮解答一下

z9051638 发表于 2022-11-27 12:12:12

zhp 发表于 2022-11-26 22:22
DS3231能正确读写,说明I2C控制程序没问题
读写AT24C32失败,很大可能是设备地址不匹配
A0、A1、A2悬空, ...

是的,如你所说,悬空不行,人家设计的本意可能是让自己焊硬件地址,先谢谢指点,我的程序中我还有点不明白的地方,上图,望帮解答一下

        Start();
                SendData(0xd0);
                RecvACK();
                SendData(0x00);
                RecvACK();
                Start();
                SendData(0xd1);
                RecvACK();
                Dat3231sec00=RecvData();
                //SendACK();                              这两个SendACK,加上就执行不到下面的printf语句,去掉就正常了,我看范例每个接收后面都加一个啊,这里为什么不行?24c32的这也加了,却没卡住,加在这好像就卡在这里了
               
               
                Start();
                SendData(0xd0);
                RecvACK();
                SendData(0x01);
                RecvACK();
                Start();
                SendData(0xd1);
                RecvACK();
                Dat3231min01=RecvData();
                //SendACK();                              这两个SendACK,加上就执行不到下面的printf语句,去掉就正常了,我看范例每个接收后面都加一个啊,这里为什么不行?
               
                Start();
                SendData(0xd0);
                RecvACK();
                SendData(0x02);
                RecvACK();
                Start();
                SendData(0xd1);
                RecvACK();
                Dat3231hour02=RecvData();
                SendNAK();
               
                Stop();
               
               
                // P_SW2 = 0x00;

   
                           TI=1;
                                printf("READ Dat24C32H=%bxDat24C32L=%bxTIME   %bx:%bx:%bx\n",Dat24c32H,Dat24c32L,Dat3231hour02,Dat3231min01,Dat3231sec00);
               
                                while(!TI);
                                delayxms(1000);
                       }

zhp 发表于 2022-11-27 12:48:28

z9051638 发表于 2022-11-27 12:12
是的,如你所说,悬空不行,人家设计的本意可能是让自己焊硬件地址,先谢谢指点,我的程序中我还有点不明 ...

I2C协议中,正常的数据读写都一定是9个数据位
读取数据后,必须回一个ACK或者NAK,所以你的这段代码应该是没问题的
我不太了解DS3231,你可以尝试读取最后一笔数据后回NAK看看(正确的I2C协议就是这样的)

276564663@qq 发表于 2025-3-11 19:25:05

我用的是STC8H8K64U自带的IIC功能,也有你的这种情况未解决,我用逻辑分析仪测试了一下。DS时钟和液晶屏都正常工作,就是这个24C32写入读取不出来。。。。我的2张图中就是写入和读取的图形,看着没啥问题,就是写入读取都是FF,我的A0A1A2都接到了上拉电阻。地址是0XAE

276564663@qq 发表于 2025-3-11 20:39:53

我的刚才处理好了,我用的是8H8K64U自带的IIC功能和官方的库修改的,我的模块和你的一样,代码如下:
写入:
void Write_IIC_24c32_command(u16 u16_addr,u8 u8_data)
{
        Start();
        SendData(0XAE|WRITE_CMD);
        RecvACK();
        SendData(((u16_addr>>8)&0xff));                        //write command
        RecvACK();
        SendData((u16_addr&0xff));
        RecvACK();
        SendData(u8_data);
        RecvACK();
        SendNAK();
        Stop();
}
读取:
u8 Read_IIC_24c32_data(u16 u16_addr)
{
        u8 reg_data=0;
        Start();
        SendData(0XAE);
        RecvACK();
        SendData(u16_addr>>8);                        //write command
        RecvACK();
        SendData(u16_addr);
        RecvACK();
        Start();
        SendData(0XAF);
        RecvACK();
        reg_data = RecvData();
        SendNAK();
        Stop();
        return reg_data;
}
attach://87614.jpg

yao眼的光 发表于 2025-3-12 08:38:30

https://www.stcaimcu.com/forum.php?mod=viewthread&tid=12065&extra=&page=11已在这个帖子帮问,到时关注下此贴102楼
页: [1] 2
查看完整版本: I2C求助贴,改的官网范例,读出的都是ff