2

I am programming a PIC1847q processor on the curiosity HPC board. My task is to design a battlestar galactica cyclon visor using the LEDs on the board. My current code does infact create and replicate the Cyclon, but I do not think the logic is correct for the way I am "assigned" to do it. I am supposed to create a second variable, but I am unsure of how to do this. My question is: How can I get the same result using a boolean variable with boolean logic instead of the way I have it done? I attached an image of what the assignment is. enter image description here

 ;; Inputs: None
    ;; Outputs: LEDs are illuminated and extinguished
    ;; Side Effects: I/O Configured. Lights and extinguishes four LEDs.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Required header items
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    PROCESSOR 18F47Q10
    #include <xc.inc>
    #include "EE367_PIC18F47Q10_Setup01.inc"
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Constants
    // Configuration values for Timer 1 control registers
    TMR1_CS_Bits EQU 00000001B // Set to TMR1CLK to FOSC/4 (Instruction Clock)
    TMR1_Con_Bits EQU 00110011B // Set to ON, RD16, SYNC-bar, 8x prescaler
    TMR1_GCon_Bits EQU 00000000B // GE = 0, Gating is disabled
    TMR1IF_Mask EQU 00000001B // TMR1IF bit is b0 or PIR4
    TMR1IF_POSN EQU 0 // Ditto
    InitialTMR1H EQU 0xe4 // Initial value for Two-byte TMR counter register
    InitialTMR1L EQU 0x00 // 0xC000 gives about 1/2 second delay


    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    // none
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Allocate space for variables
    Global TMR1_Initializer

    PSECT udata_acs
    TMR1_Initializer: DS 2 // Value used to initialize TMR 1, each cycle
    
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    // none
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; InitializeTimerOne: Setup configuration for TMR1 to count up
    ;; Inputs: none
    ;; Outputs: none
    ;; Side Effects: Reinitializes the TMR1 counter register,
    ;; and clears TMR1 IF flag bit
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  
    ;; Main program
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    PSECT Code,class=CODE,abs
    Code:
    ORG 0x000000
    GOTO Start
    ORG 0x000020
    
    // Enter program body here
    Start:
    Call InitializeIO_Ports

    Flash01:
    //initial state
    movlw 16
    movwf LATA,a// Adds value of Wreg to LATA LED 2 4
    
   BRA LeftRotate

   RightRotate: 
    CALL InitializeTimerOne // Comment required
    CALL DelayTMR1 ;; Call DelayTMR1
    
    RRNCF LATA,a
    CALL InitializeTimerOne // Comment required
    CALL DelayTMR1 ;; Call DelayTMR1
    
     RRNCF LATA,a
    CALL InitializeTimerOne // Comment required
    CALL DelayTMR1 ;; Call DelayTMR1
    

    RRNCF LATA,a
    CALL InitializeTimerOne // Comment required
    CALL DelayTMR1 ;; Call DelayTMR1
    
    BNZ LeftRotate
    
    LeftRotate: 
   RLNCF LATA,a
   CALL InitializeTimerOne // Comment required
    CALL DelayTMR1 ;; Call DelayTMR1
    
    RLNCF LATA,a
   CALL InitializeTimerOne // Comment required
    CALL DelayTMR1 ;; Call DelayTMR1
    
    RLNCF LATA,a
   
    BNZ RightRotate

    Sleep // Halt

    InitializeTimerOne:
  
   MOVLW TMR1_GCon_Bits ;; 8 bits for the TMR1 Gating Cntl Reg
   MOVWF T1GCON,A
   MOVLW TMR1_CS_Bits ;; 8 bits for the TMR1 clock signal Cntl Reg
   MOVWF T1CLK,A
   MOVLW TMR1_Con_Bits ;; 8 bits for the TMR1 Main Cntl Reg
    MOVWF T1CON,A ;; Note: this instruction starts the timer
    MOVLW InitialTMR1L ;; Set an initial value into var TMR1_Initializer 
    MOVWF TMR1_Initializer,A ;; which is a variable used to initialize
   MOVLW InitialTMR1H ;; the TMR1 counter on each pass.
    MOVWF TMR1_Initializer,A
    RETURN
   

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; DelayTMR1: Busy wait until timer one times out.
    ;; Will initialize TIMR1 counter register and return immediately,
    ;; if timer 1 is already expired.
    ;; Inputs: none
    ;; Outputs: none
    ;; Side Effects: Reinitializes the TMR1 counter reg and clears TMR1 IF flag bit
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    DelayTMR1:
    BANKSEL PIR4 ;; The flag bit is in SFR PIR4, Banked Mode required
    DelayTMR1_Repeat01:
    MOVF PIR4,W,B ;; These two steps use AND masking to detect
    ANDLW TMR1IF_Mask ;; the TMR1 IF flag bit.
    BZ DelayTMR1_Repeat01 ;; Go into busy wait until TIMR1IF is set.
    MOVFF TMR1_Initializer,TMR1H ;; Reinitialize the 16-bit TMR1 counter
    MOVFF TMR1_Initializer,TMR1L ;;
    BCF PIR4, TMR1IF_POSN,B ;; Clear the flag, ready for the next cycle
    RETURN
    
    InitializeIO_Ports:
        CLRF LATA,A // Clear Port A output bits, before activating Port A
    
    CLRF TRISA,A // Make Port A an output port
        return
        
        
    end Code
    
     
Max Sorin
  • 21
  • 2

1 Answers1

0

Even though this question is a bit old, I consider answering in the hope of helping to others those who may have similar problem. OP's implementation seems to do the job but not conforming exactly to the assignment requirements. For example it neither make use of a LEDMask variable nor the bRotateLeftLED variable. The code also has to many repeated calls which can be reduced to minimal. The timer initialization souldn't be done everytime we delay. Instead the timer module is initialized once before entering the main loop, then everytime we call delay, we only reload the timer value so that it produce the same amount of delay. Let's write a psuedo C-like code to translate the problem to the PIC assembly language. This will give us more human readble aspect of the problem and makes it easier to implement in assembly. According to the assignment the logic would be as following:

variable bRotateLeftLED
variable LEDMask

// Init timer module once
initTimer1()
// Start from right o left
LEDMask = 0x10
bRotateLeftLED = true

// Main loop
while(true) {
    if(bRotateLeftLED == true) {
        if(LEDMask & 0x80 != 1) {
            // shift the bit towards 7th bit
            LEDMask <<= 1
        }
        else {
            // Reached to the 7th bit, reverse the shifting direction
            bRotateLeftLED = false
        }
    }
    else{
        if(LEDMask & 0x10 != 1) {
            // shift the bit towards 4th bit
            LEDMask >>= 1
        }
        else {
            // Reached to the 4th bit, reverse the shifting direction
            bRotateLeftLED = true
        }
    }

    // Output the LED LEDMask through PORTA
    LATA = LEDMask
    // Delay to make the output movement visible to the human eye
    Delay
}

Now that we have an aspect on the matter, we can make our best to translate it to the PIC assembly. However I only write the code that will do the job and omit the rest since some init or similar codes might be application specific. I also will reference the assembly code to its corresponding psuedo code to make it more understandable.

; NOTE: We will interprete the false as 0 value, and the true any value other than 0.

; Initialization block
Init:
    ; Maybe other init codes...

    ; initTimer1()
    CALL    initTimer1
    ; LEDMask = 0x10
    MOVLW   0x10
    MOVWF   LEDMask
    ; bRotateLeftLED = true
    SETF    bRotateLeftLED  ; init the flag with true to start shifting towards left
    ; NOTE: Although I use byte-wise flag here for the simplicity, it's much better
    ; and memory efficient using bitwise flags instead of using the whole 8 bits
    ; to present a boolean state. Byte-wise usage is wasting other 7 bits of the byte.

; while(true): Main loop
Start:
; Following label is optional to provide better readability
DoRotateLeft:
    ; if(bRotateLeftLED == true)
    MOVF    bRotateLeftLED, W
    ANDLW   0xFF
    BNZ
    BRA     DoRotateRight
    ; if(LEDMask & 0x80 != 1)
    MOVF    LEDMask, W
    ANDLW   0x80
    BNZ      RotateLeftDone
    ; LEDMask <<= 1 - rotate left once without carry
    RLNCF   LEDMask, F
    ; end of if(LEDMask & 0x80 != 1) block
    BRA     OutputAndDelay
; end of if(LEDMask & 0x80 != 1) block
; else block of if(LEDMask & 0x80 != 1) tree
RotateLeftDone:
    ; bRotateLeftLED = false
    CLRF    bRotateLeftLED  ; Set the boolean flag to false
    BRA     OutputAndDelay
; end of if(LEDMask & 0x80 != 1) - else block
; end of if(bRotateLeftLED == true) block

; else block of if(bRotateLeftLED == true) tree
DoRotateRight:
    ; if(LEDMask & 0x10 != 1)
    MOVF    LEDMask, W
    ANDLW   0x10
    BNZ      RotateRightDone
    ; LEDMask >>= 1 - rotate right once without carry
    RRNCF   LEDMask, F
    ; end of if(LEDMask & 0x10 != 1) block
    BRA     OutputAndDelay
; end of if(LEDMask & 0x10 != 1) block
; else block of if(LEDMask & 0x10 != 1) tree
RotateRightDone:
    ; bRotateLeftLED = true
    SETF    bRotateLeftLED  ; Set the boolean flag to true
; end of if(LEDMask & 0x10 != 1) - else block
; end of if(bRotateLeftLED == true) - else block
; No need to branch to OutputAndDelay here since the program will naturally flow to there


OutputAndDelay:
    MOVFF   LEDMask, LATA
    ; Note that we do not initialize the timer1 for each call since it is done once.
    CALL    DelayT1

    BRA Start   ; end of main loop while(true) block: Loop infinitely


; Here goes Delay subroutine
DelayT1:
    ; The delay code goes here
    ; Reload the timer registers for the next delay upon the timer overflow
    MOVLW   InitialTMR1H
    MOVWF   TMR1H
    MOVLW   InitialTMR1L
    MOVWF   TMR1L
    RETURN


    ; Maybe some more codes...

    END
Kozmotronik
  • 2,080
  • 3
  • 10
  • 25