应用笔记 4641

如何为MAXQ610微控制器增加DS1904实时时钟


摘要 : MAXQ610微控制器不具备电池供电的实时时钟(RTC),但是利用1-Wire®网络的灵活性,可方便地为任何基于MAXQ610的应用直接增加一个DS1904 RTC iButton®。MAXQ610能够与DS1904通信、设定时钟和控制,并且能够相互转换时间值与原始的秒计数值,即使采用汇编语言也能支持这些功能。本应用笔记介绍如何为基于MAXQ610的应用增加RTC功能,提供了实现这一功能的例程。本文介绍的原理和方法同样适用于其它基于MAXQ®、具有1-Wire驱动通信协议的通用I/O (GPIO)的微控制器。


本应用笔记正在准备公开,您的申请将自动批准,您会收到该篇应用笔记。

概述

MAXQ610是一款灵活的低功耗微控制器,非常适合便携应用。但是,MAXQ610并未集成电池供电的实时时钟(RTC)。

本应用笔记介绍如何在基于MAXQ610的应用中增加电池供电的DS1904 RTC iButton。应用笔记中的例程采用基于汇编的MAX-IDE环境为MAXQ610编写,设计运行于MAXQ610-KIT评估(EV)板。演示应用的源代码、工程文件以及其它文档可从网站下载

尽管本应用笔记讨论的程序代码专门针对MAXQ610微控制器编写,但本文讨论的原理和方法也能很好地适用于其它基于MAXQ、具有1-Wire驱动通信协议通用I/O (GPIO)的微控制器。

关于Maxim提供的iButton及其它1-Wire器件的更多信息,请参考iButton产品1-Wire产品网站。

硬件和软件要求

运行演示程序需要以下硬件支持。
  • MAXQ610-KIT评估板
  • 5V直流电源
  • 串行至JTAG或USB至JTAG接口板
  • JTAG编程电缆(2 × 5扁平电缆,带0.100in引脚连接器)
  • DB9直通串口电缆
  • PC机提供空闲的COM口(或USB至串口转换器)
  • DS1904L-F5# RTC iButton
  • DS9094F+通孔装配iButton夹
程序设计运行在带有iButton夹(DS9094F+)的MAXQ610评估板,iButton夹安装在原型区,DS1904L-F5# RTC iButton插入iButton夹子内。通过iButton夹连接:
  • iButton夹的GROUND引脚(夹子顶端引脚位置标有“+”,连接DS1904的背面/无标签面)连接到MAXQ610评估板的一个GND测试点。
  • iButton夹子的DATA引脚(夹子的内侧引脚,连接DS1904的前面/标签面)连接到MAXQ610评估板的端口引脚P2.0 (插头引脚P3.1)。
运行本应用笔记提供的例程需要以下软件。 可从MAXQ微控制器网页下载最新的MAX-IDE环境安装包和文档。

DS1904特性

DS1904是一款坚固的RTC iButton模块,占用最少的硬件资源。数据采用1-Wire协议串行传输,仅需1根数据线和1根地回路。DS1904具有唯一的64位工厂激光刻制ROM ID,包含被作为二进制计数器的RTC/日历。坚固耐用的MicroCan封装对恶劣环境具有极高的耐受能力,例如灰尘、潮湿和振动。DS1904借助附件几乎可以安装在任何物体表面,包括:印制电路板(PCB)和塑料钥匙扣。DS1904能够为任何基于微控制器的电子装置或嵌入式应用添加日历、时间和日期标签、秒表、计时表、计时器及日志功能。

DS1904 RTC由一个分辨率为1s的32位计数器组成,可提供大约136年的计时日历。维持时钟运行的所有硬件(包括32kHz晶振和电池)都密封在F5 MicroCan封装内,DS1904能够支持10年以上的工作时间。室温(+25°C)下,时钟精度大约为每月±2分钟。工作模式(暂停或运行状态)及时钟计数值通过1-Wire接口进行读写。这意味着仅需占用MAXQ610的1个GPIO引脚即可与DS1904进行通信。

设计目标

本例程设计的主要目标是利用DS1904的1-Wire接口进行以下操作。
  • 读取DS1904的64位ROM ID。
  • 启动和停止RTC。
  • 读取RTC的当前值。
  • 将RTC设定为一个新值。
该示例还能够以直接读取格式显示当前的RTC时间,即将原始的秒计数值转换为年/月/日/时间格式。允许用户对不同的转换数据(例如:年、月、日)进行递增控制,修改时钟值,不需要用户计算新的秒数并将其输入到器件内。

与其它任何保存原始秒计数值的时钟设计相同,必须选择一个“年份”基线,将原始的秒计数值转换成年/月/日/时间格式。本应用中,所选基线为2000年1月1日12:00:00 am,为原始秒计数值为00000000h时对应的日期/时间。

1-Wire网络驱动

Maxim已经开发了各种1-Wire接口传感器等元件。该接口利用一根数据线和地线进行供电和传输数据,意味着微控制器可通过单个端口与1-Wire传感器通信。

1-Wire工作时采用一个主控制器和多个从器件架构,即多点配置。定时要求非常灵活,允许所有从器件以高达16kbps的通信速率与主控制器同步工作。每个1-Wire传感器都有一个全球唯一的64位ROM ID,所以,1-Wire主控制器可独立、准确地选择从器件,而与网络的物理位置无关。

1-Wire数据线工作在开漏模式:主控制器(以及从器件,请求它们输出数据时)将数据拉低至地电位表示“0”,数据线浮空在高电平表示“1”。通常,这种工作方式采用安装在数据线和VCC之间的分立上拉电阻实现。但在使用MAXQ610等端口引脚具有弱上拉的微控制器时,仅需将端口引脚切换至该模式并使数据线浮空在高电平即可,无需外部上拉电阻。由于主控制器和从器件只用于拉低数据线,从来不会主动将数据线拉高,所以,1-Wire网络工作在“线或”配置下。这种方法可防止多个从器件试图同时在1-Wire总线上传输数据时发生冲突。

为了驱动1-Wire网络,MAXQ610必须在软件控制下通过单个引脚产生下列时隙。由于所有时隙均由1-Wire主控制器启动,MAXQ610不与从器件通信时无需监测1-Wire数据线。关于1-Wire通信的定时要求,请参考DS1904的数据资料。
  • 复位时隙宽度约为1ms,该时隙的前半部分,主控制器(也就是MAXQ610)将1-Wire线保持在低电平。经过一半时隙后,主控制器释放1-Wire总线,使其悬浮空在高电平。总线出现的任何1-Wire从器件都通过自身复位并在时隙的后半部分拉低总线进行响应。从器件产生一个应答脉冲,向主控制器表示线上存在一个或多个1-Wire从器件,并已准备就绪进行通信。

  • 时隙的长度大约为60µs至120µs,由主控制器向一个或多个1-Wire从器件发送“0”或“1”。两种写时隙都由主控制器在开始时将数据线拉低至少一个微秒。若发送“1”,主控制器则在时隙的剩余时间内释放1-Wire总线(即悬浮在高电平);若传输“0”,主控制器则继续将数据线保持在低电平,直到时隙结束。

  • 时隙长度大约为60µs至120µs,由主控制器从某个从器件读取“0”或“1”。时隙开始时,由主控制器将数据线拉低至少一个微秒。然后主控制器释放数据线,使从器件能够拉低数据线(表示“0”)或使数据线悬浮在高电平(表示“1”)。时隙期间,主控制器对数据线进行采样,读取从器件的数据位。
