pdshyh 发表于 2020-11-25 10:29:42

52单片机的I2C读写24C08程序波形问题

52单片机I2c读写at24c08芯片,程序下载没反应,排查用示波器测量发现单片机连接at24c08芯片SDA引脚有方波,SCL引脚波形没有方波,再查SCL引脚和P2^1连接没问题,通过简单led点亮熄灭命令测量单片机2^1指令1或0测量都是5v电压,其他口没问题就换了SCL引脚连接P2^2,更换I/O口示波器测量SCL引脚还是没有方波,:L 对调 SDA=P2^0和 SCL=P2^2        为SDA=P2^2和 SCL=P2^0,都是SDA口有方波:L 问题在哪,直接用坛友提供测试没问题的程序还是不行。

isoimg2130 发表于 2020-11-25 10:51:21

你倒是把波形和程序发上来啊。

pdshyh 发表于 2020-11-25 11:23:41

isoimg2130 发表于 2020-11-25 10:51
你倒是把波形和程序发上来啊。

谢谢,程序:
I2C.H
#ifndef __I2C_H__   //文件名全部都大写,首尾各添加2个下划线”__”
#define __I2C_H__
#include<reg52.h>
#define uchar unsigned char
sbit SDA=P2^0;//24C02芯片SDA引脚位定义
sbit SCL=P2^2;       //24C02芯片SCL引脚位定义
void delay();            //分别对各函数声明
void start();
void stop();
void ack();
void nack();
void write_byte(uchar date);
uchar read_byte();
void write_at24c02(uchar address ,uchar date);
uchar read_at24c02(uchar address);
#endif


I2C.c
#include "i2c.h"//包含i2c.h头文件,注意自建的头文件是用双引号
void delay()   //微秒级延时函数
{
        ;;//用两个空语句实现短时间延时,当晶振为11.0592MHz时,约4~5微秒
}
void start() //起始信号
{
        SDA=1;
        SCL=1;
        delay();
        SDA=0;
        delay();
}
void stop()        //终止信号
{
        SDA=0;
        SCL=1;
        delay();
        SDA=1;
        delay();
}
void ack()        //应答信号
{
        uchar i;
        SCL=1;
        delay();
        while((SDA==1)&&i<250)i++;
        SCL=0;
        delay();
}
void nack()          //无应答信号
{
        SCL=1;
        delay();
        SDA=1;
        SCL=0;
        delay();
}
voidwrite_byte(uchar date) //写入一个字节到I2C总线
{
        uchar i,temp;
        temp=date;
        for(i=0;i<8;i++)
        {
                temp=temp<<1;
                SCL=0;
                delay();
                SDA=CY;       
                delay();
                SCL=1;
        }
        SCL=0;
        delay();       
        SDA=1;
        delay();
}
uchar read_byte() //从I2C读一个字节
{
        uchar i,j,k;
        SCL=0;
        delay();
        for(i=0;i<8;i++)
        {
                SCL=1;
                delay();
                j=SDA;
                k=(k<<1)|j;
                SCL=0;
                delay();
        }
        return k;       
}
void wrte_at2402(uchar address,uchar date)//at24c02按字节写入函数
{
        start();
        write_byte(0xa0);
        ack();
        write_byte(address);
        ack();
        write_byte(date);
        ack();
        stop();       
}
uchar read_dat24c02(uchar address)        //对at24c02随机读函数
{
uchar date;
        start();
        write_byte(0xa0);
        ack();
        write_byte(address);
        ack();
        start();
        write_byte(0xa1);
        ack();
        date=read_byte();
        nack();
        stop();
        return date;

}

main.c
#include<reg52.h>
#include"I2C.h"
#include<reg52.h>

void delay_10ms()
{
        uchar a,b;
        for(a=50;a>0;a--)
                for(b=200;b>0;b--) ;
}

void main()
{
   start();
   write_at24c02(10,0xaa);
   delay_10ms();
   P1=read_at24c02(10);       
   while(1);
}
示波器测量

isoimg2130 发表于 2020-11-25 11:37:13

探头用直流档啊,你是测的是电平,触发位置调一下啊。
另外把
把void delay()   //微秒级延时函数
{
      ;;//用两个空语句实现短时间延时,当晶振为11.0592MHz时,约4~5微秒
}
改成这样,你这个可能被编译器直接优化了。压根就没延时。

#include"intrins.h"
void delay()   //微秒级延时函数
{
   _nop_();
   _nop_();
   _nop_();
   _nop_();
}

chhds 发表于 2020-11-25 12:10:24

建议买台逻辑分析仪,协议的各项之间的时序关系很重要,用示波器很不好捕捉到,逻辑分析仪就方便多了

pdshyh 发表于 2020-11-25 12:16:11

isoimg2130 发表于 2020-11-25 11:37
探头用直流档啊,你是测的是电平,触发位置调一下啊。
另外把
把void delay()   //微秒级延时函数


谢谢,示波器我还不怎么会用,我下班回去示波器测量和延时按您说的设置调整,看示波器有正反向变化符合您说的可能是void delay()编译器直接优化了没延时,方波应该是delay_10ms()形成的吧间隔很长。:handshake

pdshyh 发表于 2020-11-25 12:17:57

chhds 发表于 2020-11-25 12:10
建议买台逻辑分析仪,协议的各项之间的时序关系很重要,用示波器很不好捕捉到,逻辑分析仪就方便多了

谢谢,关注过逻辑分析仪不怎么知道怎么用,原来是在这里有用。:handshake

chhds 发表于 2020-11-25 12:54:42

pdshyh 发表于 2020-11-25 12:17
谢谢,关注过逻辑分析仪不怎么知道怎么用,原来是在这里有用。

模拟信号用示波器,数字信号用逻辑分析仪,各司其职。

isoimg2130 发表于 2020-11-25 13:45:09

pdshyh 发表于 2020-11-25 12:16
谢谢,示波器我还不怎么会用,我下班回去示波器测量和延时按您说的设置调整,看示波器有正反向变化符合您 ...

就算没延时,他高低电平应该还是有的,毕竟51那么慢。波形还是会有的,你没测到只能是测量方法不对。
但是如果读出来数据不正常就是程序问题了。
这个程序没仔细深究,但是看起来总感觉怪怪的,你可以试着写255个数据进去,再隔个500毫秒读一个显示,如果LED是1.2.3.....255显示的就是没问题。如果不是就是程序有问题。

pdshyh 发表于 2020-11-25 14:45:46

chhds 发表于 2020-11-25 12:54
模拟信号用示波器,数字信号用逻辑分析仪,各司其职。

谢谢,原来是这样使用的,知道了。

pdshyh 发表于 2020-11-25 14:51:04

isoimg2130 发表于 2020-11-25 13:45
就算没延时,他高低电平应该还是有的,毕竟51那么慢。波形还是会有的,你没测到只能是测量方法不对。
...

谢谢给出测试方法,这个程序就是写入0xaa在读出来在led显示。刚刚跟着系统学单片机就碰到问题了。

isoimg2130 发表于 2020-11-25 16:38:50

pdshyh 发表于 2020-11-25 14:51
谢谢给出测试方法,这个程序就是写入0xaa在读出来在led显示。刚刚跟着系统学单片机就碰到问题了。

#include "reg52.h"
#include"intrins.h"

typedef unsigned char u8;

sbit SCL=P2^1;                                           //I2C时钟
sbit SDA=P2^2;                                           //I2C数据

void delay()                                                   //4微秒延时函数
{
   _nop_();
   _nop_();
   _nop_();
   _nop_();
}

void yanshi(unsigned int hm)                  //延时毫秒
{
        unsigned int i;
        do
        {
                i = 12000000 / 97560;
                while(--i)        ;                          
        }
        while(--hm);
}

void Start_I2c()
{
        SDA=1;                                                 //发送起始条件的数据信号
        SCL=1;
        delay();
        SDA=0;                                                 //发送起始信号
        delay();      
        SCL=0;                                               //钳住I2C总线,准备发送或接收数据
}

void Stop_I2c()
{
        SCL=0;
        SDA=0;                                              //发送结束条件的数据信号
        delay();
        SCL=1;                                              //结束条件建立时间大于4μs
        SDA=1;                                                  //发送I2C总线结束信号
        delay();
}
      
u8 I2c_wait_ack(void)                                  //等待应答信号到来       1,接收应答失败 0,接收应答成功
{
        u8 Time=0;
        SDA=1;                                        //准备接收应答位
        _nop_();
        SCL=1;               
        _nop_();
        while(SDA)                          
        {
                Time++;
                if(Time>250)
                {
                        Stop_I2c();
                        return 1;                               //无应答返回1
                }
        }
        SCL=0;                                                        //时钟输出0
        return 0;                                               //有应答返回0
}

voidSendByte(u8c)                                //字节数据发送函数   
{
        u8BitCnt;                                                   //条件 一定要开启总线 保持SCL处于0状态 才能进行写入
        for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位
        {   
                SDA=c<<BitCnt&0x80?1:0;         //判断发送位发送是由高位开始发送               
                _nop_();
                SCL=1;                               //置时钟线为高,通知被控器开始接收数据位
                _nop_();   
                SCL=0;
                _nop_();          
        }   
}

void I2C_Ack(void)                                        //产生ACK应答
{
        SCL=0;
        delay();                   
        SDA=1;
        delay();
        SDA=0;
        delay();
        SCL=1;
        delay();
        SCL=0;
        delay();
        SDA=1;
        delay();
}
          
void I2C_NAck(void)                                           //不产生ACK应答       
{
        SCL=0;
        delay();
        SDA=1;
        delay();
        SCL=1;
        delay();
        SCL=0;
        delay();
        SDA=0;
        delay();
}
      

u8 RcvByte(u8 ack)                                        //字节数据接收函数   
{                                                                       //ack1 发送应答0 不发送应答
        u8 retc=0,i;
        SDA=1;
        delay();        
        for(i=0;i<8;i++)
        {         
                SCL=0;                          //置时钟线为低,准备接收数据位
                delay();
                SCL=1;                          //置时钟线为高使数据线上数据有效
                _nop_();
                retc<<=1;
                if(SDA)retc++;                      //读数据位,接收的数据位放入retc中
                _nop_();
        }
        if (!ack)
        I2C_NAck();                                                //发送nACK
        else
        I2C_Ack();                                                 //发送ACK                  
        return retc;                                       
}

u8 AT24C_Rcvone(u8 Addr)                           //在AT24CXX指定地址读出一个数据
{
   u8 temp=0;
   Start_I2c();                                //启动总线
   SendByte(0xa0);                             //发送写命令
   I2c_wait_ack();                                           //等待应答
   SendByte(Addr);                             //发送地址
   I2c_wait_ack();                                           //等待应答

   Start_I2c();                                //重新启动总线
   SendByte(0xa1);                                     //设置为读操作
   I2c_wait_ack();                                           //等待应答;

   temp=RcvByte(0);                                           //读字节        非应答

   Stop_I2c();                               //结束总线
   return temp;
}

void AT24C_Sendone(u8 Addr,u8 Data)        //在AT24CXX指定地址写入一个数据       此函数只限于 c02-c16
{
   Start_I2c();                               //启动总线
   SendByte(0xa0);                            //发送写命令
   I2c_wait_ack();                                          //等待应答
   SendByte(Addr);                            //发送地址
   I2c_wait_ack();                                          //等待应答
   SendByte(Data);                                          //发送字节数据
   I2c_wait_ack();                                          //等待应答
   Stop_I2c();                                //结束总线
   yanshi(10);                                                  //如果是连续发送字节的时候这个延时很重要 否则将回传错
}

void main()
{
   AT24C_Sendone(10,0xaa);
   P1=AT24C_Rcvone(10);      
   while(1);
}




isoimg2130 发表于 2020-11-25 16:45:31

pdshyh 发表于 2020-11-25 14:51
谢谢给出测试方法,这个程序就是写入0xaa在读出来在led显示。刚刚跟着系统学单片机就碰到问题了。

掉个头,这样直观点。改成这样。流水显示。这样能判断是否出错。。按二进制看。
void main(void)
{
        u8 a;
        for(a=0;a<255;a++)
           AT24C_Sendone(a,a);
        for(a=0;a<255;a++)
        {
                   P1=AT24C_Rcvone(a);
                yanshi(200);
        }      
           while(1);
}

pdshyh 发表于 2020-11-25 17:28:12

isoimg2130 发表于 2020-11-25 16:38


谢谢,图文并茂还有模拟还有测量万分感谢,逻辑分析仪测量的?

补充内容 (2020-11-26 08:03):
还有仿真

分立元件 发表于 2020-11-25 20:41:31

还是用我那个分享的程序吧!
页: [1] 2 3
查看完整版本: 52单片机的I2C读写24C08程序波形问题