Max7219 question for MartinM57 or anyone

Tim Vukman

New Member
Good Afternoon:

I would appreciate some troubleshooting suggestions.

I am having a challenge with getting a MAX7219 to run 4 CC 7 segment display digits.

I have all of the segments joined on a bus and with the cathodes grounded, +5 to any segment on the bus lights up the segment on all 4 displays.

The bus is wired to each of the corresponding segments on the 7219.

I am using digit0 to digit 3 on the input side of the 7219. DIN, CLK and Load are tied low with 10K resistors. I have a 10K resistor from pin 18 to pin 19 for the ISET line.

From my 28x, Output 7 feeds the data to DIN. Output 6 provides the Load and Output 5 takes care of the clock.

I can see my outputs with debug on as I have leds on every output. From what I can see, the software is operating properly.

My thanks to MartinM for the code. I stripped down the tach / advance code that he had posted here in the forum. I have tried a couple other samples but this one clearly demonstrated to me how the bits get moved out of the 28x.

I can't seem to get any sign of life to the 7 segment displays. I have the 7219 data sheet pretty much memorized and I can see when the code enters the "test Digit". Nothing lights up, - ever.

I have replaced the 7219 in the event that it might have been the problem, but still no luck.

The code is here:
'28x
'7219 version 4

symbol displaythousand = $c0
symbol displayhundred = $c1
symbol displayten = $c2
symbol displayunit = $c3

'7 segment multiplexing
symbol load_7219 = 6
symbol din_7219 = 7
symbol clk_7219 = 5

'blank value for display
symbol display_blank = $0F

'max7219 registers
symbol decode_mode = $09
symbol intensity = $0A
symbol scan_limit = $0B
symbol shutdown = $0C
symbol digit_test = $0F

start:

poke displaythousand, display_blank
poke displayhundred, display_blank
poke displayten, display_blank
poke displayunit, 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
b0 = digit_test
b1 = $00
gosub send_data_7219

end_start:
'set displays zero
poke displaythousand, 0
poke displayhundred, 0
poke displayten, 0
poke displayunit, 0

gosub show_display

Main:
w6 = 82
w6 = w6*60

b0 = w6 / 1000
poke displaythousand, b0
b0 = w6 // 1000 / 100
poke displayhundred, b0
b0 = w6 // 100 / 10
poke displayten, b0
b0 = w6 // 10
poke displayunit, b0
gosub show_display

goto main
end

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

return

show_display:

peek displayunit, b1
b0 = $04
gosub send_data_7219

peek displayten, b1
b0 = $03
gosub send_data_7219

peek displayhundred, b1
b0 = $02
gosub send_data_7219

peek displaythousand, b1
b0 = $01
gosub send_data_7219

end_show_display:

return

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
return


Any pointers on how to isolate my problem would be appreciated.

Thanks

Tim
 

MartinM57

Moderator
Hey, my name in a thread title! :cool:

<<I have all of the segments joined on a bus and with the cathodes grounded, +5 to any segment on the bus lights up the segment on all 4 displays.>>

I don't know if you really mean that, but that isn't the way to wire up 7-segment CC displays to the 7219 :-(

You need to wire:
- the DIG0 to DIG3 pins to the CC of each individual 7-segment display
- bus together all the same segments (i.e. 'a' to 'g' and DP) and connect them to SEG A to SEG G and SEG DP

The 7219 takes care of grounding the correct digit cathode and supplying current to the appropriate segements on that digit. It, of course, switches the digits and segments very quickly, in a synchronised manner (ie 'multiplexing') so that it appears each digit is permanently displayed.

I haven't checked the code in detail, but that's my first thought....
 

Tim Vukman

New Member
Hi Martin

Thanks for the response. I really searched for help before I posted and your name came up time and again on the 7219.

My quick summary at the beginning of the post was misleading.

"I am using digit0 to digit 3 of the 7219. DIN, CLK and Load are tied low with 10K resistors. I have a 10K resistor from pin 18 to pin 19 for the ISET line."
a little later in the text is meant to specify that I am using dig0 to dig3 and that they are each going to the cathodes on one of the 7 segments.

I should know better than to post when I am frustrated.

Glad to have to looking at it

Thanks

Tim
 

MartinM57

Moderator
OK - I'll assume no wiring errors, but the software is pretty simple so it's going to be a bit of a challenge to work out what's wrong.

They really are CC displays? What part number?

You have got both pins 4 and 9 on the 7219 to GND?

I don't use any pull down resistors on the DIN, CLK and LOAD lines, but I can't see they would make much difference - why did you put them in? To avoid any doubt, try the code with them removed.

Tell me more about these LEDs....they sound like they are on the DIN, CLK and LOAD lines. Are they? How are they wired EXACTLY? Do they have current limiting resistors? What values?

If you make a real simple program

symbol load_7219 = 6
symbol din_7219 = 7
symbol clk_7219 = 5

main:
low load_7219
low din_7219
low clk_7219
pause 2000
high load_7219
high din_7219
high clk_7219
goto main
end

...does it do what you expect - ie with a voltmeter, do you see 0 and close to Vcc on all the lines, switching every 2 secs? (assuming 4Mhz resonator)

Then we need to go back to basics - just getting the test mode (all segments and DPs) working will be good, as it shows basic comms is working. So reduce the code to just this:

'7 segment multiplexing
symbol load_7219 = 6
symbol din_7219 = 7
symbol clk_7219 = 5

'max7219 registers
symbol decode_mode = $09
symbol intensity = $0A
symbol scan_limit = $0B
symbol shutdown = $0C
symbol digit_test = $0F

start:

'initialize 7219
gosub initialize_7219

'turn on test mode
b0 = digit_test
b1 = $01
gosub send_data_7219

Main:
goto main
end

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

return

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
return


Report back....
 

Tim Vukman

New Member
Hi Martin!

Thanks for the code. I will try that in a minute. When I started testing voltages, the segments came on. They are not bright, but they are visible.

Pins 4 and 9 on 7219 are confirmed as ground.

With Output Pin7 high, I have 4.5 volts on 7219 pin1

With Output Pin6 high, I have 4.47 volts on 7219 pin12

With Output Pin5 high, I have 4.47 volts on 7219 pin13.

Dig0, 1, 2 and 3 are sitting at 4.78 volts

Pins 4 and 9 are confirmed as ground.

The 7 segment digits are part number KLD-3401CR and I was using them prior to the 7219 interfaced through 4 74HC595 Latches.

I tied the interface pins to ground via 10Ks based on "AppKit: Using the MAX7219 LED Display Driver" from the Parallax Web Site. In the diagram that they posted, they also tie pins 18 + 19 together with a 10K and they run a 10uf Electrolytic along with a .1uf between +5 and Gnd. I also have these in my circuit.

The LEDs that I mentioned are rectangular, measuring 2.5x7mm according to the package. They are BSED-4113-4 and I have one on each output pin with a 330R to GND. (Looks like a small VU meter) I did that so that I could see my output pins working.

I tried the code as is posted when I saw the digits were lit, but it is looking like wiring as it did not respond to the code.

I will try the code as you have posted and will respond with the results.

Your time and effort are appreciated

Tim

 

Tim Vukman

New Member
Hi Martin:

I think I have a wiring problem. My 7 segment displays seem to be on all the time. That's new. I'm not sure what happened yet, but I will have to fix that before I can tell if it is going into test or not.

I can confirm that each of my pins on the 7219 are going high when they are supposed to in the small block of code you sent. They do cycle on and off as expected.

I can't tell if the other code did anything on the chip until I find out why all the segments are on.

Thanks - More later

Tim
 

Tim Vukman

New Member
Hi Martin:

I think I have a wiring problem. My 7 segment displays seem to be on all the time. That's new. I'm not sure what happened yet, but I will have to fix that before I can tell if it is going into test or not.

I can confirm that each of my pins on the 7219 are going high when they are supposed to in the small block of code you sent. They do cycle on and off as expected.

I can't tell if the other code did anything on the chip until I find out why all the segments are on.

Thanks - More later

Tim
 

Tim Vukman

New Member
Hi Martin:

GREAT NEWS THANKS

Sorry about the double post. I have removed the tie down 10k from Din, Clk and Load.

I also fixed my glitch that was effecting the 7 segments.

That did not make a difference, so anticipating that your next request would have been to remove the LED and 330R from Output Pin7, I did that.

I am now seeing the test mode when I run the code that you sent.

I went back and loaded the code that I had trimmed from your rpm/advance meter and the first digit does not display. I played around with the digit numbers in the code to move the numbers onto different digits, but my first digit still does not display anything. Never mind. I checked the 7219 and I used digits 1 to 4, not 0 to 3. I'll fix that.

I figured that one out since all the digits lit in test mode :)

The ultimate goal in this is to read two hex values from a ds1307 rtc (1 being hours and the other beings minutes and then split them up to display each digit on it's own 7 segment

If you have some pointers for me for my next steps I wouls appreciate that.

From my perspective you have helped immensly and I really do appreciate it.

Best regards

Tim V

 

MartinM57

Moderator
Excellent news!

I was thinking about the 10K tie-downs and concluded they are possibly there to make sure that there is no random data during startup and/or when the driver pins (in our case the PICAXE) are high impedance - and then I read the App Note. Confirmed!

That's a good App Note - now saved on my PC. Thanks!

I did note in my app that I had got random segments displayed in the short period between the display being blank immediately at startup and before the test mode was displayed. This is probably why! I've since migrated my app (and no resistors) to an AVR and it doesn't happen - maybe the AVR starts up much more quickly/reliably.

I've got exactly the code you need to set/get the DS1307 and show the time on the 7 segment LEDs - is this a School project?...honest answer required please!
 

Tim Vukman

New Member
Hi Martin.

I am in fact 48, so no, this is not a school project.

This is a personal project for my wife. She hates her alarm clock and the whole process of the switches and buttons to set it.

I decided to build her one that uses a 16 key keypad with the plan that she would enter the digits from a normal keypad layout and then use a button on the last column on the right for Set_Time, Alarm_Time, Alarm_On_Off, and Snooze.

I got as far as getting the values out of the ds1307 and out to the 4 segments using the 74LSHC595s. I read the posts about the Max 7219 and decided that I wanted the single chip solution, in part for board space and in part because I was interested in only updating a display if the information changed.

After I had the display going, I went after the keypad, but I was polling it using inputs and outputs on the 28x and ran into violating the nested gosub limits.

The keypad is now wired as columns into the 4 analog ports and there are 4 transistors doing a binary coding to supply the row information.

I am having issues with the keypad in that when I load the inputs into a variable (each row being a different variable) to test it, on the first pass of the test, I seem to pick up values from other input pins.

I set that aside in frustration in order to do the Max7219 display drive swap.

So, you asked for an honest response. Sorry for the length.

That's the project. It's my first using a picaxe and maybe I got in over my head. However, I will finish it somehow and continue on to other projects as I am really enjoying this.

I built an alarm clock 20 some years ago (with the standard switches and buttons) by using various up / counters and associated display drivers. It was a fairly high chip count and pretty complex as I recall. The piaxe / software solution really caught my eye.

Later

Tim
 

MartinM57

Moderator
OK - you didn't really have to tell me how old you are! You're a youngster BTW! I just don't like my stuff appearing in school projects where the author might not understand why it does what it does etc.

Assuming you've got the DS1307 hardware connectivity OK, and declared the appropriate SYMBOLS, here's some code:

'#########################################################
'Initialise
'#########################################################
'Initialise the DS1307 to 12:00:00
writei2c 0, ($00, $00, $12, $01, $01, $01, $01, $10)
pause 40

'#########################################################
'Read 1307 and call the display routine
'#########################################################
read_and_display:

readi2c 0, (b2, b1, b0)

b3 = b2 & %00001111
poke DisplaySecondUnit, b3
b3 = b2 / 16
poke DisplaySecondTen, b3

b3 = b1 & %00001111
poke DisplayMinuteUnit, b3
b3 = b1 / 16
poke DisplayMinuteTen, b3

b3 = b0 & %00001111
poke DisplayHourUnit, b3
b3 = b0 / 16
poke DisplayHourTen, b3

end_read_and_display:
gosub show_display
return

...using the same "show_display" routine in your originally posted code


Edited by - MartinM57 on 22/06/2006 15:36:59
 

Tim Vukman

New Member
Hi Martin.

I wanted you to be sure I wasn't some high school student trying to scam someone into doing their project.

Ok, so we mask off the variable and grab the lower nibble and that gets written to one location, then we do the same thing with the high nibble and write that out to the next location. From there we pass it to the diplay routine which reads it out of where we stored it and sends that out to the 7219.

I can see how this is working.

I am updating this from work, but I will post again after I add the code later tonight. I expect it will be fine.

I am more interested in what I learn by going through this. I had wanted the clock ready for my wife's birthday last May 21, but she and I are getting more enjoyment of the process than the product :).

I haven't found much helpful information in manipulating bit level information. I found eexamples in the picaxe manual, but since they weren't doing what I was trying to do, I'm not sure I got it. Oh well, I'm catching on.

Thanks very much

Tim

 

wilf_nv

Senior Member
<i>I am having issues with the keypad in that when I load the inputs into a variable (each row being a different variable) to test it, on the first pass of the test, I seem to pick up values from other input pins.
</i>

Sounds like contact bounce.

One solution is to read keyboard data several times until two readings before returning from the interrupt routine.
 

Tim Vukman

New Member
Hi Martin!!

I had a completely different message written with some code attached and I was detailing my question which was about why I had one digit that would not light up.

The code that references which digit is to get the data is offset from the physical pin names on the 7219 by one, ie Dig0 likes being referenced as $01 which meant Dig3 really wanted to be called $04 in the code. I saw the pattern when I was writing my question, so I dumped my reference to $00 in favour of $04 and the missing digit is working great now.

It is all working perfectly and I thank you very much for your assistance.

That means it's time to get back to the keypad and see why it is acting up.

Again, my sincere thanks!!

Tim

Wilf:

I did read your note on key bounce and since I am doing nothing to control it you are likely dead on.

I am going to start a new thread and provide some detail on exactly what is happening, because it changed when I changed the 10K resistors to ground. I originally had them (4) going to each analog port with one end. I was a ltille pressed for space so I connected the other end of all four resistors to ground on one wire.

I did split the resistors so that they are all isolated from each other and while I have a similar situation with the results, I do want to provide an accurate description

Regards,

Tim
 

Tim Vukman

New Member
Hi Wilf:

I am going to hold off with a new post until I am sure I have a real problem

The code is:
loop:
readadc 0,b0
readadc 1,b1
readadc 2,b2
readadc 3,b3
goto loop

My problem might be with how I was testing.

This code will give me a value of 222 from whichever row is pressed for the first three columns and a value of 255 for the last column which is good for me because I want to use the last column for special functions.

I haven't developed the code yet to pull the 2 bit binary to isolate row AND column, so I may not have a problem at all.

Thanks for adding your comments on this post.

I am hoping to use an interrupt to jump to a routing to read the keypad entries and then write them to the rtc by pressing the &quot;Set_Time&quot;.

I am really struggling with finding a way to be able to stop and capture 4 key strokes and then return to normal after I &quot;Set Time&quot;

More later once I have done more work and testing.

thanks

Tim
 

hippy

Technical Support
Staff member
If I read you right, you are using four ADC channels to read the keyboard ? If that's so there is a fairly easy way to do that ( both hardware and software ) ...<code><pre><font size=2 face='Courier'>.-------------------------------------- +V
| ___
}---|___|---o-----o-----o-----o
| 330R \ \ \ \ Row 3
| o o o o
| ___ | | | |
}---|___|---o--|--o--|--o--|--o |
| 1K0 \ | \ | \ | \ | Row 2
| o o o o
| ___ | | | |
}---|___|---o--|--o--|--o--|--o |
| 2K2 \ | \ | \ | \ | Row 1
| o o o o
| ___ | | | |
`---|___|---o--|--o--|--o--|--o |
4K7 \ | \ | \ | \ | Row 0
o o o o
| | | |
}-----|-----|-----|----&gt; ADC0
| }-----|-----|----&gt; ADC1
| | }-----|----&gt; ADC2
| | | }----&gt; ADC3
.|. .|. .|. .|.
4 x 2K2 | | | | | | | |
|_| |_| |_| |_|
| | | |
`-----^-----^-----^----- 0V </font></pre></code> <code><pre><font size=2 face='Courier'> SYMBOL V_ROW3 = 195
SYMBOL V_ROW2 = 150
SYMBOL V_ROW1 = 105
SYMBOL V_ROW0 = 40 </font></pre></code> <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:
RETURN </font></pre></code> This will return a value in b0 of 0 for no key press and 1 to 16 when a key is pressed. Using &quot;LOOKUP b0,(...),b0&quot; after 'GotKeyPress' will allow you to change those values to whatever you'd like each key to give.

The problem you have with working out how to handle four key presses is because of the way you've been looking at the problem. Rather than try and keep the clock running while handling setting and the display in synch, jump out of the clock displaying routine entirely, allow the time / alarm to be set and press &quot;Set Time&quot;, which updates the clock to what was set and continue then showing the clock. If you have an &quot;Abort&quot; key, then simply don't update the clock, which will have been running in the background.

Once you've detected a button push to start setting the clock, you can then have a simple wait for keypress, update that digit ( on the display only ), then wait for the next, repeat until all set and only then update the RTC itself.

I know that's a bit terse, so shout if you need me to explain in more detail.

Edited by - hippy on 23/06/2006 03:25:58
 

MartinM57

Moderator
Good news! Spread the word about the MAX7219!

On the keypad front, I'm no expert (in fact I'm a complete amateur and have never tried to interface to a keypad)...
...but I think you will have to design and program a Finite State Machine to end up with a good user interface and a maintainable piece of code.

They're not too hard (use Google to get the basics) but you will need one to, at least:
- stop the user entering a time like 12:60 (trick is that the third digit must be less than 6), 31:23 etc etc
- stop the user entering 1, 'set time' (trick is that set time is only allowed after a valid 4 digit time has already beeen entered)

More fun awaits you, but it's all doable and you'll learn a heck of a lot!
 

Tim Vukman

New Member
Hi Hippy

No worries on the &quot;terse&quot;. I view it as concise. Thanks for the R values for the keypad. I tried 8 unique values and didn't get enough voltage difference between a couple row to separate them.

I am fine with the keypad code that you have posted. I understand how to give each button a unique value and then convert it to useful information via the lookup.

After that, I am in trouble.
&quot;
Once you've detected a button push to start setting the clock, you can then have a simple wait for keypress, &quot;

I tried pause with various values to try to hold up a for next loop for 4 keypad values,
but, I have to believe there is a way that will actually stop the process and not move on until each keypress has happened.

update that digit ( on the display only ), then wait for the next, repeat until all set and only then update the RTC itself.

This is exactly what I am trying to do. I have been able to write the values I want to the RTC and then read them for the display and update the display and so forth. I'm just apparently over my head (or my code level) on the keypad.

Thanks

Tim

Hi Martin
Yes indeed, spread the word on the MAX7219. It really is a good solution for multiple digits!!! and as you said in an earlier post, it is fairly straight forward once you read the datasheet 500 times and understand how to pass it the data.

I will research the steady state machine. I am curious. As you know, I didn't mention testing the values anywhere yet and yes I know it can't be left to the user to enter data without errors. I want to get it working so that I can see where to test for what!

Thanks

Tim

 

wilf_nv

Senior Member
Nice circuit Hippy!
If you have 4 spare A/D inputs available, this analog output keyboard encoder with relatively large voltage steps should be quite reliable.

Here is a question:

Can A/D inputs with analog signals be used with interrupts?

The picaxe interrupt pattern mask can AND inputs states but is there a method that can be used to OR inputs eg any change triggers an interrupt?
 

whizzer

Senior Member
Impressive circuit &amp; code on the previous page Hippy!

I hope you won&#8217;t mind me making a mess of your tidy layout to include two extra components to allow an interrupt signal to be developed.

This is just an idea, as the modification is completely untested (since I don&#8217;t have a Picaxe in front of me right at this moment to check it out). So it&#8217;s intended as a kind of food for thought suggestion..
<code><pre><font size=2 face='Courier'> .-------- +V
|
|e
| /
.--------------------------------------b---|/ PNP
| ___ |\ transistor
}---|___|---o-----o-----o-----o \____
| 330R \ \ \ \ Row 3 c |
| o o o o |
| ___ | | | | |
}---|___|---o--|--o--|--o--|--o | |
| 1K0 \ | \ | \ | \ | Row 2 |
| o o o o |
| ___ | | | | }----&gt; Interrupt
}---|___|---o--|--o--|--o--|--o | |
| 2K2 \ | \ | \ | \ | Row 1 |
| o o o o .|.
| ___ | | | | | | 10K
`---|___|---o--|--o--|--o--|--o | |_|
4K7 \ | \ | \ | \ | Row 0 |
o o o o |
| | | | |
}-----|-----|-----|----&gt; ADC0 |
| }-----|-----|----&gt; ADC1 |
| | }-----|----&gt; ADC2 |
| | | }----&gt; ADC3 |
.|. .|. .|. .|. |
4 x 2K2 | | | | | | | | |
|_| |_| |_| |_| |
| | | | |
`-----^-----^-----^----------------^----- 0V


</font></pre></code>

 

hippy

Technical Support
Staff member
TimV : I'll get back with some thoughts / code on how I'd probably do the keypad handling.

Wilf_nv : With the right R's it might be possible to give voltages that will diode mix the four ADC's to give a dignal which could go to a Digital Input to cause an interrupt. May also be possible to interrupt on a single ADC used as a Digital Input.

Whizzer : Out of my league I'm afraid, but no problems with anyone hacking away at what I knock out, changing or improving etc.
 

hippy

Technical Support
Staff member
[ Deleted - Multiple Posting ]

Edited by - hippy on 23/06/2006 17:54:51
 

Tim Vukman

New Member
Hippy

I always appreciate the code samples. Things become more clear with an example to follow.

Whizzer / Wilf:
I certainly have the analog inputs to use and since I am no longer polling the keypad with outputs and inputs, I have the digit inputs available for an interrupt.

I will wire this up and advise on where I end up. It looks very promising and far simpler than my original thoughts.

Martin:
Sorry about the &quot;steady&quot;. A slip on my part. I have read a few articles / essays on finite state machines. Armed with that and a few statements in my various posts about &quot;approach&quot; and &quot;how I am looking at&quot; what I'm trying to do I have demonstated a very linear approach in laying out my code.

I will see if I can use what I am reading to diagram my clock project. It will no doubt become more clear when I can identify the states and transitions. The project should be completely predictable.

I rather suspect you did that on purpose to send me toward modules that have a clearly defined process rather than trying to deal with what might happen at any given point from somewhere that I don't have defined. :)

Thanks!
It is new information that I have not seen before and quite interesting.

im

 

Tim Vukman

New Member
Hi All

Hippy: I have my keypad wired according to the schematic you posted (I love your ascii schematics btw) and the voltage measurements on the rows fell right into the ranges you wrote in your code.

I have finished my lookup and have the values assigned to the keys for the numbers and my special functions.

I changed the return to a goto loop as the only code running is the code that you posted and I got an error of &quot;return without gosub&quot;.

I presume that I should use the Interrupt to gosub to this module from the main code when I add this into the code that contains the display module.

Please confirm.

Whizzer: I will add your addition of the interrupt trigger to the keypad wiring tomorrow and post the results.

Martin: I think the best place to test for valid input will be in the routine that is managing the 4 keypresses. I should be able to abort the keypresses if the data entered is invalid and beep the alarm a couple of times as a signal to the user that they will have to re enter the data.

I really appreciate all the help!!! This project has touched on so many interface and code areas that what I have learned will carry me a long way.

Tim
 

AllanBertelsen

Senior Member
Hi

I made this spreetsheet to calculate a resistornet for a keypad read by only one ADC-pin. Just enter the disired number of buttons and the ADC values are calculated.
<A href='http://www.ab-it.dk/Filer/Resistormatrix.xls' Target=_Blank>External Web Link</a>
There is an example in this PDF <A href='http://www.ab-it.dk/Filer/The%20stoker%20project.pdf' Target=_Blank>External Web Link</a>
 

hippy

Technical Support
Staff member
Here's a skeleton of how I'd probably do the clock setting. It might not be what you want exactly ( press Set Time, enter up to four digits, then press Set Time to update RTC ), but should give an idea of my thinking.

Because the RTC updates once a second at best, there's no need to do any interrupts, just poll the keypad and then jump out of the normal RTC displaying routine. In the worst case of slow response it means holding the Set Time key down until it is recognised.

I assigned the 'keyPress' values as $80 when none held, $81 for 'Set Time' and 0-9 for the ten digit keys. After every key press, the code waits until there is no key press before continuing.