由于MAXQ610工作速率大约为每微秒12个指令周期(12MHz),软件可利用一个端口引脚(P2.0)轻松执行标准的1-Wire协议。
#define OWIN       M0[0Ah].0   ; PI2.0
#define OWOUT      M0[02h].0   ; PO2.0
#define OWDIR      M0[12h].0   ; PD2.0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  Function    : Reset1Wire
;;  Description : Sends a standard-speed 1-Wire reset pulse
;;                and checks for a presence pulse reply.
;;  Inputs      : None
;;  Outputs     : C - Cleared on success; set on error (no presence
;;                    pulse detected)
;;  Destroys    : PSF, LC[0]
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Reset1Wire:
   move  OWDIR, #1           ; Output mode
   move  OWOUT, #0           ; Drive low
   move  LC[0], #RESET_LOW
   djnz  LC[0], $

   move  OWOUT, #1           ; Snap high
   move  LC[0], #SNAP
   djnz  LC[0], $

   move  OWDIR, #0           ; Change to weak pullup input
   move  LC[0], #RESET_PRESAMPLE
   djnz  LC[0], $

   move  C, OWIN             ; Check for presence detect

   move  LC[0], #RESET_POSTSAMPLE
   djnz  LC[0], $

   ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;  Function    : Write1Wire
;;  Description : Writes a standard-speed 1-Wire output byte.
;;  Inputs      : GRL - Byte to write to 1-Wire.
;;  Outputs     : None.
;;  Destroys    : PSF, AP, APC, A[0], LC[0], LC[1]
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Write1Wire:
   move  APC, #080h          ; Standard mode, select A[0] as Acc
   move  Acc, GRL
   move  OWDIR, #1           ; Output drive mode
   move  LC[1], #8           ; 8 bits to write

Write1Wire_slot:
   move  OWOUT, #0           ; Drive low for start of write slot

   move  LC[0], #WRITE_PREBIT
   djnz  LC[0], $

   rrc                       ; Get the next bit
   jump  C, Write1Wire_one
Write1Wire_zero:
   move  OWOUT, #0           ; Keep the line low (zero bit)
   jump  Write1Wire_next
Write1Wire_one:
   move  OWOUT, #1
Write1Wire_next:
   move  LC[0], #WRITE_POSTBIT
   djnz  LC[0], $            ; Finish the time slot

   move  OWOUT, #1           ; Drive back high (end of slot)
   move  LC[0], #WRITE_RECOVERY
   djnz  LC[0], $            ; Recovery time period
   
   djnz  LC[1], Write1Wire_slot

   ret
发送读时隙的功能与此类似。注意,1-Wire总线的所有数据字节均为最低有效位(LSB)在前。

另外,还需要注意利用MAXQ610实现1-Wire总线时隙的特殊性。根据1-Wire网络器件数量的不同,1-Wire总线的上拉电阻会发生变化,典型值大约为4kΩ至5kΩ。而MAXQ610端口引脚的弱上拉电阻接近于15kΩ至40kΩ,取决于工作电压。为避免1-Wire总线从低电平跳变到高电平时花费过长时间,例程中在将端口引脚设定为标称弱上拉模式之前,在P2.0端口驱动一个标准的高电平并维持一个简短时间,从而使总线“快速”拉至高电平状态。只要该操作没有在器件拉低总线期间进行,就不会在1-Wire总线上引起任何问题。一种替代方案是在1-Wire总线上安装一个外部上拉电阻,将端口引脚驱动为标准低电平时表示“0”状态,三态模式表示高电平状态。

启动、停止和设置时钟

在与1-Wire总线器件进行通信时,数据传输涉及两个独立阶段。因为总线上可能挂接了不止一个1-Wire器件,需要通过两个过程执行操作。在第一阶段,总线主控制器选择需要通信的1-Wire器件;在第二阶段,总线主控制器与该器件通信。

关于下列命令的详细信息,请参考DS1904数据资料。

选择1-Wire从器件

一旦总线主控制器发送1-Wire复位脉冲,1-Wire总线上的所有从器件均复位至默认的未选中状态。在第一阶段,总线主控制器可利用几条命令选择在第二阶段需要读取或写入的1-Wire器件。所有1-Wire器件都支持这组与每个从器件64位ROM ID相关的命令集。

