打印

为什么不能读取AT24C01?内有程序,请大家帮忙!

[复制链接]
4954|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
雁舞白沙|  楼主 | 2007-6-18 02:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include <hidef.h>
#include "derivative.h"
#include "Global.h"
//-----***-IIC延时-***-----//
void IicWait(void)
{
    asm("NOP"); //01
    //asm("NOP"); //02
    //asm("NOP"); //01
}
//-----***-IIC启示-***-----//
void IicStart(void)                                                        
{
      IicSda=1;
      IicWait();
      IicScl=1;
      IicWait();
      IicSda=0;
      IicWait();
      IicScl=0;
      IicWait();
}
//-----***-IIC停止-***-----//
void IicStop(void)                                                        
{
      IicSda=0;
      IicWait();
      IicScl=1;
      IicWait();                                                        
      IicSda=1;
      IicWait();
}
//-----***-IIC应答-***-----//
void SendAcknowledge(unsigned char IicAck)                                                
{
      IicSda=IicAck;
      IicScl=1;
      IicWait();
      IicScl=0;
      IicWait();
}             
//-----***-从slave端读取一个数据-***-----//
unsigned char IicReceiveByte(void)
{
      unsigned char i;
      unsigned char bytedata=0;
      IicSda=1;
      for(i=0;i<8;i++)
      {
            IicScl=1;
            IicWait();
            bytedata<<=1;
            if (IicSda) bytedata |=0x01;
            IicScl=0;
            IicWait();
      }
      return bytedata;
}
//-----***-传送一个 Byte 数据到 slave-***-----//
unsigned char IicSentByte(unsigned char DataByte)                                    
{
      unsigned char i,IicAck;
      for(i=0;i<8;i++)
      {
            if(DataByte & 0x80)
            {
                  IicSda=1;
            }
            else
            {
                  IicSda=0;
            }
            DataByte <<=1;
            IicWait();
            IicScl=1;
            IicWait();
            IicScl=0;
            IicWait();
      }
      IicSda=1;
      IicWait();
      IicScl=1;
      IicWait();
      IicAck=IicSda;
      IicScl=0;
      IicWait();
      return IicAck;
}
//-----***-无扇区读---单字节-***-----//
unsigned char FgTimeout;
//读取指定器件无扇区指定地址单字节的数据
//Device=器件地址---单字节
//DataAdd=字节地址---单字节
unsigned char IicByteRead(unsigned char DataAdd)      
{
        unsigned char bytedata;
        DisableInterrupts;//关中断
        IicStart();
        IicSentByte(0xa0);
        IicSentByte(DataAdd);
        IicStart();
        IicSentByte(0xa1);
        bytedata=IicReceiveByte();
        //SendAcknowledge(1);
        IicStop();
        EnableInterrupts;//开中断
      return bytedata;
}
//-----***-无扇区写---单字节-***-----//
//写入指定器件无扇区指定地址中的单字节数据
//Device=器件地址---单字节
//DataAdd=字节地址---双字节
void IicByteWrite(unsigned char DataAdd,unsigned char DataByte)
{
        unsigned char i,IicAck;
        if(BitData&0x01)
      {
            DisableInterrupts;//关中断
              for(i=0;i<3;i++)
              {
                    IicStart();
                    IicAck=IicSentByte(0xa0);if(IicAck==1){IicStop();continue;}
                    IicAck=IicSentByte(DataAdd);if(IicAck==1){IicStop();continue;}
                    IicAck=IicSentByte(DataByte);if(IicAck==1){IicStop();continue;}
                    IicStop();
                    if(IicAck==0)break;
              }
              EnableInterrupts;//开中断
              Delay(100);
    }    
}

相关帖子

沙发
HotPower| | 2007-6-18 02:33 | 只看该作者

细心就成~~~I2C都被倒塌了就不好混了~~~

1.读出EEPROM数据文件


2.写入EEPROM数据文件 


3.单/双字节EEPROM读出


4.单/双字节EEPROM写入


5.整片EEPROM读出


6.整片EEPROM写入 

使用特权

评论回复
板凳
雁舞白沙|  楼主 | 2007-6-18 02:36 | 只看该作者

我也晕了,在以前使用中,是没有问题的!

可是今天搬到一个新的MCU中,写不进去,也读不出来!

郁闷啊!

使用特权

评论回复
地板
dongshan| | 2007-6-18 07:48 | 只看该作者

楼上的界面很好看啊。

注意时钟周期。

既然在别的MCU中已成功,换了新的MCU,你的每一指令周期的时间是一样的

吗?还能满足I2C的时序吗?

使用特权

评论回复
5
张明峰| | 2007-6-18 09:03 | 只看该作者

IicSda/IicScl 是怎么定义的?

注意端口的方向控制

对于FSL:1->输出,0->输入
对于PIC:1->输入,0->输出

