Friday, April 5, 2019

7 Segment 4x4 Random Word Display

-----
This is primarily a variant of the "Four Letter Word Clock" that we modified after getting tired of Daylight Savings Time making us push a few buttons twice a year to correct the time.  Actually, the project is more entertaining now.

The "Four Letter Word Clock" project page provides the BOM and schematics.  We left the Real Time Clock (RTC) implementation in the source code below, but it is not needed as a RTC is not used.

We were able to put 1,002 four letter words into the EPROM,  Since we display two four letter words selected at random that is over a million possible combinations.  The PICAXE random number generator is seeded by doing an analog read on an ADC open pin; basically we read 'noise' and use that for the seed.  It's pretty random, but I don't expect the method to be used in Vegas slot machines
-----
It's interesting to see the combinations produced by the rig.  Bored?  Watch this 4 minute demo:

It's a fun build.
-----
The PICAXE source code is:
#rem
 *******************************
 ***** www.WhiskeyTangoHotel.Com  *****
 *******************************   
    Project Name: 4Letter Word Clock

    Start Date: August 2012
   
    Program Rev History:
       March 2019.  Now called "4Letter Word by 4Letter"
     Tired of the simple two time/year DST change
     so we changed to format to display to random 4 letter
     words side by side.  The words are now random and not sequintial.
   

 *******************************

http://www.dealextreme.com/p/8x-digital-tube-8x-key-8x-double-color-led-module-81873

#endrem

;
;LKM1638 Input pin 3 (CLK)      ---> 18M2 c.0 LEG 17
;LKM1638 Input pin 4 (DIO)      ---> 18M2 c.1 LEG 18
;LKM1638 Input pin 5 (STB0)     ---> 18M2 c.2 LEG 1

;24LC156 EERPOM WP (Write Protect) GND
;24LC156 EERPOM SDA          ----> 18M2 b.1 LEG 7
'24LC156 EERPOM SCL           ----> 18M2 b.4 LEG 10

#picaxe 18m2
#no_data    'do not read internal 18M2 EEPROM

dirsc = 010111        ;c0, c1, c2, c4 as output
symbol clock    = c.0    ;Clock output pin
symbol dio        = c.1    ;Data input output pin
symbol strobe    = c.2    ;Strobe output pin

' s1 thru s8 are the tact swithes under the single RED/Green LEDs
symbol s1        = bit16 ;b2        'to set hours
symbol s2        = bit17 ;b2        ' to set minutes - both to set seconds
symbol s3        = bit18 ;b2
symbol s4        = bit19 ;b2
symbol s5        = bit20 ;b2
symbol s6        = bit21 ;b2
symbol s7        = bit22 ;b2
symbol s8        = bit23 ;b2    'toggle to turn on and off the ticker relay

symbol dataio    = b0 ;w0 and bit 0 to bit 7
symbol pad        = b1 ;w0 and bit 8 to bit 15
symbol iobuf    = w0 ;b0, b1
symbol keys        = b2 ;bit16 to bit 23
symbol fixaddr    = b3 ;start address for DE display

symbol Segment4LEFT    = b4  ;Rightmost 7 seg, LEFT Side
symbol Segment4RIGHT     = b5  ;Rightmost 7 seg, RIGHT Side
symbol Segment2LEFT    = b6  ;Leftmiddle 7 seg, LEFT Side
symbol Segment3LEFT    = b7  ;Rightmiddle 7 seg, LEFT Side
symbol Segment2RIGHT    = b8  ;Leftmiddle 7 seg, Right Side
symbol Segment3RIGHT      = b9  ;Rightmiddle 7 seg, Right Side
symbol Segment1LEFT      = b10 ;Leftmost 7 seg, LEFT Side
symbol Segment1RIGHT    = b11 ;Leftmost 7 seg, Right Side

symbol char        = b12
symbol bank        = b13
symbol tmpry     = b14
symbol dispbrit    = b15
symbol autoaddr    = b16
symbol readmode    = b17
symbol tmpry2    = b18
symbol EEPROMChar = b19
'w10 (b20/21) = used to read var from EEPROM
symbol LEDTicker  = b22

