amoBBS 阿莫电子论坛

 找回密码
 注册
搜索
bottom↓
查看: 8787|回复: 25

m051的i2c读写24cxx,如何连续读?

[复制链接]
发表于 2010-10-17 14:14:49 | 显示全部楼层 |阅读模式
点击此处下载 ourdev_590514B9D7K3.zip(文件大小:388K) (原文件名:AN_1009_IIC_for_24LC64 V1.00.zip)
这是芯唐官方的应用笔记。有单字节读写代码,连续读取一直没能实现,大家看看。

//resive data
I2C0->DATA = 0X00;           //接收数据为何要先写数据???????
DrvI2C_Ctrl(I2C_PORT0, 0, 0, 1, 0);  //clr si  
while( I2C0->CON.SI == 0 );   //poll si flag
发表于 2010-10-17 15:38:01 | 显示全部楼层
呵呵,这就是我一直以来对使用“官方库函数”非常感冒的原因之一。

就拿LZ位的例子看,

1。代码中开始有:#include "Driver\DrvI2C.h",说明你用了它的“库”,否则 DrvI2C_Open()、DrvI2C_Ctrl()、DrvI2C_Close()来自何处?

2。既然有了DrvI2C_Open()、DrvI2C_Ctrl()、DrvI2C_Close(),为什么不实现DrvI2C_Write_Byte()和DrvI2C_Recive_Byte()?可见这个库只是帮助你设置寄存器,根本没有用户层面的接口。

3。因此你还是要看器件手册,了解各个位的意义和作用。否则DrvI2C_Ctrl(I2C_PORT0, 0, 0, 1, 0)里面的几个0/1就无法确定。所以那些说使用库可以跳过低层寄存器,(32位MCU的寄存器比8位多的多,而且性能更强)让用户很快上手的说法是片面的。

4。除了看手册,你还要看它的库函数是什么功能,不了解根本也用不好的(这里已经不考虑库函数有BUG以及局限性的问题了)。
=============================================================================================================

对LZ位的例子,我没有看过其库函数到第是如何写的。根据判断,应该使用M051的硬件I2C口,不是I/O口模拟的。这个从DrvI2C_Ctrl(I2C_PORT0, 0, 0, 1, 0)已经看出。

硬件I2C口需要一个启动工作的过程,应该在DrvI2C_Ctrl(I2C_PORT0, 0, 0, 1, 0)中实现,它清除SI,然后启动I2C工作。建议你还是要了解这个函数的具体作用。

对于读取数据

//resive data  
I2C0->DATA = 0X00;           //接收数据为何要先写数据???????
DrvI2C_Ctrl(I2C_PORT0, 0, 0, 1, 0);  //clr si   
while( I2C0->CON.SI == 0 );   //poll si flag  

我认为有两种可能。一是写个0,配合下面DrvI2C_Ctrl()启动I2C读数据过程,二是根本就是乱搬的写过程代码。但不管是为了什么,这样的NOTES,太低级了。

应该后面有一句 A = I2C0->DATA;A中就是读到的数据。

你应该先测试和实现是否能读到一个字节。如果能正确的读到一个字节,那么连续读就是这段代码的重复。

最后建议你购买我编写的AVR教程,里面有关于I2C详细的介绍和多种实现的方法,包括I/O模拟和使用硬件I2C,同时还有相应低层驱动函数如何建立,以及用户层面的使用。你掌握了方法,在M051上、在STM32上都是一样使用的。

你曾经说过经过锻炼和培训。我不知道是在何时,何地。但就今天你问的问题来讲,我不客气的说,你还需要经过一些真正的培训,才能有质的提高。
 楼主| 发表于 2010-10-17 20:48:18 | 显示全部楼层
马老师
这段代码不是我写的,这是官方的文档。

读I2C->DATA实际测试时我加了,重复这段代码确实能实现读多字节,但eeprom协议并不是这样,可以连续读的,这个您知道。