使用特权

评论回复
6
free_tech| | 2007-6-18 09:08 | 只看该作者

直接使用片内的iic模块就行了

模拟iic总线,start 信号要有冗余,
             ack也要有冗余,
             24c01最好换成24c04,

使用特权

评论回复
7
雁舞白沙|  楼主 | 2007-6-18 12:55 | 只看该作者

定义!

DDRD=0xfc;

#define IicSda   PTD_PTD2 /*该IO口用于24C01数据*/
#define IicScl   PTD_PTD3 /*该IO口用于24C01时钟*/

此程序在PIC,ATMEL,LPCMCU中运行都正常,但是在HC908JK8里面却不可以。

还望高手指教!

使用特权

评论回复
8
雁舞白沙|  楼主 | 2007-6-18 13:05 | 只看该作者

在线等!

使用特权

评论回复
9
雁舞白沙|  楼主 | 2007-6-18 13:12 | 只看该作者

调用方式!

IicByteWrite(0xa0,0x03,0x55);
ValveData=IicByteRead(0xa0,0x03);

使用特权

评论回复
10
HotPower| | 2007-6-18 13:25 | 只看该作者

没用过张教主的芯片~~~不行你用三线模拟I2C.

既然是IO模拟I2C,双向IO的问题肯定要多注意.

不行你用三线模拟I2C.

SCL
SDAIN
SDAOUT

这样都不行就只有到张教主家了~~~

我觉得你程序的结构有些问题,黑白有些分不清~~~

我喜欢读写一体化~~~

使用特权

评论回复
11
张明峰| | 2007-6-18 16:29 | 只看该作者

I/O不分造成的问题

你说:
DDRD=0xfc;
#define IicSda   PTD_PTD2 /*该IO口用于24C01数据*/
#define IicScl   PTD_PTD3 /*该IO口用于24C01时钟*/

你的程序定义了SDA/SCL均为输出且永远是输出,这样,问题就来了:
//字节发送程序
      ...
      IicSda=1;
      IicWait();
      IicScl=1;
      IicWait();
      IicAck=IicSda;   //!!!读应答位
      IicScl=0;
      IicWait();
      return IicAck;

仔细看FSL单片机IO引脚的特性,当IO引脚设定为输出时,读引脚读的永远是输出锁存器的状态而不是IO引脚的状态。由于IicSda为输出且IicSda=1,故你读到的永远是1。IIC读字节程序的问题相同。

另外楼主对I2C总线理解还是有局限性,且犯了一个常见的错误(工程师中犯错概率>80%):IIC总线上的高电平是通过外部上拉才得到的,而不是靠引脚输出高电平而得到的。尽管你的程序看似在其它芯片上可以跑,但隐患极大。试想:当读应答位时单片机引脚输出高电平(PIC的引脚驱动能力可达10-20mA),而EEPROM输出应答低电平,这时高低电平发生冲突,类似于电源短路,当然没那么严重。好的结果是功耗无谓增加,严重的结果是由于IO口急变的大电流而造成单片机死机!

使用特权

评论回复
12
free_tech| | 2007-6-18 16:34 | 只看该作者

我有一个SR12读24C04的汇编,调试过的

口线模拟起始和停止位
QISHI:  bset 0,ptb
        bset 0,ddrb;数据输出
        bset 0,ptb;数据线

        bset 1,ptb
        bset 1,ddrb;时钟输出
        bset 1,ptb
        jsr  yan   ;延时
        
        bclr 0,ptb
        bset 0,ddrb
        jsr yan         ;起始位
        RTS
        
tingzhi:bclr 1,ptb
        jsr  yan
        bclr 0,ptb
        bset 0,ddrb;      停止位
        JSR YAN
        BSET 1,PTB
        BSET 0,PTB
        JSR YAN
        rts

使用特权

评论回复
13
张明峰| | 2007-6-18 16:48 | 只看该作者

例程参考

请注意IIC总线上高低电平控制是通过改变引脚的输入/输出方向,而不是直接输出高低电平。此例程在9S08SW60上得到验证。只需改变引脚名称定义即可用到908系列。

//IIC bus assignment
#define IIC_SDA_CTL     PTCDD_PTCDD1
#define IIC_SDA_DAT     PTCD_PTCD1
#define IIC_SCL_CTL     PTCDD_PTCDD0
#define IIC_SCL_DAT     PTCD_PTCD0   
#define IIC_MST_HI      0  //引脚输入模式,释放总线(总线上呈上拉高电平)
#define IIC_MST_LO      1  //引脚输出模式,占用总线(总线上呈低电平)


void IIC_Start(void);
void IIC_Restart(void);
void IIC_Stop(void);
byte IIC_SendByte(byte);
byte IIC_ReadByte(byte);
byte IIC_Read(byte *, byte);
byte IIC_Write(byte *, byte);
void IIC_Delay(void);


