PDA

View Full Version : Measuring change of frequency with PIC



Aussie
- 17th July 2007, 04:55
Hi boys/girls.

I have a task to determine if the frequency on a PIC input changes more than certain %, let’s say 1%. If that occurs, I should turn on an LED and when the frequency is back, that LED should be off again.

I am using PIC18F458 which has 4 timers, TMR0 as per manual is able to calculate pulses on RA4, i.e. able to work as a counter.

What I decided to do is to use 2 timers TMR0 and TMR1. Initially I will reset them, after that TMR0 will count input pulses up to overflow, TMR1 will count an internal frequency within that timing interval. When TRM0 overflows, I will just stop timers and keep that value of TMR1. After that reset TMR0 and TMR1 and start counting again, etc.
Comparing the current value and the subsequent value of TMR1 I can say whether we had a difference of more than 1%, i.e. this is like an indirect way.

The problems.
1. In my program the TMR0 does not work but I checked the control codes and for me they look all right.
2. I am not sure if I use overflow of TMR0 correctly in terms of providing reset for overflow bit, etc.

Anyway, the part of the program which calculates the subsequent values in TMR1 is below and the program does not go below


Define OSC 10
define HSER_TXSTA 20h
define HSER_BAUD 9600

' variables defintion
overflow var word
OverflowValue var word
TMR1valuelow var byte
TMR1valuehigh var byte
Value var word
TMR1Overflow var bit
TMR0Overflow var bit

TRISA = %11111111 ' Set all PORT A to input
TRISC = %10010000 ' Set all PORT C to output/input for RS232

' ports variables
InputSignal var PORTA.4 ‘ actually TMR0 does not work if I remove this operator
‘ in such mode TMR0 should count pulses on PORTA.4
TMR0Overflow = INTCON.2 ‘ just in case overflow flag reset for TMR0, not sure I
‘ can like that

PIR1.0 = 0 ' clear overflow flag of TMR1 just in case
INTCON.2 = 0 ' clear overflow flag of TMR0
T1CON = %10000000 ' stop TMR1, internal clock, scale 1:1, 16-bit work
T0CON = %01101000 ' stop TMR0, 8 bit, input RA4, low-high, no prescaler
TMR1L = 0 ' clear TMR1 low
TMR1H = 0 ' clear TMR1 high
TMR0L = 0 ' clear TMR0 low

main:
T0CON = %11101000 ' start TMR0, 8 bit, input RA4, low-high, no prescaler (1:1)
T1CON = %10000001 ' start TMR1 as 16-bit timer
while TMR0Overflow = 0
wend
T1CON = %10000000 ' stop TMR1
T0CON = %01101000 ' stop TMR0
TMR1valuelow = TMR1L
TMR1valuehigh = TMR1H
OverflowValue = TMR1valuehigh * 256
Value = TMR1valuelow + OverflowValue ' this is value of TMR1
‘ overflow+remaining

Hserout [dec Value]
' for checking purposes when adjust the program
' put Value to RS232 thru hserout to see TMR1 value

TMR1L = 0 ' clear TMR1 low
TMR1H = 0 ' clear TMR1 high
TMR0L = 0 ' clear TMR0 low
PIR1.0 = 0 ' clear overflow flag of TMR1
INTCON.2 = 0 ' clear overflow flag of TMR0


goto main

End

Questions.
1. Why TMR0 does not calculate anything?
2. Am I right with TMR0 overflow handling?

Thanks for comments.

Bruce
- 17th July 2007, 13:59
1. Why TMR0 does not calculate anything?

while TMR0Overflow = 0
wend

You're testing a bit variable here that's never being updated, so it's stuck in
the loop.

Change TMR0Overflow var bit to TMR0Overflow var INTCON.2 and it should
work as expected.


2. Am I right with TMR0 overflow handling?
Testing for overflow via the overflow bit is correct.

Also, with Timer1 configured as 16-bit, you'll want to write to TMR1H first,
then TMR1L.

The value being written to TMR1H is is loaded into a buffer, then transferred
to TMR1H when a write to TMR1L occurs.

So for writes, write to TMR1H then TMR1L. For reads, read TMR1L first, then
TMR1H.

Aussie
- 18th July 2007, 11:45
while TMR0Overflow = 0
wend

You're testing a bit variable here that's never being updated, so it's stuck in
the loop.

Change TMR0Overflow var bit to TMR0Overflow var INTCON.2 and it should
work as expected.


Testing for overflow via the overflow bit is correct.

Also, with Timer1 configured as 16-bit, you'll want to write to TMR1H first,
then TMR1L.

The value being written to TMR1H is is loaded into a buffer, then transferred
to TMR1H when a write to TMR1L occurs.

So for writes, write to TMR1H then TMR1L. For reads, read TMR1L first, then
TMR1H.

Thanks Bruce!
Your idea worked fine but the issue is that it looks like at this PIC the TMR0 input signal should be synchronized with the internal phase clock which I don’t have and can’t have. My input signal is from an independent source. I found in the manual that synchronization issue.