单字节测试过,可以到,多字节写也可以,但多字节读不行,发现源代码多个写数据寄存器。
 楼主| 发表于 2010-10-17 20:57:27 | 显示全部楼层
您写的avr教程我看过了,不过那是N年前的事了,您的端口模拟i2c我的产品还在用着呢。
记得好像端口使用上于别人不同,没来回更改输入输出方式。记不太清了。

老师教导的对,我应该加强基础,谨记了。
 楼主| 发表于 2010-10-17 21:01:56 | 显示全部楼层
我认为有两种可能。一是写个0,配合下面DrvI2C_Ctrl()启动I2C读数据过程,二是根本就是乱搬的写过程代码

-------------------
测试发现如不加写数据寄存器这句,读到的是前面写的命令字0xa1,但试过先读一次,后面的就正确了,可是再启动读会跑飞。



硬件I2C口需要一个启动工作的过程,应该在DrvI2C_Ctrl(I2C_PORT0, 0, 0, 1, 0)中实现,它清除SI,然后启动I2C工作。建议你还是要了解这个函数的具体作用。

---------------------

DrvI2C_Ctrl(I2C_PORT0, 0, 0, 1, 0)这个是清标志
DrvI2C_Ctrl(I2C_PORT1, 0, 0, 1, 0)这个是发送启动位





但就今天你问的问题来讲,我不客气的说,你还需要经过一些真正的培训,才能有质的提高。   

---------------
这个我不做过多解释。
您觉得我说的内容不实,我要是再说我们的原理图,pcb,驱动层,应用层都是分开做的,您可能更不信,不过我们确实这样做的。
多说一句:技术员的项目一般都是从头做到尾,我们正好相反,必须分工,并不是我们的技术员不会,这样有利于整体发展,不让部分人控制。
我还是倡导分工的,把自己的部分做好,否则什么都做不精。这点也正是我们设计的产品不如国外的一个原因。
发表于 2010-10-18 03:14:24 | 显示全部楼层
回sde_arm9:

看你的回贴感觉你还是有点不服气,正好我也利用这个机会深入了解一下M051。

首先我知道这段代码是官方的。不客气的讲,你(或你们的团队)是否有能自己从底层,从零开始写代码的能力我都表示怀疑。
看看你的失误吧:

1。这段代码不是针对M051的,是针对UNC系列的。尽管都是M0的内核,I2C的控制基本相同,但库函数肯定有区别的!你如果使用M051,那么应该采用M051的库,至少下面这个函数就不一样:

DrvI2C_Ctrl(I2C_PORT0, 0, 0, 1, 0)  ==》这个是NUC系列的,因为它支持2个或2个以上的I2C,所以参数中多了个I2C口的选择。

而我查看了官方提供的M051函数库,它的函数为 DrvI2C_Ctrl(0, 0, 1, 0)!

你到底是在用NUC还是用M051?还是有意将他们混在一起,要提高问题的难度,考考我?

2。你的主题是“m051的i2c读写”,那么使用M051,就应该看MO51相关的东西,比如M051的手册。这里不是说的那个简单的介绍,是指NuMicro M051 Series Technical Reference Manual EN.pdf。你看了几遍?至少关于I2C的部分应该全面看吧。另外官站已经有M051的支持库和例子。其中也有对I2C操作的,你参考过吗?

不管你分工负责哪个部分,至少这个部分的工作就是没有做好。这个是最低层的接口,这个做不好,上面再好也是空的。


下面具体分析一下如何连续读数据,具体你去测试。
请看下图:这个是我从NuMicro M051 Series Technical Reference Manual EN.pdf中找到的,在151页。153页有I2C主机读数据的流程。

(原文件名:未标题-1 拷贝.jpg)

请注意右上部的文字说明部分!
看到这里,明显的看出M051的I2C启动与AVR的不同,AVR是通过一个控制位启动一次新的I2C工作,而MO51是通过操作数据寄存器加上配合控制位的设置启动一次新的I2C操作。这个与我前面分析的相同“配合下面DrvI2C_Ctrl()启动I2C读数据过程”

