📄 digclock.asm
字号:
;-----------------------------------------
; Digclock.asm -- Digital Clock Demo
; based on Charles Petzold's DIGCLOCK.C
; Translated into assembly 22/4/99 by
; Ron Thomas Ron_Thom@Compuserve.com
;-----------------------------------------
.386 ; 32 bit when .386 appears before .MODEL
.MODEL FLAT,STDCALL
INCLUDE WINDOWS.INC
INCLUDE USER32.INC
INCLUDE KERNEL32.INC
INCLUDE GDI32.INC
INCLUDELIB USER32.LIB
INCLUDELIB KERNEL32.LIB
INCLUDELIB GDI32.LIB
WinMain PROTO :DWORD, :DWORD, :DWORD, :SDWORD
DISPLAYTIME PROTO STDCALL :DWORD, :BOOL, :BOOL
.DATA
ID_TIMER EQU 1
CLASSNAME DB "SIMPLEWINCLASS",0
APPNAME DB "DIGITAL CLOCK",0
hBrushRed HBRUSH ?
fSuppress BOOL ?
f24Hour BOOL ?
CXCLIENT DD ?
CYCLIENT DD ?
CXC_OVER2 DD ?
CYC_OVER2 DD ?
SZBUFFER DB 2 DUP (?),0 ; Zero terminated buffer
; Bits define which of the 7 LED segments is illuminated (ordered top to bottom & left to right)
; On each byte, bit 6 is for Segment 1, bit 5 for segment 2, to bit 0 for segment 7
SEGMT DB 01110111B,00010010B,01011101B,01011011B,00111010B
; 0 1 2 3 4
DB 01101011B,01101111B,01010010B,01111111B,01111011B
; 5 6 7 8 9 ; 10 digit values
; Set coordinates of a 6 sided polygons used to illuminate segments of the LED display
ptSegment POINT {7,6},{11,2},{31,2},{35,6},{31,10},{11,10} ; 1st LED segment Top
POINT {6,7},{10,11},{10,31},{6,35},{2,31},{2,11} ; 2nd TLeft
POINT {36,7},{40,11},{40,31},{36,35},{32,31},{32,11} ; 3rd TRight
POINT {7,36},{11,32},{31,32},{35,36},{31,40},{11,40} ; 4th Middle
POINT {6,37},{10,41},{10,61},{6,65},{2,61},{2,41} ; 5th BLeft
POINT {36,37},{40,41},{40,61},{36,65},{32,61},{32,41} ; 6th BRight
POINT {7,66},{11,62},{31,62},{35,66},{31,70},{11,70} ; 7th Bottom
ptColon POINT {2,21},{6,17},{10,21},{6,25} ; Coords of 4 sided polygon; 1st colon
POINT {2,51},{6,47},{10,51},{6,55} ; Ditto 2nd colon
.DATA?
hInstance HINSTANCE ?
CommandLine LPSTR ?
;---------------------------------------------------------------------------
LOWORD MACRO BIGWORD ;; Retrieves the low word from double word argument
MOV EAX,BIGWORD
AND EAX,0FFFFH ;; Get low word
ENDM
HIWORD MACRO BIGWORD ;; Retrieves the high word from double word
MOV EBX,BIGWORD
SHR EBX,16 ;; Shift 16 for high word to set to high word
ENDM
RGB MACRO RED, GREEN, BLUE ;; Get composite number from red green and blue bytes
MOV AL,BLUE ;; ,,,blue
SHL EAX,8 ;; ,,blue,
ADD AL,GREEN ;; ,,blue,green
SHL EAX,8 ;; ,blue,green,
ADD AL,RED ;; ,blue,green,red
AND EAX,0FFFFFFH ;; Mask out top byte to complete COLORREF dword
ENDM
;---------------------------------------------------------------------------
.CODE
START:
INVOKE GETMODULEHANDLE, NULL
MOV HINSTANCE,EAX
INVOKE GETCOMMANDLINE
INVOKE WINMAIN, HINSTANCE,NULL,COMMANDLINE, SW_SHOWDEFAULT
INVOKE EXITPROCESS,EAX
WINMAIN PROC HINST:HINSTANCE,HPREVINST:HINSTANCE,CMDLINE:LPSTR,CMDSHOW:SDWORD
LOCAL WC:WNDCLASSEX
LOCAL MSG:MSG
LOCAL HWND:HWND
MOV WC.CBSIZE,SIZEOF WNDCLASSEX
MOV WC.STYLE, CS_HREDRAW OR CS_VREDRAW
MOV WC.LPFNWNDPROC, OFFSET WNDPROC
MOV WC.CBCLSEXTRA,NULL
MOV WC.CBWNDEXTRA,NULL
PUSH HINSTANCE
POP WC.HINSTANCE
MOV WC.HBRBACKGROUND,COLOR_WINDOW+1
MOV WC.LPSZMENUNAME,NULL
MOV WC.LPSZCLASSNAME,OFFSET CLASSNAME
INVOKE LOADICON,NULL,IDI_APPLICATION
MOV WC.HICON,EAX
MOV WC.HICONSM,0
INVOKE LOADCURSOR,NULL,IDC_ARROW
MOV WC.HCURSOR,EAX
INVOKE REGISTERCLASSEX, ADDR WC
INVOKE CREATEWINDOWEX,NULL,ADDR CLASSNAME,ADDR APPNAME,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
hInst,NULL
MOV HWND,EAX
INVOKE SHOWWINDOW, HWND,SW_SHOWNORMAL
INVOKE UPDATEWINDOW, HWND
.WHILE TRUE
INVOKE GETMESSAGE, ADDR MSG,NULL,0,0
.BREAK .IF (!EAX)
INVOKE TRANSLATEMESSAGE, ADDR MSG
INVOKE DISPATCHMESSAGE, ADDR MSG
.ENDW
MOV EAX,MSG.WPARAM
RET
WINMAIN ENDP
WNDPROC PROC USES EBX ESI EDI, HWND:HWND, UMSG:UINT, WPARAM:WPARAM, LPARAM:LPARAM
LOCAL HDC:HDC
LOCAL PS:PAINTSTRUCT
MOV EAX,UMSG
.IF EAX==WM_CREATE
RGB 255,0,0 ; Set the colour
INVOKE CREATESOLIDBRUSH, EAX
MOV HBRUSHRED,EAX
INVOKE SETTIMER, HWND, ID_TIMER, 1000, NULL ;
JMP FALLTH ; Fall through for this message
.ELSEIF EAX==WM_SETTINGCHANGE
FALLTH: INVOKE GETLOCALEINFO, LOCALE_USER_DEFAULT, LOCALE_ITIME, ADDR SZBUFFER, 2
.IF SZBUFFER[0]=="1"
MOV F24HOUR,TRUE
.ELSE
MOV F24HOUR,FALSE
.ENDIF
INVOKE GETLOCALEINFO, LOCALE_USER_DEFAULT, LOCALE_ILZERO, ADDR SZBUFFER, 2
.IF SZBUFFER[0]=="0"
MOV FSUPPRESS,TRUE
.ELSE
MOV FSUPPRESS,FALSE
.ENDIF
INVOKE INVALIDATERECT, HWND, NULL, TRUE
.ELSEIF EAX==WM_SIZE ; lParam gives new window size
LOWORD LPARAM ; Get low word from lParam in eax
MOV CXCLIENT,EAX
SHR EAX,1
MOV CXC_OVER2,EAX ; cxClient/2
HIWORD LPARAM ; Get high " " " ebx
MOV CYCLIENT,EBX
SHR EBX,1
MOV CYC_OVER2,EBX ; cyClient/2
.ELSEIF EAX==WM_TIMER
INVOKE INVALIDATERECT, HWND, NULL, TRUE
.ELSEIF EAX==WM_PAINT
INVOKE BEGINPAINT, HWND, ADDR PS
MOV HDC,EAX ; Get handle to device context before selecting GDI object into it
INVOKE SETMAPMODE, HDC, MM_ISOTROPIC
INVOKE SETWINDOWEXTEX, HDC, 276, 72, NULL ;Set horizontal and vertical extents
; (6*42 + 2*12), height is 72
INVOKE SETVIEWPORTEXTEX, HDC, CXCLIENT, CYCLIENT, NULL ;Set viewport extents
INVOKE SETWINDOWORGEX, HDC, 138, 36, NULL ;Set coordinates of new viewport
; to the centre of the window extents
INVOKE SETVIEWPORTORGEX, HDC, CXC_OVER2, CYC_OVER2, NULL ;Set viewport origin
INVOKE GETSTOCKOBJECT, NULL_PEN
INVOKE SELECTOBJECT, HDC, EAX
INVOKE SELECTOBJECT, HDC, HBRUSHRED
INVOKE DISPLAYTIME, HDC, F24HOUR, FSUPPRESS ; *** This makes the LED display ***
INVOKE ENDPAINT, HWND, ADDR PS
.ELSEIF EAX==WM_DESTROY
INVOKE KILLTIMER, HWND, ID_TIMER
INVOKE DELETEOBJECT, HBRUSHRED
INVOKE POSTQUITMESSAGE,NULL
.ELSE
INVOKE DEFWINDOWPROC, HWND, UMSG, WPARAM, LPARAM
RET
.ENDIF
XOR EAX,EAX
RET
WNDPROC ENDP
DISPLAYDIGIT PROC USES EBX ESI EDI, HDC:DWORD, INUMBER:WORD
LOCAL BIT:BYTE
MOV BIT,01000000B ; Use to test segment mask
MOV EBX,0 ; Index to sets of Segment coordinates
MOV SI,0 ; Index to segment
MOV EDI,0
MOV DI,INUMBER ; Get the Digit index (0 - 9)
.WHILE SI < 7
MOV CL,BIT ; Do this as Windows destroys cx
TEST SEGMT[DI],CL ; If mask bit not set, LED segment is OFF
JZ SKIP
INVOKE POLYGON, HDC, ADDR PTSEGMENT[EBX], 6 ; Draw segment as 6 sided polygon
SKIP: SHR BIT,1 ; Prepare to test next LED segment
ADD BX,8*6 ; Bump index to next segment
; 8 bytes/(coord pair) and six sides/segment
INC SI
.ENDW
RET
DISPLAYDIGIT ENDP
DISPLAYTWODIGITS PROC HDC:DWORD, INUMBER:WORD, FSUPPR:BOOL
MOV EAX,0 ; Calculate the 10's decade
MOV AX,INUMBER
MOV ECX,10
MOV EDX,0
DIV ECX ; eax = iNumber/10
.IF (! FSUPPR || AX !=0)
INVOKE DISPLAYDIGIT, HDC, AX
.ENDIF
INVOKE OFFSETWINDOWORGEX, HDC, -42, 0, NULL ; Negative as we work from the centre
; & digits are 42 units wide
MOV EAX,0 ; Now get the units
MOV AX,INUMBER
MOV ECX,10
MOV EDX,0
DIV ECX ; edx = modulus of iNumber/10
INVOKE DISPLAYDIGIT, HDC, DX
INVOKE OFFSETWINDOWORGEX, HDC, -42, 0, NULL
RET
DISPLAYTWODIGITS ENDP
DISPLAYCOLON PROC HDC:HDC
INVOKE POLYGON, HDC, ADDR PTCOLON[0],4 ; 1st Colon
INVOKE POLYGON, HDC, ADDR PTCOLON[8*4],4 ; 2nd Colon
INVOKE OFFSETWINDOWORGEX, HDC, -12, 0, NULL ; Colons are 12 units wide & again
; we work from the centre
RET
DISPLAYCOLON ENDP
DISPLAYTIME PROC HDC:HDC, F24HR:BOOL, FSUPPR:BOOL
LOCAL SYST:SYSTEMTIME
INVOKE GETLOCALTIME, ADDR SYST
.IF F24HR
INVOKE DISPLAYTWODIGITS, HDC, SYST.WHOUR, FSUPPRESS
.ELSE
MOV AX,SYST.WHOUR
MOV ECX,12
MOV EDX,0
DIV CX ; Get modulus in dx
.IF EDX==12
MOV AX, SYST.WHOUR
.ELSE
MOV AX,12
.ENDIF
INVOKE DISPLAYTWODIGITS, HDC, AX, FSUPPR ; Hour
.ENDIF
INVOKE DISPLAYCOLON, HDC
INVOKE DISPLAYTWODIGITS, HDC, SYST.WMINUTE, FALSE ; Minute
INVOKE DISPLAYCOLON, HDC
INVOKE DISPLAYTWODIGITS, HDC, SYST.WSECOND, FALSE ; Seconds
RET
DISPLAYTIME ENDP
END START
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -