Close
技术支持
在线客服
在线客服
在线客服
嵌入式LED点阵显示、LED数显、无线遥控、信息采集系统开发!
引导页 中文版 English

数字LED显示屏

PLC显示屏(集成modbus&profibus协议)

电子看板003

电子看板004

PLC显示屏(自由口RS485通讯)

电子看板006

电子看板007

电子看板008

PLC显示屏

电子看板010

 
 
网络时钟RTL8019AS的同步工作流程
  • 点击381
  • 发布:2011-5-16
  •        ledsup-083a用的网络芯片是rtl8019as,但是在移植u-boot到开发板的时候,网络的移植出了一点问题。所以想看看rtl8019as这个网卡是如何工作的,很不幸的是,正如网络上很多人说的那样,rtl8019的文档及其的烂,真的不是一般的烂。基本上看过它的文档,跟没看过没什么区别。现将网络同步时钟的网卡工作过程详细讲述一下。

    rtl8019as网卡的功能:

    一句话来说,网卡所完成的功能就是收发数据。

    • 接收功能:从网络上接收数据,然后存储于网卡内部的RAM(本网卡为16KB)中,然后触发中断,通知CPU来取走数据。
    • 发送功能:CPU发送的数据被复制到网卡内部的RAM中,然后网卡自主的在网络上发送这些数据。

           由此可见,对于程序员来说,网卡其实就是一片内存区域。程序员对网卡的操作实际上可以认为是对内存的读写操作。当网络上有数据传来时,LED时钟网卡存储这些数据到内存,并通知CPU到内存的相应位置取相应大小的数据。当时钟CPU想向网络上传输数据时,只需要将数据写入网卡的内存,然后给网卡一个”发送”命令即可。就是这么简单。

           很明显的,网络数据是一个层次性很强的东西,OSI就规定了网络的7层协议,TCP/IP规定了5层协议,从数据上来说,tcp帧作为IP帧的数据被打包进IP帧,而IP帧又作为以太网帧的数据被打包进以太网帧。如上所述,CPU跟网卡的交互就是数据的读和写”数据”,但是,这个数据到底是什么数据呢?我们该怎么理解从同步时钟的网卡中接收到的二进制数据呢?我应该认为它是一帧IP帧,还是一帧以太网帧呢?我们写内存来发送数据,那么,我们发送的应该是什么格式的数据呢?我们是打包成IP数据,还是需要打包成以太网数据呢?接收和发送的数据的帧格式并不一样,如下图所示:

    图片

           由上图可见,LED电子时钟只需要将如上图所示的IP帧写入RAM中,其余的就叫给网卡去办就可以了。而接收的数据,其实是一个修改过了的IP帧,整体还是在IP这个层次上。由此可见,对于网络数据,应用层程序只需要处理到IP层,将数据打包成变形的IP帧即可。至于将IP帧打包成以太网帧然后在网络上传输,这些功能都是时钟网卡自己完成的。接收数据也是一样,从网卡的RAM中接收到的数据就是变形的IP帧,至于底层的物理链路数据和以太帧的解析,这些都是网卡完成的。也就是说,IP层以下的处理,对于程序员来说,是透明的。

           时钟网络组件联网同步芯片RTL8019AS寄存器介绍:
           1、rtl8019as的工作机制以及原理:
                  网络时钟接收:rtl8019as的RAM是一个循环RAM空间,当网卡从网络上接收到数据后,会按照RAM地址从小到大依次存放接收到的数据。但是RAM的空间只有16K,而且,有一部分还是划为用来做发送缓存,另外的那一部分才是用来做接收缓存的。当网络上的数据超过了缓存的大小怎么办呢?这里就需要介绍一些,rtl8019as的RAM是一种循环RAM,所谓循环RAM,比如说用来做接收缓存的RAM的页是从50页~80页,接收的数据从第50页开始存放,一直存放到第80页。当接收的数据过多,超过了上限的第80页时,再接收到的数据就会重新从第50页开始依次从低到高存放!当然,时钟CPU也在同时的从RAM中读取走数据,所以只要安排得当,采用循环RAM,还是有可能不会将原先的数据冲掉的。而且RAM的利用率将会得到提高。那么怎么样才叫安排得当呢?在实际的机制中,引入了CURR和BNRY这两个”指针”(两个实际的寄存器)。这两个寄存器都是存放的RAM的页地址(rtl8019as也是以页为单位存储的)CURR表示如果网卡接收到了数据,应该从CURR页开始存放。而且这个CURR寄存器的值是网卡自动为它赋值的,每填满一个页,CURR寄存器的值就增加1,表示下一次有数据来的时候从下一个页开始存放。BNRY表示,CPU已经从RAM中接收的数据,到BNRY页为止,就是BNRY+1页的数据还没有被CPU取走。CPU下来再来取数据的时候就应该从BNRY+1页来取数据。那么可以想见,当网卡从网络上接收到数据,已经超过了接收缓冲的上限,重新从下限开始存放的时候,只要我不存放到超过BNRY页,都是不会引起将原来被有被CPU取走的数据覆盖的,不是么?正是这样。这真是一个很好的方法啊。
                  网络时钟发送:相对于接收,发送功能就要简单一点了。应用程序只需要将数据写入到RAM中,想网卡发出发送命令即可完成数据向网络的发送了(置RD2,RD1,RD0的值为011即可),当网口通知CPU有数据到来,或者CPU检测到RAM中有数据需要读取的时候,设置两个地址值RSAR和RBCR。RSAR0,1:要读取的数据的起始地址,RBCR0,1:要读取的数据的大小(可以以字节为单位),然后我们从数据寄存器中读取数据,每读取一次,数据寄存器中所指向的地址就会增加1。其寄存器变化原理图如下:

     图片
     

           2、CR的位定义如下:
                  时钟内部寄存器7,6bit是用来选寄存器的页的,设置完之后,对01~20的寄存器的操作
                  设置5-3bit位下列值时有不同的功能:
                         设置RD2RD1RD0=000->表示启动网卡的remote读功能,此时可以从BNRY开始通过DMA从RAM中读出数据
                         设置RD2RD1RD0=010->表示启动网卡的remote写功能,此时可以从TPSR开始通过DMA写入数据到RAM中去
                         设置RD2RD1RD0=100->表示启动网卡的向外传输数据功能,当bit2被置位,则网卡启动传输,开始向网络传输
                  具体如下图:

    图片

           3、RSR:接收状态寄存器

    图片

           4、RCR:接受配置寄存器

    图片


     

     

    了解网卡的工作流程,分析分析驱动程序是再好不过的方式了。

    网上流传的rtl8019as的驱动还是比较多版本的,这里用的是U-boot-1.1.6中的rtl8019as的驱动:

    //定义Page的地址

    #define         RTL8019_REG_00                  (RTL8019_BASE + 0x00<<1)

    #define         RTL8019_REG_01                  (RTL8019_BASE + 0x01<<1)

    #define         RTL8019_REG_02                  (RTL8019_BASE + 0x02<<1)

    #define         RTL8019_REG_03                  (RTL8019_BASE + 0x03<<1)

    #define         RTL8019_REG_04                  (RTL8019_BASE + 0x04<<1)

    #define         RTL8019_REG_05                  (RTL8019_BASE + 0x05<<1)

    #define         RTL8019_REG_06                  (RTL8019_BASE + 0x06<<1)

    #define         RTL8019_REG_07                  (RTL8019_BASE + 0x07<<1)

    #define         RTL8019_REG_08                  (RTL8019_BASE + 0x08<<1)

    #define         RTL8019_REG_09                  (RTL8019_BASE + 0x09<<1)

    #define         RTL8019_REG_0a                  (RTL8019_BASE + 0x0a<<1)

    #define         RTL8019_REG_0b                  (RTL8019_BASE + 0x0b<<1)

    #define         RTL8019_REG_0c                  (RTL8019_BASE + 0x0c<<1)

    #define         RTL8019_REG_0d                  (RTL8019_BASE + 0x0d<<1)

    #define         RTL8019_REG_0e                  (RTL8019_BASE + 0x0e<<1)

    #define         RTL8019_REG_0f                  (RTL8019_BASE + 0x0f<<1)

    #define         RTL8019_REG_10                  (RTL8019_BASE + 0x10<<1)

    #define         RTL8019_REG_1f                  (RTL8019_BASE + 0x1f<<1)

     

    //将物理寄存器映射为各种功能寄存器,方便理解

    #define         RTL8019_COMMAND                 RTL8019_REG_00  //CR寄存器

    #define         RTL8019_PAGESTART               RTL8019_REG_01  //接收缓冲启始位置

    #define         RTL8019_PAGESTOP                RTL8019_REG_02  //接收缓冲结束位置

    #define         RTL8019_BOUNDARY                RTL8019_REG_03  //Boundary寄存器

    #define         RTL8019_TRANSMITSTATUS          RTL8019_REG_04  //传输状态寄存器

    #define         RTL8019_TRANSMITPAGE            RTL8019_REG_04  //传输开始page

    #define         RTL8019_TRANSMITBYTECOUNT0      RTL8019_REG_05  //传输字节数低8位

    #define         RTL8019_NCR                     RTL8019_REG_05  //冲突次数

    #define         RTL8019_TRANSMITBYTECOUNT1      RTL8019_REG_06  //传输字节数高8位

    #define         RTL8019_INTERRUPTSTATUS         RTL8019_REG_07  //中断状态寄存器

    #define         RTL8019_CURRENT                 RTL8019_REG_07  //CURRENT寄存器

    #define         RTL8019_REMOTESTARTADDRESS0     RTL8019_REG_08  //接收数据起始地址低8位

    #define         RTL8019_CRDMA0                  RTL8019_REG_08

    #define         RTL8019_REMOTESTARTADDRESS1     RTL8019_REG_09  //接收数据起始地址高8位

    #define         RTL8019_CRDMA1                  RTL8019_REG_09

    #define         RTL8019_REMOTEBYTECOUNT0        RTL8019_REG_0a  //接收数据字节大小低8位

    #define         RTL8019_REMOTEBYTECOUNT1        RTL8019_REG_0b  //接收数据字节大小高8位

    #define         RTL8019_RECEIVESTATUS           RTL8019_REG_0c  //接收状态寄存器

    #define         RTL8019_RECEIVECONFIGURATION    RTL8019_REG_0c  //接收配置寄存器

    #define         RTL8019_TRANSMITCONFIGURATION   RTL8019_REG_0d  //发送接收寄存器

    #define         RTL8019_FAE_TALLY               RTL8019_REG_0d

    #define         RTL8019_DATACONFIGURATION       RTL8019_REG_0e  //数据配置寄存器

    #define         RTL8019_CRC_TALLY               RTL8019_REG_0e

    #define         RTL8019_INTERRUPTMASK           RTL8019_REG_0f  //中断屏蔽寄存器

    #define         RTL8019_MISS_PKT_TALLY          RTL8019_REG_0f

    #define         RTL8019_PHYSICALADDRESS0        RTL8019_REG_01  //MAC地址0

    #define         RTL8019_PHYSICALADDRESS1        RTL8019_REG_02

    #define         RTL8019_PHYSICALADDRESS2        RTL8019_REG_03

    #define         RTL8019_PHYSICALADDRESS3        RTL8019_REG_04

    #define         RTL8019_PHYSICALADDRESS4        RTL8019_REG_05

    #define         RTL8019_PHYSICALADDRESS5        RTL8019_REG_06

    #define         RTL8019_MULTIADDRESS0           RTL8019_REG_08  //多播地址配置

    #define         RTL8019_MULTIADDRESS1           RTL8019_REG_09

    #define         RTL8019_MULTIADDRESS2           RTL8019_REG_0a

    #define         RTL8019_MULTIADDRESS3           RTL8019_REG_0b

    #define         RTL8019_MULTIADDRESS4           RTL8019_REG_0c

    #define         RTL8019_MULTIADDRESS5           RTL8019_REG_0d

    #define         RTL8019_MULTIADDRESS6           RTL8019_REG_0e

    #define         RTL8019_MULTIADDRESS7           RTL8019_REG_0f

    #define         RTL8019_DMA_DATA                RTL8019_REG_10  //DMA传输寄存器(读出/写入)

    #define         RTL8019_RESET                   RTL8019_REG_1f  //NIC复位寄存器

     

    //定义一些用来设置寄存器的值

    #define         RTL8019_PAGE0                   0x22  //0010 0010

    #define         RTL8019_PAGE1                   0x62  //0110 0010

    #define         RTL8019_PAGE0DMAWRITE           0x12  //0001 0010

    #define         RTL8019_PAGE2DMAWRITE           0x92  //1001 0010

    #define         RTL8019_REMOTEDMAWR             0x12  //0001 0010

    #define         RTL8019_REMOTEDMARD             0x0A  //0000 1010

    #define         RTL8019_ABORTDMAWR              0x32  //0011 0010

    #define         RTL8019_ABORTDMARD              0x2A  //0010 1010

    #define         RTL8019_PAGE0STOP               0x21  //0010 0001

    #define         RTL8019_PAGE1STOP               0x61  //0110 0001

    #define         RTL8019_TRANSMIT                0x26  //0010 0110

    #define         RTL8019_TXINPROGRESS            0x04  //0000 0100

    #define         RTL8019_SEND                    0x1A  //0001 1010

     

    #define         RTL8019_PSTART                  0x4c  //0100 1100

    #define         RTL8019_PSTOP                   0x80  //1000 0000

    #define         RTL8019_TPSTART                 0x40  //0100 0000

     

    static void eth_reset (void)

    {

            unsigned char ucTemp;

     

            /* reset NIC */

            //向reset寄存器中写入任何值就可以完成NIC的reset

            ucTemp = get_reg (RTL8019_RESET);

            put_reg (RTL8019_RESET, ucTemp);

            //清除所有的中断位

            put_reg (RTL8019_INTERRUPTSTATUS, 0xff);

            udelay (2000);          /* wait for 2ms */

    }

     

    int eth_init (bd_t * bd)

    {

            //初始化NIC

            eth_reset ();

            put_reg (RTL8019_COMMAND, RTL8019_PAGE0STOP);//选择page0,停机状态

            put_reg (RTL8019_DATACONFIGURATION, 0x48);//设置为loopback模式,且DMA为8位模式

            put_reg (RTL8019_REMOTEBYTECOUNT0, 0x00);//清除接收数据寄存器

            put_reg (RTL8019_REMOTEBYTECOUNT1, 0x00);

            put_reg (RTL8019_RECEIVECONFIGURATION, 0x00);   //瞎写

            put_reg (RTL8019_TRANSMITPAGE, RTL8019_TPSTART);//传输起始page设为Page40

            put_reg (RTL8019_TRANSMITCONFIGURATION, 0x02);//传输配置,loopback模式(跟DCR配对,均需设置)

            put_reg (RTL8019_PAGESTART, RTL8019_PSTART);//接收数据起始page设置为Page4c

            put_reg (RTL8019_BOUNDARY, RTL8019_PSTART);//Boundary初始化为page4c

            put_reg (RTL8019_PAGESTOP, RTL8019_PSTOP);//接收数据边界页为Page80

            put_reg (RTL8019_INTERRUPTSTATUS, 0xff);//清除所有中断寄存位

            put_reg (RTL8019_INTERRUPTMASK, 0x11);  //只允许第0位和第4位中断

            put_reg (RTL8019_COMMAND, RTL8019_PAGE1STOP);//选择page1,停机状态

            put_reg (RTL8019_PHYSICALADDRESS0, bd->bi_enetaddr[0]);//设置MAC地址

            put_reg (RTL8019_PHYSICALADDRESS1, bd->bi_enetaddr[1]);

            put_reg (RTL8019_PHYSICALADDRESS2, bd->bi_enetaddr[2]);

            put_reg (RTL8019_PHYSICALADDRESS3, bd->bi_enetaddr[3]);

            put_reg (RTL8019_PHYSICALADDRESS4, bd->bi_enetaddr[4]);

            put_reg (RTL8019_PHYSICALADDRESS5, bd->bi_enetaddr[5]);

            put_reg (RTL8019_MULTIADDRESS0, 0x00);//设置多播地址(设置的值是什么意思呢??)

            put_reg (RTL8019_MULTIADDRESS1, 0x00);

            put_reg (RTL8019_MULTIADDRESS2, 0x00);

            put_reg (RTL8019_MULTIADDRESS3, 0x00);

            put_reg (RTL8019_MULTIADDRESS4, 0x00);

            put_reg (RTL8019_MULTIADDRESS5, 0x00);

            put_reg (RTL8019_MULTIADDRESS6, 0x00);

            put_reg (RTL8019_MULTIADDRESS7, 0x00);

            put_reg (RTL8019_CURRENT, RTL8019_PSTART);//设置CURRENT寄存器为Page4c

            put_reg (RTL8019_COMMAND, RTL8019_PAGE0);//选择Page0,且NIC开机(处于开机状态,使其能够接收数据)

            put_reg (RTL8019_TRANSMITCONFIGURATION, 0xe0);//设置传输模式为1110 0000

                                                          //正常模式(非loopback模式),CRC使能

            return 0;

    }

     

    static unsigned char nic_to_pc (void)

    {//返回接收操作完成之后的CURRENT寄存器值

     //该函数完成的功能是从boundary寄存器中存储的地址开始接收一帧的数据

            unsigned char rec_head_status;

            unsigned char next_packet_pointer;

            unsigned char packet_length0;

            unsigned char packet_length1;

            unsigned short rxlen = 0;

            unsigned int i = 4;

            unsigned char current_point;

            unsigned char *addr;

     

            /*

             * The RTL8019's first 4B is packet status,page of next packet

             * and packet length(2B).So we receive the fist 4B.

             */

            //rtl8019as的帧的头4Byte如上所述:

            //第一字节为status

            //第二字节为下一个帧的起始Page

            //第3,4字节为本帧的长度,以字节为单位

            put_reg (RTL8019_REMOTESTARTADDRESS1, get_reg (RTL8019_BOUNDARY));

            put_reg (RTL8019_REMOTESTARTADDRESS0, 0x00);//因为实际接收地址是boundary<<8,所以低8位地址恒定为0

            put_reg (RTL8019_REMOTEBYTECOUNT1, 0x00);

            put_reg (RTL8019_REMOTEBYTECOUNT0, 0x04);//从接收缓冲区中接收4字节的数据

     

            put_reg (RTL8019_COMMAND, RTL8019_REMOTEDMARD);//在CR中设置接收位为001(Remote Read)

     

            rec_head_status = get_reg (RTL8019_DMA_DATA);//读第一个字节

            next_packet_pointer = get_reg (RTL8019_DMA_DATA);//读第二个字节

            packet_length0 = get_reg (RTL8019_DMA_DATA);//第三个字节

            packet_length1 = get_reg (RTL8019_DMA_DATA);//第四个字节

     

            put_reg (RTL8019_COMMAND, RTL8019_PAGE0);//设置CR为Page0

            /*Packet length is in two 8bit registers */

            rxlen = packet_length1;

            rxlen = (((rxlen < < 8) & 0xff00) + packet_length0);

            rxlen -= 4;

            if (rxlen > PKTSIZE_ALIGN + PKTALIGN)

                    printf ("packet too big!\n");

            /*Receive the packet */

            put_reg (RTL8019_REMOTESTARTADDRESS0, 0x04);//配置DMA的读取起始地址(减去了4个字节)

            put_reg (RTL8019_REMOTESTARTADDRESS1, get_reg (RTL8019_BOUNDARY));

     

            put_reg (RTL8019_REMOTEBYTECOUNT0, (rxlen & 0xff));//配置DAM读取长度

            put_reg (RTL8019_REMOTEBYTECOUNT1, ((rxlen >> 8) & 0xff));

     

            put_reg (RTL8019_COMMAND, RTL8019_REMOTEDMARD);//设置CR为READ状态

     

            //这里是8位DMA的情况,16位DMA的情况需要做调整,每次能够读出16位的数据

            for (addr = (unsigned char *) NetRxPackets[0], i = rxlen; i > 0; i--)

                    *addr++ = get_reg (RTL8019_DMA_DATA);

            /* Pass the packet up to the protocol layers. */

            NetReceive (NetRxPackets[0], rxlen);//将接收到的数据交给上层协议处理

     

            while (!(get_reg (RTL8019_INTERRUPTSTATUS)) & 0x40);    /* wait for the op. */

            //等待DMA操作结束(RDC位被自动置位的时候表示DMA操作结束)

            /*

             * To test whether the packets are all received,get the

             * location of current point

             */

            put_reg (RTL8019_COMMAND, RTL8019_PAGE1);

            current_point = get_reg (RTL8019_CURRENT);

            put_reg (RTL8019_COMMAND, RTL8019_PAGE0);

            put_reg (RTL8019_BOUNDARY, next_packet_pointer);//将下一帧的起始页数写入到boundary中

                                                            //这里难道不需要考虑boundary>80的情况吗????

            return current_point;

    }

     

    /* Get a data block via Ethernet */

    extern int eth_rx (void)

    {

            unsigned char temp, current_point;

     

            put_reg (RTL8019_COMMAND, RTL8019_PAGE0);//选取Page0,开机状态

     

            while (1) {

                    temp = get_reg (RTL8019_INTERRUPTSTATUS);

     

                    if (temp & 0x90) {

                            /*中断寄存器为90表示接收数据太快,接收缓冲被用完了,此时由于循环RAM的缘故,CURRENT=BOUNDARY*/

                            put_reg (RTL8019_COMMAND, RTL8019_PAGE0STOP);//停机

                            udelay (2000);

                            put_reg (RTL8019_REMOTEBYTECOUNT0, 0);

                            put_reg (RTL8019_REMOTEBYTECOUNT1, 0);

                            put_reg (RTL8019_TRANSMITCONFIGURATION, 2);//进入内部loopback模式

                            do {

                                    //反复读取缓冲中的值,直到boundary==current(注意这时current_point是不变的!!)

                                    current_point = nic_to_pc ();

                            } while (get_reg (RTL8019_BOUNDARY) != current_point);

     

                            put_reg (RTL8019_TRANSMITCONFIGURATION, 0xe0);//推出loopback模式,设置传输配置寄存器为普通模式

                    }

     

                    if (temp & 0x1) {//如果有帧被顺利的接收到,会自动给bit0置位

                            /*packet received */

                            do {

                                    //反复读取直到NIC收到的数据全部被CPU接收

                                    put_reg (RTL8019_INTERRUPTSTATUS, 0x01);//清除bit0

                                    current_point = nic_to_pc ();

                            } while (get_reg (RTL8019_BOUNDARY) != current_point);//这个条件对么?还是应该用burndary+1 == current_point来判断???

                    }

     

                    if (!(temp & 0x1))//如果没有数据收到则退出

                            return 0;

                    /* done and exit. */

            }

    }

     

    /* Send a data block via Ethernet.发送 */

    extern int eth_send (volatile void *packet, int length)

    {

            volatile unsigned char *p;

            unsigned int pn;

     

            pn = length;

            p = (volatile unsigned char *) packet;

     

            while (get_reg (RTL8019_COMMAND) == RTL8019_TRANSMIT);//等待上一次传输结束

     

            put_reg (RTL8019_REMOTESTARTADDRESS0, 0);//设置传输起始地址

            put_reg (RTL8019_REMOTESTARTADDRESS1, RTL8019_TPSTART);

            put_reg (RTL8019_REMOTEBYTECOUNT0, (pn & 0xff));//设置传输长度

            put_reg (RTL8019_REMOTEBYTECOUNT1, ((pn >> 8) & 0xff));

     

            put_reg (RTL8019_COMMAND, RTL8019_REMOTEDMAWR);//标明处于WRITE状态,TPX为0

            while (pn > 0) {

                    put_reg (RTL8019_DMA_DATA, *p++);

                    pn--;

            }

     

            pn = length;

            //如果数据长度小于60个字节时,则自动以0补全

            while (pn < 60) {

                    /*Padding */

                    put_reg (RTL8019_DMA_DATA, 0);

                    pn++;

            }

            while (!(get_reg (RTL8019_INTERRUPTSTATUS)) & 0x40);//等待DMA操作结束(发送结束)

            put_reg (RTL8019_INTERRUPTSTATUS, 0x40);清除相应中断位

            put_reg (RTL8019_TRANSMITPAGE, RTL8019_TPSTART);复位传输起始page

            put_reg (RTL8019_TRANSMITBYTECOUNT0, (pn & 0xff));设置传输字节大小

            put_reg (RTL8019_TRANSMITBYTECOUNT1, ((pn >> 8 & 0xff)));

            put_reg (RTL8019_COMMAND, RTL8019_TRANSMIT);//哦,恍然大悟

            //此处是启动NIC通过网卡向外发送数据,上面的REMOTEDMAWR是使NIC进入DMA状态,以便从CPU传数据到发送缓冲中去。

     

            return 0;

    }

            最终,网络同步授时LED时钟将会正确获取网络NTP服务器的时间信息,并显示出年、月、日、时、分、秒、星期等信息,具体农历的计算请参考我们发布的时钟农历计算方法。



    地址:深圳市福田区上沙村忠合广场A座  电话:0796-7203100 传真:0796-7203100-8005
    版权所有:深圳市立显电子有限公司  技术支持:天地盟网络 [粤ICP09009496]
    本站所有产品资料专属于深圳立显光电,未经许可不得擅自非法转载.