Skip ROM [CCh]

该单字节命令用于激活总线上的所有从器件。如果总线上只有一个1-Wire器件,或总线主控制器需要向总线上所有1-Wire器件发送相同命令,即可采用该ROM命令快速激活主控制器需要通信的器件。

由于示例中在总线上只有一个器件(DS1904),所以MAXQ610在绝大多数情况下都可使用该命令激活DS1904,进行后续的读、写操作。

Read ROM [33h]

该单字节命令用于激活总线上的所有从器件,并使其发送64位ROM ID至总线的主控制器。由于该命令激活全部从器件,只有当总线上仅有单个器件时才可使用。若在不止一个从器件的总线上使用该命令,不同器件都将尝试把各自的ROM ID发送至总线主控制器,将导致数据冲突。

由于示例中只在总线上挂接了一个从器件(DS1904),MAXQ610可以在示例开始利用该命令读取DS1904的ROM ID。

Match ROM [55h]

该命令用于从1-Wire总线的多个从器件中选择一个从器件。总线主控制器发送该命令后,紧接着发送需要选择的从器件的64位ROM ID。ROM ID与之相匹配的从器件将进入开启状态,响应总线主控制器,而总线上的其它从器件则保持禁止状态,并等待总线主控制器的下一次1-Wire复位。

该示例没有使用该命令。

Search ROM [F0h]

总线主控制器通过该命令采用迭代查找算法确定1-Wire总线上一个或多个从器件的ROM ID,详细信息请参考DS1904数据资料。

本示例中没有使用该命令。

DS1904时钟和控制的读、写操作

一旦总线主控制器(MAXQ610)通过Skip ROM命令或Read ROM命令选择了1-Wire从器件(DS1904),DS1904即准备就绪接收发给自己的1-Wire命令。以下详细介绍了这些命令,参见图1

图1. DS1904的时钟功能命令(摘自DS1904数据资料)
图1. DS1904的时钟功能命令(摘自DS1904数据资料)

Read Clock [66h]

总线主控制器利用该命令从DS1904读取器件控制字节及4字节(32位) RTC数值。器件控制字节决定了32kHz振荡器(驱动RTC)处于运行状态还是停止状态。

如以下代码所示,只用一条命令读取器件控制字节和时钟值。即使不需要两个数值,也必须在器件输出时钟数据之前先读取器件的控制字节。
ds1904_get_control:
   push    Acc

   call    Reset1Wire

   move    Acc, #OW_SKIP_ROM
   call    Write1Wire
   move    Acc, #OW_READ_CLOCK
   call    Write1Wire

   call    Read1Wire         ; Device control byte
   move    A[2], Acc

   call    Reset1Wire

   pop     Acc
   ret


ds1904_get_clock:
   push    Acc
   push    GR

   call    Reset1Wire

   move    Acc, #OW_SKIP_ROM
   call    Write1Wire
   move    Acc, #OW_READ_CLOCK
   call    Write1Wire

   call    Read1Wire         ; Device control byte (ignore)
   call    Read1Wire         ; RTC[7:0]
   move    GRL, Acc
   call    Read1Wire         ; RTC[15:8]
   move    GRH, Acc
   move    A[2], GR
   call    Read1Wire         ; RTC[23:16]
   move    GRL, Acc
   call    Read1Wire         ; RTC[31:24]
   move    GRH, Acc
   move    A[3], GR

   call    Reset1Wire

   pop     GR
   pop     Acc
   ret

Write Clock [99h]

该命令是读时钟命令的补充,它使总线主控制器能够将DS1904的器件控制字节和4字节时钟计数器设定到一个新的数值。注意,只有当5个字节全部写入并且发送一个1-Wire复位脉冲之后,新的数值才生效。

