PDA

View Full Version : Digital Hourmeter



jmgelba
- 11th April 2005, 19:51
Hi Gang,

I have a little project that I'm fooling around with.
I need to create a 99,000.0 hour hourmeter using six, 7 seg led displays. It needs to retain the counted time in eeprom when the power is off to restart from where it stopped.
My thoughts are to use the 60hz from the mains, drop it and put it into the base of a transistor and pull high an i/p pin 60 times a second. I can then count that and when I get a total of 21600 counts, I can increment a counter by 1 and display it on the 7 seg's. (21600 = 60hz x 60 sec x 6min = 1/10th hour)

Heres how I think it should flow....

Power up
read eeprom
if eeprom = 0 set display to 0
if eeprom any other value, start display at that value

Start counter
when counter = 21600 increment display by 1
write display to eeprom.

I'll be using a 16f88, multiplexing the segments and using just the 1 i/p to measure the pulses.

Problem is, pulsein measures the pulsewidth and count measures a number of counts in a specified time, ie 1 second. I need to continually measure the pulses coming in and send an advance when we reach 21600 pulses. So how do I do that??

Luciano
- 11th April 2005, 20:26
See PIC16F87/88 Data Sheet:
TIMER1 MODULE /Timer1 Counter Operation

Circuit to extract the 60Hz clock from the power line:
http://www.maxim-ic.com/appnotes.cfm/appnote_number/1994

Luciano

jmgelba
- 12th April 2005, 19:41
If I'm reading correctly what I'm seeing, tmr1 counts backwards?

tmr1 starts at $FFFF (65535) and overflows at $0000 (0) So if I need to set a flag every 21600 pulses, I need to preload the counter, or start the counter, at $AB9F (43935) and count down to 0 from there?

Melanie
- 12th April 2005, 19:51
No, the Timer Count UP from $0000 to $FFFF and then sets a flag (or interrupt) as it rolls from $FFFF (maximum count) and starts again from $0000.

Have a look at this thread for presetting a 10mS example.

http://www.picbasic.co.uk/forum/showthread.php?t=632

jmgelba
- 12th April 2005, 21:04
SetTimer:
T1CON.0=0 ' Stop the Clock
TMR1RunOn.Highbyte=TMR1H ' Load the Run-On (Over-Run) value (if any)
TMR1RunOn.Lowbyte=TMR1L
TMR1RunOn=TMR1Preset+TMR1RunOn ' Calculate the New (adjusted) value for TMR1
If TMR1CalAR=0 then ' Calibration ADVANCE (add) or RETARD (subtract)
TMR1RunOn=TMR1RunOn+TMR1Cal
else
TMR1RunOn=TMR1RunOn-TMR1Cal
endif
TMR1H=TMR1RunOn.Highbyte ' Save new values to TMR1
TMR1L=TMR1RunOn.Lowbyte
T1CON.0=1 ' Restart the Clock
PIR1.0=0 ' Reset TMR1's Interupt Flag
Return


Ok, code killing aside.... forgive my noobness.

If I strip out the calibration aspect as I dont think i need it. (1sec/60hz = 1 pulse every 16.667ms) should be enough time.....


SetTimer:
T1CON.0=0 ' Stop the Clock
TMR1.Highbyte=TMR1H ' Load the high timer start point
TMR1.Lowbyte=TMR1L ' Load the low timer start point
TMR1.Highbyte= $AB ' Save new values to TMR1 (65535 - 21600 = 43935 = AB9F)
TMR1.Lowbyte= $9F
T1CON.0=1 ' Restart the Clock
PIR1.0=0 ' Reset TMR1's Interupt Flag
Return


This should reset the timer everytime with 43935 as a starting point, leaving 21600 pulses until a rollover and the interupt flag is set, upon which the program needs to increment a counter by 1, store the result in eeprom and reset the counter to start again. Oh, and increment the display aswell ;-)

Melanie
- 12th April 2005, 21:56
Hmmm... don't quite understand your figures...

1/60=16667uS = $411B based on 1uS tick time (4MHz clock)

$0000-$411B=$BEE5

Use Microsofts Calculator in Scientific mode... you cant do 0-411B in hex directly, so instead do FFFF-411B and just add 1 to your answer.

Setting the clock for a 16667uS count would be...

T1CON.0=0 ' Stop the Clock
TMR1H=$BE ' Set Timer Highbyte
TMR1L=$E5 ' Set Timer Lowbyte
T1CON.1=1 ' Restart the Clock
PIR1.0=0 ' Reset TMR1's Interrupt Flag

If you're returning from an Interrupt then use RESUME otherwise if it's from a subroutine use RETURN.

You may have to adjust the $E5 value slightly to trim your time accurately to account for instruction cycle time in setting the clock etc.

jmgelba
- 12th April 2005, 23:56
Melanie,
I think we have our wires crossed a little.

