이것은 예전에 어떤분이 부탁해서 작성하게된 예제입니다.
* 문제: 4개의 DIP 스위치 값을 2진수로 읽어 들이고, 이 값에 대응하는 7-세그먼트 코드를 16진수로 출력하는 프로그램을 작성하시오
* 예를들어 , 스위치가 0000으로 되어 있으면 7-세그먼트의 출력 코드는 X100 1000(세그먼트 a-f는 켜지고 g는 꺼진다)이다. 프로그램은 무한히 반복되어 새로운 값이 스위치에 설정되면 이것을 바로 출력하게 한다. 프로그램 개요도와 주석달린 프로그램 리스트를 작성하라
* HINT: 16개의 7-세그먼트 코드로 번역 표를 만들고. 스위치에서 입력되는 2진수를 이 테이블의 인덱스로 이용하라. 명령어 XLAT를 사용하여 7- 세그먼트 출력을 구할수 있다...
* 문제: 4개의 DIP 스위치 값을 2진수로 읽어 들이고, 이 값에 대응하는 7-세그먼트 코드를 16진수로 출력하는 프로그램을 작성하시오
* 예를들어 , 스위치가 0000으로 되어 있으면 7-세그먼트의 출력 코드는 X100 1000(세그먼트 a-f는 켜지고 g는 꺼진다)이다. 프로그램은 무한히 반복되어 새로운 값이 스위치에 설정되면 이것을 바로 출력하게 한다. 프로그램 개요도와 주석달린 프로그램 리스트를 작성하라
* HINT: 16개의 7-세그먼트 코드로 번역 표를 만들고. 스위치에서 입력되는 2진수를 이 테이블의 인덱스로 이용하라. 명령어 XLAT를 사용하여 7- 세그먼트 출력을 구할수 있다...
| 코드: |
|
; 실행하면 "Input code: " 라는 프롬프트가 뜨며 ; 여기에 값을 2진수(!)로 0부터 15까지의 입력을 받게 되며 ; "Value <입력한 문자열>, <입력한 값을 AX로 변환후 값>"의 형식으로 표시해주고 ; "Segment code: <결과값>" 이라고 하여 실제 결과값을 출력 합니다. ; 이 소스의 개선점으로는 범위 밖의 입력에 대한 에러처리가 되어 있지 않습니다. .386 ; 80x386이상의 머신코드를 생성 ASSUME CS:CODE, DS:DATA, ES:NOTHING, SS:STACK_AREA CODE SEGMENT PARA PUBLIC USE16 'CLASS_CODE' ; =============================================================================== L_STARTUP: ; Data segment를 DATA로 초기화 MOV AX, DATA MOV DS, AX ; Logo 문자열 출력 MOV AH, 09H MOV DX, OFFSET DATA:D_MSG_LOGO INT 21H CALL NEAR PTR CODE:P_CRLF ; "Input code"문자열 출력 MOV AH, 09H MOV DX, OFFSET DATA:D_MSG_INPUT INT 21H ; D_MSG_BUFFER에 문자열을 입력 받음 MOV AH, 0AH MOV BYTE PTR DATA:[D_MSG_BUFFER], 80 MOV DX, OFFSET DATA:D_MSG_BUFFER INT 21H ; 입력된 문자열을 AX로 변환하여 저장해줌 PUSH OFFSET DATA:D_MSG_BUFFER CALL NEAR PTR CODE:P_STRTOAX PUSH AX ; 세그먼트값 저장 <--------------- ; "Segment code"문자열 출력 MOV AH, 09H MOV DX, OFFSET DATA:D_MSG_SEGMENT INT 21H POP AX ; 세그먼트값 복원 ----------------> ; 여기에 XLAT를 사용해서 값을 Table에서 값을 찾아서 AL에 넣어줌 MOV BX, OFFSET DATA:D_TABLE_SEGMENT XLAT ; MOV AL, [BX + AL] 과 같은 명령 (Table검색에 용이함) ; 우리의 목표인 최종 세그먼트값 출력! CALL NEAR PTR CODE:P_PRINT_BIN ; 'H'찍고 MOV AH, 02H MOV DL, 'H' INT 21H ; "Bye" 메세지 출력 CALL NEAR PTR P_CRLF MOV AH, 09H MOV DX, OFFSET DATA:D_MSG_BYE INT 21H ; Program을 종료 MOV AX, 4C00H INT 21H ; 만약 종료하지 못하면 시스템을 정지 (생략해도 상관없음) CLI HLT ; 정지도 안되면 (NMI 발생시) 그냥 루프 (생략해도 상관없음) JMP SHORT $ ; =============================================================================== ; 개행문자를 출력 P_CRLF PROC NEAR ; void near pascal P_CRLF(void) MOV AH, 09H MOV DX, OFFSET DATA:D_MSG_CRLF INT 21H RETN P_CRLF ENDP ; =============================================================================== P_STRTOAX PROC NEAR ; int near pascal P_STRTOAX(const void near *) PUSH BP MOV BP, SP ; 사용될 레지스터 초기화 XOR AX, AX XOR BX, BX MOV BX, WORD PTR [BP + 2 + 2] ; 포인터 인자를 가져옴 MOV CL, BYTE PTR DATA:[BX + 1] ; 입력된 문자열의 길이를 CL에 대입 ADD BX, 02H ; 실제 문자열이 저장된 Entry로 BX를 이동 L_STRTOAX_0: JCXZ L_STRTOAX_1 DEC CX MOV DL, BYTE PTR DATA:[BX] ; [BX]를 DL에 한바이트 꺼냄 SUB DL, 30H ; 입력된 값은 ASCII이므로 '0'에 해당하는 30H를 빼줌 SHL DL, CL ; Shift시킴 ADD AL, DL ; AH는 항상 0으로 예상되고 (범위가 크지 않으므로) INC BX ; BX를 하나 증가시켜서 입력된 다음 문자를 가르키게 함 JMP SHORT L_STRTOAX_0 L_STRTOAX_1: ; DEBUG CODE: 입력된 문자열을 확인하려고... PUSH AX ; AX값을 저장 PUSH WORD PTR [BP + 2 + 2] CALL P_DEBUG_INPUT POP AX ; AX값을 복원 POP BP RETN 2 P_STRTOAX ENDP ; =============================================================================== ; 이 함수는 AX값을 문자열로 출력하는이고 초기 BX값을 바꾸면 그에 해당하는 진수표기법으로 바뀜 P_PRINT_BIN PROC NEAR ; void near pascal P_PRINT_BIN(AX) MOV BX, 16 ; 16진수 출력 (여기를 바꾸면 진수표기법이 바뀜 2는 2진법, 4는 4진법, 8은 8진법, ...) XOR CX, CX L_PRINT_BIN_0: XOR DX, DX DIV BX CMP DX, 10 JL L_PRINT_BIN_LESS_0 SUB DX, 10 ADD DX, 'A' JMP L_PRINT_BIN_LESS_1 L_PRINT_BIN_LESS_0: ADD DX, '0' L_PRINT_BIN_LESS_1: PUSH DX INC CX OR AX, AX JNZ L_PRINT_BIN_0 ; PUSH CX ; MOV AX, CX ; MOV CX, 8 ; SUB CX, AX ;L_PRINT_BIN_ZERO_0: ; JCXZ L_PRINT_BIN_ZERO_1 ; DEC CX ; MOV AH, 02H ; MOV DL, '0' ; INT 21H ; JMP SHORT L_PRINT_BIN_ZERO_0 ;L_PRINT_BIN_ZERO_1: ; POP CX L_PRINT_BIN_1: POP DX MOV AH, 02H INT 21H LOOP L_PRINT_BIN_1 RETN P_PRINT_BIN ENDP ; =============================================================================== ; DEBUG procedure P_DEBUG_INPUT PROC NEAR ; void near pascal P_DEBUG_INPUT(const void near *) PUSH BP MOV BP, SP PUSH AX ; 변환된 값을 저장 <------------------ ; 1개 줄을 넘기고 CALL NEAR PTR CODE:P_CRLF ; "Value: "문자열 출력 MOV AH, 09H MOV DX, OFFSET DATA:D_MSG_CONFIRM INT 21H ; 입력된값 확인을 위해서 출력 MOV BX, WORD PTR [BP + 2 + 2] ADD BL, BYTE PTR DATA:[BX + 1] ADC BH, 00H MOV BYTE PTR DATA:[BX + 2], '$' ; '$'를 붙이는 것은 문자열의 끝을 알리는것 ! MOV AH, 09H MOV DX, WORD PTR [BP + 2 + 2] ADD DX, 02H INT 21H ; 'B'찍고 MOV AH, 02H MOV DL, 'B' INT 21H ; ','찍고 MOV AH, 02H MOV DL, ',' INT 21H ; ' '찍고 MOV AH, 02H MOV DL, ' ' INT 21H ; 실제 입력된 값을 변환하여 AX에 저장했던 것을 확인 POP AX ; 변환된 값을 복원 -----------------> CALL NEAR PTR CODE:P_PRINT_BIN ; AX값 확인 ; 'H'찍고 MOV AH, 02H MOV DL, 'H' INT 21H ; 1개 줄을 넘기고 CALL NEAR PTR CODE:P_CRLF POP BP RETN 2 P_DEBUG_INPUT ENDP CODE ENDS ASSUME DS:DATA DATA SEGMENT PARA PUBLIC USE16 'CLASS_DATA' D_MSG_LOGO DB "BIN to Segment code convert program : Code by JaeHyuk Cho$" D_MSG_INPUT DB "Input code : $" D_MSG_CONFIRM DB "Value : $" D_MSG_SEGMENT DB "Segment code : $" D_MSG_BYE DB "Bye" ; 최적화를 위해서 반드시 D_MSG_CRLF의 위에 있어야 함. D_MSG_CRLF DB 0DH, 0AH, '$' D_MSG_BUFFER DB 80 DUP (?) COMMENT # *** 7 segment table *** ! a b c d e f g --------------- 0 0 0 0 0 0 0 1 1 1 0 0 1 1 1 1 2 0 0 1 0 0 1 0 3 0 0 0 0 1 1 0 4 1 0 0 1 1 0 0 5 0 1 0 0 1 0 0 6 0 1 0 0 0 0 0 7 0 0 0 1 1 1 1 8 0 0 0 0 0 0 0 9 0 0 0 1 1 0 0 A 0 0 0 1 0 0 0 b 1 1 0 0 0 0 0 C 0 1 1 0 0 0 1 d 1 0 0 0 0 1 0 E 0 1 1 0 0 0 0 F 0 1 1 1 0 0 0 # D_TABLE_SEGMENT DB 01000000b, 01111001b, 00100100b, 00110000b DB 00011001b, 00010010b, 00000010b, 01111000b DB 00000000b, 00011000b, 00001000b, 00000011b DB 01000110b, 00100001b, 00000110b, 00001110b DATA ENDS ASSUME SS:STACK_AREA STACK_AREA SEGMENT PARA STACK USE16 'CLASS_STACK' DB 1024 DUP (?) STACK_AREA ENDS END L_STARTUP ; End of source |




댓글을 달아 주세요