Searching \ for '[PIC] pulse counter, pulses lost' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page: www.piclist.com/techref/microchip/time.htm?key=count
Search entire site for: 'pulse counter, pulses lost'.

Exact match. Not showing close matches.
PICList Thread
'[PIC] pulse counter, pulses lost'
2012\02\19@144311 by KPL

picon face
Hi,

Since this is more about pic itself than about jal, I wll ask here.

While playing (educating myself) with timers, I tried to build a
frequency counter. The one where time period of counting pulses would
change depending on pulse rate, that is, frequency.
At first I used tmr0 and tmr1, then rebuilt using tmr1 and tmr2, but
still can not get exactly what I was looking for. I have spent many
late evenings trying, probably somebody from a side can spot my error.

Basically, TIMER2 is used to make a time frame when pulses must be
counted, but TIMER1 is the one that counts pulses. Both have
interrupts enabled, and interrupt routine just adds 1 to a variable,
which is then dealt with in main code.
No prescalers or postscalers are used.
In main code, when a time frame counter or a pulse counter exceeds
pre-defined values, both timers are stopped, their values added to
respective variables, and both variables just sent via serial link to
my PC.
The problem is:
When TIMER1 (pulse counter) is fed from internal clock, I get correct values:

Finish TMR: 5000307
Finish CNT: 5000306

20MHz crystal is used, so 5MHz instruction clock, and one tick of a
timer is 0.2us, so this gives frequency : F=(CNT * 5000000) / TMR =
4999999.0 Hz. That error of 1 pulse can be eliminated by changing
timer start/stop order.

These are about the same, which is correct, since both timers advance
at the same speed. That made me think that program works correctly.

The only pulse source with predictable frequency I have, is an quartz
oscillator, marked as 1.8432MHz. Another frequency counter shows it's
frequency as 1843150Hz.
When I change T1CON_TMR1CS to 1, and feed pulses from the oscillator,
I get results like this :

Finish TMR: 5000304
Finish CNT: 1843100

which gives F=1842987.94 Hz - which shows I am missing several hundred
pulses, or my time frame was several hundred pulses too long.
5000000 TMR pulses is one second, so it is more-than-enough time
period to count this frequency.

So, I tried to move all the stuff around, changed start and stop
sequences, checked datasheets, got a bit different results, but did
not get better precision.
Enabling or disabling T1SYNC did not change anything, since the
frequency I'm trying to measure is quite low.
It's not like this circuit is mission-critical or something, I just
want to understand what I'm doing wrong. And I want a good frequency
counter.
Where are my pulses?! :)
How can it be, it's working perfectly with internal clock, but runs
wrong with external one.
Code is in Jal2, with jallibs, and it looks like this:


include 16f886                    -- target PICmicro
pragma target clock 20_000_000     -- oscillator frequency
pragma target OSC      HS               -- HS crystal or resonator
pragma target WDT      disabled     -- no watchdog
pragma target LVP      disabled     -- no Low Voltage Programming
pragma target MCLR     internal     -- reset externally
--
enable_digital_io()
------------------------------------------------------------------------------------------------

include delay
include print

-- UART
const serial_hw_baudrate  = 115200
include serial_hardware
serial_hw_init()
alias serial_write is serial_hw_write
alias serial_read is serial_hw_read
alias serial_data is serial_hw_data
alias serial_data_available is serial_hw_data_available

-- print start
print_crlf(serial_hw_data)
print_crlf(serial_hw_data)
const byte starttmrmsg[] = "Startup"
print_string(serial_hw_data, starttmrmsg)
print_crlf(serial_hw_data)

-- time frame is made using timer2
var byte tmrupd
var dword tmrcnt
var byte running
const dword tmrmax = 5000000

T2CON = 0
T2CON_T2CKPS = 0        -- prescaler=1:1
T2CON_TOUTPS = 0        -- postscaler=1:1
T2CON_TMR2ON = 0        -- tmr2 off
TMR2 = 0                -- tmr2, pre, post scalers clear
PIR1_TMR2IF = 0         -- int flag clear
PIE1_TMR2IE = 0         -- int off

