HomeArticlesProjectsBlogContact
Articles
Simon P4
Colin Mitchell
Colin Mitchell
Make sure to subscribe to our newsletter and be the first to know the news.

Analysing the PIC16F628 program

  • P1
  • P2
  • P3
  • P4
  • P5

THE PROGRAM

To understand how ANY program works, you have to try to get into the mind of the programmer.
This is very difficult as he doesn’t leave much behind, other than the lines of code for the program.
It’s easy to see why some instructions have been included but the missing link is the overall structure of the program.
It’s easy to see what the instructions are doing in the program, but the question is, why has they been included?
Simon is a typical example.
How does it work? How are the random values created? How are they stored. How does the program keep track of the player repeating the sequence, how does it store the highest score in EEPROM, and lots of other things.
Each function or “operation” is a “building-block” and once you know how they are created, you can use them for other programs.
That’s how your skills build up.
The complete program is on the next page.
In this discussion we will analyse some of the sub-routines.

The first question you may be asking is: ”How are the random numbers created?”
The microcontroller has one or more “timers” or “counters” consisting of an 8-bit file or register, that can be connected to the main oscillator in the chip and incremented at the same rate as the micro executes the program.
The timer we have used for the random-number generation is TIMER 0. It is constantly being “clocked” and when the program gets to the sub-routine called: MakeStep it calls the MakeRandom sub-routine:

MakeStep:
    call    MakeRandom  ;ascertain random number

The MakeRandom sub-routine looks at timer 0, removes all bits except the two lowest and puts the result into file 34h:

MakeRandom:
    movf    tmr0,w
    andlw   0x03    ;mask all but bit0 and bit1
    movwf   random  ;move random number into file 34h
    return

The next mystery is: ”How are the random numbers stored?”
Firstly you have to understand some of the features of the Simon program:
The game creates up to a maximum of 52 “steps.”
Each step consists of a number: 0 = red, 1 = green, 2 = yellow, 3 = orange.
Each result requires 2 bits and the program stores four steps in a file. Bits 0&1 = step 1,
bits 2&3 = step 2, bits 4&5 = step 3, bit 5&7 = step 4.
The first memory location is 3Ah and the last location is 46h. Thirteen locations x 4 = 52 steps.
Each file holding four steps is referred to as a “line.” The program has a pointer that looks down the files, from 3Ah to 46h, called the “line pointer.”
The 2-bits for each step is called a “column.”
The column-pointer is shifted across each file and looks at the 1st, 2nd, 3rd and 4th step.
The sub-routine that places a new value into a file is: MakeStep.
The program also has two files that keeps track of the number of steps.
When power is turned on, all the files are cleared and the “line-file,” line_w is loaded with the beginning of memory for the steps (3Ah) and the column file (column_w) will be zero.
MakeStep sub-routine gets the random number and moves the value in line_w to the File Select Register (FSR) so that when the INDirect File (INDF) is accessed, the random number will be placed in the file identified by INDF.
To find out if the random number is to be placed in column 1, 2, 3 or 4, column_w is XOR’ed with 0, 1 or 2. If it is none of these values, the program assumes it is 3. The two bits are added to the file via the IOR instruction. This is the Inclusive OR instruction in which any “1” in either file is placed into the file in its correct location. If column_w is “1,” the two bits of the random number are shifted left two times so they can be put into location “2&3” via INDF.
Column_w file is then incremented and bit 2 is tested to see if the file has reached 04. If so, it is zero’ed and line_w is incremented.

MakeStep:
    call    MakeRandom  ;get random number
    movf    line_w,w    ;get current line
    movwf   fsr         ;pointer to next available memory
    bcf status,c        ;initialise carry
    movf    column_w,w  ;get current column
    xorlw   0           ;is column file = 0?
    BTFSC   STATUS,Z    ;zero flag will be set if column file is zero.
    GOTO    GCol0       ;column = 0 - don't shift the random number
    xorlw   0x01        ;is column file = 1?
    BTFSC   STATUS,Z
    GOTO    GCol1       ;column = 1 - shift random 2 times
    XORLW   0x03
    BTFSC   STATUS,Z
    GOTO    GCol2       ;column = 2 - shift random 4 times
    rlf random,f        ;column = 3 - shift random 6 times
    rlf random,f
