A simple LCD based numbers game

Post here to discuss programming with swordfish basic

Moderators: Chuckt, Garth, bitfogav

Post Reply
User avatar
brad
Site Admin
Site Admin
Posts: 2576
Joined: Fri Mar 26, 2010 10:30 pm

A simple LCD based numbers game

Post by brad » Sat Jun 19, 2010 11:48 pm

Today I sat down and wanted to see how long it would take me to make a very simple numbers game on one of those 2x16 LCD displays. All up from initial concept to the finished code was about 1 hour. I really couldn't tell you how long it would have taken me to code in assembly - but it would certainly have been ALOT longer!

I had already made up the LCD circuit with push buttons in a handy hobby box for another project I was working on, so all I needed was the code.

The game is very simple, you have a single digit at the top left of screen which can be any number between 0 and 9 inclusive. you can change this number by pressing either the up or down buttons. To the top right of screen is a random number (also between 0 and 9 inclusive) this number will scroll towards you (leaving a trail of the same number). You need to use the up/down arrows to change your number so that it matches the random number coming towards you.

If you match the number by the time it hits you, then you get a point. If you do not match it, then it is game over and the high score is displayed on the screen. You then press a button to play again.

Here's a couple of photos:
Image

Image


For those interested, here's the code:

Code: Select all

    Device = 18F4685
    Clock = 8                           // This is used to tell the compiler what clock we are using
    Config OSC = IRCIO67                // We want to use the internal oscillator.

 
// some LCD options...
#option LCD_DATA = PORTD.4              // Assign the LCD connections
#option LCD_EN = PORTD.3                //
#option LCD_RS = PORTD.2                //
 
// import library's
Include "LCD.bas"
Include "convert.bas"

// port setup
Dim button_down As PORTA.0  
Dim button_up As PORTA.1
Dim button_select As PORTA.2
Dim button_menu As PORTA.3

Dim random_number As Byte
Dim random_number_saved As Byte
Dim incoming_number As Byte
Dim number_position As Word
Dim your_number As Byte
Dim score As Byte
Dim button_debounce As Byte
Dim number_speed As Byte
Dim high_score As Byte

Sub draw_screen()
    LCD.WriteAt(1,(number_position),Convert.DecToStr(incoming_number,1))
    LCD.WriteAt(1,1,Convert.DecToStr(your_number,1))
    LCD.WriteAt(2,1,"Your Score =")
    LCD.WriteAt(2,14,Convert.DecToStr(score,3)) 
End Sub

Sub check_buttons()
    If button_down = 1 Then
        random_number_saved = random_number
    EndIf
    If button_up = 1 Then
        random_number_saved = random_number
    EndIf
    If button_up = 1 And button_debounce = 0 And your_number < 9 Then
        Inc(your_number)
        button_debounce = 50
    EndIf
    If button_down = 1 And button_debounce = 0 And your_number > 0  Then
        Dec(your_number)
        button_debounce = 50
    EndIf
End Sub

Sub debounce_buttons()
    If button_debounce <> 0 Then
        Dec(button_debounce)
    EndIf
End Sub

Sub update_incoming_number()
    If number_position = 1 And your_number = incoming_number Then
        If random_number_saved = incoming_number Then
            Inc(random_number_saved)
        EndIf
        Inc(score)
        LCD.Cls
        incoming_number = random_number_saved
        number_position = 16
    EndIf
End Sub

Sub check_if_game_over()
    If number_position = 1 And your_number <> incoming_number Then
        If score > high_score Then
            high_score = score
        EndIf 
        LCD.WriteAt(1,1,"** GAME  OVER **")
        LCD.WriteAt(2,1,"High Score = ")
        LCD.WriteAt(2,14,Convert.DecToStr(high_score,3))         
        Repeat Until button_select = 1
        incoming_number = random_number
        number_position = 16
        score = 0
        LCD.Cls
    EndIf   
End Sub

Sub move_number()
    If number_speed = 0 And number_position > 1 Then
        Dec(number_position)
        number_speed = 50
    EndIf    
End Sub

Sub update_number_speed()
    If number_speed <> 0 Then
        Dec(number_speed)
    EndIf
End Sub

Sub update_random_number()
    Inc(random_number)
    If random_number = 10 Then random_number = 0
    EndIf   
End Sub