-- pulse counter is done using timer1
var byte cntupd
var dword cntcnt
const dword cntmax = 5000000

T1CON = 0
T1CON_TMR1CS = 1        -- use input from T1CKI
;T1CON_TMR1CS = 0       -- use input from internal clock
;T1CON_T1GINV = 0       -- gate active=low
T1CON_TMR1GE = 0        -- tmr0 gate not used
;T1CON_T1OSCEN = 0      -- tmr1 osc not used
T1CON_NT1SYNC = 1       -- do not synchronize sgnal to clock (inverted logic)
T1CON_T1CKPS = 0        -- set prscaler (0:1, 1:2, 2:4, 3:8)
T1CON_TMR1ON = 0        -- tmr1 off
TMR1 = 0                -- clear timer
PIR1_TMR1IF  = 0    -- clear int flag
PIE1_TMR1IE  = 0    -- int off

const byte tmrmsg0[] = "Start TMR: "
const byte tmrmsg1[] = "Update TMR: "
const byte tmrmsg2[] = "Finish TMR: "
const byte cntmsg0[] = "Start CNT: "
const byte cntmsg1[] = "Update CNT: "
const byte cntmsg2[] = "Finish CNT: "
const byte freqmsg0[] = "Freq: "

INTCON_GIE  = 1      -- enables all unmasked interrupts
INTCON_PEIE = 1      -- enables all unmasked peripheral interrupts

portA_direction = all_output
portB_direction = all_output
portC_direction = all_output

alias   led      is pin_C3
pin_C3_direction =  output

pin_C0_direction = input

var dword freq

------------------------------------------------------------------------------------------------
forever loop
running = 0
cntcnt=0
cntupd=0
tmrcnt=0
tmrupd=0
;print_string(serial_hw_data, tmrmsg0)
;print_dword_dec(serial_hw_data, tmrcnt)
;print_crlf(serial_hw_data)
;print_string(serial_hw_data, cntmsg0)
;print_dword_dec(serial_hw_data, cntcnt)
;print_crlf(serial_hw_data)
TMR1 = 0
TMR2 = 0
;while (pin_C0) loop end loop
;while (! pin_C0) loop end loop
T1CON_TMR1ON = 1        -- tmr2 on
T2CON_TMR2ON = 1        -- tmr2 on

PIR1_TMR2IF = 0                -- int flag clear
PIE1_TMR2IE = 1                -- int on
PIR1_TMR1IF = 0                -- int flag clear
PIE1_TMR1IE = 1                -- int on

running = 1

led = on
       while (running == 1) loop
               if (cntupd > 0) then
                       cntcnt = cntcnt + 65536
                       cntupd = cntupd - 1
;                        print_string(serial_hw_data, cntmsg1)
;                        print_dword_dec(serial_hw_data, cntcnt)
;                        print_crlf(serial_hw_data)
               end if
               if (tmrupd > 0) then
                       tmrcnt = tmrcnt + 256
                       tmrupd = tmrupd - 1
;                        print_string(serial_hw_data, tmrmsg1)
;                        print_dword_dec(serial_hw_data, tmrcnt)
;                        print_crlf(serial_hw_data)
               end if

               if (tmrcnt > tmrmax) then
                       T1CON_TMR1ON = 0        -- tmr1 off
                       T2CON_TMR2ON = 0        -- tmr2 off
                       running = 0
               elsif (cntcnt > cntmax) then
                       T1CON_TMR1ON = 0        -- tmr1 off
                       T2CON_TMR2ON = 0        -- tmr2 off
                       running = 0
               end if
       end loop
led = off

cntcnt = cntcnt + TMR1
tmrcnt = tmrcnt + TMR2

print_string(serial_hw_data, tmrmsg2)
print_dword_dec(serial_hw_data, tmrcnt)
print_crlf(serial_hw_data)
print_string(serial_hw_data, cntmsg2)
print_dword_dec(serial_hw_data, cntcnt)
print_crlf(serial_hw_data)

delay_1s(3) -- some delay
print_crlf(serial_hw_data)

end loop

------------------------------------------------------------------------------------------------

procedure ISR() is
;   pragma interrupt fast
  pragma interrupt
  if PIR1_TMR2IF == true then        -- timeframe timer overflowed
     tmrupd = tmrupd+1
     PIR1_TMR2IF  = 0
  end if
  if PIR1_TMR1IF == true then        -- pulse counter overflowed
     cntupd = cntupd+1
     PIR1_TMR1IF = 0
  end if
end procedure





-- KP

2012\02\20@123333 by KPL

picon face

Oh, well.

I will never ever buy cheap crystals again.
I will never ever buy cheap crystals again.
I will never ever buy cheap crystals again.
I swear.
Seems like my 20MHz crystal was not 20MHz at all. With a different
crystal it counts correctly.


On Sun, Feb 19, 2012 at 21:43, KPL <spam_OUTkpl.listesTakeThisOuTspamgmail.com> wrote:
{Quote hidden}

--
KPL

2012\02\20@124133 by John Gardner

picon face
Crystals are designed for specific operating modes.
Sure you got that right?  Just a thought...

2012\02\20@125948 by Bob Ammerman

flavicon
face
Some years ago I bought some 20MHZ xtals from DigiKey. They came in, I
installed them and all my timing was a bit off. After spending a whole bunch
of time looking at my code and the hardware I finally took a closer look at
the xtals and found they were marked 19.<something>. Apparently DigiKey
mispicked them, and I didn't perform an appropriate incoming inspection.

-- Bob Ammerman



{Original Message removed}

2012\02\20@142507 by KPL

picon face

Who knows. There was no more info.
I think this one came from here:
http://futurlec.com/ICCrystalsMain.shtml
but since I have no proper tools to test them, I can not say all of
them are bad. Probably that's just that one. Unfortunately I had it
solderet in a small plug-in development board, where it is difficult
to replace.


On Mon, Feb 20, 2012 at 19:41, John Gardner <.....goflo3KILLspamspam@spam@gmail.com> wrote:
> Crystals are designed for specific operating modes.
> Sure you got that right?  Just a thought....
>

2012\02\20@154916 by KPL

picon face

Now i'm wondering what would be the best way to calculate frequency
itself, without overflowing 4-byte integer, with maximum possible
precision.

CNT=131129
TMR=355708
Freq==5000000*CNT/TMR=1843211.28566127

CNT can be quite large number, so multiplied by 5e6 it can overflow. I
would like to get maximum significant digits, not for precision but
for resolution. Are there any tricks?

I see I can define frequency as a byte*6 variable, for example - but
seems like I am getting weird results. is JALv2 able to deal with such
numbers?


On Mon, Feb 20, 2012 at 21:25, KPL <kpl.listesspamKILLspamgmail.com> wrote:
{Quote hidden}

>> -

2012\02\20@160352 by Rob Hamerling

picon face


On 02/20/12 09:49 pm, KPL wrote:

> I see I can define frequency as a byte*6 variable, for example - but
> seems like I am getting weird results. is JALv2 able to deal with such
> numbers?

I would think so! In Jallib you can find a sample program (16f688_print.jal) which uses a byte*32 variable.

Regards, Rob.


-- R. Hamerling, Netherlands --- http://www.robh.n

2012\02\20@161209 by Carl Denk

flavicon
face
Set up the timer to increment an up counter, when the counter >= a number you select, could increment another counter, cascading until you accumulate the number of timer periods you need, then reset counter() and set flag you have arrived. This sort of thing can be done with down counters also. Sorry my explanation isn't very ellagant, but hope the message gets through. :)

On 2/20/2012 3:49 PM, KPL wrote:
{Quote hidden}

>>> --

2012\02\20@170016 by IVP

