Max7219 question for MartinM57 or anyone

G

Guest

Guest
<i>Wilf:

I am sorry if my attempt at humour might have offended you. I did not intend to dismiss your suggestion, only to advise that I knew nothing about the infra features and thus believed I would have a new series of self inflicted problems to post about. </i>

No worry Tim, I hate losing remotes as much as the next guy. In fact it made me think of hardwiring the remote as a handy way to implement a one wire keypad add on. It requires a small mod to replace the IR LED with a resistor and to add a capacitor to suppress the 38kH carrier.

wilf


 

Tim Vukman

New Member
Hi Wilf:

Thanks for your post. I feel better now. I indeed do hope that it lead to something useful for you as it may turn out to be very useful for more of us down the line!

Hippy:

No good news yet. I am flooding the 4 gosub limit :( I did notice that nowhere in my code does keypress actually get set to $80.

Still working on it

Tim
 

Tim Vukman

New Member
Hi Hippy

Progress has been made which has led to a new question.

The Set_Hour_T, etc has been placed under a label of Get_New_Time:

On entry, I am setting KeyPress = $80 and the code for setting the new time is executing.

A snippet of
&quot;GET_NEW_TIME:
keypress = $80
SET_HOUR_T:
GOSUB GET_NEW_KEY_PRESS
IF keyPress = $81 THEN UPDATE_RTC
IF keyPress &gt; 2 THEN SET_HOUR_T
hourT = keyPress ; 0..2
GOSUB DISPLAY_TIME&quot;

should illustrate my question.

When Gosub &quot;Display_Time&quot; is called, it is the same module that is called from the main_loop and thus updates all 4 digits of the display sequentially.

I think I should create a label for each digit and call each one separately from the &quot;Get_New_Time&quot; module.

I could put them in order in the main_loop instead of the Display_Time label thus changing

Gosub Display_Time

to a gosub for each label

Gosub Display_Hour_T
Display_Hour_T:
....
Return

Gosub Display_Hour_U
Display_Hour_U:
....
Return

etc

At this point, no updates will have been written to the rtc, so I'm thinking since I am in set time mode I would blank all four digits, and then update each digit as it gets its new value in the Set_New_Time module. If I abort the set_time process, the next loop through the main_loop would update the digits as though nothing had happened.

That would also give me a visual indication that I have actually entered the Set_Time_Module when in normal operation and each digit displaying the update would allow me to see when it was appropriate to press the &quot;Set_Time&quot; key to write the new time to the rtc.

If I have gone astray, please advise, but I think this will make my challenge easier.

Thanks

Tim
 

hippy

Ex-Staff (retired)
You appear to have used GOSUB into Set_Hour_T which eats up one level; if you can make that a non-GOSUB ( yes, the PICAXE limititations often mean throwing out good practice ), that may get back you within the limit.
 

Tim Vukman

New Member
Hi All!!!!!!!!!!!

We have a miracle!!!

I know it doesn't mean completion just yet, but......

I have changed the display_time module to 4 seperate digit modules and update each digit in sequence from the main_loop for normal operation.

This has allowed me to update each single digit as the new information is entered via the keypad and then update the rtc once the &quot;Set_Time&quot; key is pressed.

I am currently running on the simulator so that I could follow the code and press the keypad at the appropriate times.

I know that's not real life, but for me, the code is finally working properly and I can get ready for running it on the PicAxe.

Hippy:

I need to put the WaitForNoKeyPressed code back in now that everything is working properly, and I still want to blank the digits and display the input one digit at a time as it goes in from the keypad.

I couldn't wait to share the news that I have so far :)

The updated version of the code is below in the event that it might help others.

Thanks

Tim
' PicAxe 28x
' Digit Alarm Clock with 16 Key Keypad Interface and
' Max 7219 Display driver and
' DS1307 RTC
'control level outputs
symbol load_7219 = 6
symbol din_7219 = 7
symbol clk_7219 = 5
'data variables
symbol DisplayMinuteUnit = $c0
symbol DisplayMinuteTen = $c1
symbol DisplayHourUnit = $c2
symbol DisplayHourTen = $c3
symbol display_blank = $0F
'max7219 registers
symbol decode_mode = $09
symbol intensity = $0A
symbol scan_limit = $0B
symbol shutdown = $0C
symbol digit_test = $0F
'keypad variables
SYMBOL V_ROW3 = 195
SYMBOL V_ROW2 = 150
SYMBOL V_ROW1 = 105
SYMBOL V_ROW0 = 40
symbol keypress = b8
symbol hourT = b9
symbol hourU = b10
symbol minsT = b11
symbol minsU = b12
rtc initialization
i2cslave %11010000, i2cslow, i2cbyte
pause 100
writei2c 0, ($00, $00, $12, $01, $01, $01, $06, $10)
pause 40
START:
poke DisplayMinuteUnit, display_blank
poke DisplayMinuteTen, display_blank
poke DisplayHourUnit, display_blank
poke DisplayHourTen, display_blank
initialize 7219
GOSUB INITIALIZE_7219
'turn on test mode
b0 = digit_test
b1 = $01
GOSUB SEND_DATA_7219
pause 1000
'turn off test mode
b0 = digit_test
b1 = $00
GOSUB SEND_DATA_7219
'set displays zero
poke DisplayMinuteUnit, 0
poke DisplayMinuteTen, 0
poke DisplayHourUnit, 0
poke DisplayHourTen, 0
END_START:

goto MAIN_LOOP

INITIALIZE_7219:
b0 = decode_mode
b1 = $FF ' code b decode all digits
GOSUB SEND_DATA_7219
b0 = intensity
b1 = $0F
GOSUB SEND_DATA_7219
b0 = scan_limit
b1 = $03
GOSUB SEND_DATA_7219
b0 = shutdown
b1 = $01
GOSUB SEND_DATA_7219
END_INITIALIZE_7219:

return

MAIN_LOOP:
GOSUB READ_RTC
GOSUB DISPLAY_MINS_UNIT
GOSUB DISPLAY_MINS_TENS
GOSUB DISPLAY_HOUR_UNIT
GOSUB DISPLAY_HOUR_TENS
gosub get_new_time
gosub update_rtc
IF keyPress &lt;&gt; $81 THEN MAIN_LOOP
END_MAIN_LOOP:

SEND_DATA_7219:
'send the data
low LOAD_7219
pin7 = bit7
pulsout clk_7219, 1
pin7 = bit6
pulsout clk_7219, 1
pin7 = bit5
pulsout clk_7219, 1
pin7 = bit4
pulsout clk_7219, 1
pin7 = bit3
pulsout clk_7219, 1
pin7 = bit2
pulsout clk_7219, 1
pin7 = bit1
pulsout clk_7219, 1
pin7 = bit0
pulsout clk_7219, 1
pin7 = bit15
pulsout clk_7219, 1
pin7 = bit14
pulsout clk_7219, 1
pin7 = bit13
pulsout clk_7219, 1
pin7 = bit12
pulsout clk_7219, 1
pin7 = bit11
pulsout clk_7219, 1
pin7 = bit10
pulsout clk_7219, 1
pin7 = bit9
pulsout clk_7219, 1
pin7 = bit8
pulsout clk_7219, 1
high load_7219
END_SEND_DATA_7219:

return

READ_RTC:
readi2c 0, (b5, b6, b7)
b3 = b6 &amp; %00001111
poke DisplayMinuteUnit, b3
b3 = b6 / 16
poke DisplayMinuteTen, b3
b3 = b7 &amp; %00001111
poke DisplayHourUnit, b3
b3 = b7 / 16
poke DisplayHourTen, b3
END_READ_RTC:

return

DISPLAY_TIME:
DISPLAY_MINS_UNIT:
peek DisplayMinuteUnit, b1
b0 = $03
gosub send_data_7219

return

DISPLAY_MINS_TENS:
peek DisplayMinuteTen, b1
b0 = $04
gosub send_data_7219

return

DISPLAY_HOUR_UNIT:
peek DisplayHourUnit, b1
b0 = $02
gosub send_data_7219

return

DISPLAY_HOUR_TENS:
peek DisplayHourTen, b1
b0 = $01
gosub send_data_7219
END_DISPLAY_TIME:

return

GET_KEY_PRESS:
b0=12
READADC 3,b1
IF b1 &gt; V_ROW0 THEN FIND_KEY
b0=8
READADC 2,b1
IF b1 &gt; V_ROW0 THEN FIND_KEY
b0=4
READADC 1,b1
IF b1 &gt; V_ROW0 THEN FIND_KEY
b0=0
READADC 0,b1
IF b1 &gt; V_ROW0 THEN FIND_KEY
END_GET_KEY_PRESS:

return

FIND_KEY:
IF b1 &lt; V_ROW1 THEN GOT_KEY_PRESS
b0 = b0+1
IF b1 &lt; V_ROW2 THEN GOT_KEY_PRESS
b0 = b0+1
IF b1 &lt; V_ROW3 THEN GOT_KEY_PRESS
b0 = b0+1
END_FIND_KEY:

GOT_KEY_PRESS:
lookup b0,($00, $07, $04, $01, $00, $08, $05, $02, $0d, $09, $06, $03, $0d, $0c, $0e, $81), keypress
END_GOT_KEY_PRESS:

return

GET_NEW_TIME:
keypress = $80
SET_HOUR_T:
GOSUB GET_KEY_PRESS
IF keyPress = $81 THEN UPDATE_RTC
IF keyPress &gt; 2 THEN SET_HOUR_T
hourT = keypress
POKE DisplayHourTen, keyPress ; 0..2
GOSUB DISPLAY_HOUR_TENS

SET_HOUR_U:
GOSUB GET_KEY_PRESS
IF keyPress = $81 THEN UPDATE_RTC
IF keyPress &gt; 9 THEN SET_HOUR_U
IF hourT = 2 AND keyPress &gt; 3 THEN SET_HOUR_U
hourU = keypress
POKE DisplayHourUnit, keyPress ; 0..9
GOSUB DISPLAY_HOUR_UNIT

SET_MINS_T:
GOSUB GET_KEY_PRESS
IF keyPress = $81 THEN UPDATE_RTC
IF keyPress &gt; 5 THEN SET_MINS_T
minst = keypress
POKE DisplayMinuteTen, keyPress ; 0..5
GOSUB DISPLAY_MINS_TENS

SET_MINS_U:
GOSUB GET_KEY_PRESS
IF keyPress = $81 THEN UPDATE_RTC
IF keyPress &gt; 9 THEN SET_MINS_U
minsU = keypress
POKE DisplayMinuteUnit, keyPress ; 0..9
GOSUB DISPLAY_MINS_UNIT

GOTO SET_HOUR_T ; Keep updating until Set Time key
END_GET_NEW_TIME:

UPDATE_RTC:
b3 = hourT &amp; $000F
b7 = b3 * $10 + hourU
b4 = minsT &amp; $000F
b6 = b4 * $10 + minsU
writei2c 0, (b5,b6,b7) ; Write null--&gt; seconds, then minutes and hours
keypress = 0
GOTO MAIN_LOOP
END_UPDATE_RTC:
 

Tim Vukman

New Member
Hi:

Hippy: To no great surprise, the code flies by so fast that I can't set the time. It will take the keypad entry, but it is not usable the way it is.

It might not be returning to the main_loop either as it does not appear that the rtc is counting or perhaps the code is not updating the displays. I suspect the rtc hardware is working as it has been very stable.

Getting awful close though :)