// Start Of Program...
OSCCON = %01111111                  // Sets the internal oscillator for 8Mhz
TRISD = %00000000                   // Makes PORTD all outputs
TRISA = %00001111                   // PORTA 0-3 inputs and 4-7 outputs

number_position = 16
random_number = 9
your_number = 0
incoming_number = 7
button_debounce = 50
number_speed = 50
score = 0
high_score = 0


DelayMS(150)                            // Let the LCD warm up

While true
     draw_screen
     check_buttons
     debounce_buttons
     update_incoming_number 
     check_if_game_over
     move_number
     update_number_speed
     update_random_number
Wend
Attachments
game_over.jpg
game_over.jpg (37.55 KiB) Viewed 13110 times
gameplay.jpg
gameplay.jpg (37.59 KiB) Viewed 13110 times

User avatar
bitfogav
Moderator
Moderator
Posts: 908
Joined: Sun Mar 28, 2010 9:03 pm
Location: United Kingdom
Contact:

Post by bitfogav » Sun Jun 20, 2010 6:07 am

Wow that is a great idea for a project Brad :)

This is a 16bit counter on a LCD display I made up.

Image


And heres the souce code to give people an example of how much different the programs are :D

Code: Select all

	LIST	p=16F628a  ;tell assembler what chip we are using
	include "P16F628a.inc"   ;include the defaults for the chip
	ERRORLEVEL	0,	-302	;suppress bank selection messages
	__config 0x3D18   ;sets the configuration settings (oscillator type etc.)




	cblock	0x20  ;start of general purpose registers
			count	;used in looping routines
			count1	;used in delay routine
			counta	;used in delay routine
			countb	;used in delay routine
			tmp1	;temporary storage
			tmp2
			templcd	;temp store for 4 bit mode
			templcd2

        	NumL   ;Binary inputs for decimal convert routine
	NumH	

        		TenK	;Decimal outputs from convert routine
	        	Thou	
        		Hund	
	        	Tens	
        		Ones	
		endc

LCD_PORT	Equ	PORTA
LCD_TRIS	Equ	TRISA
LCD_RS		Equ	0x04	;LCD handshake lines
LCD_RW		Equ	0x06
LCD_E		Equ	0x07

		org	0x0000

		movlw	0x07
    movwf	   CMCON ;turn comparators off (make it like a 16F84)

Initialise	clrf	count
		clrf	PORTA
		clrf	PORTB
		clrf	NumL
		clrf	NumH



SetPorts	bsf 	STATUS,		RP0 ;select bank 1
		movlw	0x00	;make all pins outputs
		movwf	LCD_TRIS
		bcf 	STATUS,	RP0  ;select bank 0

		call	LCD_Init		;setup LCD


		clrf	count    ;set counter register to zero
Message		movf	count, w   ;put counter value in W
		call	Text ;get a character from the text table
		xorlw	0x00   ;is it a zero?
		btfsc	STATUS, Z
		goto	NextMessage
		call	LCD_Char
		incf	count, f
		goto	Message

NextMessage	call	LCD_Line2		;move to 2nd row, first column
	
		call	Convert			;convert to decimal
		movf	TenK,	w		;display decimal characters
		call	LCD_CharD		;using LCD_CharD to convert to ASCII
		movf	Thou,	w
		call	LCD_CharD
		movf	Hund,	w
		call	LCD_CharD		
		movf	Tens,	w
		call	LCD_CharD
		movf	Ones,	w
		call	LCD_CharD
		movlw	' '			;display a 'space'
		call	LCD_Char
		movf	NumH,	w		;and counter in hexadecimal
		call	LCD_HEX
		movf	NumL,	w
		call	LCD_HEX
		incfsz	NumL, 	f
		goto	Next
		incf	NumH,	f
Next		call	Delay255		;wait so you can see the digits change
		goto	NextMessage


;Subroutines and text tables

;LCD routines

;Initialise LCD
LCD_Init	call	Delay100		;wait for LCD to settle

		movlw	0x20	;Set 4 bit mod
		call	LCD_Cmd

		movlw	0x28	;Set display shift
		call	LCD_Cmd

		movlw	0x06	;Set display character mode
		call	LCD_Cmd

	movlw	0x0c ;Set display on/off and cursor command
		call	LCD_Cmd	 ;Set cursor off

		call	LCD_Clr	;clear display

		retlw	0x00

