Question

So, I have created a program which measures the degrees that a stepper motor has turned. We must measure the degrees to the nearest 10th of a degree (i.e. if the motor has turned 141.75 degrees, we must print out 14175 since the LED doesn't have decimal points).

Well, I've come to a roadblock in which when I try to print any degrees that is greater than 327.67, the LED displays a negative number since the microprocessor automatically expresses signed numbers. For instance, 348.75 should print onto the LED display as 34875, but instead it uses the two's complement negative of the binary value that represents 34875, which is -31786. Would anybody know how to show 36000 on this LED display?

The logic to my code is as follows:

  • For every move to the right, SI increases
  • For every move to the left, DI increases

To find the degrees, I move compare them to see if they're not at the start Second I subtract one from the other depending on which is larger. If DI is larger, then I moved to the left (or clockwise) then I add 58 to jump to the value that corresponds to the degrees needed to be printed.

    #start=stepper_motor.exe# 
    #start=led_display.exe#

data segment
ANGLE  dw 0, 1125, 2250, 3375, 4500, 5625, 6750, 7875, 9000, 10125,
   dw 11250, 12375, 13500, 14625, 15750, 16875, 18000, 019125,
   dw 020250, 021375, 022500, 023625, 024750, 025875, 027000, 028125,
   dw 029250, 030375, 031500, 032625, 033750, 034875, 036000

; words for the menu
menu db "MENU", 13, 10
 db " ", 13, 10
 db "                1- Reset", 13, 10
 db "                2- Select clockwise or counterclockwise", 13, 10
 db "                3- Select continuous or keyboard input", 13, 10
 db "                4- Turn", 13, 10     
 db "                >- Turn Right", 13, 10
 db "                <- Turn Left", 13, 10
 db " ", 13, 10
 db "                Q-QUIT", 13, 10
 db " ",13,10
 db " ",13,10
 db "                                  ENTER CHOICE: $"
tcw  db "Turning clockwise       $"
tccw db "Turning counterclockwise $"
tcont db "Turn continuously $"
tman db "Turn manually     $"


pkey db "press any key...$"
ends

stack segment
dw 128 dup(0)
ends

code segment
start:
; set segment registers:
mov ax, data
mov ds, ax
mov es, ax


setup:    
mov si, 0     ;index for left move
mov di, 0     ;index for right move
call blubox   ;sets up the screen with menu

MOV AL, 02H   ;TURN MIDDLE MAGNET ON
OUT 7, AL 

functionator:

CALL KEYPRESS ;check if key has been pressed
CALL MOUSEGRAB

JMP functionator



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;CHECKS THE DEGREES OF THE STEPPER;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CHECKDEGREES PROC NEAR
    PUSH SI
    PUSH DI

    CMP SI, DI            ;CHECKS IF 0 DEGREES
    JE ZERO
    JG LEFTDEGREE         ;STEPPER IS ON LEFT HALF, CHECK DEGREES THERE

    SUB DI, SI
    SHL DI, 1     
    MOV BX, 64
    SUB BX, DI
    MOV DI, BX

    MOV AX, ANGLE[DI]


    OUT 199, AX
    JMP DONEDEGREE

    LEFTDEGREE:
    SUB SI, DI 
    SHL SI,1

    MOV AX, ANGLE[SI]

    OUT 199, AX
    JMP DONEDEGREE

    ZERO:     
    XOR AX, AX
    OUT 199, AX

    DONEDEGREE:
    POP DI
    POP SI

    RET 
CHECKDEGREES ENDP

;;;;;;;;;;;;;;;;;;;;;;
;RESTARTS THE STEPPER;
;;;;;;;;;;;;;;;;;;;;;;
RESETIT PROC NEAR
push ax
push bx
push cx
resetstep:

CMP SI, DI
JE DONERESET
JG LEFTCOMMAND

RIGHTCOMMAND:
SUB DI, SI
MOV CX, DI
GORIGHT1:
CALL DELAY
CALL MOVERIGHT
CMP CX, 1
JE DONERESET
DEC CX
JMP GORIGHT1

JMP DONERESET

LEFTCOMMAND:
SUB SI, DI
MOV CX, SI
GOLEFT1:
CALL DELAY
CALL MOVELEFT
CMP CX, 1
JE DONERESET
DEC CX

JMP GOLEFT1


DONERESET:
MOV SI, 0H
MOV DI, 0H

POP CX
POP BX
POP AX

RET
RESETIT ENDP


;;;;;;;;;;;;;;;;;;;;;
;creates a delay;;;;;
;;;;;;;;;;;;;;;;;;;;;
delay proc near


mov ax, 5    
countit:


cmp ax, 0
je donedelay
dec ax
jmp countit

donedelay:

ret
delay endp


 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;moves the stepper to the LEFT;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 MOVERIGHT PROC NEAR
  IN AL, 7


  CMP AL, 81H   ;IF RIGHTMOST MAGNET IS ON, TURN
  JE RIGHT2     ;TWO LEFTMOST MAGNETS ON

  CMP AL, 82H   ;IF MIDDLE MAGNET IS ON,
  JE RIGHT1     ;TURN ON TWO RIGHTMOST MAGNETS

  CMP AL, 83H   ;IF TWO RIGHTMOST MAGNETS ARE ON,
  JE RIGHT3      ;TURN ON THE RIGHTMOST MAGNET

  CMP AL, 84H   ;IF ONE LEFTMOST MAGNET IS ON,
  JE RIGHT2      ;TURN ON TWO LEFTMOST MAGNETS

  CMP AL, 86H   ;IF TWO LEFTMOST MAGNETS ARE ON,
  JE RIGHT4      ;TURN MIDDLE MAGNET ON



  RIGHT1:
  MOV AL, 03H   ;TURN ON THE TWO RIGHT MAGNETS 
  OUT 7, AL     ;FOR A HALFSTEP TO THE RIGHT
  JMP DONERIGHT

  RIGHT2:
  MOV AL, 06H   ;TURN THE TWO LEFTMOST MAGNETS ON
  OUT 7, AL     ;FOR A HALFSTEP TO THE RIGHT
  JMP DONERIGHT

  RIGHT3:
  MOV AL, 01H   ;TURN RIGHTMOST MAGNET ON
  OUT 7, AL     ;FOR FULL STEP TO RIGHT
  JMP DONERIGHT                                   

  RIGHT4:
  MOV AL, 02H   ;TURN MIDDLE MAGNET ON FOR 
  OUT 7, AL     ;FULL STEP TO RIGHT

  DONERIGHT:
  CMP SI, 20H
  JE RESETSI
  inc SI
  JMP FINALRIGHT

  RESETSI:
  MOV SI, 1H

  FINALRIGHT:
  CALL checkdegrees
RET
MOVERIGHT ENDP 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;moves the stepper to the right;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

MOVELEFT PROC NEAR
  IN AL, 7

  CMP AL, 86H   ;IF TWO LEFT MAGNETS ARE ON,
  JE LEFT2      ;TURN LEFTMOST MAGNET ON

  CMP AL, 84H   ;IF ONE LEFTMOST MAGNET IS ON,
  JE LEFT3      ;TURN ON TWO RIGHTMOST MAGNETS ON

  CMP AL, 83H   ;IF TWO RIGHTMOST MAGNETS ARE ON,
  JE LEFT4      ;TURN ON MIDDLE MAGNET

  CMP AL, 82H   ;IF MIDDLE MAGNET IS ON,
  JE LEFT1      ;TURN ON TWO LEFTMOST MAGNETS

  CMP AL, 81H   ;IF RIGHTMOST MAGNET IS ON, TURN
  JE LEFT3      ;TWO RIGHTMOST MAGNETS  

  LEFT1:
  MOV AL, 06H   ;TURN ON THE TWO LEFT MOTORS 
  OUT 7, AL     ;FOR A HALFSTEP TO THE LEFT
  JMP DONELEFT

  LEFT2:
  MOV AL, 04H   ;TURN THE LEFTMOST MAGNET ON
  OUT 7, AL
  JMP DONELEFT

  LEFT3:
  MOV AL, 03H   ;TURN TWO RIGHTMOST MAGNETS ON
  OUT 7, AL
  JMP DONELEFT                                   

  LEFT4:
  MOV AL, 02H   ;TURN MIDDLE MAGNET ON
  OUT 7, AL   

  DONELEFT:
  CMP DI, 20H
  JE RESETDI    ;when 
  inc DI
  JMP FINALLEFT

  RESETDI:
  MOV DI, 1H

  FINALleft:
  CALL CHECKDEGREES
RET
MOVELEFT ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;CHECKS IF MOUSE HAS BEEN PRESSED;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

MOUSEGRAB PROC NEAR    
PUSH CX
PUSH BX

MOV AX, 01H        ;DISPLAY CURSOR
INT 33H
MOV AX, 03H        ;FIND OUT THE BUTTON PRESS
INT 33H            
CMP BX, 01H         ;IF MOUSE NOT PRESSED, JUMP OUT
JE GOMOUSE
POP BX
POP CX
JMP MOUSEDONE

GOMOUSE:
CMP DX, 20H
JL MOUSEDONE

CMP DX, 28H
JL RESETMOUSE

CMP DX, 30H
JL DIRECTMOUSE

CMP DX, 38H
JL INPUTMOUSE

CMP DX, 40H
JL TURNMOUSE

CMP DX, 48H
JL RIGHTMOUSE

CMP DX, 50H
JL LEFTMOUSE

CMP DX, 58H
JG MOUSEDONE


DIRECTMOUSE:
POP BX
POP CX
CALL DIRECT
JMP MOUSEDONE

INPUTMOUSE:
POP BX
POP CX
CALL ENTER
JMP MOUSEDONE

TURNMOUSE:
POP BX
POP CX
CMP BH, 1
JE CONT_TURN_MOUSE
JMP MOUSEDONE

RIGHTMOUSE:
POP BX
POP CX
CALL MOVERIGHT
JMP MOUSEDONE

LEFTMOUSE:
POP BX
POP CX
CALL MOVELEFT
JMP MOUSEDONE

CONT_TURN_MOUSE:
CMP BL, 1
JE TURNCLOCK_MOUSE
CALL TURNCCW
JMP MOUSEDONE

TURNCLOCK_MOUSE:
CALL TURNCW
JMP MOUSEDONE

RESETMOUSE:
POP BX
POP CX
CALL RESETIT 

MOUSEDONE:

RET
MOUSEGRAB ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;CHECKS TO SEE IF KEY HAS BEEN PRESSED;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

KEYPRESS PROC NEAR


MOV AH, 1H        ;CHECKS IF KEY IS IN BUFFER
INT 16H
JZ DONE

mov ah, 0h        ;MOVES PRESS FROM BUFFER
int 16h

CMP AH, 10H       ;IF Q, THEN QUIT
JE FINISH

CMP AL, 34H       ;if 4, turn (only if continuous)
JE TURNIT    

CMP AH, 4BH       ;if <- then move left
JE GOLEFT

CMP AH, 4DH       ;if -> then move right
JE GORIGHT

CMP AL, 31H       ;if 1 then reset
JE GORESET

CMP AL, 32H       ;if 2, select clockwise or counter
JE DIRECTION

CMP AL, 33H       ;if 3, select continuous or manual
JE INPUT




JMP DONE


INPUT:
CALL ENTER
JMP DONE

TURNIT:
CMP BH, 1
JE  CONTINUOUSTURN
JMP DONE

DIRECTION:
CALL DIRECT
JMP DONE

GOLEFT:
CALL MOVELEFT
JMP DONE

GORIGHT:
CALL MOVERIGHT
JMP DONE

GORESET:
CALL RESETIT
JMP DONE

CONTINUOUSTURN:
CMP BL, 1
JE TURNCLOCK
CALL TURNCCW
JMP DONE

TURNCLOCK:
CALL TURNCW

DONE:
RET
KEYPRESS ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;TURNS CONTINUOUSLY CLOCKWISE;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TURNCW PROC NEAR
TURNCWLOOP:
CALL MOVELEFT
CALL DELAY

MOV AH, 1H        ;CHECKS IF KEY IS IN BUFFER
INT 16H                                      
JNZ doneturning

PUSH CX
PUSH BX
MOV AX, 03H        ;FIND OUT THE MOUSE PRESS
INT 33H            
CMP BX, 01H         ;IF MOUSE NOT PRESSED, JUMP OUT
POP BX
POP CX    
JNE TURNCWLOOP                                      

doneturning:

RET
TURNCW ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;TURNS CONTINUOUSLY COUNTERCLOCKWISE;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TURNCCW PROC NEAR
TURNCCWLOOP:
CALL MOVERIGHT
CALL DELAY

MOV AH, 1H        ;CHECKS IF KEY IS IN BUFFER
INT 16H       
JNZ doneturningccw

    PUSH CX
PUSH BX
MOV AX, 03H        ;FIND OUT THE MOUSE PRESS
INT 33H            
CMP BX, 01H         ;IF MOUSE NOT PRESSED, JUMP OUT
POP BX
POP CX
JNE TURNCCWLOOP

doneturningccw: 
RET
TURNCCW ENDP



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;DETERMINES IF CONTINUOUS OR MANUAL;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

ENTER PROC NEAR
PUSH BX
MOV AH, 02H           ;moves cursor to letter
MOV BH, 0H            ;after "Turn" 
MOV DH, 11H           
MOV DL, 5
INT 10H

MOV AH, 08H           ;OBTAIN THE LETTER IN AL
MOV BH, 0H
INT 10H

MOV AH, 02H           ;moves cursor to print new 
MOV BH, 0H            ;string
MOV DH, 11H            
MOV DL, 0H
INT 10H

POP BX

CMP AL, 'c'           ;CHECK IF CONTINOUS
JE MANTURN

MOV AH, 09H           ;print "turn continuously"
MOV DX, OFFSET tcont
INT 21H

MOV BH, 1             ;index for moving motor

JMP DONEENTER  

MANTURN:

MOV AH, 09H
MOV DX, OFFSET tman   ;print "turn manual"
INT 21H

MOV BH, 0

doneenter:    

RET
ENTER ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;CHECKS CURRENT DIRECTION THEN CHOOSES THE NEW ONE;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

DIRECT PROC NEAR
PUSH BX

MOV AH, 02H           ;moves cursor to letter
MOV BH, 0H            ;after "C" in either clockwise
MOV DH, 10H            ;or counterclockwise
MOV DL, 9
INT 10H

MOV AH, 08H           ;OBTAIN THE LETTER IN AL
MOV BH, 0H
INT 10H

MOV AH, 02H           ;moves cursor to print new 
MOV BH, 0H            ;string
MOV DH, 10H            
MOV DL, 0H
INT 10H

POP BX

CMP AL, 'l'           ;CHECK IF CLOCKWISE
JE CCWCOUNT

MOV AH, 09H           ;print "turning clockwise"
MOV DX, OFFSET tcw
INT 21H

MOV BL, 1             ;index for moving motor

JMP DONEDIRECT  

CCWCOUNT:

MOV AH, 09H
MOV DX, OFFSET tccw   ;print "turning ccw"
INT 21H

MOV BL, 0

donedirect:
ret
DIRECT ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;CREATES BLUE BACKGROUND;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BLUBOX PROC NEAR
MOV AH, 7H          ;creates a blue background         
MOV AL, 0H
MOV BH, 1EH
MOV CH, 0H
MOV CL, 0H
MOV DH, 24
MOV DL, 79
INT 10H


MOV AH, 02H           ;moves cursor for menu
MOV BH, 0H  
MOV DH, 2H
MOV DL, 25H
INT 10H

MOV AH, 09            ;PRINTS "MENU"
MOV DX, OFFSET MENU
INT 21H



RET
BLUBOX ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;
;clears the screen;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;

CLEARSCREEN PROC NEAR

MOV AH, 06H                   ;clear screen
MOV AL, 0
MOV BH, 7
MOV CH, 0
MOV CL, 0
MOV DH, 24
MOV DL, 79
INT 10H

MOV AH, 02H                   ;moves the cursor
MOV BH, 0H
MOV DH, 0H
MOV DL, 0H
INT 10H

RET
CLEARSCREEN ENDP


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;program is finished;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 

FINISH:  

call clearscreen    


lea dx, pkey
mov ah, 9
int 21h        ; output string at ds:dx

; wait for any key....    
mov ah, 1
int 21h

mov ax, 4c00h ; exit to operating system.
int 21h    
ends

end start ; set entry point and stop the assembler.

No correct solution

OTHER TIPS

16-bit signed int can only hold values from -32768 to 32767. There's no way to express larger signed values except using other encodings such as excess-n

If you don't need negative angles then just use an unsigned type and you'll get twice the range. Otherwise you'll have to use 32-bit int (dd) instead, and drop the old 8086 if possible

However, you're measuring to the 100th of a degree instead of the nearest 10th of a degree as mentioned, so you're losing 10 times the range. If 1/10 degree resolution is what you really want then with a 16-bit int you'll be able to store angles from -3276.8° to 3276.7°, just reduce the input by 10 times

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top