Tim
 

Tim Vukman

New Member
Hi:

It was a little early to have posted my code.
&quot;Get_New_Time&quot; in the main_loop should be &quot;GET_KEY_PRESS&quot;
and
&quot;Get_New_Time&quot; should be after the IF KeyPress &lt;&gt; $81 test instead of before it.

Sorry about that.

Hi Hippy:

Mike sent me a new version of the simulator which now supports the &quot;pinx = &quot; and it now updates the 28x during program execution.

That's how I found the statement changes above. I was getting locked in a loop between getting the keypress and setting the value.

Your original sample for the WaitForNoKeyPress code is still here and I am going to try to implement that now that the rest of the code is working properly.

Thanks

Tim
 

Tim Vukman

New Member
Hi:

I have been successful at adding the no_key_pressed routine and on the simulator everything is working perfectly. Hopefully it will do the same at full speed on the 28x.

Hippy:

I am running the no_key_pressed mechanism on two variables.

Since the program exits the main loop on the &quot;set_Time&quot; value of $81, the first loop through was fine if I pressed a key to change the value off of $81. If I then didn't hit another key to set the Hour_T value, $81 would still be in keypress and it would go off and update the RTC.

I set keypress to $80 on the entry to the get_new_time.

There is a test at the end of the get_key_press module for keypress = $80 When true it goes to a no_key_pressed module.

My other new addition is keypress81bypass which is set at $91 when the program starts.

This is part of an AND test after the keypress value has been set. When this is $91 and keypress is $81 I can bypass the problem of not pressing a key when the last enty of the keypad was the initial $81 to entry the time set module.

After the last time value is loaded the keypress81bypass is set to zero so that when the module ends and the next get_key_press happens the value of $81 can then be used as the final &quot;set_time&quot; value to send the code to the write rtc module.

In each of the set modules for the different digits, I test for the no_key_pressed value of $80 and call the no_key_pressed module.

I'm not sure if I did it the best way possible, but I' sure pleased to have figured out how to achieve the results I was looking for.

It will indeed wait until each digit is updated before moving on to the next.

I am going to add some code to beep the alarm at the end of each digit's value being captured so the user will know the clock is ready for the next digit.

If you folks are tired of reading all the status reports, just let me know and I'll stop posting them.

thanks

Tim
 

Tim Vukman

New Member
Hi:

The code is hanging on the 28x. It works fine on the simulator where things are slow enough for me to manually push the buttons at the correct times.

I added a piezo and use it to signal entry to the set_time mode and to signal when a time value has been captured.

The code will correctly detect the $81 that sends it to the set_time module. From there, it will correctly capture the hourT value.

It does not beep to indicate the capture, so I know where to start looking. I may have overcomplicated the testing and I suspect I am locked in a loop. Likely around the no_key_pressed, but I will have to trace it on paper to try to find the error