face picon face
> Seems like my 20MHz crystal was not 20MHz at all

I've had one occassion where grounding the crystal case solved a
timing issue, so I routinely do that now. Whether that really was just
a one-off funny crystal, don't kno

2012\02\21@093056 by Mark Hanchey

flavicon
face
On 2/20/2012 12:33 PM, KPL wrote:
> Oh, well.
>
> I will never ever buy cheap crystals again.
> I will never ever buy cheap crystals again.
> I will never ever buy cheap crystals again.
> I swear.
> Seems like my 20MHz crystal was not 20MHz at all. With a different
> crystal it counts correctly.
>

One of the first test I do on every setup is to set the timer to toggle a pin at 500Khz and I measure that with a frequency counter before I start to write code specific to the chip. That lets me know that everything is running correctly clock wise . I have had issues before that were crystal related and pic related where either one was at fault. Especially useful for when using the internal clock of the pic chips that have them . I used to assume that the internal clock is what it says but depending on the application can be a source of problems if you don't check it first.

Mark

2012\02\21@093423 by Mark Hanchey

flavicon
face
On 2/20/2012 5:00 PM, IVP wrote:
>> Seems like my 20MHz crystal was not 20MHz at all
> I've had one occassion where grounding the crystal case solved a
> timing issue, so I routinely do that now. Whether that really was just
> a one-off funny crystal, don't know
I do this too. Often just a tiny bit of flux on the case and the solder easily will stick to it. Also helps to keep the crystal from getting pulled off the board accidentally , I have several broken crystals from that.

Mark

2012\02\21@095015 by jim

flavicon
face


snip... That lets me know that everything is running correctly clock
wise ..snip.
But does it run counterclockwise?



Regards,

Jim

> ---{Original Message removed}

2012\02\21@100440 by Chris Roper

picon face
You are confusing it with the Arduino Jim

On 21 February 2012 16:50, <@spam@jimKILLspamspamjpes.com> wrote:

{Quote hidden}

2012\02\24@163015 by KPL

picon face
And so, I'm still playing with same stuff.
Results from those previous tests were unstabe, so i decided to try
the "default" way to count a frequency, that is - make a 1 second
delay, and directly count pulses. No big number divisions, almost no
math at all.
But still, I can not get really useful results, since I'm always
geting more pulses counted than there should be.
I tried counting timer overflows using interrupts, then rebuilt the
code to work without them, with about the same results. In this case I
can avoid delays caused by context saving and restoring at interrupts.
I could see place where error of several pulses could be coming from,
but I'm getting thousands of them!
Timing should be almost right, since timer2 overflow bit is checked in
a loop, and just last iteration has several more instructions, where
several additional pulses could get added if fast enough pulses are
coming in.
Timer1 counts pulses, and just full overflows are counted, to save
instructions. When time period is over, those are multiplied by 65536,
and TMR1 value is added.
For testing purposes, I'm feeding counter with pulses from internal
source, so it should count 4000000 pulses in that second. But I'm
getting 4016008.
I see some error could be generated if both timers overflowed at the
same time, but then some pulses would get lost, not added. I see a way
to avoid that, but in this case it should not matter.

I feel much more familiar with timers now, but still do not get this. Any ideas?


include 16f876a                    -- target PICmicro
pragma target clock 16_000_000     -- oscillator frequency
pragma target OSC      HS               -- HS crystal or resonator
pragma target WDT      disabled     -- no watchdog
pragma target LVP      disabled     -- no Low Voltage Programming
------------------------------------------------------------------------------------------------
enable_digital_io()

include delay
include print
include format

-- UART
const serial_hw_baudrate  = 115200   -- set the baudrate
include serial_hardware
serial_hw_init()
alias serial_write is serial_hw_write
alias serial_read is serial_hw_read
alias serial_data is serial_hw_data
alias serial_data_available is serial_hw_data_available

-- print start
print_crlf(serial_hw_data)
print_crlf(serial_hw_data)
const byte starttmrmsg[] = "Startup"
print_string(serial_hw_data, starttmrmsg)
print_crlf(serial_hw_data)

