(* 说明:全志A20的RTC底层操作封装类。单例。 TRTC类,可对寄存器直接操作,并实现了一些功能的简化。 作者:tjCFeng 邮箱:tjCFeng@163.com 更新日期:2014.12.06 *) unit RTC; {$mode objfpc}{$H+} interface uses SysUtils, A20; type TWeek = (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday); TYMDHNSW = packed record //not TDateTime; Year: Byte; Month: Byte; Day: Byte; Hour: Byte; Minute: Byte; Second: Byte; Week: TWeek; end; TRTC = class private class var FInstance: TRTC; class function GetInstance: TRTC; static; public class procedure Release; class property Instance: TRTC read GetInstance; private FRTC_BASE: ^LongWord; procedure SetDT(Value: TYMDHNSW); function GetDT: TYMDHNSW; constructor Create; destructor Destroy; override; protected FLOSC_CTRL: ^LongWord; FRTC_DATE: ^LongWord; FRTC_TIME: ^LongWord; //Alarm Reg ... public property DateTime: TYMDHNSW read GetDT write SetDT; end; implementation const RTC_BASE = $01C20D00; class function TRTC.GetInstance: TRTC; begin if FInstance = nil then FInstance:= TRTC.Create; Result:= FInstance; end; class procedure TRTC.Release; begin FreeAndNil(FInstance); end; constructor TRTC.Create; var Base: LongWord; begin inherited Create; FRTC_BASE:= TA20.Instance.GetMMap(RTC_BASE); Base:= LongWord(FRTC_BASE) + TA20.Instance.BaseOffset(RTC_BASE); FLOSC_CTRL:= Pointer(Base + $00); FRTC_DATE:= Pointer(Base + $04); FRTC_TIME:= Pointer(Base + $08); FLOSC_CTRL^:= FLOSC_CTRL^ and not ($1 shl 14); FLOSC_CTRL^:= FLOSC_CTRL^ or ($1 shl 15) or $16AA0000; FLOSC_CTRL^:= FLOSC_CTRL^ or $8; //($3 shl 2) or ($1 shl 0); end; destructor TRTC.Destroy; begin TA20.Instance.FreeMMap(FRTC_BASE); inherited Destroy; end; procedure TRTC.SetDT(Value: TYMDHNSW); var Leap: Byte; YMDFlag, HMSFlag: LongWord; begin with Value do begin if not (Year in [0..100]) then raise Exception.Create('Year must in [0..100]'); if not (Month in [1..12]) then raise Exception.Create('Month Error!'); if not (Day in [1..31]) then raise Exception.Create('Day Error!'); if not (Hour in [0..23]) then raise Exception.Create('Hour Error!'); if not (Minute in [0..59]) then raise Exception.Create('Minute Error!'); if not (Second in [0..59]) then raise Exception.Create('Second Error!'); end; if IsLeapYear(Value.Year) then Leap:= 1 else Leap:= 0; YMDFlag:= ($1 shl 7); HMSFlag:= ($1 shl 8); with Value do begin FRTC_DATE^:= 0; while (FLOSC_CTRL^ and YMDFlag) <> 0 do Sleep(100); FRTC_DATE^:= FRTC_DATE^ or (Leap shl 24) or (Year shl 16) or (Month shl 8) or (Day shl 0); while (FLOSC_CTRL^ and YMDFlag) <> 0 do Sleep(100); FRTC_TIME^:= 0; while (FLOSC_CTRL^ and HMSFlag) <> 0 do Sleep(100); FRTC_TIME^:= FRTC_TIME^ or (Ord(Week) shl 29) or (Hour shl 16) or (Minute shl 8) or (Second shl 0); end; end; function TRTC.GetDT: TYMDHNSW; var YMD, HMS: LongWord; begin YMD:= FRTC_DATE^; HMS:= FRTC_TIME^; with Result do begin Year:= (YMD shr 16) and $FF; Month:= (YMD shr 8) and $F; Day:= YMD and $1F; Hour:= (HMS shr 16) and $1F; Minute:= (HMS shr 8) and $3F; Second:= HMS and $3F; case (HMS shr 29) and $7 of 0: Week:= Monday; 1: Week:= Tuesday; 2: Week:= Wednesday; 3: Week:= Thursday; 4: Week:= Friday; 5: Week:= Saturday; 6: Week:= Sunday; end; end; end; finalization TRTC.Instance.Release; end.