JZ2440 裸机驱动 第12章 I2C接口

本章目标:
了解I2C总线协议;
掌握S3C2410/S3C2440中I2C接口的使用方法;
12.1 I2C总线协议及硬件介绍
12.1.1 I2C总线协议
1 I2C总线的概念
2 I2C总线的信号类型
3 I2C总线的数据传输格式
12.1.2 S3C2410/S3C2440 I2C总线控制器
1. S3C2410/S3C2440 I2C总线控制器寄存器介绍
    S3C2410/S3C2440的I2C接口有4种工作模式:主机发送、主机接收、从机发送、
从机接收。其内部结构如图12.6所示。
    从图12.6可知,S3C2410/S3C2440提供4个寄存器来完成所有的I2C操作。SDA线上的数据
从IICDS寄存器发出,或传入IICDS寄存器中;IICADD寄存器中保存S3C2410/S3C2440当做从
机时的地址;IICCON、IICSTAT 两个寄存器用来控制或标识各种状态,比如选择工作模式,发出
S信号、P信号,决定是否发出ACK信号,检测是否收到ACK信号。各寄存器的用法如下:
(1)IICCON寄存器(Multi-master IIC-bus control)
    IICCON寄存器用于控制是否发出ACK信号、设置发送器的时钟、开启IIC中断,并标识中断是
发生。它的各位含义如下表12.2所示。
     使用IICCON寄存器时,有如下注意事项:
    ① 发送模式的时钟频率由位[6]、位[3:0]联合决定。另外,当IICCON[6] = 0时,IICCON[3:0]
不能去0或1。
    ② IIC中断在以下3种情况下发生:
        当发出地址信息或接收到一个从机地址并且吻合时;
        当总线仲裁失败时;
        当发送/接收完一个字节的数据(包括响应位)时。
    ③ 基于SDA 、SCL线上时间特性的考虑,要发送数据时,先将数据写入IICDS寄存器,
然后清除中断。
    ④ 如果IICCON[5] = 0,IICCON[4]将不能正常工作。所以即使不使用IIC中断,也要将
IICCON[5]设为1。
(2)IICSTAT寄存器(Multi-master IIC-bus control/status)。
    IICSTAT寄存器用于选择IIC接口的工作模式,发出S信号、P信号,使能接收/发送功能,
并标识各种状态,比如总线仲裁是否成功、作为从机时是否被寻址、是否接收到0地址、是
否接收到ACK信号等。
    IICSTAT寄存器的各位如表12.3所示:
(3)IICADD寄存器(Multi-master IIC-bus address)
    用到位[7:1],表示从机地址。在IICSTAT[4]为1时,才可以写入;随时都可以读出。
(4)IICDS寄存器(Multi-master IIC-bus Tx/Rx data shift)
    用到位[7:0],其中保存的是要发送或已经接收到的数据。在IICSTAT[4]为1时才可写入,
随时可以读出。
2.S3C2410/S3C2440 I2C总线操作方法
    启动或复位S3C2410/S3C2440 的IIC传输有以下两种方法。
(1)当IICCON[4]即中断状态位为0时,通过写IICSTAT寄存器启动IIC操作。有以下两种
情况。
    ① 在主机模式:
        令IICSTAT[5:4]等于0b11,将发出S信号和IICDS寄存器的数据(寻址),
        令IICSTAT[5:4]等于0b01,将发出P信号。
    ② 在从机模式,令IICSTAT[4]等于1,将等待其他主机发出S信号及地址信息。
(2)当IICCON[4]即中断状态位为1时,表示I2C操作被暂停。在这期间设置好其他寄存器
之后,向IICCON[4]写入0即可恢复I2C操作。
    所谓“设置其他寄存器”,有以下3种情况。
    ① 对于主机模式,可以按照上面(1)的方法写IICSTAT寄存器,恢复I2C操作后即可发出
S信号和IICDS寄存器的值(寻址),或发出P信号。
    ② 对于发送器,可以将下一个要发送的数据写入IICDS寄存器中,恢复I2C操作后即可发
出这个数据。
    ③ 对于接收器,可以从IICDS寄存器中读出接收到的数据。最后向IICCON[4]写入0的同时,
设置IICCON[7]以决定在接收到下一个数据后是否发出ACK信号。
 
    通过中断服务程序驱动I2C传输。