-- time frame is made using timer2
var byte tmrupd
var byte tmrcnt = 100        -- we need 10 overflows
var byte running
var byte PRval=250        -- 16x250x10x(1/4MHz)=100000us=10ms

---------------- timeframe
T2CON = 0
-- to get 10ms
T2CON_T2CKPS = 2        -- prescaler=1:16
T2CON_TOUTPS = 9        -- postscaler=1:10
-- to get 1ms
;T2CON_T2CKPS = 0        -- prescaler=1:1
;T2CON_TOUTPS = 15        -- postscaler=1:16

T2CON_TMR2ON = 0        -- tmr2 off
TMR2 = 0                        -- tmr2, pre, post scalers clear
PR2 = PRval                        -- value when tmr has to be reset
PIR1_TMR2IF = 0                -- int flag clear
PIE1_TMR2IE = 0                -- int off

---------------- pulse counter
var dword cntcnt
var byte cntupd
T1CON = 0
;T1CON_TMR1CS = 1        -- use input from T1CKI
T1CON_TMR1CS = 0        -- use input from internal clock
T1CON_NT1SYNC = 1        -- do not synchronize sgnal to clock (inverted logic)
T1CON_T1CKPS = 0        -- set prscaler (0=1:1, 1=1:2, 2=1:4, 3=1:8)
T1CON_TMR1ON = 0        -- tmr1 off
TMR1 = 0                        -- clear timer
PIR1_TMR1IF  = 0    -- clear int flag
PIE1_TMR1IE  = 0    -- int off

const byte tmrmsg2[] = "Finish TMR: "
const byte cntmsg2[] = "Finish CNT: "

INTCON_GIE  = 0
INTCON_PEIE = 0

portA_direction = all_output
portB_direction = all_output
portC_direction = all_output

alias   led      is pin_C3
pin_C3_direction =  output

pin_C0_direction = input
pin_C1_direction = input

------------------------------------------------------------------------------------------------
forever loop
tmrcnt=100
cntcnt=0
T2CON_TMR2ON = 0        -- tmr2 off
T1CON_TMR1ON = 0        -- tmr1 off
PR2 = PRval

PIR1_TMR2IF = 0                -- int flag clear
PIR1_TMR1IF = 0                -- int flag clear
TMR1 = 0
TMR2 = 0
-- start both timers
T1CON_TMR1ON = 1        -- tmr1 on
T2CON_TMR2ON = 1        -- tmr2 on

led = on
;        while (tmrcnt != 0) loop                -- unnecessary test?
       forever loop
               if (PIR1_TMR2IF==1) then
                       tmrcnt = tmrcnt-1
                       if (tmrcnt == 0) then
                               T1CON_TMR1ON = 0    -- stop both
timers as fast as possible
                               T2CON_TMR2ON = 0
                               exit loop                        --
needed only in forever loop
                       end if
                       PIR1_TMR2IF = 0
               end if
               -- will skip this if tmrcnt was already 0 -> may cause errors
               if PIR1_TMR1IF == 1 then        -- pulse counter overflowed
                       cntcnt = cntcnt + 1            -- adding 1
should be faster than adding 65536
                       PIR1_TMR1IF = 0
               end if
       end loop
led = off
cntcnt = cntcnt * 65536                -- sum full overflows
cntcnt = cntcnt + TMR1                -- add leftover from the last cycle
tmrcnt = TMR2

print_string(serial_hw_data, tmrmsg2)
print_dword_dec(serial_hw_data, tmrcnt)
print_crlf(serial_hw_data)
print_string(serial_hw_data, cntmsg2)
print_dword_dec(serial_hw_data, cntcnt)
print_crlf(serial_hw_data)


delay_1s(3) -- some delay
print_crlf(serial_hw_data)

end loop



-- KP

More... (looser matching)
- Last day of these posts
- In 2012 , 2013 only
- Today
- New search...