void IIC_Delay(void)
{
   byte i;
   for (i=0;i<8;i++) {}
}

//==============================================================
// Master generates a START condition on IIC bus
//==============================================================
void IIC_Start(void)
{
   IIC_SDA_CTL = IIC_MST_HI;
   IIC_SCL_CTL = IIC_MST_HI;
   
   IIC_Delay();
   IIC_SDA_CTL = IIC_MST_LO;
   IIC_SDA_DAT = 0;
   IIC_Delay();
   IIC_SCL_CTL = IIC_MST_LO;
   IIC_SCL_DAT = 0;
   IIC_Delay();
}

//==============================================================
// Master generates a RESTART condition on IIC bus
//==============================================================
void IIC_Restart(void)
{
   IIC_SDA_CTL = IIC_MST_HI;  //SDA back to high while SCL remain in low
   IIC_Delay();
   IIC_SCL_CTL = IIC_MST_HI;  //SCL back to high, bus idle now
   IIC_Delay();
   IIC_SDA_CTL = IIC_MST_LO;  //RESTART condition occur
   IIC_Delay();
   IIC_SCL_CTL = IIC_MST_LO;  //SCL to low for standby
   IIC_Delay();
}

//==============================================================
// Master generates a STOP condition on IIC bus
//==============================================================
void IIC_Stop(void)
{
   IIC_SDA_CTL = IIC_MST_LO;  //make sure SDA is low
   IIC_Delay();
   IIC_SCL_CTL = IIC_MST_HI;  //I2C_SCL_CTL go to high first
   IIC_Delay();
   IIC_SDA_CTL = IIC_MST_HI;  //I2C_SDA_CTL have low-high transition while SCL is high
   IIC_Delay();
}

//==============================================================
// Master send out a byte of data and return with ACK condition
// return with 0x00 if ACK received
// reyurn with 0xff if NACK received
//==============================================================
byte IIC_SendByte(byte outDat)
{
   byte bit;
   
   //send out 8-bit data
   for (bit=0;bit<8;bit++) {
      if (outDat&0x80)
         IIC_SDA_CTL = IIC_MST_HI;
      else
         IIC_SDA_CTL = IIC_MST_LO;
      IIC_Delay();
      IIC_SCL_CTL = IIC_MST_HI;
      IIC_Delay();
      IIC_SCL_CTL = IIC_MST_LO;
      outDat <<= 1;
   }
   
   //check for the ACK/NACK
   IIC_SDA_CTL = IIC_MST_HI;    //master release SDA
   IIC_Delay();
   IIC_SCL_CTL = IIC_MST_HI;    //master send a clock
   IIC_Delay();
   if (IIC_SDA_DAT) bit = 0xff; //NACK
   else bit = 0;                //ACK
   IIC_SCL_CTL = IIC_MST_LO;
   IIC_Delay();
   
   return(bit);
}

//==============================================================
// Master write a series of bytes through IIC bus
// Return with 0x00 if successful
// Return with 0xff if failed
//==============================================================
byte IIC_Write(byte *buff, byte total)
{
   while (total) {
      if (IIC_SendByte(*buff++)) //get NACK after data byte out
         return(0xff);           //abort
      total--;
      __RESET_WATCHDOG();
   }
   return(0);
}

//==============================================================
// Master read a byte of data and echo with ACK/NACK
// return with data read
//==============================================================
byte IIC_ReadByte(byte ackFlag)
{
   byte bit, dat;
   
   IIC_SDA_CTL = IIC_MST_HI;    //make sure master release SDA
   
   //read 8 bits sof data
   for (bit=0;bit<8;bit++) {
      dat <<= 1;
      IIC_SCL_CTL = IIC_MST_HI;
      IIC_Delay();
      if (IIC_SDA_DAT)          //read back data
         dat |= 0x01;
      IIC_SCL_CTL = IIC_MST_LO;
      IIC_Delay();
   }
   
   //echo with ACK/NACK
   if (ackFlag==0) 
      IIC_SDA_CTL = IIC_MST_LO; //echo back ACK
   else
      IIC_SDA_CTL = IIC_MST_HI; //echo back NACK

   IIC_Delay();
   IIC_SCL_CTL = IIC_MST_HI;
   IIC_Delay();
   IIC_SCL_CTL = IIC_MST_LO;
   IIC_Delay();
   
   return(dat);
}

//==============================================================
// Master read a string of data byte through IIC bus
// Return: no. of bytes read
//==============================================================
byte IIC_Read(byte *buff, byte total)
{
   byte count;
    
   if (total==0) return(0);

   if (total==1) {                  //read one byte only
      buff[0] = IIC_ReadByte(1);    //NACK after read
      return(1);
   }
   
   else {                           //read more than one bytes
      count = 0;
      while(total>1) {
         IIC_Delay();
         buff[count++] = IIC_ReadByte(0);    //echo ACK after read
         total--;
         __RESET_WATCHDOG();
      }
      IIC_Delay();
      buff[count++] = IIC_ReadByte(1);       //read last byte. echo NACK
      return(count);
   }
}

使用特权

评论回复
14
雁舞白沙|  楼主 | 2007-6-18 23:57 | 只看该作者

感谢张工!

您所说的问题:

另外楼主对I2C总线理解还是有局限性,且犯了一个常见的错误(工程师中犯错概率>80%):IIC总线上的高电平是通过外部上拉才得到的,而不是靠引脚输出高电平而得到的。尽管你的程序看似在其它芯片上可以跑,但隐患极大。试想:当读应答位时单片机引脚输出高电平(PIC的引脚驱动能力可达10-20mA),而EEPROM输出应答低电平,这时高低电平发生冲突,类似于电源短路,当然没那么严重。好的结果是功耗无谓增加,严重的结果是由于IO口急变的大电流而造成单片机死机!

我不同意。

因为:

在我所设计的电路中所有的IO口除了有上拉之外,还有IO口限制电阻!

我一般选择4.7K阻值!目的就是您所说的IO口高低匹配的问题!






所以我的程序可以在其它的MCU中运行!

为什么不能在飞思卡尔中运行,是因为其IO口特性不允许在输出的时候读取IO口电平(读的永远是状态寄存器的)

这一点是我所犯的错误!

对于PIC,LPC我都是应用的开漏输出,并为使用强电流输出模式!


最后:

非常感谢张工的程序执导,白沙向您鞠躬了!

使用特权

评论回复
15
hotpower| | 2007-6-19 00:35 | 只看该作者

哈哈~~~我想也是这个问题~~~都是51惹得祸~~~~

让你做3线模拟I2C的意思就是出入分明.

告你的:
SCL
SDAIN
SDAOUT

真不如写成:
SCK
MISO
MOSI


51的IO你随便用,结果只能是惨痛的~~~

多玩些MCU,ARM.DSP就知道管脚配置是多么倒塌的重要呀~~~

感谢张教主给俺上了堂课~~~

可惜菜农一直没机会做飞思卡尔单片机菜鸟~~~

MC68HC05早年曾看过,...不知何日能倒塌它~~~

祝教主端五节快乐~~~明教一统天下~~~

使用特权

评论回复
16
张明峰| | 2007-6-19 08:03 | 只看该作者

加IO口限制电阻

“在我所设计的电路中所有的IO口除了有上拉之外,还有IO口限制电阻!
我一般选择4.7K阻值!目的就是您所说的IO口高低匹配的问题!”

这样做当然可以简单地避免高低电平驱动输出直接发生冲突的问题,但也引入另外一些问题:
1)如果串4.7K电阻,则上拉电阻一般要用47K或更大,这样当总线上需要出现低电平时可以得到约0.5V的电压(5V系统),其实这已经超出了IIC总线协议规定的低电平<0.4V的指标。如果加大上拉电阻,虽然可以降低低电平电压,但将引起传输延时,严重影响通讯速率,要知道IIC总线上是有容性负载存在的。
2)IIC总线其实是一种多主总线,即总线上可以挂多个主器件master。这时主器件在掌控总线前必须要进行仲裁判断以获得控制权。对于IO高电平驱动的控制法,你永远无法实现总线冲突的检测。
3)IIC总线上主从器件之间的数据交换是可以相互延时等待的,这可以通过从器件持续拉低SCL线来要求主器件等待。同样的,对于IO高电平驱动的控制法,你永远无法实现这种等待协调机制。

你用现在的方法在特定的场合(单主,低速率)实现特定的功能(EEPROM读写)是可以的,但这并不能证明协议的实现是完美的和通用的。通过对IIC总线协议的认识和具体实现,基本可以看一个电工的经验和功底。^_^(开个玩笑)

使用特权

评论回复
17
张明峰| | 2007-6-19 08:05 | 只看该作者

祝HOTPOWER和各位

端午快乐,多吃粽子

使用特权

评论回复
18
gxs64| | 2007-6-19 09:11 | 只看该作者

re

对于fsl单片机,应注意io口方向,因为ack是输入的。

使用特权

评论回复
19
雁舞白沙|  楼主 | 2007-6-19 12:29 | 只看该作者

您说的太对了!

通过对IIC总线协议的认识和具体实现,基本可以看一个电工的经验和功底!

您说的太对了!

使用特权

评论回复
20
HotPower| | 2007-6-19 19:09 | 只看该作者

哈哈~~~看看SMBus总线就知道上拉限流钳位电压有多重要了~~~

祝教主万福~~~

使用特权

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

本版积分规则

213

主题

789

帖子

243

粉丝