Comparing Inputs To A Random Sequence URGENT!

Sergei Ko

Member
Hi there I'm a student looking for some help programming an 08M2 microcontroller for a specific function. I have lots of experience coding in python and java but BASIC is quite new to me and I can't find a way to define my own functions.

I have a circuit which has two input buttons and two output LEDs. The left button corresponds to the left LED and same for the right side. The premise is simple, a random sequence of length x (ideally x is as large as possible) is generated, possible values are either 1 or 0 for left led / right led.
Example sequence: left, right, right, right, left, left ...
The first entry in the list will flash so in this case the left LED.
If the left button is then pressed the sequence will play through the first two entrys, left LED and then right LED
If the left button and the right button is then pressed the first three entries of the list will play through and so on and so forth.
If the input is wrong a new sequence is generated and played once again from the first entry and if the entire sequence is correct a new sequence is generated and then played from the beginning.

If this is impossible im willing to remove progressive nature of 1LED flash, 2 LED flash etc... and just have a sequence of 10 flashes and compare input to the sequence and if incorrect repeat the sequence and try again or if correct create a new sequence to play.
 

Buzby

Senior Member
Hi Sergei,

Welcome to the forum !.

Your project sounds like a simpler version of 'Simon Says', a project available from the PICAXE store.

The code for 'Simon Says' is already provided for you in the 'open samples'/'basic' folder in PE6, as AXE106.

Have a look at this, you should be able to see how to reduce it from 4 buttons to two buttons.

Cheers,

Buzby
 

erco

Senior Member
Welcome, Sergei.

"URGENT!" sure sounds like a soon-due class assignment. We are here to help but certainly not do your homework for you. Start writing your code and try it out. Post it here with specific problems and questions and we're happy to nudge you in the right direction.
 

Sergei Ko

Member
Hi all I've had a good go looking at various methods to implement something like this on an 08M2 looking through a previous https://github.com/leonsodhi/simon-says GitHub project and another similar project on the forum but I still can not get it to work for me (I'm not using a piezo like these other two). Originally this was a school assignment but I do genuinely want to try and fix this.

Code:
symbol startBtn = pinC.3
symbol countPin = C.2
symbol ledMSB = C.4
symbol ledLSB = C.0
symbol buttonsPin = C.1

symbol seg7Count = b1
symbol btnHit = b2
symbol numSteps = b4

symbol STEP_DATA_START = 28
symbol BTN1_HIT = 1
symbol BTN2_HIT = 2
symbol BTN3_HIT = 3



start0:
    input C.3
    output countPin
    output ledMSB
    output ledLSB
    input buttonsPin

    low countPin

    numSteps = 0
    call initSteps

    call runDemo
    seg7Count = 0    ;7seg is reset in hw

    goto main

main:
    call ledsoff
    call incCount        ;start counter @ 1
    pause 1000

    symbol i = b5
    symbol k = b6
    symbol stepCount = b7
    symbol thisStepStart = b8

    thisStepStart = STEP_DATA_START
    for i = 1 to numSteps
        bptr = thisStepStart
        stepCount = @bptrinc

        ;======================
        for k = 1 to stepCount
            call bptrLedOn
            pause 1000
            call ledsoff
            pause 500
            inc bptr
        next k
        ;======================

        ;======================
        bptr = thisStepStart
        stepCount = @bptrinc
        for k = 1 to stepCount
            call readButtonsLoop
            call bptrLedOn
            pause 100
            if btnHit != @bptrinc then
                 ;reset 7seg to 0
                k = 10 - seg7Count
                for i = 1 to k
                    call incCount
                next i
                goto start0
            else
                call ledsoff
            end if
        next k
        ;======================

        thisStepStart = bptr
        call incCount
    next i

    goto missionComplete


initSteps:
    bptr = STEP_DATA_START

    @bptrinc = 3    ;count
    @bptrinc = 1
    @bptrinc = 2
    @bptrinc = 3
    inc numSteps

    @bptrinc = 5    ;count
    @bptrinc = 2
    @bptrinc = 1
    @bptrinc = 2
    @bptrinc = 3
    @bptrinc = 1
    inc numSteps

    ;this isn't very random!
    symbol randomByte1 = b10
    symbol randomByte2 = b11
    symbol randomWord = w5
    @bptrinc = 5    ;count
    randomWord = time
    for i = 1 to 5
        random randomWord
        @bptrinc = b10 & 3
    next i
    inc numSteps

    ;Counter imposes a limit of 9 steps
    numSteps = numSteps MAX 9

    return


runDemo:
    call led1On
    for i = 0 to 6
        if startBtn = 1 then
            call waitForStartButt
            return
        else
            pause 50
        end if
    next i

    call led2On
    for i = 0 to 6
        if startBtn = 1 then
            call waitForStartButt
            return
        else
            pause 50
        end if
    next i

    call led3On
    for i = 0 to 6
        if startBtn = 1 then
            call waitForStartButt
            return
        else
            pause 50
        end if
    next i

    goto runDemo


waitForStartButt:
    ;wait utill button isn't pressed
    if startBtn = 1 then
        goto waitForStartButt
    end if
    return


missionComplete:
    call incCount
    if startBtn = 1 then
        call waitForStartButt
        goto start0
    end if
    goto missionComplete


bptrLedOn:
    select case @bptr
        case 1
            call led1On
        case 2
            call led2On
        case 3
            call led3On
        else
    endselect
    return


led1On:
    low ledMSB
    high ledLSB
    return

led2On:
    high ledMSB
    low ledLSB
    return

led3On:
    high ledMSB
    high ledLSB
    return

ledsOff:
    low ledMSB
    low ledLSB
    return


incCount:
    pulsout countPin,10

    inc seg7Count
    seg7Count = seg7Count % 10
    return


readButtonsLoop:
    symbol ledResist = b0
    disconnect
    readadc buttonsPin, ledResist
    pause 100
    if ledResist >= 150 AND ledResist <= 160 then
        btnHit = BTN1_HIT
    elseif ledResist >= 170 AND ledResist <= 180 then
        btnHit = BTN2_HIT
    elseif ledResist >= 190 AND ledResist <= 200 then
        btnHit = BTN3_HIT
    else
        goto readButtonsLoop
    endif
    return

How would I modify the above to work on two buttons, pin3 and 4 and two LEDs pin 0 and 1.
Any help is very much appreciated
 
Last edited by a moderator:

Buzby

Senior Member
That code in post #4 looks a bit strange.

It's got mentions of 7seg displays, with MSB and LSB drives, but seems to drive two single LEDs instead.
It also appears to detect the specific button by reading an analogue input into a variable called 'LEDresist'.
Why use a variable with 'LED' in it's name when you are trying to read a 'BUTTON' ?

I still think the AXE106 solution is best for you.

Put it in the simulator, see how it uses 4 buttons and LEDs, then try to see how to use less buttons/LEDs.
 

Sergei Ko

Member
That code in post #4 looks a bit strange.

It's got mentions of 7seg displays, with MSB and LSB drives, but seems to drive two single LEDs instead.
It also appears to detect the specific button by reading an analogue input into a variable called 'LEDresist'.
Why use a variable with 'LED' in it's name when you are trying to read a 'BUTTON' ?

I still think the AXE106 solution is best for you.

Put it in the simulator, see how it uses 4 buttons and LEDs, then try to see how to use less buttons/LEDs.
Although I’d love to use something other than the 08M2 I simply don’t have access to a better microcontroller.
 

Buzby

Senior Member
The AXE106 uses the 18M2 chip, but thats no problem for you, because the simulator will run it as a 18M2.

Use the simulator to see how the code works on 18M2, make changes to 'remove' two buttons and LEDs, then switch the simulation to 08M2.

When you are happy that the simulation works as you want, then you can try it on your real 08M2.

The simulator is a really good tool, it will make life much easier if you use it !.

Cheers,

Buzby
 

hippy

Ex-Staff (retired)
I would have thought it quite an advanced challenge for a school project but it is possible to do it from scratch. The 08M2 is rather limited in its capabilities, a limited number of variables and no Scratchpad memory, so it's worth defining a starting point which we know is within its capabilities. We can extend that later if need be.

For me that would primarily mean having a maximum 16 step sequence. It would be a reasonable number to start with and it means each step can be held in a single 16-bit variable using a bit value of 0 or 1 to indicate which LED is selected. The MSB (bit 15) can be the first in the sequence, LSB (bit 0) the last. Those would also actually be 'bit15' through 'bit0' variables once that sequence had been moved into the 'w0' variable.

I would also suggest it's just as easy to create a maximum step sequence whenever we need a new one rather than do anything else.

So, a starting point for coding would be to have a routine which can create a maximum length sequence, a routine which prints that out using SERTXD so we can see what is being generated as a sequence, and a routine which will flash a certain length of sequence on the LED's. We can start by showing the full length of the sequence. Plus we'll need to define the variables we are using for that.

This would be my starting point -
Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

Symbol LED0          = C.1 ; One LED
Symbol LED1          = C.2 ; The other LED