在官方提供的例子中,我也没有找到I2C连续读操作的DEMO。根据NuMicro M051 Series Technical Reference Manual EN.pdf手册上151页和153页的解释,建议你做如下尝试:

如果你准备连续读10个数据:

//resive data   
I2C->DATA = 0X00;       //接收数据为何要先写数据?==》随便写个数据,表示操作了I2C数据寄存器,用于配合下一次的I2C启动  

for(i=0;i<9;i++)
{
    DrvI2C_Ctrl(0, 0, 1, 1);   //clr si,启动一次工作 ==》收到数据返回ACK为1,此时才能连续读。这个是I2C规程规定的!   
    while( I2C0->CON.SI == 0 ); //poll si flag
    r_data = I2C->DATA;      //读数据,同时操作了I2C数据寄存器,也配合了下次启动
}                              // 这个循环只能读9个数据,因为读第10个数据后,返回ACK要为0  

DrvI2C_Ctrl(0, 0, 1, 0);      //clr si,启动第10次读数据,设置读到后返回ACK=0,表示连续读结束。   
while( I2C0->CON.SI == 0 );   //poll si flag
r_data[9] = I2C->DATA;        //读第10个数据。

=============================================================
以上供你参考。

你在4楼写到:“您写的avr教程我看过了,不过那是N年前的事了,您的端口模拟i2c我的产品还在用着呢。记得好像端口使用上于别人不同,没来回更改输入输出方式。记不太清了。”

实际你并没有认真的学习和体会,也没真正彻底的了解I2C!只是搬了段代码。后面还有使用AVR的I2C硬件接口的例子,有批量读和写的例子,你都没看。 上面的参考与AVR书中的方法是一样的,只是I2C的启动方式不同。

建议你重新仔细再看看,N年后这本书的思想和方法仍旧没有落后,比现在的许多新书或什么DEMO都要好。
发表于 2010-10-18 03:21:07 | 显示全部楼层
M051可以玩了?

    明天我也去拿个板子回来玩玩~~~~~  但愿这次没烧得太快
 楼主| 发表于 2010-10-18 08:45:55 | 显示全部楼层
