PDA

View Full Version : Slow speed tachometer



fpeixeiro
- 12th April 2014, 20:58
Hello everybody.

I'm very new to pic, beeing learning for almoast one year on my own.

I've been reading some time for a tachometer, and all i've found is info about tacho's for high speed.

I'm trying to make a tacho for 20 to 60 rpm. I gathered the hardware, it's based on the 16f628a, 4mhz crystal and three 7 seg display common anode.

I'm doing this so i can be shure that a line of 7 conveyors are in sync, at 36 rpm. I need to be shure that the conveyors are running at 36 rpm, not 35,5 or 36,5. So i added three 7seg display to do the decimals.

The rpm are checked by means of an ir emiter/receiver.

I've made a circuit based on a counter from the book "PIC Basic Projects 30 Projects using PIC BASIC and PIC BASIC PRO", "Dual 7-segment LED event counter".

The code is being simulated on proteus and it says that the pic is under excessive load, and it doesn't work.

The code:

' DEFINITIONS


RPM VAR WORD ' RPM is a word variable
Digit VAR Byte ' Digit is a byte variable
Pattern VAR Byte ' Pattern is a byte variable
Digit1 VAR PORTA.1 ' Digit 1 enable bit
Digit2 VAR PORTA.2 ' Digit 2 enable bit
Digit3 VAR PORTA.3 ' Digit 3 enable bit
Counter VAR WORD ' Variable
TMPlowbyte var byte ' TMP word variable for timer1
TMR1Overflow var byte ' TMR1 Overflow counter
i var byte ' Variable


' START OF MAIN PROGRAM


CMCON = 7 ' RA0-RA3 are digital I/O
TRISA = 0 ' Set PORTA as output
TRISB = $80 ' Bit 7 of PORTB input, others outputs
TMR1Overflow = 0 ' Reset TMR1 Overflow counter
RPM = 0 ' Variable reset
i = 0 ' Variable reset


' Enable TMR0 timer interrupts


INTCON = 100000 ' Enable TMR0 interrupts
OPTION_REG = 000111 ' Initialise the prescale
TMR0 = 217 ' Load TMR0 register


' Enable TMR1
T1CON = 111101 ' bit0 = TMR1 on
' bit1 = TMR1CS Internal Clock
' bit2 = T1SYNC = 1
' bit3 = T1OSCEN = 1
' bit4-5 = 11 = 1:8 Prescale value


ON INTERRUPT GOTO ISR


INTCON = 100000 ' Enable Interrupts


MLOOP:
BUTTON PORTA.7, 0, 255,0,i, 0, MLOOP ' Wait until push-button is pressed and debounce switch
TMPlowbyte = TMR1L ' Saves value of TMR1

If PIR1.0 = 1 Then ' Checks TMR1 OIF bit and
TMR1Overflow = TMR1Overflow + 1 ' increments if TMR1 overflows
ENDIF


Counter = TMR1Overflow + TMPLowbyte
RPM = 60 / Counter


GOTO MLOOP


' This is the Interrupt Service Routine (ISR). The program jumps to
' this routine whenever a timer interrupt is generated. Inside this
' routine the value of variable RPM is displayed.


DISABLE ' Disable further interrupts


ISR:
TMR0 = 217
Digit = RPM DIG 2 ' Get 100s digit
LOOKUP Digit, [$3F, $06, $5B, $4F, $66, $6D, $7D, $07, $7F, $6F], Pattern
Pattern = Pattern ^ $FF ' Invert bits of variable Pattern
' Use with Comon Anode Display
Digit3 = 0 ' Disable digit 3
Digit2 = 0 ' Disable digit 2
PORTB = Pattern ' Display 100s digit
Digit1 = 1 ' Enable digit 1
Pause 1 ' Wait 2ms

Digit = RPM DIG 1 ' Get 10s digit
LOOKUP Digit, [$3F, $06, $5B, $4F, $66, $6D, $7D, $07, $7F, $6F], Pattern
Pattern = Pattern ^ $FF ' Invert bits of variable Pattern
Digit3 = 0 ' Disable digit 3
Digit1 = 0 ' Disable digit 1
PORTB = Pattern ' Display 10s digit
Digit2 = 1 ' Enable digit 2
Pause 1 ' Wait 2ms

Digit = RPM DIG 0 ' Get 1s digit
LOOKUP Digit, [$3F, $06, $5B, $4F, $66, $6D, $7D, $07, $7F, $6F], Pattern
Pattern = Pattern ^ $FF ' Invert bits of variable Pattern
Digit1 = 0 ' Disable digit 1
Digit2 = 0 ' Disable digit 2
PORTB = Pattern ' Display 1s digit
Digit3 = 1 ' Enable digit 3
PAUSE 1 ' Wait 2ms

INTCON.2 = 0 ' Re-enable TMR0 interrupts


RESUME ' Return to main program
ENABLE ' Enable interrupts


TMPlowbyte = 0 ' Variable reset
PIR1.0=0 ' Reset TMR1's Interupt Flag
TMR1Overflow = 0 ' Reset TMR1 Overflow counter


END ' End of program

What's wrong?
I know this is very complicated, but any help is very god.
Thanks.

Amoque
- 13th April 2014, 11:18
Immediately I see that you have not put a "%" before your binary values - this is required. Check at each register assignment.

fpeixeiro
- 13th April 2014, 11:47
Interesting!

But i have, it seems that if i copy/paste they disapear.

By the way i use PBP 2.60 and microcode studio 4, and the schema goes like this:

7308

richard
- 13th April 2014, 12:22
a few thoughts :-
1, INTCON.7 "GIE" and INTCON.6 "PEIE" probably need to be set

2, this piece of code can never execute because its orphaned

RESUME ' Return to main program
ENABLE ' Enable interrupts


TMPlowbyte = 0 ' Variable reset
PIR1.0=0 ' Reset TMR1's Interupt Flag
TMR1Overflow = 0 ' Reset TMR1 Overflow counter


END ' End of program


3, the " on interrupt " latency is variable and unpredictable and is unlikey to give accurate results.
dt interrupts is vastly better.

4, for your purposes rpm measurement using "pulsin" is far simpler to do and a lot easier to get working.

fpeixeiro
- 13th April 2014, 19:50
Thanks Richard

I'm going to explain myself better.

My goal is to use timer0 to refresh the 7 segment displays, and use timer1 free running so i can count the pulses from portb.7 so i think setting interrupts for timer1 won't be nedded. The part that captures TMR1L and calculates RPM, is the one that is giving me problems.

Can you explain me better the part of tho orphaned code?

From what i have read, and correct me if i'm wrong, since i'm trying to aquire a signal near 0.625hz, those command won't serve my purposes.

There is one thing that i'm going to try is to use a 32.768 Khz crystal, my doubt is can i use as a primary crystal or do i have to connect it to RB6 and RB7?

Because i'm running out os pins, i'm setting on another breadboard the same schematic, but with a 16f877a.

Thanks.

richard
- 14th April 2014, 00:13
My goal is to use timer0 to refresh the 7 segment displays, and use timer1 free running so i can count the pulses from portb.7 so i think setting interrupts for timer1 won't be nedded. The part that captures TMR1L and calculates RPM, is the one that is giving me problems.
with your t1con setting the max period for TMR1 is 524.295 mSec : not enough
tmr1 is 16 bits just reading TMR1L will not work.
if you leave tmr1 free running you need to read ITS 16 bit value at "say the leading edge " of the timing pulse
then read the timer again at the next "leading edge" and calculate the difference (maybe check and clear the overflow also).or start the timer on "say the leading edge " and stop it on the next . either way you need to sync up with the timing pulse
the other way is to count the timing pulses over a fixed timebase , in this case you would need some tens of seconds to get meaningfull results.


Can you explain me better the part of tho orphaned code?
the isr returns to the main loop after the RESUME /ENABLE
any code after that will never run ever


From what i have read, and correct me if i'm wrong, since i'm trying to aquire a signal near 0.625hz, those command won't serve my purposes.

correct , can you modify the machine to get 2 pulses per rev ?

Amoque
- 14th April 2014, 20:06
Perhaps I do not wholly understand your purpose, but why is it necessary to use a timer for the display? It seems (from what I understand of your intent) that something like the pseudo-code below would suffice:



Set up interrupt on complete rotation
Set up interrupt on Timer1 overflow

RPM = 0

Main:
If (button pushed) and (Flag = 0) enable interrupts and Flag = 1
if (button pushed) and (Flag = 1) disable interrupts and Flag = 0
For Digit = 1 to 3 'multiplex display
PORTA.Digit = 1
Lookup
.
.
.
PortA.Digit = 0
Next Digit
XXXXXXX 'No pause here, it slows interrupts
Goto Main

On Timer1 Overflow:
Timer1Overflows = Timer1Overflows + 1 'Timer0 may be used here, but will result in a higher multiplier
Resume

On rotation interrupt:
RPM = Timer1Overflows * [Time to Overflow] + [Timer1 current value in mSecs]... 'Calculate new RPM
Timer1Overflows reset : Timer1 reset
Resume


I would not question, but it seems at the very slow RPM you are measuring, the frequency of updating the display will happen many times and is not nearly so critical... It will take relatively many iterations before there is new information to display and there is no benefit (as I see it) to worry so long as the loop executes fast enough to avoid flicker. It seems, if I understand you correctly, that each rotation interrupt is a full rotation and yields new RPM data or am I mistaken?

tasmod
- 15th April 2014, 09:31
I think you need to increase the resolution to increase the accuracy of the pulse read before 1 minute is up.

Why deal with 36 pulses per minute ? I don't know how you are breaking the IR beam but maybe you could add extra pulses using extra beam breaks.

1 pulse per revolution of conveyer "drum" wheel could be multiplied up to 10 pulses per revolution or whatever using more beam breaks on the "drum" ? Easier to read a RPM during the one minute period.


Just thoughts. :)

fpeixeiro
- 22nd April 2014, 22:05
Thank for all the help, i'll try to see if can manage myself.

Good programming

fpeixeiro
- 4th May 2014, 23:34
Hello, tanks for all the suggestions.


Perhaps I do not wholly understand your purpose, but why is it necessary to use a timer for the display?
I saw one example that is based on that principle, and i tought it would to the job, but it was just an ideia.


I would not question, but it seems at the very slow RPM you are measuring, the frequency of updating the display will happen many times and is not nearly so critical...
I tought that too, and i increased the time to refresh to help on the task of timer1, but didn't gave any result.
First, each time i pressed the button, to simulate a rotation, it gave me completly different numbers, then nothing happend.


It will take relatively many iterations before there is new information to display and there is no benefit (as I see it) to worry so long as the loop executes fast enough to avoid flicker. It seems, if I understand you correctly, that each rotation interrupt is a full rotation and yields new RPM data or am I mistaken?
You are right. On booth.

The pseudo code you gave me looks simple, i'll try to build it.



I think you need to increase the resolution to increase the accuracy of the pulse read before 1 minute is up.

Why deal with 36 pulses per minute ? I don't know how you are breaking the IR beam but maybe you could add extra pulses using extra beam breaks.

1 pulse per revolution of conveyer "drum" wheel could be multiplied up to 10 pulses per revolution or whatever using more beam breaks on the "drum" ? Easier to read a RPM during the one minute period.


Just thoughts. :)

You are absolutly right tasmod, the problem is that i have 7 conveyours in 1 line, and 39 lines, 273 conveyours plus 193 conveyours in another zone. The conveyours are different in diameter, there are 4 types, and the shaft is visible only in the center, so i plan to break the beam with plain white paper, since the optoelectronics i'm usig where taken from a printer, the detection of paper.

With this, i'm not saing you are wrong, but to be fast enough to check the rotation of the shafts, i must not take too much time or be too complicated, althoug i only have to do it once every year