该示例提供了一个分别设置器件控制字节和时钟的例程。代码首先从DS1904读取5个字节(1个器件控制字节和4字节时钟计数器)的数据,然后进行适当改变后再将数据写回器件。
ds1904_set_clock:
   push    Acc
   push    GR

   call    Reset1Wire

   move    Acc, #OW_SKIP_ROM
   call    Write1Wire
   move    Acc, #OW_READ_CLOCK
   call    Write1Wire

   call    Read1Wire         ; Device control byte (save)
   move    GR, Acc
   call    Read1Wire         
   call    Read1Wire         
   call    Read1Wire         
   call    Read1Wire         

   call    Reset1Wire

   move    Acc, #OW_SKIP_ROM
   call    Write1Wire
   move    Acc, #OW_WRITE_CLOCK
   call    Write1Wire

   move    Acc, GR           ; Device control byte
   call    Write1Wire

   move    GR, A[2]
   move    Acc, GRL
   call    Write1Wire        ; New clock LSB
   move    Acc, GRH
   call    Write1Wire

   move    GR, A[3]
   move    Acc, GRL
   call    Write1Wire        
   move    Acc, GRH
   call    Write1Wire        ; New clock MSB

   call    Reset1Wire

   pop     GR
   pop     Acc
   ret



ds1904_set_control:
   push    Acc
   push    GR
   push    A[3]
   push    A[4]

   call    Reset1Wire

   move    Acc, #OW_SKIP_ROM
   call    Write1Wire
   move    Acc, #OW_READ_CLOCK
   call    Write1Wire

   call    Read1Wire         ; Device control byte 

   call    Read1Wire         ; Clock LSB
   move    GRL, Acc
   call    Read1Wire         
   move    GRH, Acc
   move    A[3], GR

   call    Read1Wire         
   move    GRL, Acc
   call    Read1Wire         
   move    GRH, Acc          ; Clock MSB
   move    A[4], GR

   call    Reset1Wire

   move    Acc, #OW_SKIP_ROM
   call    Write1Wire
   move    Acc, #OW_WRITE_CLOCK
   call    Write1Wire

   move    Acc, A[2]         ; New device control byte
   call    Write1Wire

   move    GR, A[3]
   move    Acc, GRL
   call    Write1Wire        ; New clock LSB
   move    Acc, GRH
   call    Write1Wire

   move    GR, A[4]
   move    Acc, GRL
   call    Write1Wire        
   move    Acc, GRH
   call    Write1Wire        ; New clock MSB

   call    Reset1Wire

   pop     A[4]
   pop     A[3]
   pop     GR
   pop     Acc
   ret

转换时间和日期值

为了把原始的秒计数值转换成打印格式,需要应用程序分别确定每个日期和时间字段的数值(例如年、月、日、时、分和秒)。通常,实现这一功能的程序首先从最大字段(年)开始,然后逐步向下转换。
  1. 当秒计数值≥ (每年秒数)时,从秒计数值中减去(每年秒数)并递增年份。
  2. 当秒计数值≥ (每月秒数)时,从秒计数值中减去(每月秒数)并递增月份。
  3. 当秒计数值≥ (每天秒数)时,从秒计数值中减去(每天秒数)并递增日期。
  4. 当秒计数值≥ (每小时秒数)时,从秒计数值中减去(每小时秒数)并递增小时值。
  5. 当秒计数值≥ 60时,从秒数中减去60并递增分钟值。
  6. 剩下的秒计数值即为秒字段数值。
即使MAXQ610硬件支持除法运算,一次简单的除法运算也不能够计算前两个字段的数值(年和月)。考虑到闰年(涉及到年和月)和每月天数(仅涉及月)的不同,每个字段的秒数是变化的。