Thanks

Tim
 

MartinM57

Moderator
...maybe you should have designed a rock solid Finite State Machine on paper, coded it up nice and simply and moved on to your next project already!

I haven't read all of this thread but it seems that you are chasing around different 'states' in the code trying to find the magic combination that works, have had mixed success and are now considering resorting to paper to work out what might be going on

This isn't meant to be harsh, by the way, it's just an observation on how this thread, and your success, is going!
Martin
 

hippy

Ex-Staff (retired)
I think you may need to take a step back again. I'm not entirely clear on the changes you've made and the requirement to pre-initialise keyPress etc. The example code I orginally produced should work okay without any tweaking. I'd take another look at the key press handling agaian.

Also, removing the actual display routines and getting just the key press and then time handling routines working on the real chip is probably a good idea.

Rather than using the display you can use SERTXD to send data to the PC, and you can also place SERTXD's in the code ( often after labels ) so you can report where the code is going and where it may be stopping or going into a loop.

The best way to work is iteratively as you have done, and to verify that what works in the simulator also works on the real chip as you progress, that way when something goes wrong you know roughly in which area to look.

Simulators represent a perfect and ideal world whereas real chips inhabit a far less perfect one - I spent ages perfecting a high-speed bit banging routine only to find that capacitance on an I/O line meant it couldn't ever work.

No offence to any of the simulator writers, but there is a possibiity that they have subtle bugs or do not accurately reflect how a real chip will work, and can rarely simulate things like slightly fluctuating voltage inputs, button bouncing and real world time lags.
 

Tim Vukman

New Member
Hi Martin:

I did some reading on the finite state machines and no, I have not built one on paper, largely because when I started to sit down and try to put it together from my stuff it didn't seem as straight forward as the conceptual information that I had read on the web. I would like to get there.

I felt that I was very close to having this all sorted out, and when it ran as desired on the simulator I thought I had it beat.

Hi Hippy:

'Rather than using the display you can use SERTXD to send data to the PC, and you can also place SERTXD's in the code ( often after labels ) so you can report where the code is going and where it may be stopping or going into a loop.'

You have mentioned this before and I will look it up in the manual and review the sample you provided in this post. If there is nothing in my wiring to get in the way, it looks like it will provide more information than I thought it would. I've only used the debug line in the code on the picaxe.

I thought I had the code in the way you had drafted it earlied. I started adding more tests and controls because there was no indication of where to set keypress to $80 in the sample code.

Once the &quot;set_time&quot; button was hit, keypress became $81 and remained at that value until another key was pressed. If I didn't get a key pressed fast enough, the $81 would just send me off to the write i2c routine and out of the whole key capture routine.

Thanks very much to you both

Tim



 

hippy

Ex-Staff (retired)
Oops - What's happened is that we glossed-over converting a key push into a return value in GetKeyPress earlier on. That routine puts a value 0 to 16 in b0 to represent none or one of the buttons pushed. That then needs to get converted to a keycode in 'keyPress', 0 to 9 for the digits, $80 for none, $81 for Set time and so on ...<code><pre><font size=2 face='Courier'>GetKeyPress:
b0=12 : READADC 3,b1 : IF b1 &gt; V_ROW0 THEN FindKey
b0=8 : READADC 2,b1 : IF b1 &gt; V_ROW0 THEN FindKey
b0=4 : READADC 1,b1 : IF b1 &gt; V_ROW0 THEN FindKey
b0=0 : READADC 0,b1 : IF b1 &gt; V_ROW0 THEN FindKey
GOTO GotKeyPress
FindKey:
IF b1 &lt; V_ROW1 THEN GotKeyPress
b0 = b0+1
IF b1 &lt; V_ROW2 THEN GotKeyPress
b0 = b0+1
IF b1 &lt; V_ROW3 THEN GotKeyPress
b0 = b0+1
GotKeyPress:
' 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
LOOKUP b0,($80,0,1,2,3,4,5,6,7,8,9,$81,$82,$83,$84,$85,$86),keyPress
RETURN </font></pre></code> b0 will be zero when no keys are pressed so the first entry in the LOOKUP list needs to be $80. The rest will depend on how the keypad is wired up and may need a bit of experimenting with to get the value in keyPress to represnt the button pushed ( code like that at the top of page 3 will help ).

And &quot;why $80, $81 etc ?&quot; - It's arbitrary really, any numbers &gt; 9 could be used, but $80 up are handy because that bit 7 can be tested to quickly see if it's a special key. Also $8X stands out as not 'being a number'.

Edited by - hippy on 29/06/2006 22:56:20
 

Tim Vukman

New Member
Hi Hippy:

Thanks for setting my mind to rest on the $80. I had figured they were arbitrary, but I have struggled with where to set it.

Once again you have provided a very elegant solution.

I did something pretty linear here, but thanks to the sertxd I worked through it.

I didn't think of what you have now done to set $80. It's beautiful.

I did things the hard way (which I assure you I will change)

I forced the $80 on entry into each set_digit (all four) and then tested for it right after the return from get_key gosub.
If it was still $80, I forced it back to the start of it's respective digit set routine until it got a passing keypress that could be set.

I then disabled the tests in each digit for $81 which would send it to update the rtc.

After the fourth digit it goes to the update_rtc routine on it's own, and from there back to the main loop.

It is admittedly brute force, but I can set the time directly on the picaxe :), while it is running in real time!

I'm going to change the code now to what you have suggested in part because it looks so much neater, but also to learn from adding it.

I suspect it will make it easier to add the alarm module.

Thanks very much

Tim
 

Tim Vukman

New Member
Hi Hippy:

Great News!!!!!!!

I changed my code to what you were kind enough to post and it works perfectly on the 28x.

I was going to wait until tomorrow to remove all the comment characters that I had put in to shut down all the other modules, but I couldn't :)

I have updated the time and the clock is running happily :)

It seemed a little tough to get the minute tens in. I had to try a couple time, but the program waited for me without complaint.

This has been a wonderful journey and I thank you so much for your patience and your support.

Yes, I still have the alarm stuff to do, but I see that as another module that compares some stored values against the rtc when it updates and triggers the buzzer from there. Yes, snooze needs to be dealt with and a the alarm on / off, but I actually have some pretty solid ideas in my head for how to do that.

This is amazing!!!!!

I thank all of you who have followed this and so kindly offered comments, observations and suggestions.

This has been so much better than working through the book I bought on PicAxe programming.

What a book you guys could write!!!!!!!

All the very best

Tim
P.S. I will toss in updates on what is left to do. It just might not be a straight forward as I think it is
 

Tim Vukman

New Member
Hi Hippy:

I wasn't able to pass $85 (Alarm_Set) without getting lost, so I put some limits on the code.

I have replicated the set digits from the time settings and I call the alarm version when I want to set the alarm time.

So, for example, Set_Hour_T: is
SET_HOUR_T:
GOSUB GET_KEY_PRESS
if keypress = $80 then set_hour_t
IF keyPress = $81 THEN UPDATE_RTC
IF keyPress &gt; 2 THEN SET_HOUR_T
hourT = keypress
POKE DisplayHourTen, keyPress ' 0..2
high piezo
pause 500
low piezo
keypress = $80
'GOSUB DISPLAY_HOUR_TENS

As you can see, if there is no keypress I do not leave the module. I keep cycling until I get a valid entry and then move on to the next digit.
$80 is still the indication that no key has been pressed.

I do the same thing for setting the alarm times, but I use $85 for Set_Alarm.

I found that in the original code, I was unable to reliably advance to the next digit without having to occassionally try entering the data a second time.

This does set the time or the alarm reliably and I haven't yet had to try a second time to enter the data.

I added a test for keypress = $85 in the main loop, just before the if keypres &lt;&gt; $81 goto main loop. Thus a keypress of $85 sends me to update the alarm, no keypress cycles through the main loop, and a keypress of $81 sends me to set time.

I expect you had a plan to use the same Get_Time modules for both time and alarm, but I saw no way to accomplish that

Thanks

Tim

SET_ALARM_HOUR_T:
GOSUB GET_KEY_PRESS
if keypress = $80 then set_alarm_Hour_t
if keypress = $85 then update_alarm
IF keyPress &gt; 2 THEN SET_ALARM_HOUR_T
hourT = keypress
POKE ALARMHourTen, keyPress ' 0..2
high piezo
pause 500
low piezo
keypress = $80
GOSUB DISPLAY_ALARM_HOUR_TENS
 

Tim Vukman

New Member
Hi All:

28x Alarm Clock with 16 key keypad interface, Max7219 Display Driver and DS1307 RTC.

Well, the alarm clock is working 100% on the 28x.

I'm not going to post the code here as it came in around 400 lines.

If anyone wants a copy of the final code, please leave a post here and I can email it.

Please accept my sincere thanks and appreciation to all of you who provided suggestions, help and encouragement!

I know that I would not have been able to do this without the help that I received here.

Thanks very much indeed,

Tim
 
Top