PDA

View Full Version : Tachometer with Interrupts



serkanc
- 25th August 2009, 10:41
I tried to make a tachometer using RB0 and Timer1 interrupt. I simulated on ISIS with a Pulse generator... I choose 200mS from pulse generator, but on LCD it shows always different values. I cannot find the reason. Pls help...

DEFINE LCD_DREG PORTB' LCD Data Port
DEFINE LCD_DBIT 4 ' LCD Data Bit
DEFINE LCD_RSREG PORTA ' LCD RS Port
DEFINE LCD_RSBIT 0 ' LCD RS Bit
DEFINE LCD_EREG PORTA ' LCD Enable Port
DEFINE LCD_EBIT 1 'LCD Enable Bit
DEFINE LCD_BITS 4 ' LCD Data Bit Sayisi
DEFINE LCD_LINES 2 ' LCD Satir Sayisi
SONUC1 VAR WORD
SONUC2 VAR WORD
X VAR WORD ' 1mS
EK VAR WORD
PIE1.0=1 ' 1 = Enables the TMR1 overflow interrupt

TRISB.0=1
T1CON=%00000001 ' bit 7-6 Unimplemented - bit 5-4=00 1:1 Prescale value - bit 0= 1=Disables Timer1
OPTION_REG.7=1 ' 1 = PORTB pull-ups are disabled
OPTION_REG.6=1 ' 1 = Interrupt on rising edge of RB0/INT pin
INTCON.4=1 ' 1 = Enables the RB0/INT external interrupt
INTCON.6=1 ' 1 = Enables all unmasked peripheral interrupts
INTCON.7=1 ' 1 = Enables all unmasked interrupts
CMCON=7 ' Turn comparators off and enable pins for I/O functions
ON INTERRUPT GOTO KESME ' Kesme Durumunda Gidecegi Alt Yordam
x=0

Basla:
@NOP
goto basla

DISABLE
KESME:
IF PIR1.0 THEN
IF X<1000 THEN X=X+1
PIR1.0=0
endif


IF INTCON.1 THEN
SONUC2=TMR1H*256+TMR1L
SONUC2=SONUC2/1000

SONUC1=X**65535
X=DIV32 1000
sonuc2=SONUC2+X
LCDOUT $FE,1,DEC SONUC2," mS Passed"

INTCON.1=0
X=0
endif

RESUME
ENABLE

Acetronics2
- 25th August 2009, 11:26
Hi,

Use ASM interrupts ...

NOT PBP Interrupts

Alain

aratti
- 25th August 2009, 11:48
If you oscillator is wired as per your diagram it will not work!

Al.

serkanc
- 25th August 2009, 11:58
If you oscillator is wired as per your diagram it will not work!

Al.

I don't understand what you mean? Should I remove crystal on ISIS?

serkanc
- 25th August 2009, 12:13
Hi,

Use ASM interrupts ...

NOT PBP Interrupts

Alain

how to use ASM interrupts in PBP ?

fratello
- 25th August 2009, 12:15
Check this picture.

serkanc
- 25th August 2009, 12:23
Check this picture.

I see, but Crystal has no effect on Simulation. I wired it now correctly, but it gives again different values.

serkanc
- 25th August 2009, 12:27
I tried also with the command count
Count PortB.0,1000,Value, and it gives the correct value

Acetronics2
- 25th August 2009, 12:39
Hi,

Some " real world " ideas ...

http://www.usinages.com/compte-tours-t26.html

Alain

serkanc
- 25th August 2009, 12:58
I want to use this for my wind turbine...

Archangel
- 25th August 2009, 21:21
how to use ASM interrupts in PBP ?
Easiest way is use Darrel's Instant Interrupts

Charles Linquis
- 26th August 2009, 02:57
Tach input on any pin

Uses Darrel Taylor's Instant Interrupts
Fast, since is in ASM
This routine uses TMR0, but will work with any other unused timer.

To use -

Set interrupt period so that there will ALWAYS be an interrupt in the shortest
"high" or "low" period you want to measure. For example, if highest tach freq
is 100Hz and is a square wave, the period will be 10msec and the "high" part
of the square wave will be 5msec and the "low" period will be 5msec. In this case
the interrupt period should be 5msec minimum - choose 4 msec or less (must be a
little less than 5msec to cover interrupt latency). If the tach frequency is higher
or the input is not a square wave, you will have to increase the interrupt rate
accordingly.

In your main PBP routine - Clear TachCounter,ShaftCounter1,ShaftCounter2,Shaftcount erX.
Then clear PeriodDone. The routine will count for 1000 interrupts. When you want to
read the tachs, check if PeriodDone bit 0 is set - if it is, then the count is finished.
Move the ShaftCounters into PBP variables, Clear the shaftcounters and clear PeriodDone.
The cycle repeats and runs totally in the background.

You will have to mutliply the ShaftCounter variables by a value determined by
the tachometer and interrupt rate to get actual RPM.

The code can probably be improved, but it works for me.



Asm

ReadTachs

movlw 0xEC ; Reload TMR0 with your own value - sets INT rate - see explanation above
movwf TMR0H ; Load the high byte first
movlw 0x7E ; Load the low byte
movwf TMR0L


btfss PeriodDone,0 ; Check to see if counting period is over
bra CheckTach
bra DoneForNow


infsnz TachCounter ; 16 bit counter
incf TachCounter + 1

movlw 0x03 - 1 ; 1000 = 0x3E8, but must have one less
cpfsgt TachCounter + 1 ; to compare with greater than (choose a different number if you like)
bra FanRoutine
movlw 0xE8 - 1 ; Again, subtract one
cpfsgt FanCounter
bra MainRoutine
bsf PeriodDone,0 ; Set the PERIOD Done lsbit
clrf TachCounter ; Clear the counter
clrf TachCounter+ 1
bra DoneForNow

MainRoutine

movf PORTB,0,0 ; Load all of Port B
movwf Temp,0 ; Copy it into TEMP for safety
xorwf OldPortB,0,0 ; XOR it with previous read
movwf changedB,0 ; Move the XORed byte into variable
movff Temp,OldPortB ; Move Temp to OldPortB


movf PORTC,0,0 ; Do the same for PORTC (or any port with a tach input)
movwf Temp,0
xorwf OldPortC,0,0
movwf changedC,0
movff Temp,OldPortC


movf PORTD,0,0
movwf Temp,0
xorwf OldPortD,0,0
movwf changedD,0
movff Temp,OldPortD



Shaft1
btfss changedB,0 ; Read in the bit - if it changed from last read it will be a "1"
bra Shaft2 ; It hasn't changed, so go to next
infsnz Shaft1Counter ; Increment the counter lowbyte
incf Shaft1Counter+1 ; If necessary, increment the high byte



Shaft2
btfss changedC,1 ; This shaft tach is fed into PORTC.1
bra Shaft3
infsnz Shaft2Counter
incf Shaft2Counter+1


; Put more shaftcounters here if you need them.


DoneForNow
bcf INTCON,2 ; Clear the TIMER0 interrupt flag

INT_RETURN

ENDASM

serkanc
- 26th August 2009, 14:54
Thanks for help.. I tried to write codes with CCS C, it's very simple.. Asm codes are difficult for me.. So it works without any problem. If someone needs I can paste the codes..

naga
- 27th August 2009, 09:59
Thanks for help.. I tried to write codes with CCS C, it's very simple.. Asm codes are difficult for me.. So it works without any problem. If someone needs I can paste the codes..

Please paste the code,would love to see.. Regards.

serkanc
- 28th August 2009, 08:10
#include <16F628A.h>

#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) #FUSES NOPUT //No Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOBROWNOUT //No brownout reset
#FUSES MCLR //Master Clear pin enabled
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or
#FUSES NOCPD //No EE protection
#use delay(clock=4000000)

#define LCD_DATA_PORT getenv("SFR:PORTB")
#define LCD_ENABLE_PIN PIN_A1
#define LCD_RS_PIN PIN_A0
#define LCD_RW_PIN PIN_A2
#define LCD_DATA0 PIN_B4
#define LCD_DATA1 PIN_B5
#define LCD_DATA2 PIN_B6
#define LCD_DATA3 PIN_B7
#define LCD_TYPE 2
#include <lcd.c>

long suretmp;
long sure;

#int_EXT
void EXT_isr(void)
{
suretmp=sure;
sure=0;
set_timer0(0);
}

#int_TIMER2
void TIMER2_isr(void)
{
sure++;
}

void main()
{
long devir;
int i;
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DIV_BY_1,99,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_oscillator( OSC_4MHZ );
lcd_init();
enable_interrupts(INT_EXT);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);

while(1)
{
for(i=0;i<250;i++)
{
delay_us(2);
}
lcd_gotoxy(1,1);
devir=600000/suretmp;
if((600000%suretmp)>(suretmp/2))
devir++;

printf(lcd_putc,"%Lu mS Passed",suretmp);
printf(lcd_putc,"\n%Lu RPM",devir);
}

}