没有考马老师的意识,您别误会,昨天在家,没有测试的代码,官方提供的都是nuc100的代码,和m051没什么区别,下面是从官方修改过来用于m051的代码
/*i2c写数据*/
void write_i2c_byte(uint8_t *byte,uint32_t address,uint8_t count)
{
        uint8_t n;
        uint16_t i;

           //send i2c start
        DrvI2C_Ctrl(1, 0, 1, 0);        //set start                                发送启动位
        while (I2C->CON.SI == 0);                        //poll si flag       
                       
        //send writer command
        I2C->DATA = 0XA0;                                        //send writer command        发送写命令
    DrvI2C_Ctrl(0, 0, 1, 0); //clr si flag
    while( I2C->CON.SI == 0 );                    //poll si flag

        //send address high
        //I2C->DATA = (address>>8)&0XFF;                                                               
        //DrvI2C_Ctrl(0, 0, 1, 1); //clr si and set ack       
        //while( I2C->CON.SI == 0 );                        //poll si flag

        //send address low
        I2C->DATA = address&0XFF;                                                                        //发送数据地址
        DrvI2C_Ctrl(0, 0, 1, 1); //clr si and set ack       
        while( I2C->CON.SI == 0 );                        //poll si flag

        for(n=0;n<count;n++){
                //send data
                I2C->DATA = *(byte+n);                                        //write data to                 发送数据
                DrvI2C_Ctrl(0, 0, 1, 1); //clr si and set ack       
                while( I2C->CON.SI == 0 );                        //poll si flag
        }

           //send i2c stop
        DrvI2C_Ctrl(0, 1, 1, 0); //send stop                                发送停止位
        //while( I2C0->CON.SI == 0 );
        for(i=0;i<60;i++);                                                                                        //延时
        //DrvI2C_Close(I2C_PORT0);                                                                        //关闭I2C
         
        for(i=0;i<6000;i++);
        for(i=0;i<6000;i++);
}
/*i2c读数据*/
void read_i2c_byte(uint8_t *byte,uint32_t address,uint8_t count)
{
        uint8_t n;
        uint16_t i;
        for(n=0;n<count;n++){
        //send i2c start
    DrvI2C_Ctrl(1, 0, 1, 0);                 //set start                   发送启动位
        while (I2C->CON.SI == 0);                                //poll si flag
         
           //send writer command
        I2C->DATA = 0XA0;                                                                                   //发送写命令
    DrvI2C_Ctrl(0, 0, 1, 0);           //clr si
    while( I2C->CON.SI == 0 );                           //poll si flag
       
        //send address high
    //I2C->DATA = (address>>8)&0XFF;       
        //DrvI2C_Ctrl(0, 0, 1, 1);    //clr si and set ack
        //while( I2C->CON.SI == 0 );                           //poll si flag
   
        //send address low
        I2C->DATA = (address+n)&0XFF;                                                                   //发送地址
        DrvI2C_Ctrl(0, 0, 1, 1);    //clr si        and set ack
        while( I2C->CON.SI == 0 );                           //poll si flag
       
        //send start flag
        DrvI2C_Ctrl(1, 0, 1, 0);    //clr si and send start                        发送启动位       
        while( I2C->CON.SI == 0 );                           //poll si flag
       
        //send read command
        I2C->DATA = 0XA1;                                                                                   //发送读命令
        DrvI2C_Ctrl(0, 0, 1, 0);    //clr si
    while( I2C->CON.SI == 0 );                           //poll si flag

        //resive data
        I2C->DATA = 0XFF;
        DrvI2C_Ctrl(0, 0, 1, 0);    //clr si       
        while( I2C->CON.SI == 0 );                           //poll si flag

        *(byte+n)= I2C->DATA;                                                                   //读取数据
                //DrvI2C_Ctrl(0, 0, 1, 0); //clr si and set ack       
                //while( I2C->CON.SI == 0 );                        //poll si flag
        //send i2c stop
        DrvI2C_Ctrl(0, 1, 1, 0);    //clr si and set stop   发送停止位
        //DrvI2C_Close(I2C_PORT0);                           //关闭I2C
        }
}
 楼主| 发表于 2010-10-18 09:04:25 | 显示全部楼层
代码:
        //resive data
        I2C->DATA = 0XFF;
        for(n=0;n<(count-1);n++){
        DrvI2C_Ctrl(0, 0, 1, 1);    //clr si       
        while( I2C->CON.SI == 0 );                           //poll si flag
        *(byte+n)= I2C->DATA;                                                                   //读取数据
        }
        DrvI2C_Ctrl(0, 0, 1, 0);    //clr si       
        while( I2C->CON.SI == 0 );                           //poll si flag
        *(byte+n)= I2C->DATA;                                                                   //读取数据

读里程数据,测试结果:
应该输出 09 81 00 00  实际输出 01 00 00 06
发表于 2010-10-18 12:14:11 | 显示全部楼层

(原文件名:未标题-1 拷贝.jpg)

根据上面的M051描述的过程和你提供的代码,我给出一段完整连续读代码,请你参考。

1。不知道你的24CXX是多大的,你把送高位地址字节屏蔽了,应该是小容量的EEPROM
2。注意:address(开始地址)   以及  address+count(结束地址)的值必须是在该芯片同一个页地址范围内,不的跨页



/*i2c读数据*/
void read_i2c_byte(uint8_t *byte,uint32_t address,uint8_t count)
{
   uint8_t n;
   uint16_t i;

//send i2c start
    DrvI2C_Ctrl(1, 0, 1, 0);   //set start    发送启动位
    while (I2C->CON.SI == 0); //poll si flag
  
//send writer command
    I2C->DATA = 0XA0;    //发送写命令
    DrvI2C_Ctrl(0, 0, 1, 1);      //clr si   ===>最好应该 set ack,表示24CXX应该回ACK=1
    while( I2C->CON.SI == 0 );    //poll si flag

//send address high
//    I2C->DATA = (address>>8)&0XFF;
//    DrvI2C_Ctrl(0, 0, 1, 1);    //clr si and set ack
//    while( I2C->CON.SI == 0 );    //poll si flag
     
//send address low
    I2C->DATA = (address)&0XFF;   //发送地址
    DrvI2C_Ctrl(0, 0, 1, 1);      //clr si and set ack
    while( I2C->CON.SI == 0 );    //poll si flag

//send start flag
   DrvI2C_Ctrl(1, 0, 1, 0);      //clr si and send start 发送启动位
   while( I2C->CON.SI == 0 );    //poll si flag

//send read command
   I2C->DATA = 0XA1;           //发送读命令
   DrvI2C_Ctrl(0, 0, 1, 1);    //clr si ===>最好应该 set ack,表示24CXX应该回ACK=1
   while( I2C->CON.SI == 0 );    //poll si flag

//resive data
   I2C->DATA = 0XFF;

   for(n=0;n<(count-1);n++){
      DrvI2C_Ctrl(0, 0, 1, 1);      //clr si  ===>这里肯定set ack,表示M051收到数据回ACK=1
      while( I2C->CON.SI == 0 );    //poll si flag
      *(byte+n)= I2C->DATA;         //读取数据
   }

   DrvI2C_Ctrl(0, 0, 1, 0);    //clr si
   while( I2C->CON.SI == 0 );    //poll si flag
   *(byte+n)= I2C->DATA;    //读取数据

//send i2c stop
  DrvI2C_Ctrl(0, 1, 1, 0);    //clr si and set stop   发送停止位
  DrvI2C_Close(I2C_PORT0);    //关闭I2C
}
 楼主| 发表于 2010-10-18 12:55:38 | 显示全部楼层
谢谢马潮老师,您是对的,代码已验证是能正确读写多字节。


再次表示感谢!


//send read command  
   I2C->DATA = 0XA1;           //发送读命令  
   DrvI2C_Ctrl(0, 0, 1, 1);    //clr si ===>最好应该 set ack,表示24CXX应该回ACK=1  
   while( I2C->CON.SI == 0 );    //poll si flag  
--------------------
试了,这里设不设应答都能得到正确结果。

呵呵,确信您能提供我们需要的培训!
发表于 2010-10-18 13:41:25 | 显示全部楼层
恭喜我通过你的考核。

下面还是要提醒的是关于是否使用“官方库”的问题。

你的代码肯定使用了官方的库,函数DrvI2C_Ctrl()就是这个库中的。下面是它的原形。

void DrvI2C_Ctrl(uint8_t start, uint8_t stop, uint8_t intFlag, uint8_t ack)
{       
        uint32_t Reg = 0;
               
        if (start)
                Reg |= I2C_STA;
        if (stop)
            Reg |= I2C_STO;
        if (intFlag)
                Reg |= I2C_SI;
        if (ack)
                Reg |= I2C_AA;

        *((__IO uint32_t *)&I2C->CON) = (*((__IO uint32_t *)&I2C->CON) & ~0x3C) | Reg;                   
}

其实就是一个对I2C->CON寄存器赋值,从这里可以看出使用库效率是如何的。

官方同时还提供了直接操作寄存器的例子,我也贴出代码,你可以比较代码的效率,选择采用什么方式来编写自己的代码

/*-----------------------------------------------------------------------------
  Function:                Read_Page                                                                        
                                                                                                         
  Parameter:                                                                                                                                                                                          
                        None                                    
  Returns:                                                                                                
                       None                                                                                      
  Description:                                                                                            
                       Read out pages have been written and verify them.                                    
*-----------------------------------------------------------------------------*/
void Read_Page(void)
{
    uint8_t ucPage, ucRead_Byte;

    // START
    I2CON |= STA;         
    I2CON |= SI;                                       //Clear SI
    while ((I2CON & SI) != SI);                        //Check SI set or not
    I2CON &= ((~STA)&(~SI));                           //STA needs to be cleared after START codition is generated

    if (I2STATUS != 0x08)                              //Check status value after every step
    {
        LED = ERROR_CODE;
        while (1);
    }

    //Control byte (SLA+W)  
    I2DAT = EEPROM_SLA | EEPROM_WR;
    I2CON |= SI;
    while ((I2CON & SI) != SI);

    if (I2STATUS != 0x18)              
    {
        LED = ERROR_CODE;
        while(1);
    }

    //Address High (DATA)
    I2DAT = 0;
    I2CON |= SI;
    while ((I2CON & SI) != SI);

    if (I2STATUS != 0x28)              
    {
        LED = ERROR_CODE;
        while (1);
    }

    //Address Low (DATA)
    I2DAT = 0;
    I2CON |= SI;
    while ((I2CON & SI) != SI);
    if (I2STATUS != 0x28)              
    {
        LED = ERROR_CODE;
        while (1);
    }

    // Repeated START
    I2CON |= STA;         
    I2CON |= SI;                                       //Clear SI
    while ((I2CON & SI) != SI);                        //Check SI set or not
    I2CON &= ((~STA)&(~SI));                           //STA needs to be cleared after START codition is generated

    if (I2STATUS != 0x10)                              //Check status value after every step
    {
        LED = ERROR_CODE;
        while (1);
    }

    //Control byte (SLA+R)  
    I2DAT = EEPROM_SLA | EEPROM_RD;
    I2CON |= SI;
    while ((I2CON & SI) != SI);

    if (I2STATUS != 0x40)              
    {
        LED = ERROR_CODE;
        while (1);
    }

    I2CON |= AA;

    for (ucPage = 0; ucPage <= 15; ucPage++)    //Read Microchip 24xx256 first 16 pages
    {
        //Data
        for (ucRead_Byte = 0; ucRead_Byte <= (PAGE_SIZE - 1); ucRead_Byte++)
        {
            I2CON |= SI;
            while ((I2CON & SI) != SI);
            if (I2STATUS != 0x50)              
            {
                LED = ERROR_CODE;
                while (1);
            }

   
            if (I2DAT != (ucPage))                     //Verify
            {
                LED = ERROR_CODE;
                while (1);
            }
        }
    }   

    //send a NACK to disconnect 24xx256
    I2CON &= (~AA);
    I2CON |= SI;
    while ((I2CON & SI) != SI);
        
    //STOP
    I2CON |= STO;
    I2CON |= SI;
    while (I2CON & STO);                               //To ensure STOP condition is generated, polling STO flag
}


实际上,不管采用哪种方式,都需要了解I2C的规程,了解M051的I2C接口是如何工作的,在这个方面是相同的。好象使用库可以少记几个具体位的名称和作用,但换得的代价是效率低,同时你也需要化时间去知道这个库函数的使用。更加可怕的是,如果库函数中有BUG,。。。。。
发表于 2010-10-18 14:27:40 | 显示全部楼层
系统如果需要大批量的连续读/写操作I2C,高效率的方法是使用I2C的中断。

这样大量的 while( I2C->CON.SI == 0 );    //poll si flag时间都可以省掉。要知道硬件I2C的速度在怎么高,也比不上MCU的指令执行速度。

如果你使用UNC系列,那么效率最高的是I2C中断触发DMA传送,这样,在连续的一个批量写/读过程中,CPU的干涉处理降到最少。
 楼主| 发表于 2010-10-19 22:08:20 | 显示全部楼层
对马老师的无私奉献精神表示钦佩!
受您的指点是我们的福分。