Are you setting up the timer to count internal pulses? I am trying to count a 60hz 50% duty cycle pulse from the mains supply. When I've counted 21600 of them, I want the counter to reset, send a increment to a counter, and start again.

Therefore, I dont understand why we need to measure 16.67ms. This is the period between highs at the i/p. Time really has nothing to do with it, we just need to get to 21600 and say, ok, im done, reset me please :-)
So thats why I have the numbers in there that I do. Start the counter at 43935, when we've counted 21600 pulses we should be at 65535. The next pulse will set the interupt, and we start again. Well, start the timer at 43936 I guess.

65535 = $FFFF
43935 = $AB9F
21600 = $5460

65535 - 21600 = 43935

According to Microsoft's calculator.
Thanks for the tidbit on the resume command.

Disclaimer:- I know you're not stupid, so the natural conclusion is that I must be LOL. Thanks for your help Mel.

Melanie
- 13th April 2005, 00:57
No, it's my fault... not reading the thread properly from the beginning...

What I told you was valid for the timer keeping it's own time...

But, nevertheless if you want the Timer to count 21600 (or however many) pulses from an external source then yes, it's 65536-21600=43936, or $ABA0 that needs to be preset into TMR1H & TMR1L. Note I'm subtracting from 65536 ($0000 or zero) and not from 65535 ($FFFF), because the interrupt is on the roll from 65535 ($FFFF) to 65536 ($0000).

Look at the T1CON Register for your PIC... you will also have to set TMR1CS for EXTERNAL input and provide your 60Hz pulses on the appropriate T1CKI pin for your PIC.

jmgelba
- 13th April 2005, 20:24
So I am on track with this?
Timer counts up, sets the interupt. Interupt causes CounterA to advance by 1, which increments the digits for the display. Obviously, the segment drive logic is not there yet.



Tenths var word
Units var word
Tens var word
Hundreds var word
Thousands var word
Tenthousands vAR WORD

Gosub SetTimer ' Set the Timer
On Interrupt goto CounterA
PIE1.0=1 ' Enable TMR1 Interrupts

SetTimer:
T1CON.0=0 ' Stop the Clock
TMR1H=$AB ' Set Timer Highbyte
TMR1L=$A0 ' Set Timer Lowbyte
T1CON.1=1 ' Restart the Clock
PIR1.0=0 ' Reset TMR1's Interrupt Flag
Return

CounterA:
' Timer Interrupt Handler
' =======================

Gosub SetTimer ' Set the Timer for next count
Tenths=Tenths+1 ' Increment 1/10TH minute Counter

If Tenths>9 then
Tenths=0
Units=Units+1 ' Increment the Units

If Units>9 then
Units=0
Tens=Tens+1 ' Increment the Tens

If Tens>9 then
Tens=0
Hundreds=Hundreds+1 ' Increment the Hundreds

If Hundreds>9 then
Hundreds=0
Thousands=Thousands+1 'Increment the Thousands

If Thousands>9 then
Thousands=0
Tenthousands=Tenthousands+1 'Increment the Tenthousands

endif
endif
endif
endif
endif
endif
endif
Resume
End

Melanie
- 14th April 2005, 10:00
Ummm.... on track?.... well maybe you're on a siding but you've not reached the main line yet... theory might be there, but reality it won't run - way to go yet...

Tenths var word
Units var word
Tens var word
Hundreds var word
Thousands var word
Tenthousands vAR WORD

Where's the PIC initialisation here? No Registers are configured, no I/O, TMR1 is not set up to accept external pulses...

Gosub SetTimer ' Set the Timer
On Interrupt goto CounterA
PIE1.0=1 ' Enable TMR1 Interrupts

At this point your program runs into a subroutine without calling it. You should have a logical program loop.

SetTimer:
T1CON.0=0 ' Stop the Clock
TMR1H=$AB ' Set Timer Highbyte
TMR1L=$A0 ' Set Timer Lowbyte
T1CON.1=1 ' Restart the Clock
PIR1.0=0 ' Reset TMR1's Interrupt Flag
Return

Your program encounters a Return with nowhere to return to... so at this point it dies - quite apart from the fact it's counting INTERNAL clock ticks.

You've not set any ENABLE/DISABLE to identify which sections of your code will be interruptable, and which sections should be protected from interrupt.

That's just a starter without going into any depth.

jmgelba
- 14th April 2005, 14:23
I realize all the initialization settings are not there! I was just asking if what I posted made any sence. I also realize that there is no program loop, becuase I havent created it. I'm just trying to learn this stuff piece by piece. It easier for me to break it down into sections to figure exactly what is going on before I attempt to write a huge program with a 1000 mistakes only to get disheartened and pay someone to do it for me.

Dwayne
- 14th April 2005, 14:47
Hello Jm,

Jm>>I was just asking if what I posted made any sence. I also realize that there is no program loop, becuase I havent created it. I'm just trying to learn this stuff piece by piece. It easier for me to break it down into sections to figure exactly what is going on before I attempt to write a huge program with a 1000 mistakes only to get disheartened and pay someone to do it for me.<<

Naw, I think we can help you figure it out <smile>..

I am curious... what are you going to use your hour meter for??? I am a pilot, and I am building a new airplane right now... I am going to use a PIC chip as a HOBBS meter for my Engine, as well as a RPM and a possibly a Altimeter/Velocity (if I can find a sensor that is cheap enough). Your project looks almost exactly like mine to many a degree, that is why I ask.

Dwayne

jmgelba
- 14th April 2005, 17:24
Hi Dwayne,

The project is for an air compressor system. Your project sounds more interesting though. Godd luck with that, and post up some pictures of your work in progress on the airplane.

James.

Dwayne
- 14th April 2005, 20:40
Hello James,

They would kill me if I posted pics of a bird here..<g>. I would be more than happy to email pics. But when I get my project done on the PIC, I will post the code and schematic for everyone.

Dwayne

I am using a inductor type system to monitor the RPM. I have found that just 1 turn of wire around the spark wire is more than 50 volts!!

So, what I did, was put a 5V zenor to the base of a PNP, and let the PNP be the trigger to my PIC. Using Pulsein, I count the time between off and on, and for 1000 hz, I get about 960 on my Pulsein calculation. From there I calculate the RPM's via the value of the Pulsein measurement. At the higher RPM, lets say 2000 the value changes to 480, and 4000 RPM the value changes to 240. The higher RPM I loose accuracy, but I could care a less on 50 RPM or so. My Max RPM is about 6200 RPM (Can go to 6600, but it would have to be without the prop). At 8000 RPM, the Value is 120... Thus you have 120 values that represent 4000 RPM (at Highest speed) 4000/120 = 33 RPM per increment...

Dwayne

jmgelba
- 16th April 2005, 21:34
OK, here are some more ramblings. I hope I'm further along the siding and the track is in view?? :-) There are some things missing obviously. I still need to figure out how to put the overflow flag somewhere and count how many times it has been set. 1 flag = 1/10th of an hour. Thats basically the counter that I will be displaying on the seven segments.
Anyway, any help is welcomed. I *think* I'm learning something... ;-)



INCLUDE "modedefs.bas"
define OSC 4
TRISA = %00010000
TRISB = %00000000
T0CON = %00101000
ADCON0 = %00011100
ADCON1 = %01111111

CNT var word
Tenths var word
Units var word
Tens var word
Hundreds var word
Thousands var word
Tenthousands vAR WORD

'RB0 = SEG A
'RB1 = SEG B
'RB2 = SEG C
'RB3 = SEG D
'RB4 = SEG E
'RB5 = SEG F
'RB6 = SEG G
'RA0 = DIGIT1 = TENTHS
'RA1 = DIGIT2 = UNITS
'RA3 = DIGIT3 = TENS
'RA5 = DIGIT4 = HUNDREDS
'RA6 = DIGIT5 = THOUSANDS
'RA7 = DIGIT6 = TENTHOUSANDS

Start:
READ 0,CNT ' Read location 0 and put result into CNT
'(should this be a hi and low)
IF CNT = 0 THEN
SetTimer
ENDIF
If CNT => 1 then '?? i want to put this value into the incremental display
'counter and start counting from this point
endif

'Segment Test LIGHTS ALL SEGMENTS FOR 1SEC
PORTA = %1111011
PORTB = %0111111
PAUSE 1000
PORTA = %0000000
PORTB = %0000000


On Interrupt goto CounterA


SetTimer:
T0CON.0=0 ' Stop the Clock
TMR0H=$AB ' Set Timer Highbyte
TMR0L=$A0 ' Set Timer Lowbyte
T0CON.1=1 ' Restart the Clock
resume


CounterA:
DISABLE

' Interuptable code goes here?
' This is the incremental aspect of the program.
' Any value here is displayed on the segments.

Gosub SetTimer ' Set the Timer for next count
Tenths=Tenths+1 ' Increment 1/10TH minute Counter

If Tenths>9 then
Tenths=0
Units=Units+1 ' Increment the Units

If Units>9 then
Units=0
Tens=Tens+1 ' Increment the Tens

If Tens>9 then
Tens=0
Hundreds=Hundreds+1 ' Increment the Hundreds

If Hundreds>9 then
Hundreds=0
Thousands=Thousands+1 'Increment the Thousands

If Thousands>9 then
Thousands=0
Tenthousands=Tenthousands+1 'Increment the Tenthousands

endif
endif
endif
endif
endif
Resume

' Display code goes here.

End