例如,从2000年开始(该年为闰年),我们计算如下:
(2000年一年的秒数) = 366 (天数) × 24 (小时/日) × 60 (分钟/小时) × 60 (秒/分钟) = 31,622,400秒
而对于标准年份,一年的天数减少一天(365天),这就意味着(秒数/年)变为:(31,622,400 - 86,400) = 31,536,000。由于每4年有一个闰年,所以我们可计算年份如下。
  1. 如果秒计数值≥ (闰年秒数),从秒计数值中减去(每个闰年的秒数)并递增年份,否则停止。
  2. 如果秒计数值≥ (每年秒数),从秒计数值中减去(每年秒数)并递增年份,否则停止。
  3. 如果秒计数值≥ (每年秒数),从秒计数值中减去(每年秒数)并递增年份,否则停止。
  4. 如果秒计数值≥ (每年秒数),从秒计数值中减去(每年秒数)并递增年份,否则停止。
  5. 返回至第1行。
月份的计算方法类似。
  1. 如果秒计数值≥ (一月秒数),从秒计数值中减去(一月秒数)并递增月份,否则停止。
  2. 如果秒计数值≥ (二月秒数),从秒计数值中减去(二月秒数)并递增月份,否则停止。
  3. 如果秒计数值≥ (三月秒数),从秒计数值中减去(三月秒数)并递增月份,否则停止。
  4. 依次类推。
注意,二月份的秒数也受当年是否为闰年的影响。
;; A[6]  - Number of days in current month
;; A[7]  - Leap-year flag (leap year if 1, regular year if 0)
;; A[8]  - RTC value (low 16 bits)
;; A[9]  - RTC value (high 16 bits)
;; A[10] - Seconds  (00-59)
;; A[11] - Minutes  (00-59)
;; A[12] - Hours    (00-23)
;; A[13] - Days     (01-31, depending on month)
;; A[14] - Months   (01-12)
;; A[15] - Years    (00-99)

convToFields:
   push    A[8]
   push    A[9]

   call    zeroFields

convToFields_year:
   move    A[3], #SEC_IN_LEAPYEAR_H
   move    A[2], #SEC_IN_LEAPYEAR_L
   call    Sub32
   jump    C, convToFields_month
   call    incYear

   move    A[3], #SEC_IN_YEAR_H
   move    A[2], #SEC_IN_YEAR_L
   call    Sub32
   jump    C, convToFields_month
   call    incYear

   move    A[3], #SEC_IN_YEAR_H
   move    A[2], #SEC_IN_YEAR_L
   call    Sub32
   jump    C, convToFields_month
   call    incYear

   move    A[3], #SEC_IN_YEAR_H
   move    A[2], #SEC_IN_YEAR_L
   call    Sub32
   jump    C, convToFields_month
   call    incYear
   jump    convToFields_year

convToFields_month:
   move    A[3], #SEC_IN_MON_31_H      ; >Jan
   move    A[2], #SEC_IN_MON_31_L
   call    Sub32
   jump    C, convToFields_day
   call    incMonth

   move    A[3], #SEC_IN_MON_28_H      ; >Feb
   move    A[2], #SEC_IN_MON_28_L
   move    Acc, A[7]
   jump    Z, convToFields_month_noLeap
   move    A[3], #SEC_IN_MON_29_H      ; >Feb
   move    A[2], #SEC_IN_MON_29_L
   