If you want to use Allan's single ADC mechanism, you just need to alter the 'GetKeyPress' subroutine and return the same 'keyPress' values<code><pre><font size=2 face='Courier'>MainLoop:
GOSUB ReadRtcData ; Set hourT, hourU, minsT, minsU vars
GOSUB DisplayTime ; Display hourT, hourU, minsT, minsU vars
GOSUB GetKeyPress ; Check for a keypress
IF keyPress &lt;&gt; $81 THEN MainLoop </font></pre></code> <code><pre><font size=2 face='Courier'>SetHourT:
GOSUB GetNewKeyPress
IF keyPress = $81 THEN UpdateRtc
IF keyPress &gt; 2 THEN SetHourT
hourT = keyPress ; 0..2
GOSUB DisplayTime </font></pre></code> <code><pre><font size=2 face='Courier'>SetHourU:
GOSUB GetNewKeyPress
IF keyPress = $81 THEN UpdateRtc
IF keyPress &gt; 9 THEN SetHourU
IF hourT = 2 AND keyPress &gt; 3 THEN SetHourU
hourU = keyPress ; 0..9
GOSUB DisplayTime </font></pre></code> <code><pre><font size=2 face='Courier'>SetMinsT:
GOSUB GetNewKeyPress
IF keyPress = $81 THEN UpdateRtc
IF keyPress &gt; 5 THEN SetMinsT
minsT = keyPress ; 0..5
GOSUB DisplayTime </font></pre></code> <code><pre><font size=2 face='Courier'>SetMinsU:
GOSUB GetNewKeyPress
IF keyPress = $81 THEN UpdateRtc
IF keyPress &gt; 9 THEN SetMinsU
minsU = keyPress ; 0..9
GOSUB DisplayTime </font></pre></code> <code><pre><font size=2 face='Courier'> GOTO SetHourT ; Keep updating until Set Time key </font></pre></code> <code><pre><font size=2 face='Courier'>UpdateRtc:
GOSUB WriteRtcData ; Write hourT, hourU, minsT, minsU vars
GOSUB WaitForNoKeyPress
GOTO MainLoop </font></pre></code> <code><pre><font size=2 face='Courier'>GetNewKeyPress:
IF keyPress = $80 THEN GetKeyPress
GOSUB WaitForNoKeyPressed </font></pre></code> <code><pre><font size=2 face='Courier'>GetKeyPress: ; As previous
:
RETURN </font></pre></code> <code><pre><font size=2 face='Courier'>WaitForNoKeyPressed:
GOSUB GetKeyPress
IF keyPress &lt;&gt; $80 THEN WaitForNoKeyPressed
RETURN </font></pre></code>

Edited by - hippy on 24/06/2006 14:34:25
 

Tim Vukman

New Member
Good Afternoon

Allen: Thankyou for the resistor network calculator. I have saved that as I think it will be very handy. For now, I am going to stay with the 4 Analog lines as I understand exactly what is happening and how the values get returned.

Hippy:

You write very elegant code that is easy to follow and logical in its approach. I hope in time to be able to think various scenarios through as completely.

I was truly perplexed on how to manage the keypad and you have made that quite obvious in an effective manner.

Would you know of some book titles that I might be able to find to help me with controlling program flow?

I seem to be writing for what I expect to see at each line rather than writing for the bigger picture. You do far less testing in your routines; sometimes by elimination and sometimes by creating something to test (like what you have done with assigning $80 and $81) rather than the detail of each key.

I really do appreciate what I have learned through examining the code that you have been posting.

Sincere thanks

Tim
 

hippy

Technical Support
Staff member
I'm afraid I don't know of any books which I can recommend for programming but hopefully one of the educators who posts on the forum may. I'm one of those people who learns best by seeing an example, and then going to try and it building on knowledge gained.

I've got a lot of experience behind me, and as with most things, the more one does the better one becomes at it, although it helps not to be going in the wrong direction entirely. I started the same way as everyone else does, writing spaghetti and very linear code, but there are two things which I think are important and helpful to grasp ...

<b>Modularisation </b> and <b>Abstraction </b>

Splitting code into definable chunks, and not necessarily worrying about what those chunks do in detail, but thinking about how they interact, what they need to work, and what they return.

As with 'GOSUB ReadRtcData', I don't have to worry about how that works and can just assume it will do what I want it to. It may be incredibly difficult, or not, but why should I care ?

Likewise with &quot;GOSUB GetKeyPress&quot;, I don't have to worry about what hardware you finally choose ( it could even be a routine which reads characters from a PC ).

If there's a function which is going to get called a lot, &quot;GetKey&quot;, then making that a 'module' often really simplifies things. Just call it when you need to, once you're clear on exactly what it will do.

This ties in with ...

<b>Top-Down </b> and <b>Bottom-Up Design </b>

Top-Down means designing without worrying about the detail ( as per my example ). The only thing I had to decide was data storage ( keyPress, hourT, hourU etc ), but even there I haven't worried if they are bit, byte or word, nor worried about what data may be used in the routines I call.

Bottom-Up means designing low-level routines which will do a small job, like the 'GetKeyPress' routine earlier, and tying it all togther as a whole.

In reality, it's a mix of both, because it's usually not really possible to design entirely from one direction or the other. For most designs, top down I find is the best way, but with a bit of bottom up letting you know what is and isn't possible.

If we were designing houses, we could either draw the outline and then add more details like rooms and then furniture placement ( top down ), or we can decide what furniture we want, design rooms around them, and then put the rooms together to determine the house we'll need ( bottom up ).

With experience, practice and looking how other people do it ( and being able to tell what looks good and what feels bad ), it all gells and becomes second nature, but that doesn't mean perfection, and we can all still learn a lot from others. Programming is, IMHO, an art and a science.

I think the key to good programming is understanding what you are doing and why, and programming is peppered with 'flashes of blinding light realisations', with people looking at you oddly while you run round going, &quot;Yes!, yes! YES!&quot;, because they don't understand the feeling of suddenly understanding another part of the nature of that universe - Okay, it's art, science and 'religious' experience :)

