打印
[PIC®/AVR®/dsPIC®产品]

PIC16F877A硬件读写24c02用4M正常工作,而16M就不工作问题请教

[复制链接]
610|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
huang3088549|  楼主 | 2021-11-30 09:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
//**************************************************
//*****************定义头文件**********************
//**************************************************
#include<pic.h>


//**************************************************
//******************定义配置位*********************
//**************************************************
__CONFIG(0x1871);      
//FLASH代码保护,RB6和RB7为普通IO口,数据代码保护RB3为数字
//IO口,低电压复位使能,上电延时开,看门狗关,4M晶体XT振荡器


//**************************************************
//******************定义常量***********************
//**************************************************
#define uchar unsigned char
#define uint  unsigned int
#define SDA RC4
#define SCL RC3


//**************************************************
//****************定义写入EEPROM数据****************
//**************************************************
uchar display[8]={0X81,0X42,0X24,0X18,0X24,0X42,0X81,0X00};


//**************************************************
//**************定义读取EEPROM数据变量*************
//**************************************************
uchar data[8];



//***********************************************
//函 数 名:delayms(uchar time);
//入口参数:time
//出口参数:无
//函数作用:延时
//说    明:
//***********************************************
void delayms(uchar time)
{
  uint i;
  while(time--)
  {
    for(i=93;i>0;i--){;}
  }
}


//***********************************************
//函 数 名:iic_init(void);
//入口参数:无
//出口参数:无
//函数作用:iic初始化
//说    明:
//***********************************************
void iic_init(void)
{
  TRISA=0X00;    //设置RA口为输出口
  PORTA=0X00;    //RA口输出低电平
  ADCON1=0X07;   //设置RA口和RE口为普通IO口
  TRISC3=1;
  TRISC4=1;
  TRISD=0X00;
  SSPCON=0x28;   //设置控制寄存器
  SSPCON2=0X00;
//  SSPSTAT=0X80;
  SSPADD=9;   //用于产生100K信号  SCL=Fosc/[4*(SSPADD+1)]=4000000/4*(9+1)=100KHZ
// SSPADD=39;   //用于产生100K信号  SCL=Fosc/[4*(SSPADD+1)]=16000000/4*(39+1)=100KHZ
  CKE=1;    //SSPSTAT寄存器BIT6的设置
  SMP=1;    //SSPSTAT寄存器BIT7的设置
  SSPIE=0;      
}


//***********************************************
//函 数 名:iic_start(void);
//入口参数:无
//出口参数:无
//函数作用:产生启动信号
//说    明:
//***********************************************
void iic_start(void)
{
  SEN=1;
  while(SSPIF==0){;}
  SSPIF=0;
}


//***********************************************
//函 数 名:iic_restart(void);
//入口参数:无
//出口参数:无
//函数作用:产生重启信号
//说    明:
//***********************************************
void iic_restart(void)
{
  RSEN=1;
  while(SSPIF==0){;}
  SSPIF=0;
}


//***********************************************
//函 数 名:iic_stop(void);
//入口参数:无
//出口参数:无
//函数作用:产生停止信号
//说    明:
//***********************************************
void iic_stop(void)
{
  PEN=1;
  while(SSPIF==0){;}
  SSPIF=0;
}


//***********************************************
//函 数 名:iic_waitACK(void);
//入口参数:无
//出口参数:无
//函数作用:等待ACK应答信号
//说    明:
//***********************************************
void iic_waitACK(void)  
{  
  uchar temp=0;
  while(ACKSTAT)
  {
    temp++;
    if(temp==255){break;}
  }
}


//***********************************************
//函 数 名:iic_writebyte(uchar data);
//入口参数:data
//出口参数:无
//函数作用:写一个字节函数
//说    明:
//***********************************************
void iic_writebyte(uchar data)
{
  SSPBUF=data;
  while(SSPIF==0){;}
  SSPIF=0;
}


//***********************************************
//函 数 名:iic_writedata(uchar addr,uchar *ptt);
//入口参数:addr,*ptt
//出口参数:无
//函数作用:按地址向EEPROM写数据块
//说    明:
//***********************************************
void iic_writedata(uchar addr,uchar *ptt)
{
  uchar i;      
  iic_start();             //产生启动信号
  iic_writebyte(0xA0);     //I2C写指令和IC地址
  iic_waitACK();           //调用等待ACK应答信号
  iic_writebyte(addr);     //写EEPROM地址
  iic_waitACK();           //调用等待ACK应答信号
  for(i=0;i<8;i++)         //写8个数据
  {   
    iic_writebyte(ptt[i]);
    iic_waitACK();         //调用等待ACK应答信号
  }
  iic_stop();              //产生停止信号
}