convToFields_month_noLeap:
   call    Sub32
   jump    C, convToFields_day
   call    incMonth

   move    A[3], #SEC_IN_MON_31_H      ; >Mar
   move    A[2], #SEC_IN_MON_31_L
   call    Sub32
   jump    C, convToFields_day
   call    incMonth

   move    A[3], #SEC_IN_MON_30_H      ; >Apr
   move    A[2], #SEC_IN_MON_30_L
   call    Sub32
   jump    C, convToFields_day
   call    incMonth

   move    A[3], #SEC_IN_MON_31_H      ; >May
   move    A[2], #SEC_IN_MON_31_L
   call    Sub32
   jump    C, convToFields_day
   call    incMonth

   move    A[3], #SEC_IN_MON_30_H      ; >Jun
   move    A[2], #SEC_IN_MON_30_L
   call    Sub32
   jump    C, convToFields_day
   call    incMonth

   move    A[3], #SEC_IN_MON_31_H      ; >Jul
   move    A[2], #SEC_IN_MON_31_L
   call    Sub32
   jump    C, convToFields_day
   call    incMonth

   move    A[3], #SEC_IN_MON_31_H      ; >Aug
   move    A[2], #SEC_IN_MON_31_L
   call    Sub32
   jump    C, convToFields_day
   call    incMonth

   move    A[3], #SEC_IN_MON_30_H      ; >Sep
   move    A[2], #SEC_IN_MON_30_L
   call    Sub32
   jump    C, convToFields_day
   call    incMonth

   move    A[3], #SEC_IN_MON_31_H      ; >Oct
   move    A[2], #SEC_IN_MON_31_L
   call    Sub32
   jump    C, convToFields_day
   call    incMonth

   move    A[3], #SEC_IN_MON_30_H      ; >Nov
   move    A[2], #SEC_IN_MON_30_L
   call    Sub32
   jump    C, convToFields_day
   call    incMonth


convToFields_day:
   move    A[3], #SEC_IN_DAY_H
   move    A[2], #SEC_IN_DAY_L
   call    Sub32
   jump    C, convToFields_hour
   call    incDay
   jump    convToFields_day

convToFields_hour:
   move    A[3], #SEC_IN_HOUR_H
   move    A[2], #SEC_IN_HOUR_L
   call    Sub32
   jump    C, convToFields_minute
   call    incHour
   jump    convToFields_hour

convToFields_minute:
   move    A[3], #0
   move    A[2], #60
   call    Sub32
   jump    C, convToFields_second
   call    incMinute
   jump    convToFields_minute

convToFields_second:
   move    A[10], A[8]

   pop     A[9]
   pop     A[8]
   ret
示例应用程序按照类似的方式将字段转换成秒数。此时,代码将每个字段累计值增加至秒数(而不是减)。

运行示例

运行例程时,请加载并运行应用程序。然后利用DB9串行电缆将MAXQ610评估板的J1 SKT连接至PC的COM1。启动MTK (或其它终端仿真器)并以38400波特率打开COM1。例程的初始化输出类似如下:
@
ID: 24B91231000000B2  AC  18F83065

+   18F83065   Apr 10 2013, 02:15:01 pm
+   18F83066   Apr 10 2013, 02:15:02 pm
+   18F83067   Apr 10 2013, 02:15:03 pm
+   18F83068   Apr 10 2013, 02:15:04 pm
+   18F83069   Apr 10 2013, 02:15:05 pm
代码的第二行含有DS1904的ROM ID (24B91231000000B2)、器件控制字节(AC)和当前的时钟(18F83065)。在随后几行中,“+”表示时钟正在运行。时间在发生变化后即进行刷新并显示,应该为每秒一次。

按下“-”停止时钟。此时,即可通过按下其它键修改时钟值,如下所示。

+ 再次启动时钟并开始自动更新。
Y 增加年份(将月份和日期复位为01/01)。
M 增加月份(将日期复位为01)。
D 增加日期(根据当前的月份循环)。
h 增加小时。
m 增加分钟。
s 将秒计数值复位为00。
Z 将计数器归零,将时间复位至2001年1月1日12:00:00 am。

结论

尽管MAXQ610不带电池供电的RTC,但是利用1-Wire网络的灵活性,可采用DS1904 RTC iButton方便地为任何基于MAXQ610的应用增加一个RTC。MAXQ610能够与DS1904通信、设定时钟和控制,并且可以转换时间和原始的秒计数值,使用汇编语言即可实现。
下一步
EE-Mail 订阅EE-Mail,接收关于您感兴趣的新文档的自动通知。
© , Maxim Integrated Products, Inc.
The content on this webpage is protected by copyright laws of the United States and of foreign countries. For requests to copy this content, contact us.
APP 4641:
应用笔记 4641,AN4641, AN 4641, APP4641, Appnote4641, Appnote 4641