As a result, the timer shows basically random results.
I gave up with TMR0 and will calculate the input pulses just using counting. I changed the program for that and noticed that it works but the problem is that the TMR1H accumulates the value and I can’t realise why. every circle TMR1 does notr have reset despite I put an operator to do that.

The program is below.
Do any have any suggestions? It’s some stupid error…


Define OSC 10
define HSER_TXSTA 20h
define HSER_BAUD 9600

' variables defintion
Counter var byte
TMR1valuelow var byte
TMR1valuehigh var byte

TRISA = %11111111 ' Set all PORT A to input
TRISB = %11111111 ' Set all port B to input
TRISC = %10010000 ' Set all PORT C to output/input for RS232

' ports variables
InputSignal var PORTB.0


clear
main:
Counter = 0
T1CON = %10000000 ' stop TMR1, internal clock, scale 1:1, 16-bit work
TMR1L = 0 ' clear TMR1 low
TMR1H = 0 ' clear TMR1 high
PIR1.0 = 0 ' reset overflow flag for TMR1 just in case
T1CON = %10000001 ' start TMR1 as 16-bits

loop1:
while InputSignal = 0
wend ‘ waiting for rising edge of input signal
Counter = Counter + 1 ' counting rising edges of input pulses
if Counter = 250 then exit ' when 250 input pulses – look at TMR1 values
while InputSignal = 1
wend ‘ waiting for falling edge of input signal
goto loop1 ‘ going back on falling edge

exit:
T1CON = %10000000 ' stop TMR1
TMR1valuelow = TMR1L
TMR1valuehigh = TMR1H

Hserout ["TMR1low =",dec TMR1valuelow, "TMR1high =",dec TMR1valuehigh]

goto main

End

So, what I noticed in here is that it looks like TMR1H does not go to zero when I reset it at each stage clearing TMR1high and accumulates the value. Why is that?
Appreciate your comments.

Bruce
- 18th July 2007, 12:48
With Timer1 configured for 16-bit read/write, you need to write to TRM1H
first, then write to TMR1L.

So change;
TMR1L = 0 ' clear TMR1 low
TMR1H = 0 ' clear TMR1 high

To;
TMR1H = 0 ' writes to TMR1H buffer
TMR1L = 0 ' writes TMR1H 'buffer' to TMR1H register & writes to TMR1L

Bruce
- 18th July 2007, 15:27
If RC2 is avilable you could also use the hardware capture module.


' Measuring pulse width with capture module
' Input signal connected to RC2/CCP1 pin

DEFINE OSC 4

Symbol Capture = PIR1.2 ' CCP1 capture flag
T1 VAR WORD ' 1st capture value
T2 VAR WORD ' 2nd capture value
T3 VAR WORD ' 3rd capture value
LowCycle VAR WORD ' low pulse width rsult
HighCycle VAR WORD ' high pulse width result

TRISC.2 = 1 ' CCP1 input pin (Capture input)
INTCON = 0 ' Interrupts off
CCP1CON = %00000101 ' Capture mode, capture on rising edge
T1CON = %10000001 ' TMR1 prescale=1, clock=Fosc/4, TMR1=on

Main:
WHILE !Capture ' wait for rising edge capture
WEND
' Rising edge detected so record timer1 value
T1.HighByte = CCPR1H : T1.LowByte = CCPR1L

Capture = 0 ' Clear capture flag bit
CCP1CON.0 = 0 ' Configure capture for falling edge now

While !Capture ' While here for capture on falling edge
Wend
' Falling edge detected so record timer1 value again
T2.HighByte = CCPR1H : T2.LowByte = CCPR1L

Capture = 0 ' Clear capture flag bit
CCP1CON.0 = 1 ' Configure capture for rising edge now

While !Capture ' While here for capture on falling edge
Wend

' Falling edge detected so record timer1 value again
T3.HighByte = CCPR1H : T3.LowByte = CCPR1L

CCP1CON = 0 ' disable capture during data processing

HighCycle = T2-T1 ' High pulse width = T2 - T1
LowCycle = T3-T2 ' Low pulse width = T3 - T2

HSEROUT ["High pulse width = ",DEC HighCycle,"uS",13,10]
HSEROUT ["Low pulse width = ",DEC LowCycle,"uS",13,10]
HSEROUT ["Period = ",DEC LowCycle+HighCycle,"uS",13,10]

Capture = 0 ' Clear capture flag bit
CCP1CON = %00000101 ' Capture mode, capture on rising edge

GOTO Main

END
If the measured frequency is too slow you can use the timer prescaler. You
want the frequency to be high enough so the timer doesn't overflow during
the measurement period.

Aussie
- 19th July 2007, 01:47
With Timer1 configured for 16-bit read/write, you need to write to TRM1H
first, then write to TMR1L.

So change;
TMR1L = 0 ' clear TMR1 low
TMR1H = 0 ' clear TMR1 high

To;
TMR1H = 0 ' writes to TMR1H buffer
TMR1L = 0 ' writes TMR1H 'buffer' to TMR1H register & writes to TMR1L

Thanks a lot Bruce,
I changed only that thing in my program and it started working .
Have never seen in the manual that such a sequence of work with the timers should be...