Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

comparing multiple button presses

Status
Not open for further replies.

MrDEB

Well-Known Member
before I get too screwed up but want to compare a series of button presses corisponding to leds. Think of the old Simon game
using Swordfish basic
LED1comes on then off. Led2 comes on then off. Led4 comes on then off
now the player must repeat the same sequence Swt1, Swt2, Swt4
thinking COMPARE (StrA, StrBm StrD as string) as short INT but maybe just give each button press a value but it dosen't add up correctly.
Another thought was LED1comes on then off. Led2 comes on then off. Led4 comes on then off
LED1=1and Led2 = 3 and LED4 - 5
so if button presses = 9 then pattern was correct. If other than 9 then incorrect. Issue is if SAME pattern is in different order then it still adds up to 9
getting confussed already
 
I know arrays and bit fields aren't your strong suit, so how about this...

By default, a string in Swordfish can hold up to 23 chars.
Start off with an empty string, and everytime a button is pressed append (add) a char to that string
that represents the button.

For example, for button 1 append a "1" char, for button 2 append a "2" char, etc.
When you're done you end up with a string that has the button sequence in the order they were pressed,
like "132465"

Save that string (that's your "challenge" string), and then start over to get the second string input.
When done, if string 1 = string 2, they match.

This is by no means complete...
Code:
dim challenge as string
dim user_str as string

// start off with both strings empty
challenge = ""
user_str = ""

// loop getting the challenge string (#1)
// (add your loop code)
if (key = 1) then
    challenge = challenge + "1"
elseif (key = 2) then
    challenge = challenge + "2"
elseif (key = 3) then
    challenge = challenge + "3"
elseif (key = 4) then
    challenge = challenge + "4"
endif

// loop getting the user string (#2)
// (add your loop code)
if (key = 1) then
    user_str = user_str + "1"
elseif (key = 2) then
    user_str = user_str + "2"
elseif (key = 3) then
    user_str = user_str + "3"
elseif (key = 4) then
    user_str = user_str + "4"
endif

// when you're done with gettings button presses, compare the two strings
if (challenge = user_str) then
    // THEY MATCH
else
    // NO MATCH
endif
 
WILL GIVE IT A TRY tUMBLEWEED
here is the trash I was trying but it comes up w/ 252
Code:
{
*****************************************************************************
*  Name    : UNTITLED.BAS                                                   *
*  Author  : [select VIEW...EDITOR OPTIONS]                                 *
*  Notice  : Copyright (c) 2021 [select VIEW...EDITOR OPTIONS]              *
*          : All Rights Reserved                                            *
*  Date    : 11/1/2021                                                      *
*  Version : 1.0                                                            *
*  Notes   :                                                                *
*          :                                                                *
*****************************************************************************
Device = 18F43K22
Clock = 16
// int osc and IO pin libraries
Include "intosc.bas"

#option DIGITALIO_INIT = true       // automatically call setalldigital
#option DIGITALIO_SLEWRATE = 1      // 1=slow (we don't need fast edges)
Include "setdigitalio.bas"

#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.2
#option LCD_EN = PORTD.3
}
Device = 18F43k22 ' Tell the compiler what chip we are using
Clock = 16 ' Tell the compiler what we will be setting the clock to (Mhz)
//CONFIG MCLRE = OFF
#option DIGITALIO_INIT = true       // automatically call setalldigital
#option DIGITALIO_SLEWRATE = 1      // 1=slow (we don't need fast edges)
Include "setdigitalio.bas"

#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.2
#option LCD_EN = PORTD.3
Config fOSC = INTIO67 ' Internal oscillator, IO on pins 6 and 7
Include "intosc.bas"
Include "utils.bas"
Include "convert.bas"
Include "LCD.bas"
#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.2
#option LCD_EN = PORTD.3




 
Dim SWT0 As PORTB.0
Dim SWT1 As PORTB.1
Dim SWT2 As PORTB.2
Dim SWT3 As PORTB.3
Dim SWT4 As PORTB.4
Dim SWT5 As PORTB.5
Dim SWT6 As PORTB.6
Dim SWT7 As PORTB.7
Dim Duration As Word

Dim Led0 As PORTC.0
Dim Led1 As PORTC.1
Dim Led2 As PORTC.2
Dim Led3 As PORTC.3
Dim Led4 As PORTC.4
Dim Led5 As PORTC.5
Dim Led6 As PORTC.6
Dim Led7 As PORTC.7
Dim Score As Byte

'Dim Battery As PORTA.2  'hlvd
'Dim Power As PORTA.1     'hlvd

Led0=0
Led1=0
Led2=0
Led3=0
Led4=0
Led5=0
Led6=0
Led7=0
Score = 0

While true
 
  Toggle(Led0)//turn on led0   PORTC.0
  If SWT0=0 Then   //PORT B .0
  Score=Score +1
  Else
  Score = Score - 1
  DelayMS(1000)
  Toggle (Led0)
  End If
         Toggle(Led3)//turn on led1 PORTC.3
         If SWT3=0 Then   //PORTB.3
         Score=Score +1
         Else
         Score = Score - 1
         DelayMS(1000)
         Toggle (Led3)
         End If
         Cls
  WriteAt(1,1,"SCORE", DecToStr(Score))
  DelayMS(3000)
  Wend
 
well turning good code to bad code.
Wife has a chore so will get back the this later
Code:
{
*****************************************************************************
*  Name    : UNTITLED.BAS                                                   *
*  Author  : [select VIEW...EDITOR OPTIONS]                                 *
*  Notice  : Copyright (c) 2021 [select VIEW...EDITOR OPTIONS]              *
*          : All Rights Reserved                                            *
*  Date    : 11/1/2021                                                      *
*  Version : 1.0                                                            *
*  Notes   :                                                                *
*          :                                                                *
*****************************************************************************
Device = 18F43K22
Clock = 16
// int osc and IO pin libraries
Include "intosc.bas"

#option DIGITALIO_INIT = true       // automatically call setalldigital
#option DIGITALIO_SLEWRATE = 1      // 1=slow (we don't need fast edges)
Include "setdigitalio.bas"

#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.2
#option LCD_EN = PORTD.3
}
Device = 18F43k22 ' Tell the compiler what chip we are using
Clock = 16 ' Tell the compiler what we will be setting the clock to (Mhz)
//CONFIG MCLRE = OFF
#option DIGITALIO_INIT = true       // automatically call setalldigital
#option DIGITALIO_SLEWRATE = 1      // 1=slow (we don't need fast edges)
Include "setdigitalio.bas"

#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.2
#option LCD_EN = PORTD.3
Config fOSC = INTIO67 ' Internal oscillator, IO on pins 6 and 7
Include "intosc.bas"
Include "utils.bas"
Include "convert.bas"
Include "LCD.bas"
#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.2
#option LCD_EN = PORTD.3




 
Dim SWT0 As PORTB.0
Dim SWT1 As PORTB.1
Dim SWT2 As PORTB.2
Dim SWT3 As PORTB.3
Dim SWT4 As PORTB.4
Dim SWT5 As PORTB.5
Dim SWT6 As PORTB.6
Dim SWT7 As PORTB.7
Dim Duration As Word

Dim Led0 As PORTC.0
Dim Led1 As PORTC.1
Dim Led2 As PORTC.2
Dim Led3 As PORTC.3
Dim Led4 As PORTC.4
Dim Led5 As PORTC.5
Dim Led6 As PORTC.6
Dim Led7 As PORTC.7
Dim Score As Byte
Dim challenge As String
Dim user_str As String
Dim Key(6) As Byte
dim Press(6) as byte
'Dim Battery As PORTA.2  'hlvd
'Dim Power As PORTA.1     'hlvd
//turn off all leds
Led0=0
Led1=0
Led2=0
Led3=0
Led4=0
Led5=0
Led6=0
Led7=0
Score = 0
challenge = ""
user_str = ""
Key(0)=Led0
Key(1)=Led1
Key(2)=Led2
Key(3)=Led3
Key(4)=Led4
Key(5)=Led5
press(0)=swt0
press(1)=swt1
press(2)=swt2
press(3)=swt3
press(4)=swt4
press(5)=swt5

While true
 


// start off with both strings empty


// loop getting the challenge string (#1)
// (add your loop code)
Toggle (Led0)
DelayMS(1000)
If (Key(0) = 1) Then
    challenge = challenge + "1"
ElseIf (Key(1) = 2) Then
    challenge = challenge + "2"
ElseIf (Key(2)=3) Then
    challenge = challenge + "3"
ElseIf (Key(3) = 4) Then
    challenge = challenge + "4"
EndIf

// loop getting the user string (#2)
// (add your loop code)
If (press(0) = 0) Then
    user_str = user_str + "1"
ElseIf (press(1) = 0) Then
    user_str = user_str + "2"
ElseIf (press(3) = 0) Then
    user_str = user_str + "3"
ElseIf (press(4) = 0) Then
    user_str = user_str + "4"
EndIf

// when you're done with gettings button presses, compare the two strings
If (challenge = user_str) Then
writeat(1,1,"match")
    // THEY MATCH
Else
writeat(1,1,"NO MATCH")
EndIf
  Wend
 
I redid the code but?
need to edit so it is waiting for input of the button presses
{ ***************************************************************************** * Name : UNTITLED.BAS * * Author : [select VIEW...EDITOR OPTIONS] * * Notice : Copyright (c) 2021 [select VIEW...EDITOR OPTIONS] * * : All Rights Reserved * * Date : 11/1/2021 * * Version : 1.0 * * Notes : * * : * ***************************************************************************** Device = 18F43K22 Clock = 16 // int osc and IO pin libraries Include "intosc.bas" #option DIGITALIO_INIT = true // automatically call setalldigital #option DIGITALIO_SLEWRATE = 1 // 1=slow (we don't need fast edges) Include "setdigitalio.bas" #option LCD_DATA = PORTD.4 #option LCD_RS = PORTD.2 #option LCD_EN = PORTD.3 } Device = 18F43k22 ' Tell the compiler what chip we are using Clock = 16 ' Tell the compiler what we will be setting the clock to (Mhz) //CONFIG MCLRE = OFF #option DIGITALIO_INIT = true // automatically call setalldigital #option DIGITALIO_SLEWRATE = 1 // 1=slow (we don't need fast edges) Include "setdigitalio.bas" #option LCD_DATA = PORTD.4 #option LCD_RS = PORTD.2 #option LCD_EN = PORTD.3 Config fOSC = INTIO67 ' Internal oscillator, IO on pins 6 and 7 Include "intosc.bas" Include "utils.bas" Include "convert.bas" Include "LCD.bas" #option LCD_DATA = PORTD.4 #option LCD_RS = PORTD.2 #option LCD_EN = PORTD.3 Dim SWT0 As PORTB.0 Dim SWT1 As PORTB.1 Dim SWT2 As PORTB.2 Dim SWT3 As PORTB.3 Dim SWT4 As PORTB.4 Dim SWT5 As PORTB.5 Dim SWT6 As PORTB.6 Dim SWT7 As PORTB.7 Dim Duration As Word Dim Led0 As PORTC.0 Dim Led1 As PORTC.1 Dim Led2 As PORTC.2 Dim Led3 As PORTC.3 Dim Led4 As PORTC.4 Dim Led5 As PORTC.5 Dim Led6 As PORTC.6 Dim Led7 As PORTC.7 Dim Score As Byte Dim challenge As String Dim user_str As String Dim Key As Byte dim Press as string 'Dim Battery As PORTA.2 'hlvd 'Dim Power As PORTA.1 'hlvd //turn off all leds Led0=0 Led1=0 Led2=0 Led3=0 Led4=0 Led5=0 Led6=0 Led7=0 Score = 0 challenge = "" user_str = "" key=0 { Key(0)=Led0 Key(1)=Led1 Key(2)=Led2 Key(3)=Led3 Key(4)=Led4 Key(5)=Led5 press(0)=swt0 press(1)=swt1 press(2)=swt2 press(3)=swt3 press(4)=swt4 press(5)=swt5 } While true // start off with both strings empty // loop getting the challenge string (#1) // (add your loop code) Toggle (Led0) DelayMS(1000) toggle(led0) Toggle (Led1) DelayMS(1000) toggle (led1) Toggle (Led2) DelayMS(1000) toggle (led2) Toggle (Led3) DelayMS(1000) toggle (led3) If (Key = 1) Then challenge = challenge + "1" ElseIf (Key = 2) Then challenge = challenge + "2" ElseIf (Key=3) Then challenge = challenge + "3" ElseIf (Key = 4) Then challenge = challenge + "4" EndIf // loop getting the user string (#2) // (add your loop code) if swt1=0 then key = 1 end if if swt2=0 then key=2 endif if swt3=0 then key=3 endif if swt4=0 then key=4 endif If (key = 1) Then user_str = user_str + "1" ElseIf (key = 2) Then user_str = user_str + "2" ElseIf (key = 3) Then user_str = user_str + "3" ElseIf (key = 4) Then user_str = user_str + "4" EndIf // when you're done with gettings button presses, compare the two strings If (challenge = user_str) Then writeat(1,1,"match") // THEY MATCH Else writeat(1,1,"NO MATCH") EndIf Wend
 
need to edit so it is waiting for input of the button presses
Yup. That code was just the basic idea of how you could gather up two sequences of key presses and compare them.

It didn't show how to generate the initial challenge sequence string using LEDs instead of keys, or how to read keys.
It wasn't meant to be pasted directly into your code and work.

If you want that, I'll have to write the whole thing for you.
 
just head me in the right direction.
I kinda got lost with the string KEY
thinking how to obtain the sequence of key presses.
With the second code, the LCD just shows MATCH without any keypresses.
 
problem is "challenge" always comes up with 4 regardless what I change "key" value
I want same pattern.
Code:
While true
 


// start off with both strings empty


// loop getting the challenge string (#1)
// (add your loop code)
Toggle (Led0)
key=3
DelayMS(1000)
toggle(led0)
            Toggle (Led3)
            key=3
            DelayMS(1000)
            toggle (led3)
                        Toggle (Led2)
                        key=3
                        DelayMS(1000)
                        toggle (led2)
                                    Toggle (Led3)
                                    key=4             //keep track of which LED is on
                                    DelayMS(1000)
                                    toggle (led3)
If Key = 1 Then
    challenge = challenge + "1"        //key(x) indicates which led is on
ElseIf (Key = 2) Then
    challenge = challenge + "2"
ElseIf (Key = 3) Then
    challenge = challenge + "3"
ElseIf (Key = 4) Then
    challenge = challenge + "4"
EndIf
cls
writeat(1,1,"challenge",(challenge))    //should be 13?
delayms(4000)
// loop getting the user string (#2)
// (add your loop code)
if swt1=0 then
key = 1
end if
    if swt2=0 then
    key=2
    endif
       if swt3=0 then
       key=3
       endif
            if swt4=0 then
            key=4
            endif
    
If (key = 1) Then
    user_str = user_str + "1"
ElseIf (key = 2) Then
    user_str = user_str + "2"
ElseIf (key = 3) Then
    user_str = user_str + "3"
ElseIf (key = 4) Then
    user_str = user_str + "4"
EndIf

// when you're done with gettings button presses, compare the two strings
If (challenge = user_str) Then
writeat(1,1,"match")
    // THEY MATCH
Else
writeat(1,1,"NO MATCH")
EndIf
  Wend
 
try this...
it will automatically generate a random 8 char challenge string

Code:
program simple_simon

device = 18F43K22
clock = 16

// int osc and IO pin libraries
include "intosc.bas"
#option DIGITALIO_INIT = true       // automatically call setalldigital
include "setdigitalio.bas"

// lcd
#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.2
#option LCD_EN = PORTD.3
include "LCD.bas"

// hardware
dim SWT0 as PORTB.0
dim SWT1 as PORTB.1
dim SWT2 as PORTB.2
dim SWT3 as PORTB.3
dim SWT4 as PORTB.4
dim SWT5 as PORTB.5
dim SWT6 as PORTB.6
dim SWT7 as PORTB.7
dim SW_PORT as PORTB

dim LED0 as PORTC.0
dim LED1 as PORTC.1
dim LED2 as PORTC.2
dim LED3 as PORTC.3
dim LED4 as PORTC.4
dim LED5 as PORTC.5
dim LED6 as PORTC.6
dim LED7 as PORTC.7
dim LED_PORT as PORTC

//-------------------------------------
// subroutines and functions
//-------------------------------------

// wait for a keypress and return key number, 1-8
function GetKey() as byte
    // wait for a key press
    repeat
        if (SWT0 = 0) then
            result = 1
        elseif (SWT1 = 0) then
            result = 2
        elseif (SWT2 = 0) then
            result = 3
        elseif (SWT3 = 0) then
            result = 4
        elseif (SWT4 = 0) then
            result = 5
        elseif (SWT5 = 0) then
            result = 6
        elseif (SWT6 = 0) then
            result = 7
        elseif (SWT7 = 0) then
            result = 8
        else    // no valid key press            
            result = 0
        endif
    until (result <> 0)
    
    // now wait for the key to be released
    while (SW_PORT <> $FF)
        delayms(50)
    end while
    
    // wait a bit for release bounce
    delayms(50)
end function

// given an ledno 1-8, turn it off (0) or on (>0)
// if ledno = 0 then set them all on or off
sub SetLED(ledno as byte, onoff as byte)
    select (ledno)
        case 0
            if (onoff > 0) then
                onoff = $FF
            endif                
            LED_PORT = onoff 
        case 1
            LED0 = onoff
        case 2
            LED1 = onoff
        case 3
            LED2 = onoff
        case 4
            LED3 = onoff
        case 5
            LED4 = onoff
        case 6
            LED5 = onoff
        case 7
            LED6 = onoff
        case 8
            LED7 = onoff
    end select            
end sub

// given a number n=1-8, convert it to a char and append it to the string s
sub AddToString(byref s as string, n as byte)
    dim ch as char
    
    ch = n + byte("0")
    s = s + ch 
end sub

// given a string s and an index n=1-8, get the char value
function GetFromString(byref s as string, n as byte) as byte
    dim ch as char
    
    // convert n to 0-based index
    if (n > 0) then
        n = n - 1
    endif        
    // get nth char from string
    ch = s(n)
    // convert numeric char to value 0-9
    result = byte(ch) - byte("0")
end function

// random number generator
// based on https://www.sfcompiler.co.uk/wiki/pmwiki.php?n=SwordfishUser.PseudoRandomNumberGenerator
dim LCG,GLFSR as byte
sub initRND()
    GLFSR = 1
    LCG = 84
end sub

function GetRND() as byte
    // init rand (just in case)
    if (LCG = 0) or (GLFSR = 0) then
        initRND()
    endif
    
    'LCG
    LCG=(7*LCG+17) 

    'Galios LFSR
    if (GLFSR and 1) = 1 then
        GLFSR = GLFSR xor 135 '135 is the tap 
        GLFSR = (GLFSR >> 1) or $80
    else
        GLFSR = (GLFSR >> 1)
    endif
    result = GLFSR xor LCG

    // for our application we want a number from 1 to 8
    result = (result mod 8) + 1 
end function


//-------------------------------------
// main program variables
//-------------------------------------
dim challenge as string     // challenge pattern
dim user as string          // user input
dim i as byte
dim n as byte
    
//-------------------------------------
// start of main program
//-------------------------------------
main:
// init hdw
TRISC = 0               // LED port - all outputs
TRISB = $FF             // SW port - all inputs
WPUB = $FF              // PORTB pullup mask - all PORTB pullups
INTCON2.bits(7) = 0     // RBPU bit - turn on pullups

//turn off all LEDs
SetLED(0, 0)

// init random number generator
initRND()

// do forever
while true
    // start off with both strings empty
    challenge = ""
    user = ""
    
    // generate a random 8-char challenge string
    // as the string is generated, light the LEDs
    lcd.writeat(1,1,"challenge...")
    for i = 1 to 8
        n = getRND()                // get a new random number from 1 to 8
        AddToString(challenge, n)   // add it to the challenge string
        SetLED(n, 1)                // turn on the corresponding LED
        delayms(500)                // wait a bit...
        SetLED(n, 0)                // and turn led off
    next
            
    // get user response
    lcd.writeat(1,1,"enter keys...")
    for i = 1 to 8
        n = GetKey()
        AddToString(user, n)        // add it to the user response
        SetLED(n, 1)                // turn on the corresponding LED
        delayms(500)                // wait a bit...
        SetLED(n, 0)                // and turn led off
    next

    // compare the two strings
    if (challenge = user) then
        lcd.writeat(1,1,"match")
    else
        lcd.writeat(1,1,"NO MATCH")
    endif
    delayms(500)

    // show the two strings
    lcd.writeat(1,1, challenge)
    lcd.writeat(2,1, user)
    delayms(1000)
end while
            
end program
 
I am looking over the code and ran it. It has an issue.
It turns on several LEDS then "enter keys"
thats it.
will try later after minor chjanges??
 
before you do that...

when it runs, the first things it does is generate the challenge string (8 random numbers, the appropriate LED's blink for 1/2 sec while it does this)
it then displays "enter keys..." on the LCD, and you press the 8 buttons you think match (it blinks the LEDs while you do this)
it then displays "match" or "no match" and the two strings... challenge and user input (assuming you have a two-line LCD)
 
The buttons on PORTB are normally high and connect to GND when you push them, right?
You press and release the button(s) eight times, right?
 
Are you running this with the pickit connected?
The pickit has 4.7K pulldowns on the ICSP lines connected to pins RB6 and RB7,
so those buttons won't work very well, and likely always read 0 for those two pins.

The code would probably get stuck inside the GetKey function at this part...
Code:
    // now wait for the key to be released
    while (SW_PORT <> $FF)
        delayms(50)
    end while

edit: see the next post
 
Last edited:
Here's an updated version that allows you to set the max number of keys/buttons from 1 to 8
This is controlled by the lines
Code:
// option to limit max numbers of PORTB keys
// if the ICSP programmer is connected, limit this to 6 (no RB6 or RB7)
#option MAX_NUM_KEYS = 4
The default is now set for 4, so SWT0-SWT3

It also lets you set the length of the challenge, from 1 to 23
Code:
// this option controls the max length of the challenge sequence, from 1-23
#option MAX_SEQ_LENGTH = 8
The default is set to 8, so that'll require 8 button presses

Code:
program simple_simon

device = 18F43K22
clock = 16

// int osc and IO pin libraries
include "intosc.bas"
#option DIGITALIO_INIT = true       // automatically call setalldigital
include "setdigitalio.bas"

// lcd
#option LCD_DATA = PORTD.4
#option LCD_RS = PORTD.2
#option LCD_EN = PORTD.3
include "LCD.bas"

// hardware
dim SWT0 as PORTB.0
dim SWT1 as PORTB.1
dim SWT2 as PORTB.2
dim SWT3 as PORTB.3
dim SWT4 as PORTB.4
dim SWT5 as PORTB.5
dim SWT6 as PORTB.6
dim SWT7 as PORTB.7
dim SW_PORT as PORTB

dim LED0 as PORTC.0
dim LED1 as PORTC.1
dim LED2 as PORTC.2
dim LED3 as PORTC.3
dim LED4 as PORTC.4
dim LED5 as PORTC.5
dim LED6 as PORTC.6
dim LED7 as PORTC.7
dim LED_PORT as PORTC

// this option limits max numbers of PORTB keys, from 1-8
// if the ICSP programmer is connected, limit this to 6 (no RB6 or RB7)
#option MAX_NUM_KEYS = 4
#if not (MAX_NUM_KEYS in (1 to 8))
  #error MAX_NUM_KEYS, "MAX_NUM_KEYS must be 1-8"
#endif  
const MAX_KEY = MAX_NUM_KEYS
const KEY_MASKS(9) as byte = ($00, $01, $03, $07, $0F, $1F, $3F, $7F, $FF)

// this option controls the max length of the challenge sequence, from 1-23
#option MAX_SEQ_LENGTH = 8
#if not (MAX_SEQ_LENGTH in (1 to 23))
  #error MAX_SEQ_LENGTH, "MAX_SEQ_LENGTH must be 1 to 23"
#endif  
const MAX_SEQ = MAX_SEQ_LENGTH
   
//-------------------------------------
// subroutines and functions
//-------------------------------------

// wait for a keypress and return key number, 1-8
function GetKey() as byte
    // wait for a key press
    repeat
        if (SWT0 = 0) then
            result = 1
        elseif (SWT1 = 0) then
            result = 2
        elseif (SWT2 = 0) then
            result = 3
        elseif (SWT3 = 0) then
            result = 4
        elseif (SWT4 = 0) then
            result = 5
        elseif (SWT5 = 0) then
            result = 6
        elseif (SWT6 = 0) then
            result = 7
        elseif (SWT7 = 0) then
            result = 8
        else    // no valid key press            
            result = 0
        endif
        // limit response to max number of supported keys
        if (result > MAX_KEY) then
            result = 0
        endif            
    until (result <> 0)
    
    // now wait for any/all keys to be released
    while ((SW_PORT and KEY_MASKS(MAX_KEY)) <> KEY_MASKS(MAX_KEY))
        delayms(50)
    end while
    
    // wait a bit for release bounce (for next time)
    delayms(50)
end function

// given an ledno 1-8, turn it off (0) or on (>0)
// if ledno = 0 then set them all on or off
sub SetLED(ledno as byte, onoff as byte)
    select (ledno)
        case 0
            if (onoff > 0) then
                onoff = $FF
            endif                
            LED_PORT = onoff 
        case 1
            LED0 = onoff
        case 2
            LED1 = onoff
        case 3
            LED2 = onoff
        case 4
            LED3 = onoff
        case 5
            LED4 = onoff
        case 6
            LED5 = onoff
        case 7
            LED6 = onoff
        case 8
            LED7 = onoff
    end select            
end sub

// given a number n=1-8, convert it to a char and append it to the string s
sub AddToString(byref s as string, n as byte)
    dim ch as char
    
    ch = n + byte("0")
    s = s + ch 
end sub

// given a string s and an index n=1-8, get the char value
function GetFromString(byref s as string, n as byte) as byte
    dim ch as char
    
    // convert n to 0-based index
    if (n > 0) then
        n = n - 1
    endif        
    // get nth char from string
    ch = s(n)
    // convert numeric char to value 0-9
    result = byte(ch) - byte("0")
end function

// random number generator
// based on https://www.sfcompiler.co.uk/wiki/pmwiki.php?n=SwordfishUser.PseudoRandomNumberGenerator
dim LCG,GLFSR as byte
sub initRND()
    GLFSR = 1
    LCG = 84
end sub

function GetRND() as byte
    // init rand (just in case)
    if (LCG = 0) or (GLFSR = 0) then
        initRND()
    endif
    
    'LCG
    LCG=(7*LCG+17) 

    'Galios LFSR
    if (GLFSR and 1) = 1 then
        GLFSR = GLFSR xor 135 '135 is the tap 
        GLFSR = (GLFSR >> 1) or $80
    else
        GLFSR = (GLFSR >> 1)
    endif
    result = GLFSR xor LCG

    // for our application we want a number from 1 to MAX_KEYS
    result = (result mod MAX_KEY) + 1 
end function


//-------------------------------------
// main program variables
//-------------------------------------
dim challenge as string     // challenge pattern
dim user as string          // user input
dim i as byte
dim n as byte
    
//-------------------------------------
// start of main program
//-------------------------------------
main:
// init hdw
TRISC = 0               // LED port - all outputs
TRISB = $FF             // SW port - all inputs
WPUB = $FF              // PORTB pullup mask - all PORTB pullups
INTCON2.bits(7) = 0     // RBPU bit - turn on pullups

//turn off all LEDs
SetLED(0, 0)

// init random number generator
initRND()

// do forever
while true
    // start off with both strings empty
    challenge = ""
    user = ""
    
    // generate a random 8-char challenge string
    // as the string is generated, light the LEDs
    lcd.writeat(1,1,"challenge...")
    for i = 1 to MAX_SEQ
        n = getRND()                // get a new random number from 1 to 8
        AddToString(challenge, n)   // add it to the challenge string
        SetLED(n, 1)                // turn on the corresponding LED
        delayms(500)                // wait a bit...
        SetLED(n, 0)                // and turn led off
    next
            
    // get user response
    lcd.writeat(1,1,"enter keys...")
    for i = 1 to MAX_SEQ
        n = GetKey()
        AddToString(user, n)        // add it to the user response
        SetLED(n, 1)                // turn on the corresponding LED
        delayms(500)                // wait a bit...
        SetLED(n, 0)                // and turn led off
    next

    // compare the two strings
    if (challenge = user) then
        lcd.writeat(1,1,"match")
    else
        lcd.writeat(1,1,"NO MATCH")
    endif
    delayms(500)

    // show the two strings
    lcd.writeat(1,1, challenge)
    lcd.writeat(2,1, user)
    delayms(1000)
end while
            
end program
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top