Edited by - hippy on 24/06/2006 19:02:32
 

wilf_nv

Senior Member
Hi Tim,

and for now something completely different:

May I belately suggest that using an IR remote control unit may be an atractive alternative to the hardwired hex keypad for setting and controlling your clock.

wilf

 

Tim Vukman

New Member
Hi

Hippy: Your post has been printed and I will keep it in my project binder to read over and over again. It's very good advice and something I will need to remind myself of.

I am admittedly fond of the blinding light realizations and looking back over things that didn't seem to make sense at all and now seem perfectly clear. Only learning changes the former to the latter.

I have always been on a journey of learning and research and that it how I view this current project.

I have assembled all the various modules into a final package. The display module is working but I am not sure that $81 and $80 are working quite according to plan for the keypad.

I have my lookup in the &quot;gotkeypress&quot; module and I assigned $81 to pin 15 (starting from 0) which is in the top right, but debug shows the value as decimal 15 so I suspect I am not carrying a variable assignment through.

I use LEDs on my outputs as flags so that I can see where the code actually goes. For example High 4 as the first line of a module will show me that the code took the inputs required to end up in that module and so on.

I expect that I will find my current problem and correct it this weekend. I really do think I will add some beeps as an indication to the user of where they are in the input cycle, but not until I find my little bug.

Thanks for sharing uour knowledge and your thoughts.

Wilf

Yes, that is something completely different indeed. It could lead to setting a new record here for the longest running post :)

I might just keep the IR remote idea for another project :) I will look into it for a possible next clock, but I'm not convinced I need another remote to lose right now.

I've been toying with the idea of a time machine.......Could be a bit tricky in places I suspect, but once I have the clock done I'll have a little more free time......

Thanks

Tim
 

hippy

Technical Support
Staff member
A good way to debug things like keypads where one's never sure if the keys match the software ( hence the LOOKUP suggestion anyway ) is ...