(1)当仲裁失败时,发生中断——本次传输没有抢到总线,可以稍后继续。
(2)对于主机模式,当发出S信号、地址信息并经过一个SCL周期(对应ACK信号)后,发生
中断——主机可在此时判断是否成功寻址到从机。
(3)对于从机模式,当接收到的地址与IICADD寄存器吻合时,先发出ACK信号,然后发生
中断——从机可在此时准备后续的传输。
(4)对于发送器,当发送完一个数据并经过一个SCL周期(对应ACK信号)后,发生中断。这
时可以准备下一个要发送的数据,或发出P信号以停止传输。
(5)对于接收器,当接收到一个数据时,先根据IICCON[7]决定是否发出ACK信号后,然后
发生中断。这是可以读取IICDS寄存器得到数据,并设置IICCON[7]已决定接收到下一个数
后是否发出ACK。
 
    对于4种工作模式,S3C2410/S3C2440数据手册中都有它们的操作流程图。现在以主机发
送器为例说明,它的工作流程如图12.7所示,其他的工作模式请参考数据手册。

    下面结合I2C寄存器的用法,详细讲解图12.7中各步骤的含义。
(1)配置主机发送器的各类参数
    设置GPE15、GPE14引脚用于SDA、SCL,设置IICCON寄存器选择I2C发送时钟,最后,
设置IICSTAT[4]为1,这样,后面才能写IICDS寄存器。
    注意:初始时IICCON[4]为0,不能将IICSTAT设为主机模式,否则就会立刻发出S信号、
发送IICDS寄存器里的值。
(2)将要寻址的从机地址写入IICDS寄存器。
(3)将0xF0写入IICSTAT寄存器,即设为主机发送器、使能串行输出功能、发出S信号。
(4)发出S信号后,步骤(2)中设置的IICDS寄存器值也将被发出,它用来寻址从机。
(5)在响应周期之后,发生中断,此时IICCON[4]为1,I2C传输暂停。
(6)如果没有数据要发送,则跳到步骤(10);否则跳到步骤(7)。
(7)将下一个要发送的数据写入IICDS寄存器中。
(8)向IICCON[4]中写入0,恢复I2C传输。
(9)这时,IICDS寄存器中的值将被一位一位地发送出去。当8位数据发送完毕,再经过
另一个SCL周期(对应ACK信号)后,中断再次发生,跳到步骤(5)。
    步骤(5)~(9)不断循环知道发出所有数据。当要停止传输时,跳到步骤(10)。
(10)将0xF0写入IICSTAT寄存器,即设为主机发送器、使能串行输出功能、发出P信号。
            注意:这时的P信号并没有实际发出,只有清除了IICCON[4]后才会发出P信号。
(11)清除IICCON[4],P信号得以发出。
(12)等待一段时间,使得P信号完全发出。
12.2 I2C总线操作实例
12.2.1 I2C接口RTC芯片M41t11的操作方法
    本书所用开发板中,通过I2C总线连接RTC(实时时钟)芯片M4lt11,它使用电池供电,
断电时也可以维持日期和时间。S3C2410/S3C2440作为I2C主机向M4lt11发送数据以设
置日期和时间、读取M4lt11以获取日期和时间。连接图如图12.8所示。
     M4lt11中有8个寄存器,分别对应秒、分、时、天(星期几)、日、月、年、控制寄存器,
其中的数据都是以BCD格式保存(BCD格式例子:0x15表示数值15),如表12.4所示。
     除上表的8个寄存器(地址为0~7)之外,M4lt11内部还有56字节的RAM(地址为8~63)。
访问M4lt11前,先设置寄存器地址,以后每次读写操作完成后,M4lt11内部会自动将寄
存器地址加1.
    所以读写M4lt11分以下两个步骤:
    (1)主机向M4lt11发出要操作的寄存器起始地址(0~7)。
    (2)要设置M4lt11时,主机连续发出数据;读取M4lt11时,主机连续读取数据。
    M4lt11的I2C从机地址为0xD0。
12.2.2 程序设计
    本实例将在串口上输出一个菜单,可以选择设置时间和日期,或者将它们读出来。将
通过本实例验证I2C主机的发送、接收操作。
12.2.3 设置/读取M4lt11的源码详解
    本实例的源码在/work/hardware/i2c目录下。
    文件i2c.c封装了S3C2410/S3C2440作为主机发送器、主机接收器的4个操作函数:
i2c_init用于初始化,i2c_write用于发起发送数据,i2c_read用于发起读取数据,
I2CIntHandle是I2C中断服务程序,用于完成后续的数据传输。
1.S3C2410/S3C2440 I2C控制器初始化
    i2c_init函数对应于图12.7中的步骤(1),初始化I2C,代码如下:
 1 行号
 2 24行/*
 3 25行 *I2C初始化
 4 26行 */
 5 27行 void i2c_init(void)
 6 28行 {
 7 29行    GPEUP |= 0xc000;        //禁止内部上拉
 8 30行    GPECON |= 0xa0000000;    //选择引脚功能,GPE15:IICSDA,GPE14:IICSCL
 9 31行
10 32行    INTMSK &= ~(BIT_IIC);
11 33行
12 34行    /*bit[7] = 1,使能ACK
13 35行     *bit[6] = 0,IICCLK = PCLK/16
14 36行     *bit[5] = 1,使能中断
15 37行     *bit[3:0] = 0xf,Tx clock = IICCLK/16
16 38行     *PCLK = 50MHz、IICCLK = 3.125MHz,Tx Clock = 0.195MHz
17 39行     */
18 40行    IICCON = (1 << 7) | (0 << 6) | (1 << 5) | (0xf);    //0xaf
19 41行
20 42行    IICADD  = 0x10;        //S3C24xx slave address = [7:1]
21 43行    IICSTAT = 0x10;        //I2C串行输出使能(Rx/Tx)
22 44行 }
23 45行
i2c.c->i2c_init()
    第32行在INTMSK寄存器中开启I2C中断,这样,以后调用i2c_read、i2c_write启动传
输时,即可触发中断,进而可以在中断服务程序中进一步完成后续的传输。
    第40行用于选择发送时钟,并进行一些设置:使能ACK、使能中断。
    第42行用于设置S3C2410/S3C2440作为I2C从机时的地址,本实例未用到。
    第43行使能I2C串行输出(设置IICSTAT[4]为1),这样,在i2c_write、i2c_read
函数中就可以写IICDS寄存器了。
2.S3C2410/S3C2440 I2C主机发送函数
    初始化完成后,就可以调用i2c_read、i2c_write读写I2C从机了。它们的使用方法从参数
名称就可以看出。这两个函数只是启动I2C传输,然后等待,知道数据在中断服务程序中传
输完毕后再返回。
    i2c_write函数的实现如下:
 1 行号
 2 46行 /* 
 3 47行  *主机发送
 4 48行  *slvAddr:从机地址,buf:数据存放的缓冲区,len:数据长度
 5 49行  */
 6 50行 void i2c_write(unsigned int slvAddr, unsigned char *buf, int len)
 7 51行 {
 8 52行    g_tS3C24xx_I2C.Mode      = WRDATA;    //写操作
 9 53行    g_tS3C24xx_I2C.Pt        = 0;         //索引值初始化为0
10 54行    g_tS3C24xx_I2C.pDATA     = buf;       //保存缓冲区地址
11 55行    g_tS3C24xx_I2C.DataCount = len;       //传输长度
12 56行
13 57行    IICDS   = slvAddr;
14 58行    IICSTAT = 0xf0;        //主机发送、启动
15 59行
16 60行    /*等待直至数据传输完毕*/
17 61行    while(g_tS3C24xx_I2C.DataCount != -1);
18 62行 }
19 63行
i2c.c->i2c_write()
    第57行将从机地址写入IICDS寄存器,这样,在第58行启动传输并发出S信号后,紧接
着就自动发出从机地址。
    第58行设置IICSTAT寄存器,将S3C2410/S3C2440设为主机发送器,并发出S信号。
后续的传输工作将在中断服务程序中完成。
    第61行等待g_tS3C24xx_I2C.DataCount在中断服务程序中被设为-1,这表明传输完成,
于是返回。
3.S3C2410/S3C2440 I2C主机接收函数
    i2c_read函数的实现与i2c_write类似,代码如下:
 1 行号
 2 64行 /*
 3 65行  *主机接收
 4 66行  *slvAddr:从机地址,buf:数据存放的缓冲区,len:数据长度
 5 67行  */
 6 68行 void i2c_read(unsigned int alvAddr, unsigned char *buf, int len)
 7 69行 {
 8 70行     g_tS3C24xx_I2C.Mode      = RDDATA;     //读操作
 9 71行     g_tS3C24xx_I2C.Pt        = -1;         //索引值初始化为-1,表示第一个中断时不接收数据(地址中断)
10 72行     g_tS3C24xx_I2C.pData     = buf;        //保存缓冲区地址
11 73行     g_tS3C24xx_I2C.DataCount = len;        //传输长度
12 74行 
13 75行     IICDS   = slvAddr;
14 76行     IICSTAT = 0xb0;        //主机接收,启动
15 77行 
16 78行     /*等待直至数据传输完毕*/
17 79行     while(g_tS3C24xx_I2C.DataCount != -1);
18 80行 }
19 81行 
i2c.c->i2c_read()
    需要注意的是第71行将索引值设为-1,在中断处理函数中会根据这个值决定是否从
IICDS寄存器中读取数据。读操作时,第1次中断发生时表示发出了地址,这时候不能
读取数据。
4.S3C2410/S3C2440 I2C中断服务程序
    I2C操作的主体在中断服务程序,它分为3部分:首先在SRCPND、INTPND中清除中
断,后面两部分对应于写操作和读操作。先看清除中断的代码:
 1 行号
 2 82行 /*
 3 83行  *I2C中断服务程序
 4 84行  *根据剩余的数据长度选择继续传输或者结束
 5 85行  */
 6 86行 void I2CInitHandle(void) 
 7 87行 {
 8 88行    unsigned int iicSt, i;
 9 89行    
10 90行    //清中断
11 91行    SRCPND = BIT_IIC;
12 92行    INTPND = BIT_IIC;
13 93行
14 94行    iicSt  = IICSTAT;
15 95行
16 96行    if(iicSt & 0x8){printf("Bus arbitration failed\n\r");}    //仲裁失败
i2c.c->I2CInitHandle()
    第91、92行用来清除I2C中断的代码。需要注意的是,即使清除中断后,IICCON寄存器
中的位[4](中断标识位)仍为1,这导致I2C传输暂停。
    第94行读取状态寄存器IICSTAT,发生中断时有可能时因为仲裁失败,在第96行对它进行
处理。本程序忽略仲裁失败,因为只有一个I2C主机。
    接下来是一个switch语句,分别处理写操作、读操作。先看写操作:
 1 行号
 2 98行  switch(g_tS3C24xx_I2C.Mode)
 3 99行  {
 4 100行    case WRDATA:
 5 101行    {
 6 102行        if((g_tS3C24xx_I2C.DataCount--) == 0)
 7 103行        {
 8 104行            //下面两行用于恢复I2C操作,发出P信号
 9 105行            IICSTAT = 0xd0;
10 106行            IICCON  = 0xaf;
11 107行            Delay(10000);    //等待一段时间以便P信号已经发出
12 108行            break;
13 109行        }
14 110行    
15 111行        IICDS = g_tS3C24xx_I2C.pData[g_tS3C24xx_I2C.Pt++];
16 112行
17 113行        //将数据写入IICDS后,需要一段时间才能出现在SDA线上
18 114行        for(i = 0; i < 10; i++);
19 115行
20 116行        IICCON = 0xaf;        //恢复I2C传输
21 117行        break;
22 118行    }
23 119行
i2c.c->I2CInitHandle()->switch()->case WRDATA
    g_tS3C24xx_I2C.DataCount表示剩余等待传输的数据个数,第102行判断数据是否已经
全部发送完毕:若是,则通过第105、106行发出P信号,停止传输;
    第105行设置IICSTAT寄存器以便发出P信号,但是由于这时IICCON[4]仍为1,P信号还没
有实际发出;
    当第106行清除IICCON[4]后,P信号才真正发出去;
    第107行等待一段时间,确保P信号已经发送完毕。
    如果数据还没有发送完毕,第111行从缓冲区中得到下一个要发送的数据,将它写入IICDS
寄存器中。稍等之后,即可在第116行清除IICCON[4]以恢复I2C传输,这时,IICDS寄存器中
的数据就会发送出去,这将触发下一个中断。
    I2C读操作的处理与写操作相似,代码如下:
 1 行号
 2 120行 case RDDATA:
 3 121行 {
 4 122行     if(g_tS3C24xx_I2C.Pt == -1)
 5 123行     {
 6 124行         //这次中断时在发送I2C设备地址后发生的,没有数据
 7 125行         //只接收一个数据时,不要发出ACK信号
 8 126行         g_tS3C24xx_I2C.Pt = 0;
 9 127行         if(g_tS3C24xx_I2C.DataCount == 1)
10 128行             IICCON = 0x2f;    //恢复I2C传输,开始接收数据,接收到数据时不发出ACK
11 129行         else
12 130行             IICCON = 0xaf;    //恢复I2C传输,开始接收数据
13 131行         break;
14 132行     }
15 133行 
16 134行     if((g_tS3C24xx_I2C.DataCount--) == 0)
17 135行     {
18 136行         g_tS3C24xx_I2C.pData[g_tS3C24xx_I2C.Pt++] = IICDS;
19 137行 
20 138行         //下面两行恢复I2C操作,发出P信号
21 139行         IICSTAT = 0x90;
22 140行         IICCON  = 0xaf;
23 141行         Delay(10000);        //等待一段时间以便P信号已经发出
24 142行         break;
25 143行     }
26 144行 
27 145行     g_tS3C24xx_I2C.pData[g_tS3C24xx_I2C.Pt++] = IICDS;
28 146行 
29 147行     //接收最后一个数据时,不要发出ACK信号
30 148行     if(g_tS3C24xx_I2C.DataCount == 0)
31 149行         IICCON = 0x2f;        //恢复I2C传输,接收到下一个数据时无ACK
32 150行     else
33 151行         IICCON = 0xaf;        //恢复I2C传输,接收到下一个数据时发出ACK
34 152行     break;
35 153行  }
case RDDATA
    读操作比写操作多一个步骤:第一次中断发生时,表示发出了地址,这时候还不能读取
数据。在代码中要分辨这点。对应第122~132行:如果g_tS3C24xx_I2C.Pt等于-1,表示
这是第一次中断,然后修改g_tS3C24xx_I2C.Pt为0,并设置IICCON寄存器恢复I2C传输
(第127~130行)。
    当数据传输已经开始后,每接收到一个数据就会触发一次中断。后面的代码读取数据,
判断所有数据是否已经完成:如果完成则发出P信号,否则继续下一次传输。
    第134行判断数据是否已经发送完毕。
    第19行设置IICSTAT寄存器以便发出P信号,但是由于这时IICCON[4]仍为1,P信号还没
有实际发出。
    第140行清除IICCON[4]后,P信号才真正发出。
    第145~151行用来启动下一次数据的接收。
    第148~151行判断是否只剩下最后一个数据了:若是,则通过第149行的清除IICCON[4]、
IICCON[7],这样即可恢复IIC传输,并使得接收到数据后,S3C2410/S3C2440不发出ACK
信号(这样从机即可知道数据传输完毕);否则在第151行中只要清除IICCON[4]以恢复IIC传输。
    中断服务程序中,当数据数据传输完毕时,g_tS3C24xx_I2C.DataCount将自减为-1,这样,
i2c_read或i2C_write函数即可跳出等待,直接返回。
5.RTC芯片M4lt11特性相关的操作
    m4lt11.c文件中提供两个函数m4lt11_set_datetime、m4lt11_get_datetime。它们都通过调
用i2c_read或i2c_write函数来完成与M4lt11的交互。
    前面说过,操作M4lt11只需要两步:发出寄存器地址,发出数据或读取数据。
m4lt11_set_datetime函数把这两个步骤合并为一个I2C写操作,m4lt11_get_datetime函数先发
起一个I2C写传输,再发起一个I2C读传输。
    m4lt11_set_datetime函数代码如下:
 1 行号
 2 29行 /*
 3 30行  *写m4lt11,设置日期和时间
 4 31行  */
 5 32行 int m4lt11_set_datetime(struct rtc_time *dt)
 6 33行 {
 7 34行    unsigned char leap_yr;
 8 35行    struct{
 9 36行        unsigned char addr;
10 37行        struct rtc_registers rtc;
11 38行     }__attribute__ ((packed)) addr_and_regs;
12          ... .../*设置rtc结构,即根据传入的参数构造各寄存器的值*/
13 76行    i2c_write(0xD0, (unsigned char *)&addr_and_regs, sizeof(addr_and_regs));
14 77行
15 78行    return 0;
16 79行 }
m4lt11.c->m4lt11_set_datetime()
    省略号表示的代码用来设置addr_and_regs结构体。这个结构体分为两部分:
addr_and_regs表示M4lt11寄存器地址(它被设为0);
addr_and_regs.rtc表示M4lt11的8个寄存器——秒、分、时、天(星期几)、日、月、年、控制寄存器。
    根据传入参数填充好addr_and_regs结构体后,就可以启动I2C写操作了。
    第38行使用“__attribute__((packed))”设置这个结构体为紧凑格式。使得它的大小
为9字节(否则大小为12字节):1字节用来保存寄存器的地址,8字节用来保存8个寄存器的值。
    m4lt11_get_datetime函数的代码与m4lt11_set_datetime函数类似,如下所示:
 1 行号
 2 81行 /*
 3 82行  *读取m4lt11,获取日期与时间
 4 83行  */
 5 84行 int m4lt11_get_datetime(struct rtc_time *dt)
 6 85行 {
 7 86行    unsigned char addr[1] = {0};
 8 87行    struct rtc_registers rtc;
 9 88行
10 89行    memset(&rtc, 0, sizeof(rtc));
11 90行
12 91行    i2c_write(0xD0, addr, 1);
13 92行    i2c_read(0xD0, (unsigned char *)&rtc, sizeof(rtc));
14 93行
15         ... .../*根据读出的各寄存器的值,设置dr结构体*/
16 110行    return 0;
17 111行 }
m4lt11.c->m4lt11_get_datetime()
    第91行发起一次I2C写传输,设置要操作的M4lt11寄存器地址为0;
    第92行发起一次I2C读传输,读出M4lt11各寄存器的值;
    省略号对应的代码根据读出的各寄存器的值,设置dr结构。M4lt11中以BCD码表示
日期与时间,需要转换为程序使用的一般二进制格式。
12.2.4 I2C实例的连接脚本
    本实例要用到第8章NAND Flash控制器的代码将代码从NAND Flash复制到SDRAM
中。由于nand代码中用到全局变量,而全局变量要运行与可读写的内存中,为了方便,
使用连接脚本将这些初始代码放到Steppingstone中。
    连接脚本为i2c.lds,内容如下:
 1 SECTIONS{
 2     . = 0x00000000;
 3     .init : AT(0){head.o init.o nand.o}
 4     . = 0x30000000;
 5     .text : AT(4096){ *(.text)}
 6     .rodata ALIGN(4) : AT((LOADADDR(.text)+SIZEOF(.text)+3)&~(0x03)){*(.rodata*)}
 7     .data ALIGN(4) :AT((LOADADDR(.rodata)+SIZEOF(.rodata)+3)&~(0x03)){*(.data)}
 8     __bss_start = .;
 9     .bss ALIGN(4) :{ *(.bss) *(COMMON)}
10     __bss_end = .;
11 }
i2c.lds
    第2~3行将head.S和nand.c对应的代码的运行地址设为0,加载地址(存在NAND Flash
上的地址)设为0。从NAND Flash启动时,这些代码被复制到Steppingstone后就可以直接运行。
    第4行设置其余代码的运行地址为0x3000 0000;第5行将代码段的加载地址设为4096,
表示代码段将存在NAND Flash地址4096处。
    第6~7行的“AT(...)”设置rodata段、data段的加载地址依次位于代码段之后。
“LOADADDR(...)”表示某段的加载地址,SIZEOF(...)表示它的大小。这两行的前面使用
“ALIGN(4)”使得它们的运行地址为4字节对齐。为了使各段之间加载地址的相应偏移值等于
地址的相对偏移,需要将“AT(...)”中的值也设为4字节对齐:先加上3,然后与~(0x03)进
行与操作(将低2位清0)。
12.2.5 实例测试    
    本程序在main函数中通过串口输出一个菜单,用于设置或读取时间,步骤如下:
(1)使用串口将开发板的COM0和PC的串口相连,打开PC的穿裤工具设为115200、8N1;
(2)在i2c目录下执行make,将可执行文件烧入NAND Flash中运行;
(3)在PC的串口工具上,可以看到如下菜单:
#### RTC Menu ####
Data format: 'year.month.day w hour:min:sec', 'w' is week day
eg:2007.08.30 4 01:16:57
[S] Set the RTC
[R] Read the RTC
Enter your selection:
(4)要设置RTC,输入"s"或“S”。可以看到如下字符。
Enter data&time:
    在串口工具中按照"year.month.day w hour:min:sec"格式输入日期与时间,比如:"2007.08.30 4 01:16:57",然后按回车键。
注意:只能输入2000.01.1至2099.12.31之间的日期与时间;年月日与星期必须真实存
在,否则RTC芯片无法正常工作。
(5)要可读取RTC,输入"r"或"R",即可看到当前日期与时间,串口上回输出类似
下面的结果。
*** Now is: 2007.08.30 4 01:16:57 ***
(6)断电后重启,输入“R”,仍可看到正确的时间。
附:代码:
链接: https://pan.baidu.com/s/1kV24a9L 密码: tfab
posted @ 2017-10-23 13:20  sz189981  阅读(1029)  评论(0编辑  收藏  举报