symbol seconds = b23 ' vars for RTC
symbol minutes = b24
symbol hours = b25
symbol blinky = b26 'for RTC 010000 would Enable output at 1Hz blink rate.  000000 is no blink
symbol junkread = b27 'used to read/write RTC day, month, year, date.  Also as a temp var in time set adjust routines

fixaddr        = $c0
dispbrit        = $88    '$88 (136DEC)  min bright.   $8F (143DEC) max bright
autoaddr        = $40
readmode         = $42

init:
high strobe            ;Ensure strobe is initially high
gosub clearchars        ;Clear all characters
blinky = 010000 ' 010000 would Enable output at 1Hz blink rate, start w/ relay click ON..  000000 is no blink.

' Set the time on the DS1307 RTC
i2cslave %11010000, i2cslow, i2cbyte    ; set PICAXE as master and DS1307 slave address
pause 50
'\/ \/ \/ \/ Un_REM THESE LINES (BELOW) IF SETTING UP A NEW RTC  \/ \/ \/ \/
#rem
' Set the RTC chip time
;  write time and date e.g. to 11:59:00 on Thurs 25/12/03
'; would be "writei2c 0,($00, $59, $11, $03, $25, $12, $03, 010000)"
' readi2c 0, (b0,b1,b2,b3,b4,b5,b6,b7) reads back the data

let hours = $19        ; 01-12 Note all BCD format
let minutes = $11         ; 00-59 Note all BCD format  
let seconds = $10    ; 00-59 Note all BCD format

; program does not use for we use seconds.  Set manually in the write statement
' for SQ Wave out on RTC.  Last val: 010000 would Enable output at 1Hz blink rate.  000000 is no blink

writei2c 0, (seconds, minutes, hours, 01, 01, 01, 01, blinky)
pause 50

#endrem
'/\ /\ /\ /\ Un_REM THESE LINES (ABOVE) IF SETTING UP A NEW RTC  /\ /\ /\ /\


;--------------------------------------------------------

'I have laid out the 8 segments in the display as:

'| Segment1LEFT | Segment2LEFT | Segment3LEFT | Segment4LEFT | Segment1RIGHT | Segment2RIGHT | Segment3RIGHT | Segment4RIGHT

    ;Segment Values                0-9   = ( 0 , 1,  2 , 3 , 4 , 5 , 6 , 7, 8 , 9,
    '                              10-19 =   A , b , C , d , E , F , g,  H, i,  J,
    '                              20-29 =   K,  L,  M,  N,  o,  P,  q,  r, S,  T, 
    '                              30-35 =   U, V, W,  X,  y,   Z ,
    '                              36-44 =   segA, segB, segC, segD, segE, segF, segG, dp, off)

'the 'gosub display' routine expect 8 values; SegmentxLEFT and SEGMENTxRIGHT coded as
'lookup values shown in the rem above.

' At Startup turn the clicky relay on.  S8 button will turn it off
blinky = 010000
i2cslave %11010000, i2cslow, i2cbyte
writei2c 0, (seconds, minutes, hours, 01, 01, 01, 01, blinky)

main:

if s1 = 1 or s2 = 1 or s8 = 1 then 'setting the clock time or relay ticker
    if s1 = 1 and s2 = 0 then 'setting hours
        junkread = junkread + 1
        if junkread > 23 then
            junkread = 0
        end if
        lookup junkread, ($00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23), hours
         i2cslave %11010000, i2cslow, i2cbyte
        writei2c 0, (seconds, minutes, hours, 01, 01, 01, 01, blinky)
        pause 10
    endif ' s1 = 1, setting hours
   
    if s2 = 1 and s1 = 0 then 'setting minutes
        junkread = junkread + 1
        if junkread > 59 then
            junkread = 0
        end if
        lookup junkread, ($00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59), minutes
         i2cslave %11010000, i2cslow, i2cbyte
        writei2c 0, (seconds, minutes, hours, 01, 01, 01, 01, blinky)
        pause 10
    endif 's2 = 1, setting minute
   
    if s1 = 1 and s2 = 1 then 'reset seconds to 00
        seconds = $00
        i2cslave %11010000, i2cslow, i2cbyte
        writei2c 0, (seconds, minutes, hours, 01, 01, 01, 01, blinky)
        pause 10
    endif 'settin seconds to zero

    if s8 = 1 then ' turn on/off the clicking relay
        'read the RTC to dected the seconds for the write to RTC below keeps them accurate
        i2cslave %11010000, i2cslow, i2cbyte    ; set PICAXE as master and DS1307 slave address
        readi2c 0,(seconds, minutes, hours, junkread, junkread, junkread, junkread, blinky)
        pause 10
        if blinky = 010000 then 'blinky from RTC is ON and clinking the relay. turn it OFF
            blinky = 000000
        else              'blinky from RTC is OFF and NOT clinking the relay. turn it ON
            blinky = 010000
        end if
        i2cslave %11010000, i2cslow, i2cbyte
        writei2c 0, (seconds, minutes, hours, 01, 01, 01, 01, blinky)
        pause 500
    end if
   

else ' not settign the clock, check for brightness adjust and run as normal; so read a new 4letter word
   
    if s7 = 1 then 'increase brightness
        dispbrit = 140 'other values cause random LED7 behavior
    end if

    if s6 = 1 then 'decrease brightness
        dispbrit = 136   ' 136 is min bright
    end if   

sertxd (#dispbrit, 13,10)
   
    'Get SegmentxLEFT values for clock by reading the RTC
    i2cslave %11010000, i2cslow, i2cbyte    ; set PICAXE as master and DS1307 slave address
    readi2c 0,(seconds, minutes, hours, junkread, junkread, junkread, junkread, blinky)
    pause 10
    gosub ReadEEPROM  ' read the four letter word.  These are loaded into SegmentxRIGHT vars
    gosub Ticker    'ticks thru the R/G LEDs to show seconds
endif

' THIS IS WHERE SEGMENT LEFT IS LOADED WITH THE TIME.
' CHANGE IT TO A WORD
'
'Segment1LEFT = hours & %11110000 / 16  'BCD so shift upper 4 bits to lower 4 bits
'Segment2LEFT = hours & 001111

'Segment3LEFT = minutes & %11110000 / 16   'BCD so shift upper 4 bits to lower 4 bits
'Segment4LEFT = minutes & 001111

gosub display   'Put the SegmentxLEFT and SEGMENTxRIGHT characters onto the 7 seg displays.

gosub getkeys        ;Read tact buttons
           
goto main

'-------------------------------------------------------
Ticker: 'ticks thru the R/G LEDs to show seconds by cycling through each LED address

junkread = seconds & %11110000
junkread = junkread / 16 * 10
seconds = seconds & 001111
seconds = junkread + seconds

lookup seconds, (1,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3,5,5,5,5,5,5,5,5,7,7,7,7,7,7,7,7,9,9,9,9,9,9,9,9,11,11,11,11,11,11,11,11,13,13,13,13,13,13,13,13,15,15,15,15), dataio

dataio = dataio + fixaddr    ;LEDs are at odd addresses 1 to 15
junkread = dataio   'used to turn off LED later in this sub
low strobe
gosub sendchar

LEDTicker = LEDTicker + 1

if LEDTicker = 2 then
    LEDTicker = 1
end if

dataio = LEDTicker  'Light the LEDs.  1 = RED.  2 = GREEN.  3 = R/G
gosub sendchar
high strobe

'Turn off LED here
dataio = junkread   
low strobe
gosub sendchar
dataio = 0   '0 turns off the currently selected LED
gosub sendchar
high strobe;

dataio    = dispbrit        ;Display control on, brightness level
low strobe                 ;Strobe low
gosub sendchar
high strobe                ;Strobe high

return 'Ticker

ReadEEPROM:
'24LC256 EEPROM is loaded with 987 four letters words (3948 characters)
'Each character is an address from 0 to 3947
'readi2c addrs, (charvalue)

i2cslave %10100000, i2cslow, i2cword    ; set PICAXE as master and DS1307 slave address

'Read and Translate the char read from the EEPROM for the lookup(.,...), dataio command.
'Read the EEPROM letter then subtract 87 from that ASCII value for the "lookupchar" sub.  Examples:
'ASCII value for a = 97; Lookup in this program value is 10.  So, 97 - 87 = 10
'ASCII value for j = 106; Lookup in this program value is 19.  So, 106 - 87 = 19
'ASCII value for k = 122; Lookup in this program value is 35.  So, 122 - 87 = 35

'Last word in EEPROM is YURT and starts at Location 4008

touch16 B.7, b20 'lower bits w10
touch16 B.7, b21 'w10 upper
'RANDOM number for w10
w12 = w10 // 1003  ; scale it to 0-1002 (4 * 4008 = 4008)
w10 = w12 * 4  ; max is YURT at 4008 start

readi2c w10, (Segment1LEFT)
Segment1LEFT = Segment1LEFT - 87

w10 = w10 + 1
readi2c w10, (Segment2LEFT)
Segment2LEFT = Segment2LEFT - 87

w10 = w10 + 1
readi2c w10, (Segment3LEFT)
Segment3LEFT = Segment3LEFT - 87

w10 = w10 + 1
readi2c w10, (Segment4LEFT)
Segment4LEFT = Segment4LEFT - 87
'
'
'
touch16 B.7, b20 'lower bits w10
touch16 B.7, b21 'w10 upper
'RANDOM number for w10  
w12 = w10 // 1003  ; scale it to 0-1002 (4 * 4008 = 4008)
w10 = w12 * 4  ; max is YURT at 4008 start

readi2c w10, (Segment1RIGHT)
Segment1RIGHT = Segment1RIGHT - 87

w10 = w10 + 1
readi2c w10, (Segment2RIGHT)
Segment2RIGHT = Segment2RIGHT - 87

w10 = w10 + 1
readi2c w10, (Segment3RIGHT)
Segment3RIGHT = Segment3RIGHT - 87

w10 = w10 + 1
readi2c w10, (Segment4RIGHT)
Segment4RIGHT = Segment4RIGHT - 87

pause 1500 'keep the secs LED on and slow down the words

return ' ReadEEPROM


;--------------------------------------------------------

display:    ;Displays data on the 7 seg displays, using 2 blocks of 4 digits

    bank = 0   ;LEFT Side: First block of digits

    dataio    = fixaddr + bank + 0 ;Set Leftmost 7 seg, LEFT Side write address
    low strobe                 ;Strobe low
    gosub sendchar
    char = Segment1LEFT        ;Leftmost 7 seg, LEFT Side
    gosub lookupchar
    gosub sendchar
    high strobe                ;End of data - Strobe high
   
    dataio    = fixaddr + bank + 2 ;Set Leftmiddle 7 seg, LEFT Side write address
    low strobe                 ;Strobe low
    gosub sendchar
    char = Segment2LEFT        ;Leftmiddle 7 seg, LEFT Side
    gosub lookupchar
    gosub sendchar
    high strobe                ; End of data - Strobe high
   
    dataio    = fixaddr + bank + 4 ;Set Rightmiddle 7 seg, LEFT Side write address
    low strobe             ; Strobe low
    gosub sendchar
    char = Segment3LEFT    ;Rightmiddle 7 seg, LEFT Side
    gosub lookupchar
    gosub sendchar
    high strobe            ;End of data - Strobe high
   
    dataio    = fixaddr + bank + 6 ;Set Rightmost 7 seg, LEFT Side write address
    low strobe             ; Strobe low
    gosub sendchar
    char = Segment4LEFT    ;Rightmost 7 seg, LEFT Side
    gosub lookupchar
    gosub sendchar
    high strobe            ;End of data - Strobe high
   
    'RIGHT BANK
    bank = 8  ;RIGHT Side: Second block of 4 digits
    dataio    = fixaddr + bank + 0 ;Set Leftmost 7 seg, Right Side write address
    low strobe             ;Strobe low
    gosub sendchar
    char = Segment1RIGHT    ;Leftmost 7 seg, Right Side
    gosub lookupchar
    gosub sendchar
    high strobe            ;End of data - Strobe high
   
    dataio    = fixaddr + bank + 2 ;Set Leftmiddle 7 seg, Right Side write address
    low strobe             ;Strobe low
    gosub sendchar
    char = Segment2RIGHT    ;Leftmiddle 7 seg, Right Side
    gosub lookupchar
    gosub sendchar
    high strobe            ;End of data - Strobe high
   
    dataio    = fixaddr + bank + 4 ;Set Rightmiddle 7 seg, Right Side write address
    low strobe             ; Strobe low
    gosub sendchar
    char = Segment3RIGHT    ;Rightmiddle 7 seg, Right Side
    gosub lookupchar
    gosub sendchar
    high strobe            ; End of data - Strobe high
   
    dataio    = fixaddr + bank + 6 ;Set Rightmost 7 seg, RIGHT Side write address
    low strobe             ; Strobe low
    gosub sendchar
    char = Segment4RIGHT    ;Rightmost 7 seg, RIGHT Side
    gosub lookupchar
    gosub sendchar   
   
    '-----------------
   
    'must refresh dispbrit each time
    dataio    = dispbrit ;Display brightness level. $88 (136DEC)  min bright.   $8F (143DEC) max bright
    low strobe         ; Strobe low
    gosub sendchar
    high strobe        ; Strobe high

return   'display

;--------------------------------------------------------

clearchars:            ;Clear LEDs and 7 seg displays.  ALL LEDS OFF. Segs and LEDs
    dataio    = autoaddr ; Data mode auto increment
    low strobe         ; Strobe low
    gosub sendchar
    high strobe        ; Strobe high
    ;
    low strobe         ; Strobe low
    dataio    = fixaddr ; Set start address
    gosub sendchar
    for tmpry = 1 to $0f    ;$0F = 15, so loop runs 16 times.  7 LEDs and 7 seg displays
        dataio = 0        ;Zero blanks the  display
        gosub sendchar
    next
    high strobe            ;Strobe high, keep low to end of data
return

;--------------------------------------------------------

sendchar:    ;Routine to send all characters to LKM1638 module serially
    pad        = $ff    ;$FF = 255.  Set counter
    high clock        ;Ensure clock is high for pulseout
    do
      pinc.1 = bit0    ;Make c.1 the value in bit0
      iobuf = iobuf/2    ;Shift right
      pulsout clock,1 '10us clock pulse
    loop Until pad = 0  'excecute 256 times
return

;--------------------------------------------------------

getkeys:    ;Reads the input tact buttons in and places them in bits16 to bits23
dataio    = readmode    ; Data mode read
low strobe
gosub sendchar
input c.1            ;set c.1 as input
high clock            ;Ensure clock is high for pulseout
for tmpry = 1 to 16    ;Read in bits 0-15
    bit0 = pinc.1    ;Make bit0 the value on c.1. Need to use c.1 as it is both in & out
    iobuf = iobuf*2    ;Shift bit left
    pulsout clock,1    ;10us clock pulse, read next bit
next
s6 = bit3            ;Move 1st word switch values out of buffer
s2 = bit7
s5 = bit11
s1 = bit15
for tmpry = 1 to 16    ;Read in bits 16-31
    bit0 = pinc.1    ;Make bit0 the value on b.0. Need to use c.1 as it is both in & out
    iobuf = iobuf*2    ;Shift bit left
    pulsout clock,1    ;10us clock pulse, read next bit
next
s8 = bit3            ;Move 2nd word switch values out of buffer
s4 = bit7
s7 = bit11
s3 = bit15   
output c.1            ;Return c.1 to output
high strobe
return

;--------------------------------------------------------

lookupchar:    ;Looks up the code to display the digit in 'char' on the 7 seg display
    ;character  0-9   =    ( 0 , 1,  2 , 3 , 4 , 5 , 6 , 7, 8 , 9,
    '               10-19 =         A , b , C , d , E ,  F , g,  H, i,   J,
    '               20-29 =         K,  L,  M,  N, o,   P,  q,  r,  S,  T, 
    '               30-35 =         U, V, W,  X,  y,   Z ,
    '               36-44 =        segA, segB, segC, segD, segE, segF, segG, dp, off)

    lookup char,(63,6,91,79,102,109,125,7,127,111,119,124,57,94,121,113,111,118,16,30,118,56,21,84,92,115,103,80,109,120,62,28,42,118,110,91,1,2,4,8,16,32,64,128,0),dataio

return

;------------------------