Symbol reserveW0     = w0  ; Temporary storage
Symbol random_number = w1  ; Random number
Symbol sequence      = w2  ; Random sequence
Symbol length        = w3  ; Length of sequence
Symbol sequence_bit  = w4  ; Which sequnce bit

#Macro Randomize
  Random random_number
#EndMacro

MainProgram:
  Do
    Gosub CreateSequence
    Gosub PrintSequence
    length = 16
    Gosub ShowSequence
    Pause 5000
  Loop

CreateSequence:
   For sequence_bit = 1 To 16
     Randomize
     sequence = sequence * 2 + random_number
   Next
   Return

PrintSequence:
  w0 = sequence
  SerTxd( #bit15, #bit14, #bit13, #bit12 )
  SerTxd( #bit11, #bit10, #bit9,  #bit8  )
  SerTxd( #bit7,  #bit6,  #bit5,  #bit4  )
  SerTxd( #bit3,  #bit2,  #bit1,  #bit0, CR, LF )
  Return

ShowSequence:
  w0 = sequence
  For sequence_bit = 1 To length
    If bit15 = 0 Then
      High LED0
    Else
      High LED1
    End If
    Pause 500
    Low LED0
    Low LED1
    Pause 500
    w0 = w0 * 2
  Next
  Return
 

Sergei Ko

Member
Ive spent some time looking over the code and think I think I now understand it all. Bringing me back to the title of the post, how would I compare a sequence of inputs to a the sequence variable in the above?
 

hippy

Ex-Staff (retired)
In my code above I have the 'ShowSequence' routine which can produce the sequence of any length, from 1 to 16. Getting to a point where we would be trying to produce a sequence of length 17 means we have successfully matched all previous sequences; "game over", "you win".

So the basic premise is, create a sequence, output length 1 of the sequence, check button pushes match a length 1 sequence, if it does, output length 2 of the sequence, check button pushes match a length 2 sequence, repeat until a length 16 sequence has been matched. If any sequence doesn't match, "you lose", and we can start again by generating a new sequence.

We already have the 'ShowSequence' and we can add a 'MatchSequence' which sets a 'matched' variable which indicates if the sequence was matched (1) or wasn't (0) and adjust our 'MainProgram' to replicate the game play described above -
Code:
Symbol matched       = w5     ; Sequence matched flag

MainProgram:
  Do
    Gosub CreateSequence
    length = 1
    Do
      Gosub ShowSequence
      Gosub MatchSequence
      If matched = 0 Then
        Gosub YouLose
        Goto MainProgram      ; Start again
      End If
      length = length + 1
    Loop Until length > 16
    Gosub YouWin
  Loop

YouWin:
  ; Some celebratory LED flashing
  Return

YouLose:
  ; Some derogatory LED flashing
  Return
We then need to create that 'MatchSequence' routine which comes in the next instalment.
 

hippy

Ex-Staff (retired)
To match a sequence we can do similar to 'ShowSequence' but rather than outputting on the LED's we can wait for a button push and see if the button push matches the LED which would have been set. If it doesn't we can immediately return with 'matched' set to 0, otherwise we can keep going until the full length of the sequnce we had shown has been matched, returning 1 in the 'matched' variable to indicate that -

Code:
MatchSequence:
  w0 = sequence
  For sequence_bit = 1 To length
    ; Wait for a button push returned in the
    ; 'buttonPushed' variable.
    Gosub GetButtonPush
    ; Check the button push matches the step
    ; of the sequence. If not return with
    ; 'matched' set to zero
    If bit15 = 0 And buttonPushed <> 0 Then
      matched = 0
      Return
    End If
    If bit15 = 1 And buttonPushed <> 1 Then
      matched = 0
      Return
    End If
    w0 = w0 * 2
  Next
  ; If we matched all steps in the sequence
  ; return with 'matched' set to 1.
  matched = 1
  Return
We have introduced a new 'GetButtonPush' routine which waits for a button push, and returns a 0 or 1 value in a 'buttonPushed' variable which indicates which that was. That's in the next instalment.
 

hippy

Ex-Staff (retired)
Our final routine is our 'GetButtonPush' which returns a 0 or 1 in the 'buttonPushed' variable.

First we need to define the pins used for the buttons and what level they go to when the button is pushed; 0 if active low, where the button shorts the pin to 0V and there is a pull-up to V+, 1 if active high, where the button shorts to V+ with a pull-down to 0V. And we also need to define our 'buttonPushed' variable -

Code:
Symbol BTN0          = pinC.4 ; Button for LED0
Symbol BTN1          = pinC.3 ; Button for LED1

Symbol PUSHED        = 1      ; Buttons high when pushed

Symbol buttonPushed  = w6     ; Which button pushed
Then the actual routine code -

Code:
GetButtonPush:
  Gosub WaitForButtonsToBeReleased
  ; Wait for a button to be pushed. Put
  ; the number of the button pushed in
  ; the 'buttonPushed' variable. We set
  ; 'buttonPushed' initially to a value
  ; which isn't valid, will only return
  ; when it becomes 0 or 1.
  buttonPushed = -1
  Do
    If BTN0 = PUSHED Then
      buttonPushed = 0
     End If
    If BTN1 = PUSHED Then
      buttonPushed = 1
    End If
    Pause 10
  Loop Until buttonPushed = 0 Or buttonPushed = 1
  Gosub WaitForButtonsToBeReleased
  Return

WaitForButtonsToBeReleased:
  ; Wait until both buttons released
  Do
    Pause 10
  Loop Until BTN0 <> PUSHED And BTN1 <> PUSHED
  Pause 10
  Return
 

hippy

Ex-Staff (retired)
The full code will be -
Code:
#Picaxe 08M2
#Terminal 4800
#No_Data

Symbol LED0          = C.1    ; One LED
Symbol LED1          = C.2    ; The other LED

Symbol BTN0          = pinC.4 ; Button for LED0
Symbol BTN1          = pinC.3 ; Button for LED1

Symbol PUSHED        = 1      ; Buttons high when pushed

Symbol reserveW0     = w0     ; Temporary storage
Symbol random_number = w1     ; Random number
Symbol sequence      = w2     ; Random sequence
Symbol length        = w3     ; Length of sequence
Symbol sequence_bit  = w4     ; Which sequence bit
Symbol matched       = w5     ; Sequence matched flag
Symbol buttonPushed  = w6     ; Which button pushed

#Macro Randomize
  Random random_number
#EndMacro

MainProgram:
  Do
    Gosub CreateSequence
    length = 1
    Do
      Gosub ShowSequence
      Gosub MatchSequence
      If matched = 0 Then
        Gosub YouLose
        Goto MainProgram      ; Start again
      End If
      length = length + 1
    Loop Until length > 16
    Gosub YouWin
  Loop

YouWin:
  ; Some celebratory LED flashing
  Return

YouLose:
  ; Some derogatory LED flashing
  Return

CreateSequence:
   For sequence_bit = 1 To 16
     Randomize
     sequence = sequence * 2 + random_number
   Next
   Return

ShowSequence:
  w0 = sequence
  For sequence_bit = 1 To length
    If bit15 = 0 Then
      High LED0
    Else
      High LED1
    End If
    Pause 500
    Low LED0
    Low LED1
    Pause 500
    w0 = w0 * 2
  Next
  Return

MatchSequence:
  w0 = sequence
  For sequence_bit = 1 To length
    ; Wait for a button push returned in the
    ; 'buttonPushed' variable.
    Gosub GetButtonPush
    ; Check the button push matches the step
    ; of the sequence. If not return with
    ; 'matched' set to zero
    If bit15 = 0 And buttonPushed <> 0 Then
      matched = 0
      Return
    End If
    If bit15 = 1 And buttonPushed <> 1 Then
      matched = 0
      Return
    End If
    w0 = w0 * 2
  Next
  ; If we matched all steps in the sequence
  ; return with 'matched' set to 1.
  matched = 1
  Return

GetButtonPush:
  Gosub WaitForButtonsToBeReleased
  ; Wait for a button to be pushed. Put
  ; the number of the button pushed in
  ; the 'buttonPushed' variable. We set
  ; 'buttonPushed' initially to a value
  ; which isn't valid, will only return
  ; when it becomes 0 or 1.
  buttonPushed = -1
  Do
    If BTN0 = PUSHED Then
      buttonPushed = 0
     End If
    If BTN1 = PUSHED Then
      buttonPushed = 1
    End If
    Pause 10
  Loop Until buttonPushed = 0 Or buttonPushed = 1
  Gosub WaitForButtonsToBeReleased
  Return

WaitForButtonsToBeReleased:
  ; Wait until both buttons released
  Do
    Pause 10
  Loop Until BTN0 <> PUSHED And BTN1 <> PUSHED
  Pause 10
  Return
 

Sergei Ko

Member
Hi again, have spent some time going over the code trying to understand everything and I think I've got it!

Just wanted to thank everyone for the tremendous help!
 
Top