GCol2:  rlf random,f
    rlf random,f
GCol1:  rlf random,f
    rlf random,f
GCol0:  movf    indf,w  ;file looked at by FSR is put into W
    iorwf   random,w    ;merge new random number into table
    movwf   indf        ;restore in sequence table
    incf    column_w,f  ;update column
    btfss   column_w,2  ;have 4 steps been put into the column file?
    return              ;no - return
    clrf    column_w    ;yes - clear the column counter file.
    incf    line_w,f    ;increment the line file for the next 4 steps
    return

“How does the program read the steps?”

The sub-routine to read the steps is called “ShowSequence.”
Another sub-routine allows the creation of up to a maximum of 52 steps which the player has to repeat.
These steps are placed in 13 files - from 3A to 46h - with four steps in each file.
The ShowSequence starts at file 3A by loading 3A into FSR and reading INDF. The answer will be the value stored in file 3A. The first two bits indicate the first step, etc up to bits 6,7 for step 4 of the sequence.
The value in file 3A is transferred to steptemp to work on it.
ShowSequence will not be accessed unless at least one step has been created.
ShowSequence knows the number of steps in the highest file by referring to column_w pointer. The sub-routine assumes all lower files have 4 steps - even though some steps will be “00.”
The column-pointer read-file is zeroed and the first line in memory is loaded into FSR.
The value in the first memory location is placed into file 47h (steptemp) to work on it. It may have 1, 2, 3 or 4 steps if the program has just started. The sub-routine gets the number of steps from column_r pointer. If column_r pointer is zero, only one step is in the sequence. File 47h is put into W and bits 2-7 are masked to get only bit 0 and 1. This value is moved to a temporary file called RANDOM and one of the LEDs is displayed on the screen, along with a tone.
The column-read file is then incremented and checked to see if more than 4 passes of the sub-routine have been made and if not it is compared to column_w pointer to see if less than 4 steps are in the file.
When the correct number of steps have been displayed, the micro exits the sub-routine.
Obviously the program would be much simpler if 52 separate files were used. The micro could simply advance down the files and display the particular LED. But that would not demonstrate the skill of the programmer!

ShowSequence:
    clrf    column_r        ;zero the read-column pointer
    movlw   LINE_OFFSET     ;load 3A into line-pointer
    movwf   line_r          ;   to start at file 3A
Ss1:    movf    line_r,w        ;this instruction is needed when looping
    movwf   fsr             ;put 3A into File Select Register
    movf    indf,w          ;put value in file looked-at by FSR into W
    movwf   steptemp        ;move value into file 47h to work on it
    movf    column_r,w      ;get current column (will be 0, 1, 2 or 3)
    xorlw   0               ;is column-pointer = 0?
    BTFSC       STATUS,Z    ;yes, for the first pass of the routine
    GOTO    SCol0           ;column-pointer = 0 - don't shift
    xorlw   0x01            ;yes, for the second pass of the routine
    BTFSC       STATUS,Z
    GOTO    SCol1           ;column-pointer = 1 - shift random 2 times
    XORLW       0x03
    BTFSC       STATUS,Z
    GOTO    SCol2           ;column-pointer = 2 - shift random 4 times
    rrf steptemp,f          ;column-pointer will be 3 - shift random 6 times
    rrf steptemp,f
SCol2:  rrf steptemp,f
    rrf steptemp,f
SCol1:  rrf steptemp,f
    rrf steptemp,f
SCol0:  movf    steptemp,w  ;get current memory byte of table
    andlw   0x03            ;mask bits 2-7
    movwf   random          ;move the step-value to a file called RANDOM
    call    ShowStep        ;display LED according to stored value
    call    Delay150        ;wait a little after player
    call    Delay150        ;has pressed a key
    call    Delay150
    incf    column_r,f      ;1st pass=0, 2nd pass=1, 3rd pass=2, 4th pass=3
    btfsc   column_r,2      ;5th pass = 0000 0100 -  bit 2 detected
    goto    Colov1          ;
Ss2:    movf    column_r,w  ;no
    xorwf   column_w,w      ;column pointers the same? We are detecting
    btfss   status,z        ;  if only one, two or three steps are in the file.
    goto    Ss1             ;no - at least another step to show
    movf    line_r,w        ;yes
    xorwf   line_w,w        ;reached the end of sequence?
    btfsc   status,z        ;no - jump next instruction
    return                  ;yes - sequence complete!
    goto    Ss1             ;at least another step to show
Colov1: clrf    column_r    ;zero the pointer as the job is done
    incf    line_r,f        ;increment the line pointer
    goto    Ss2

“How does the program show the steps?”

A ‘step” consists of showing the LED then producing a corresponding tone. The program does this via the ShowSep sub-routine.
The value for the LED is contained in file: RANDOM.
This file is XOR’ed with 0, 1 or 2 (and if not one of these values, it assumes the value is 3) to get the value for the LED.
This is done in sub-routine ShowLED and after outputting the value of the LED, the micro returns with a beep value in W so the tone can be produced.

ShowStep:
    call    ShowLed         ;show random number on led
    movwf   note_tone       ;ShowLed returns with beep value in W
    movlw   LENGTH_SEMIBREVE
    movwf   note_length
    movlw   0x10            ;easy level
    btfss   porta,LEVEL     ;get level of difficulty
    movlw   0x01            ;hard level
    movwf   note_tempo      ;speed of beep
    call    SoundPlay       ;play button beep
    clrf    portb           ;turn all leds off
    return
ShowLed:
    movf    random,w        ;get random number
    xorlw   0
    BTFSC       STATUS,Z
    goto    ShowRed         ;random=0
    xorlw   0x01
    BTFSC       STATUS,Z
    GOTO    ShowGreen       ;random=1
    xorlw   0x03
    BTFSC       STATUS,Z
    GOTO    ShowYellow      ;random=2
    goto    ShowOrange      ;random=3

ShowRed:
    bsf portb,LED_RED       ;turn on red led
    retlw   KEY_RED_SOUND   ;tone frequency

ShowGreen:
    bsf portb,LED_GREEN     ;turn on green led
    retlw   KEY_GREEN_SOUND ;tone frequency

ShowYellow:
    bsf portb,LED_YELLOW    ;turn on yellow led
    retlw   KEY_YELLOW_SOUND    ;tone frequency

ShowOrange:
    bsf portb,LED_ORANGE    ;turn on orange led
    retlw   KEY_ORANGE_SOUND    ;tone frequency

“How does the program recognise the player?”

The player needs to repeat the sequence of flashes and beeps. This is handled by “GetUserSequence” sub-routine.
The sub-routine gets the first step and by Indirectly addressing memory and placing the value of the first file into steptemp shifting it to the right (if necessary) and ANDing it with 03 to get the two lowest bits. These are placed in a file called RANDOM.

GetUserSequence:
    clrf    column_r        ;begin at start of step sequence
    movlw   LINE_OFFSET
    movwf   line_r
Us1:    movf    line_r,w
    movwf   fsr
    movf    indf,w
    movwf   steptemp
    movf    column_r,w      ;get current column
    xorlw   0
    BTFSC       STATUS,Z
    GOTO    UCol0           ;column=0 - don't shift
    xorlw   0x01
    BTFSC       STATUS,Z
    GOTO    UCol1           ;column=1 - shift random 2 times
    xorlw   0x03
    BTFSC       STATUS,Z
    GOTO    UCol2           ;column=2 - shift random 4 times
UCol3:  rrf steptemp,f      ;column=3 - shift random 6 times
    rrf steptemp,f
UCol2:  rrf steptemp,f
    rrf steptemp,f
UCol1:  rrf steptemp,f
    rrf steptemp,f
UCol0:  movf    steptemp,w  ;get current memory byte of table
    andlw   0x03            ;mask bits 2-7
    movwf   random

    call    Keypad          ;get player's input - returned in W
                            ;W=0 - no key pressed (timeout)
                            ;W=1 - player has pressed a key

The Keypad sub-routine is then called. Keypad sub-routine firstly clears the “key” file and loads three files to create a delay loop of 5 seconds looking for a button-press. If the sub-routine
times-out before a key is pressed, W will be zero.
When a key is pressed, the appropriate LED is illuminated and the a tone is produced. The LED is kept illuminated while the key is pressed.
When the key is released, the output port is cleared and the sub-routine returns.

Keypad:
    clrf    key         ;initialise key
    movlw   0x07        ;assume easy level - 5 sec timeout
    btfss   porta,LEVEL ;get level of difficulty
    movlw   0x03        ;hard level - 2 sec timeout
    movwf   timerc
Kp2:    movlw   0xff
    movwf   timerb
Kp1:    movlw   0xff
    movwf   timera

Kwait:  btfsc   portb,KEY_RED
    goto    KeyRed
    btfsc   portb,KEY_GREEN
    goto    KeyGreen
    btfsc   portb,KEY_YELLOW
    goto    KeyYellow
    btfsc   portb,KEY_ORANGE
    goto    KeyOrange
    decfsz  timera,f
    goto    Kwait
    decfsz  timerb,f
    goto    Kp1
    decfsz  timerc,f
    goto    Kp2
    retlw   0           ;player hasn't pressed key!

KeyRed:
    bsf portb,LED_RED       ;turn on red led
    clrf    key             ;key=0
    movlw   KEY_RED_SOUND   ;tone frequency
    goto    Beep1

KeyGreen:
    bsf portb,LED_GREEN     ;turn on green led
    bsf key,0               ;key=1
    movlw   KEY_GREEN_SOUND ;tone frequency
    goto    Beep1

KeyYellow:
    bsf portb,LED_YELLOW        ;turn on yellow led
    bsf key,1                   ;key=2
    movlw   KEY_YELLOW_SOUND    ;tone frequency
    goto    Beep1

KeyOrange:
    bsf portb,LED_ORANGE        ;turn on orange led
    bsf key,0                   ;key=3
    bsf key,1
    movlw   KEY_ORANGE_SOUND    ;tone frequency
Beep1:  movwf   note_tone       ;save tone
    movlw   LENGTH_SEMIBREVE
    movwf   note_length
    movlw   0x03
    movwf   note_tempo      ;speed of beep
Beep2:  call    SoundPlay   ;play button beep
    movf    portb,w         ;test for a key press
    andlw   0x0f            ;mask keys
    xorlw   0x00            ;are any keys being pressed?
    btfss   status,z        ;no - skip next instruction
    goto    Beep2           ;yes - keep beeping!
    clrf    portb           ;turn off all leds
    retlw   1               ;return to calling function

After calling Keypad, the sub-routine compares the key with the step. If the key is incorrect, the micro exits the sub-routine. If the key is correct, the sub-routine gets the next step and waits for the key to be pressed.

        call    Keypad      ;get player's input - returned in W
                            ;W=0 - no key pressed (timeout)
                            ;W=1 - player has pressed a key
    xorlw   0               did player press a key?
    btfsc   status,z        ;yes
    retlw   0               ;no - exit function
    movf    key,w           ;compare pressed key with step
    xorwf   random,w        ;is it the same?
    btfss   status,z        ;yes - jump next instruction
    retlw   0               ;no - incorrect, exit function
    incf    column_r,f      ;update column
    btfsc   column_r,2      ;overflow?
    goto    Colov2          ;yes
Us2:    movf    column_r,w  ;no
    xorwf   column_w,w      ;column pointers the same?
    btfss   status,z
    goto    Us1             ;no - at least another step to show
    movf    line_r,w        ;yes
    xorwf   line_w,w        ;reached the end of sequence?
    btfsc   status,z        ;no - jump next instruction
    retlw   1               ;yes - sequence complete!
    goto    Us1             ;at least another step to show

Colov2: clrf    column_r
    incf    line_r,f
    goto    Us2

There are other routines in the program however, at this stage, you only need to follow the ones we have discussed.
If you are new to programming or just want to modify some of the program, go to Start Here with PIC16F628. It has the instruction-set and templates for the micro.


Colin Mitchell

Colin Mitchell

Expertise

electronics
writing
PIC-Chips

Social Media

instagramtwitterwebsite

Related Posts

TODO
Transistor Test
© 2021, All Rights Reserved.

Quick Links

Advertise with usAbout UsContact Us

Social Media