; command set routine
LCD_Cmd		movwf	templcd
		swapf	templcd,	w	;send upper nibble
		andlw	0x0f	;clear upper 4 bits of W
		movwf	LCD_PORT
		bcf	LCD_PORT, LCD_RS	;RS line to 0
		call	Pulse_e	;Pulse the E line high

		movf	templcd,	w	;send lower nibble
		andlw	0x0f	;clear upper 4 bits of W
		movwf	LCD_PORT
		bcf	LCD_PORT, LCD_RS	;RS line to 0
		call	Pulse_e	;Pulse the E line high
		call 	Delay5
		retlw	0x00

LCD_CharD	addlw	0x30 ;add 0x30 to convert to ASCII
LCD_Char	movwf	templcd
		swapf	templcd,	w	;send upper nibble
		andlw	0x0f	;clear upper 4 bits of W
		movwf	LCD_PORT
		bsf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e	;Pulse the E line high

		movf	templcd,	w  ;send lower nibble
		andlw	0x0f	;clear upper 4 bits of W
		movwf	LCD_PORT
		bsf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e	;Pulse the E line high
		call 	Delay5
		retlw	0x00

LCD_Line1	movlw	0x80	;move to 1st row, first column
		call	LCD_Cmd
		retlw	0x00

LCD_Line2	movlw	0xc0	;move to 2nd row, first column
		call	LCD_Cmd
		retlw	0x00

LCD_Line1W	addlw	0x80	;move to 1st row, column W
		call	LCD_Cmd
		retlw	0x00

LCD_Line2W	addlw	0xc0	;move to 2nd row, column W
		call	LCD_Cmd
		retlw	0x00

LCD_CurOn	movlw	0x0d	;Set display on/off and cursor command
		call	LCD_Cmd
		retlw	0x00

LCD_CurOff	movlw	0x0c	;Set display on/off and cursor command
		call	LCD_Cmd
		retlw	0x00

LCD_Clr		movlw	0x01		;Clear display
		call	LCD_Cmd
		retlw	0x00

LCD_HEX		movwf	tmp1
		swapf	tmp1,	w
		andlw	0x0f
		call	HEX_Table
		call	LCD_Char
		movf	tmp1, w
		andlw	0x0f
		call	HEX_Table
		call	LCD_Char
		retlw	0x00

Delay255	movlw	0xff		;delay 255 mS
		goto	d0
Delay100	movlw	d'100'		;delay 100mS
		goto	d0
Delay50		movlw	d'50'	;delay 50mS
		goto	d0
Delay20		movlw	d'20'	;delay 20mS
		goto	d0
Delay5		movlw	0x05	;delay 5.000 ms 
d0		movwf	count1
d1		movlw	0xC7	;delay 1mS
		movwf	counta
		movlw	0x01
		movwf	countb
Delay_0
		decfsz	counta, f
		goto	$+2
		decfsz	countb, f
		goto	Delay_0

		decfsz	count1	,f
		goto	d1
		retlw	0x00

Pulse_e		bsf	LCD_PORT, LCD_E
		nop
		bcf	LCD_PORT, LCD_E
		retlw	0x00

;end of LCD routines

HEX_Table  	ADDWF   PCL       , f
            	RETLW   0x30
            	RETLW   0x31
            	RETLW   0x32
            	RETLW   0x33
            	RETLW   0x34
            	RETLW   0x35
            	RETLW   0x36
            	RETLW   0x37
            	RETLW   0x38
            	RETLW   0x39
            	RETLW   0x41
            	RETLW   0x42
            	RETLW   0x43
            	RETLW   0x44
            	RETLW   0x45
            	RETLW   0x46

Text		addwf	PCL, f
		retlw	'1'
		retlw	'6'
		retlw	' '
		retlw	'B'
		retlw	'i'
		retlw	't'
		retlw	' '
		retlw	'C'
		retlw	'o'
		retlw	'u'
		retlw	'n'
		retlw	't'
		retlw	'e'
		retlw	'r'
		retlw	'.'
		retlw	0x00