- MainLoop:
- GOSUB GetKeyPress
- GOTO MainLoop
-
- GetKeyPress:
- :
- GotKeyPress:
- SERTXD( &quot;Raw &quot;,#b0&quot;)
- LOOKUP b0,(...),b0
- SERTXD( &quot; gives &quot;,#b0,CR,LF)
- RETURN

Use the Terminal window to see what comes out with each key press, and a bit of paperwork anaylysis and it should all fall into place.
 

Tim Vukman

New Member
Hi Hippy:

Thanks for the troubleshooting tip. Once I know which module it is in, I could put the ' to comment out the routines I don't need to see at that time. I actually didn't think of that.

In this case the program never made it to the GotKeyPressed. In the previous version, GotKeyPressed was right after FindKey, so once the FindKey completed, it would drop right into where I wanted it.

When I put all the modules together today I had placed the WaitForNoKeyPressed in front of the GotKeyPressed with a return between the two modules.

As a result, as soon as FindKey finished, the return took it back to the main program loop without the value from the lookup.

I'm not sure of your thoughts on the topic, but I am a HUGE fan of Mike Collier's Basic Chip Simulator. It has done an excellent job for me of showing the values of all the variables and catching some of my hardware and software problems so far.

I let it run in single step mode and watch one line at a time to see where the program goes and what the values are at each point.

That is actually how I found the return that should not have been there. I watched the program go back to the main loop instead of the GotKeyPressed routine.

Mike has given me a version that fully interfaces with my 28x hardware and until I started using PinX = Bitxx, I could watch my circuit working at the same time as I was reading the code that was running and noting the values of the variables.

For my level of experience it has been a great help as physically seeing that the project is not working hasn't always led me to what I had done wrong.

Based on what I have learned from our discussions and following through the code, I did actually have the thought of a return in the wrong place and since the value wasn't being returned from the lookup, that was the place to look.

In time, my experience will no doubt lead me to using the simulator less often as I will have a better idea of where the problems are.

For anyone just starting out (and this clock is my first experience with a microcontroller) I would highly recommend the simulator.

Thanks for the tip

Tim
 

Tim Vukman

New Member
Hi Hippy:

I have more work to do in the morning, The SetHourT,U and SetMinsT,U never get called.

They are right after the
IF KeyPress &lt;&gt; $81 THEN MAIN_LOOP
statement that is in the main loop in the post on this forum.

I will try some fresh eyes in the morning to see where they should go in the full program. I guess they would be fine in the main program with a GOTO MAIN_LOOP after the last Set statement, but I want to be sure.

Later

Tim
 

wilf_nv

Senior Member
<i>I might just keep the IR remote idea for another project :) I will look into it for a possible next clock, but I'm not convinced I need another remote to lose right now. </i>

Well then to keep track of the darn thing just hardwire the IR remote straight to the INFRAIN pin and be done with it. Saves an IR receiver to boot.

wilf



Edited by - wilf_nv on 25/06/2006 05:14:25
 

hippy

Technical Support
Staff member
You seem to be making excellent progress. I will admit I haven't used the BasicSim that much, but you are really showing the usefulness of it, and I have had similar success with MPLAB Simulator.

It's another trick one learns; only ever having one RETURN from a routine so a debugging statement can be put there.

As to execution not getting to where it should be, the trick is to trace back why it isn't where it should be, in this case ...

- IF keyPress &lt;&gt; $81 THEN MainLoop

The code after would be reached if keyPress were $81, so logically the keyPress isn't being set to $81 in the 'GetKeyPress' routine.

First thing, check what value keyPress has when the IF is executed. Then check that the GetKeyPress routine is written to put its return value in keyPress. Then it's off to see why keyPress is never having that value put in there by concentrating on single-stepping through the getKeyPress routine.

One problem with simulators is that it's sometimes hard to tweak input stimuli to get code which reads hardware to give the right answers. One solution is to comment out the routine, and temprarily add one which is more simulator friendly ...

- GetKeyPress:
- keyPress = $FF
- WaitForKeyPress:
- IF keyPress = $FF THEN WaitForKeyPress
- RETURN

When you run the code it will stay in this routine until you stop it, update the keyPress variable manually and then continue.

This is handy because it means you can test the functionality of the rest of the program without worrying why your hardware interface routines aren't working, and come back to that later.

That was another trick earlier; writing code which calls a routine to allow checking if working or not without having to worry about the rest of the code which may have its own bugs in it. If you can prove all the little bits work by themselves, if you've not gone wrong anywhere else, they should all work when put together.

Good luck, it looks like you're well on the right path.
 

MurrayJ

Senior Member
If you want a simple to use, although reasonably expensive keypad solution try R.T.Nollet. It only requires 5V, 0V, and one serial connection to work and works great with picaxes, also no soldering or assembly required. The one I have works great. Check it out at -

http://www.nollet.com.au/Serialkeypad.htm
 

Tim Vukman

New Member
Good Morning

Murray: Thanks for the info on the keypad. You're right, it is ideal and it is expensive. A schematic for it would be nice to see although I may have one.

My keypads are $10.00 CDN and from what I have read, I think adding a 74c922 keyboard encoder would produce an equivalent product.

http://www.fairchildsemi.com/ds/MM%2FMM74C922.pdf

I tried at my local electronics store to get one but I would have to wait for two weeks while they order one in. I still might do it for future projects though.

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 have read through the information in the picaxe manuals and it looks like it would be a good alternate for the the keypad.

I do appreciate the suggestion.

Thanks

Tim
 

whizzer

Senior Member
I can really understand why TimV is building this project. I quite literally inherited (in perfect working order) a GE clock-radio which is over 20 years old. And here&#8217;s the interesting bit &#8211;although very old, this set also has a calculator-like keypad which allows the alarm time to be directly keyed in; so that punching 6 3 0 &lt;enter&gt; will set the alarm to 06:30 AM. It&#8217;s amazing just how handy this is, especially when there&#8217;s a requirement to arise at different times.

The old GE has another feature you may care to implement &#8211;the ability to store two alarm times with a front selector switch to choose one or the other. Then one alarm time can be used for weekdays &amp; the other for weekends or, one for yourself &amp; the other for your partner who is sleeping a little later.

This is all hardly ground-breaking news of course, but it&#8217;s a pity that the el-cheapo products that are mainly available today tend not to have these useful features.

PS: Once the project is up &amp; running, maybe a bit more Picaxe code could be added to automatically handle daylight saving changes thru-out the year also.
 

Tim Vukman

New Member
Good Afternoon:

Hippy: I am trying to track down a flow issue.

I'm getting bounced around the keypad routines once I pass the $81 to the mainloop.

MAIN_LOOP:
'GOSUB READ_RTC
'GOSUB DISPLAY_TIME
GOSUB GET_KEY_PRESS ; Check for a keypress
IF keyPress &lt;&gt; $81 THEN MAIN_LOOP
gosub SET_HOUR_T
end

Once I hit the Set_Hour_T
&quot;GOSUB GET_NEW_KEY_PRESS&quot; in Set_Hour_T&quot;

sends me to
&quot;GET_NEW_KEY_PRESS:
IF keyPress = $80 THEN GET_KEY_PRESS
GOSUB WAIT_FOR_NO_KEY_PRESSED&quot;

which sends me to
&quot;WAIT_FOR_NO_KEY_PRESSED:
GOSUB GET_KEY_PRESS
IF keyPress &lt;&gt; $80 THEN WAIT_FOR_NO_KEY_PRESSED&quot;

which of course sends me back to
&quot;GET_KEY_PRESS&quot;

and so on.....

This is a status, not a plea for help. I should be able to figure this out.

I will start from the furthest module out and work my way back :)

Whizzer:
Thanks for your post. With the age of your clock, I wonder how they did it from a hardware perspective. My wife and I went to every store we could think of that might sell clocks and every one of them was the same interface. I suspect they all use roughly the same clock module inside with different buttons and cases.

When I read your PS about daylight savings changes, I thought I had read that the DS1307 handled that. I have just re-read the datasheet and it is not mentioned anywhere.

Thanks for a good idea. If I set all the values when I initialize the rtc and then update them periodically, there is no reason why the feature could not be implemented.

I am going to add things slowly from this point on. I think things are getting close to actually working as intended and I would like to get the whole keypad / set stuff settled before I tackle the alarms and other features.

I have noted the suggestion and it will be added at some point in the future.

Thanks

Tim
 
Top