//***********************************************
//函 数 名:iic_readbyte(void);
//入口参数:无
//出口参数:SSPBUF
//函数作用:从EEPROM读取一个字节数据
//说    明:
//***********************************************
uchar iic_readbyte(void)
{
  RCEN=1;
  while(SSPIF==0){;}
  SSPIF=0;
  return SSPBUF;
}


//***********************************************
//函 数 名:iic_readdata(uchar addr);
//入口参数:addr
//出口参数:data[8]
//函数作用:按地址从EEPROM读取数据块
//说    明:
//***********************************************
void iic_readdata(uchar addr)
{
  uchar i;
  iic_start();              //产生启动信号
  iic_writebyte(0xA0);      //I2C写指令和IC地址
  iic_waitACK();            //调用等待ACK应答信号
  iic_writebyte(addr);      //读EEPROM数据的地址
  iic_waitACK();            //调用等待ACK应答信号
  iic_restart();            //产生重起信号
  iic_writebyte(0xA1);      //I2C读指令和IC地址
  iic_waitACK();            //调用等待ACK应答信号
  for(i=0;i<8;i++)          //读取8个byte
  {
    data[i]=iic_readbyte();
    if(i!=7)                //最后一个数据不应答
    {
      ACKDT=0;
      ACKEN=1;
      while(SSPIF==0){;}
      SSPIF=0;
    }
    else
    {
      ACKDT=1 ;
      ACKEN=1;
      while(SSPIF==0){;}
      SSPIF=0;
    }
  }
  iic_stop();               //产生停止信号
}

//***********************************************
//函 数 名:main(void);
//入口参数:无
//出口参数:无
//函数作用:MAIN函数
//说    明:
//***********************************************
void main(void)
{
  uchar i;
  iic_init();                    //调用初始化程序
  iic_writedata(0x00,display);   //调用写数据函数,写EEPROM地址,要写的数据
  delayms(250);
//  iic_readdata(0x00);          //调用读数据函数,读EEPROM数据地址  
  while(1)
  {
    iic_readdata(0x00);  
    for(i=0;i<8;i++)
    {
      PORTD=data[i];             //输出指示
      delayms(250);
    }
  }
}

上程序选用4MHZ晶振时能正常工作,而选用16MHZ时就不能正常工作,改用16MHZ时只需修改:SSPADD=39;   //用于产生100K信号  SCL=Fosc/[4*(SSPADD+1)]=16000000/4*(39+1)=100KHZ,在规格书上没有看到其他要修改的,请大侠指导,谢谢!

使用特权

评论回复
评论
橘子阿小 2021-11-30 16:13 回复TA
配置位需要改成16M 
沙发
wangchangwenqq| | 2021-11-30 17:58 | 只看该作者
配置将 XT 改 HS

使用特权

评论回复
板凳
huang3088549|  楼主 | 2021-11-30 19:15 | 只看该作者
配置位XT改成HS也不行,不知道哪里还有问题

使用特权

评论回复
地板
huang3088549|  楼主 | 2021-12-3 20:11 | 只看该作者
硬件IIC读写24C01不行,后面用软件模拟来实现

//*****************************************************
//******************定义常量***************************
//*****************************************************
#define  uchar unsigned char
#define  uint  unsigned int

#define  SCL  TRISC3
#define  SDA  TRISC4

//***********************************************
//函 数 名:i2c_start(void);
//入口参数:无
//出口参数:无
//函数作用:产生启动信号
//说    明:
//***********************************************
void i2c_start(void)
{
  SDA=1;                                                  //当SCL为高电平时使SDA产生一个负跳变

  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop"); //大于4.7US,实测5.2US
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");   
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");

  SCL=1;

  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop"); //大于4.7US,实测5.2US
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");   
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");

  SDA=0;

  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop"); //大于4US,实测5.2US
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");   
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");

  SCL=0;                                                  //钳住I2C总线,准备发送数据或接收数据

  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop"); //大于4US,实测5.2US
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");   
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
}


//***********************************************
//函 数 名:i2c_stop(void);
//入口参数:无
//出口参数:无
//函数作用:产生停止信号
//说    明:
//***********************************************
void i2c_stop(void)
{
  SDA=0;                                                  //当SCL为高电平时使SDA产生一个正跳变

  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop"); //大于4US,实测5.2US
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");   
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");

  SCL=1;

  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop"); //大于4.7US,实测5.2US
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");   
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");

  SDA=1;

  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop"); //大于4US,实测5.2US
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");   
  asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
}


//***********************************************
//函 数 名:i2c_writebyte(uchar data);
//入口参数:data
//出口参数:无
//函数作用:写一个字节函数
//说    明:
//***********************************************
void i2c_writebyte(uchar data)
{
  uchar i;
  for(i=0;i<8;i++)                                          //写8位数据
  {
    if(data&0x80){SDA=1;}                                   //先写高位
    else {SDA=0;}
    asm("nop");                                             //实测1.8US
    SCL=1;
    asm("nop");asm("nop");asm("nop");asm("nop");asm("nop"); //大于4US,实测5.2US
    asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");   
    asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");  
    SCL=0;
    data=data<<1;                                           //写下一位
  }
  asm("nop");asm("nop");asm("nop");                         //实测2.2US
  SDA=1;
  asm("nop");asm("nop");asm("nop");                         //实测2.2US
  SCL=1;
  asm("nop");asm("nop");asm("nop");asm("nop");              //实测3.6US
  asm("nop");asm("nop");asm("nop");asm("nop");  
  if(RC4){ack=0;}                                           //等待应答信号,RC4=0则有应答
  else ack=1;
  SCL=0;
  asm("nop");asm("nop");asm("nop");                         //实测2.2US
}


//***********************************************
//函 数 名:i2c_readbyte(void);
//入口参数:无
//出口参数:SSPBUF
//函数作用:从EEPROM读取一个字节数据
//说    明:
//***********************************************
unsigned char i2c_readbyte(void)
{
  uchar i,data=0;  
  SDA=1;
  for(i=0;i<8;i++)                                          //读8位数据
  {
    asm("nop");
    SCL=0;
    asm("nop");asm("nop");asm("nop");asm("nop");asm("nop"); //大于4US,实测5.2US
    asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");   
    asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");  
    SCL=1;
    asm("nop");asm("nop");asm("nop");
    data=data<<1;
    if(RC4)                                                 //判断读取数据是否为1
    {
      data=data|0x01;
    }
    asm("nop");asm("nop");asm("nop");                       //实测2.2US
  }
  SCL=0;
  asm("nop");asm("nop");asm("nop");                         //实测2.2US
  return (data);                                            //返回读取的数据
}


//***********************************************
//函 数 名:i2c_writedata(uint addr);
//入口参数:addr,*ptt
//出口参数:无
//函数作用:按地址向EEPROM写数据块
//说    明:按首地址连续写三个地址的三个8位数据
//***********************************************
void i2c_writedata(uint addr)
{
  uchar i;
  i2c_start();                     //产生启动信号
  i2c_writebyte(0XA0);             //I2C写指令和IC地址
  i=(addr>>8)&0xff;                //取高八位地址
  i2c_writebyte(i);                //写EEPROM高八位地址
  i=addr&0xff;                     //取低八位地址
  i2c_writebyte(i);                //写EEPROM低八位地址
  for(i=0;i<3;i++)                 //写8个数据
  {
    i2c_writebyte(wreep_data[i]);   
  }
  i2c_stop();                      //产生停止信号
}

//***********************************************
//函 数 名:i2c_readdata(uchar addr);
//入口参数:addr
//出口参数:data[8]
//函数作用:按地址从EEPROM读取数据块
//说    明:按首地址连续读三个地址的三个数据
//***********************************************
void i2c_readdata(uint addr)
{
  uchar i,j;
  for(i=0;i<3;i++,addr++)
  {
    i2c_start();                    //产生启动信号
    i2c_writebyte(0xA0);            //I2C写指令和IC地址

    j=(addr>>8)&0xff;               //取高八位地址
    i2c_writebyte(j);               //读EEPROM数据的地址

    j=addr&0xff;                    //取低八位地址
    i2c_writebyte(j);               //写EEPROM低八位地址

    i2c_start();                    //重新产生启动信号
    i2c_writebyte(0xA1);            //I2C读指令和IC地址
    reeep_data[i]=i2c_readbyte();   //读取数据
    i2c_stop();                     //产生停止信号
  }
}

使用特权

评论回复
5
hu9jj| | 2021-12-4 08:46 | 只看该作者
我觉得可能还是延时的时间不正确造成的。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

5

帖子

0

粉丝