Convert:                
        swapf   NumH, w
        iorlw	  B'11110000'
        movwf   Thou
        addwf   Thou,f
        addlw   0XE2
        movwf   Hund
        addlw   0X32
        movwf   Ones

        movf    NumH,w
        andlw   0X0F
        addwf   Hund,f
        addwf   Hund,f
        addwf   Ones,f
        addlw   0XE9
        movwf   Tens
        addwf   Tens,f
        addwf   Tens,f

        swapf   NumL,w
        andlw   0X0F
        addwf   Tens,f
        addwf   Ones,f

        rlf     Tens,f
        rlf     Ones,f
        comf    Ones,f
        rlf     Ones,f

        movf    NumL,w
        andlw   0X0F
        addwf   Ones,f
        rlf     Thou,f

        movlw   0X07
        movwf   TenK

        movlw   0X0A            ; Ten
Lb1:
        addwf   Ones,f
        decf    Tens,f
        btfss   3,0
        goto   Lb1
Lb2:
        addwf   Tens,f
        decf    Hund,f
        btfss   3,0
        goto   Lb2
Lb3:
        addwf   Hund,f
        decf    Thou,f
        btfss   3,0
        goto   Lb3
Lb4:
        addwf   Thou,f
        decf    TenK,f
        btfss   3,0
        goto   Lb4

        retlw	0x00


		end  
Attachments
16bitcounter.jpg
16bitcounter.jpg (72.21 KiB) Viewed 13099 times

User avatar
brad
Site Admin
Site Admin
Posts: 2576
Joined: Fri Mar 26, 2010 10:30 pm

Post by brad » Sun Jun 20, 2010 8:52 am

Very nice indeed! Thanks for posting that.

i am not sure what those extra numbers to the right of screen are, but here is my version of the 16 bit counter, it just increments by one each second.

Image

Here is the code:

Code: Select all

Device = 18F4685
Clock = 8                           // This is used to tell the compiler what clock we are using
Config OSC = IRCIO67                // We want to use the internal oscillator.

 
// some LCD options...
#option LCD_DATA = PORTD.4              // Assign the LCD connections
#option LCD_EN = PORTD.3                //
#option LCD_RS = PORTD.2                //
 
// import library's
Include "LCD.bas"
Include "convert.bas"

// variable declaration
Dim counter as word

// Start Of Program...
OSCCON = %01111111                  // Sets the internal oscillator for 8Mhz
TRISD = %00000000                   // Makes PORTD all outputs except for pin 0

counter = 0                         // set the start point for the count

DelayMS(150)                     // Let the LCD warm up

While true
    LCD.WriteAt(1,1,"16 Bit Counter.")
    LCD.WriteAt(2,3,Convert.DecToStr(counter,5))
    delaymS(1000)
    inc(counter)
Wend
Attachments
16_bit_counter.png
16_bit_counter.png (331.67 KiB) Viewed 13094 times

User avatar
bitfogav
Moderator
Moderator
Posts: 908
Joined: Sun Mar 28, 2010 9:03 pm
Location: United Kingdom
Contact:

Post by bitfogav » Sun Jun 20, 2010 8:57 am

The numbers to the bottom right of the screen are the hexadecimal numbers.. :) they count up aswell as the 16bit counter

User avatar
brad
Site Admin
Site Admin
Posts: 2576
Joined: Fri Mar 26, 2010 10:30 pm

Post by brad » Sun Jun 20, 2010 9:00 am

bitfogav wrote:The numbers to the bottom right of the screen are the hexadecimal numbers.. :) they count up aswell as the 16bit counter
Here's my ammended code, I have added the line:

Code: Select all

LCD.WriteAt(2,9,convert.hextostr(counter,4))

Code: Select all

Device = 18F4685
Clock = 8                           // This is used to tell the compiler what clock we are using
Config OSC = IRCIO67                // We want to use the internal oscillator.

 
// some LCD options...
#option LCD_DATA = PORTD.4              // Assign the LCD connections
#option LCD_EN = PORTD.3                //
#option LCD_RS = PORTD.2                //
 
// import library's
Include "LCD.bas"
Include "convert.bas"

// variable declaration
Dim counter as word

// Start Of Program...
OSCCON = %01111111                  // Sets the internal oscillator for 8Mhz
TRISD = %00000000                   // Makes PORTD all outputs except for pin 0

counter = 0                         // set the start point for the count

DelayMS(150)                     // Let the LCD warm up

While true
    LCD.WriteAt(1,1,"16 Bit Counter.")
    LCD.WriteAt(2,3,Convert.DecToStr(counter,5))
    LCD.WriteAt(2,9,convert.hextostr(counter,4))
    delaymS(1000)
    inc(counter)