有些仪表有钟表功能,我们使用外部主晶振作为时钟源,通过定时器定时唤醒芯片来处理计时,看了半天M051手册,休眠时只有10K时钟能工作,实现不了钟表功能精度。看来只能使用nuc100的芯片了,这个有32k外部晶振。
仪表非工作状态电流要求:<2mA
有钟表的一般做到4mA
发表于 2010-10-19 23:29:55 | 显示全部楼层
如果需要做真正的RTC,我建议还是采用专用的RTC芯片,精度好,耗电少,系统软件设计还剩了不少麻烦事情。一旦MCU跑非,时钟总是正确的。(有些系统当MCU跑飞后,可以通过DOG等措施拉回正常,尽管时间短,外观上没有影响系统工作,但实际时钟系统已经不正常了,至少需要重新设置正确的RTC时间)

专用RTC芯片也不贵,核算M051+RTC芯片与NUC100不会差多少,但RTC系统好多了,系统设计也简单很多。

带RTC功能的MCU做不到实际上的真正的RTC,你能保证MCU永远运行正常吗,系统不会掉电吗。我做过实验,断电后,用一个470u的电容供RTC专用芯片工作,可以保证48小时正常。

如果不是真正的RTC,而且系统经常处于断电不使用状态,那么10K的时钟也能做RTC。

拿一个手机,把电池拿掉,放上几小时,然后上电池打开,如果发现时钟不对了,需要设置,就是假的RTC。如果时钟正确,就是真的RTC。

你的仪表需要哪种?
 楼主| 发表于 2010-10-20 09:17:22 | 显示全部楼层
仪表上只显示小时和分钟

仪表不会断电,但芯片干扰复位是有的。

10K时钟精度很差,+-50%

rtc芯片不错,但不知价格如何?



-----------------------------
这个应该可以
PCF8563,价格0.70元, i2c接口

点击此处下载 ourdev_591426WXBS0L.pdf(文件大小:232K) (原文件名:pcf8563.pdf)
发表于 2010-10-20 10:35:14 | 显示全部楼层
回复【16楼】sde_arm9
仪表上只显示小时和分钟
仪表不会断电,但芯片干扰复位是有的。
10k时钟精度很差,+-50%
rtc芯片不错,但不知价格如何?
-----------------------------
这个应该可以
pcf8563,价格0.70元, i2c接口
点击此处下载  
-----------------------------------------------------------------------

仪表不会断电,但芯片干扰复位是有的。===》那么你用MCU构成的RTC也就失效了。

既然仪表不会断电,那么串个二极管给RTC芯片供电,并上470u电容。如果万一仪表断电,至少RTC还能工作48小时。

一片RTC才0.7元(我的概念在1-2元,零售),系统软件相应也简单了,自己盘算。

再下去要付培训费了。这样的培训上哪找,价格很高的。
 楼主| 发表于 2010-10-21 10:17:53 | 显示全部楼层
哈哈!
这样的培训真的没处找,付费付费
发表于 2010-10-21 22:22:23 | 显示全部楼层
请问马老师,
为什么我在vista下面先装MDK4.12,然后装Nu-Link_Keil_Driver.exe,打开MDK,然后新建project,找不到新塘的M0系列,只能找到NUC系列呢???
发表于 2010-10-27 16:03:41 | 显示全部楼层
你们都犀利!我无语。
发表于 2010-12-4 13:58:48 | 显示全部楼层
华邦的这个例程不怎么样,没一点i2c的风格,那个回调函数的例程还有些模样。
发表于 2013-3-20 10:01:22 | 显示全部楼层
和马老师的想法一样,坚持使用寄存器的路过
发表于 2014-4-27 21:05:56 | 显示全部楼层
路过路过了  顺便看看
友情提示:标题不合格、重复发帖,将会被封锁ID。详情请参考:论坛通告:封锁ID、获得注册邀请码、恢复被封ID、投诉必读
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|阿莫电子论坛(原ourAVR/ourDEV) ( 公安备案:44190002001997(交互式论坛) 工信部备案:粤ICP备09047143号 )

GMT+8, 2019-9-18 22:47

阿莫电子论坛, 原"中国电子开发网"

© 2004-2018 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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