Wend
Image
Attachments
counter_with_hex.png
counter_with_hex.png (361.79 KiB) Viewed 13082 times
16_bit_with_hex.jpg
16_bit_with_hex.jpg (101.49 KiB) Viewed 13084 times

User avatar
bitfogav
Moderator
Moderator
Posts: 908
Joined: Sun Mar 28, 2010 9:03 pm
Location: United Kingdom
Contact:

Post by bitfogav » Mon Jun 21, 2010 11:00 pm

Yeah it looks easier doing it in basic. :)

Brad do you know how to make the lcd scroll in asm?, Im having a problems? it will probably be very easy in basic with just a few lines?.

I can make text scroll from left to right and vise versa but only doing it in software by addressing the lcd display, but is there not a way that the LCD will do it basically for you?

For example: looking at the datasheet for a lcd 16x2 it says theres a command for Display/Cursor Shift I have tried setting the Display shift but it dont work? Or isn't this a scroll function and just a shift function, I just can't get my head around it hehe! having one of those days hehe!, anyway I just wondered if you knew or had any ideas? :)

User avatar
brad
Site Admin
Site Admin
Posts: 2576
Joined: Fri Mar 26, 2010 10:30 pm

Post by brad » Tue Jun 22, 2010 6:31 am

Unfortunately I am not sure, I haven't ever used these displays with ASM before...

I think it would be great to have scrolling text, I'll have to check the data sheet to see if I can figure it out in Basic. then I guess I can have a look at the ASM file that basic spits out once compiled.

User avatar
bitfogav
Moderator
Moderator
Posts: 908
Joined: Sun Mar 28, 2010 9:03 pm
Location: United Kingdom
Contact:

Post by bitfogav » Tue Jun 22, 2010 6:38 am

Thats aright Brad thank you :)

I have been working on it quite abit and think I have sorted it..

Heres the ASM if you want to have a look

http://www.bradsprojects.com/phpBB2/upl ... _3_147.rar

It writes Hello on the LCD screen at the top left and then scrolls it to the right, gets to the end of the LCD screen and then goes down to the 2nd line and then scrolls back to the left.. :)

PLEASE NOTE that this is not a finished asm, so some comments might be wrong or incomplete.
Attachments
LCD Scroller 3.rar
(1.93 KiB) Downloaded 488 times

User avatar
brad
Site Admin
Site Admin
Posts: 2576
Joined: Fri Mar 26, 2010 10:30 pm

Post by brad » Wed Jun 23, 2010 6:47 am

Sounds like a nifty little lcd screensaver :D

User avatar
bitfogav
Moderator
Moderator
Posts: 908
Joined: Sun Mar 28, 2010 9:03 pm
Location: United Kingdom
Contact:

Post by bitfogav » Thu Jun 24, 2010 8:55 am

hehe yeah thats all it is really :)

Your enjoy making your own user graphics, its a little tricky to program but once you crack it then its fun making them :)

you can draw faces, to battery symbols and even speakers :)

Mitchy
decided to stick around...
decided to stick around...
Posts: 30
Joined: Sun Jul 04, 2010 10:44 am
Location: Australia
Contact:

Post by Mitchy » Sun Jul 04, 2010 9:09 pm

bitfogav wrote:Your enjoy making your own user graphics, its a little tricky to program but once you crack it then its fun making them :)
They come in really handy and add the finishing touch in most cases!

Swordfish has a LCD Character plugin which makes the whole process a breeze.

Image

I did a small write up about the plugin, and have used it several times over the last year or so -- the first time was for a temperature logger which displayed "°C" (I couldn't settle for the text "Deg C")

User avatar
bitfogav
Moderator
Moderator
Posts: 908
Joined: Sun Mar 28, 2010 9:03 pm
Location: United Kingdom
Contact:

Post by bitfogav » Sun Jul 04, 2010 10:22 pm

Thats really cool :)

heres the website that ive been using to draw my user graphics, as it gives you your user graphics in dec, hex and binary :)

http://www.quinapalus.com/hd44780udg.html

User avatar
brad
Site Admin
Site Admin
Posts: 2576
Joined: Fri Mar 26, 2010 10:30 pm

Post by brad » Mon Jul 05, 2010 8:02 pm

I had no idea that was built into swordfish!

And as for that site, that's brilliant :)

There are so many handy resources out there, it's just a matter of being able to find them I guess.

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest