# Thread: Is there a way to count pulses (a steady 120hz) for a changing length of a butt

1. I agree with Jon that the Stamp will be quite accurate in its counting, and the discrepancies you are seeing might be something in your 555 circuit or more likely in our collective misunderstanding of what you want to do.

The existing routine counts for 1/2 of a cycle of your 555 input, whereas it looks to me that you probably want to count for a full cycle.

Here is the existing subroutine:

Count_Pulses:
DO : LOOP UNTIL (Bttn = Pressed)
DO : LOOP UNTIL (Bttn = Released)
DO
IF (Hz = 1) THEN
pCount = pCount + 1
DO : LOOP UNTIL (Hz = 0)
ENDIF
LOOP UNTIL (Bttn = Pressed)
RETURN

It starts counting when the button is "released" and stops counting when it is next "pressed". That is 1/2 cycle. And that may explain why you need 3600/pcount instead of 7200/pcount. Also, since 555 oscillators are usually not symmetrical output, more time in one state than the other, that 3600 would not be right on either, so that might explain your "+10".

To count for the full cycle, you need something more like this:

Count_Pulses:
DO : LOOP UNTIL (Bttn = Pressed)
DO : LOOP UNTIL (Bttn = Released)
DO ' count the + half cycle
IF (Hz = 1) THEN
pCount = pCount + 1
DO : LOOP UNTIL (Hz = 0)
ENDIF
LOOP UNTIL (Bttn = Pressed) ' until + half cycle ends
DO ' then count the - half cycle
IF (Hz = 1) THEN
pCount = pCount + 1
DO : LOOP UNTIL (Hz = 0)
ENDIF
LOOP UNTIL (Bttn = released) ' until it ends
RETURN ' this should give the 7200/pcount=bpm

That will have the effect of waiting until the button is pressed and released, then counting the + half cycle, then the - half cycle. The counting ends when the button is released a second time. The system then waits for the button to be pressed and released again before it starts counting. That is, the alternate program skips every other cycle of your 3hz button input.

I'm puzzled why your experiment yielded such scattered reults. Was that also from the 3hz 555 oscillator, or was it from a real finger pressing a button? The 555 should not bounce. If it is a real pushbutton, you can deal with that using an RC circuit in parallel with the button, or by a software test outside the main counting loop, where it will not limit your counting speed.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com

2. ok. Ran this code to verify HZ

COUNT PulseIn, 1000, countHz
DEBUG ? countHz
END

My results.
Heres my 555 BUTTON simulator.
countHz = 4
countHz = 5
countHz = 5
countHz = 5
countHz = 5
countHz = 5
countHz = 5
I then swapped pins to measure 120hz....
countHz = 120
countHz = 120
countHz = 120
countHz = 120
countHz = 120
countHz = 120
countHz = 120
countHz = 120
countHz = 120
countHz = 119
countHz = 119

I then used this code, file attached.
This is NOT MODIFIED, from you.

My results are this

Press button. Wait. Press again.
Count = 12
BPM = 600

The BPM is double, for 5hz.
5 X 60 = 300. BPM.

So then I changed ONLY ONE THING in the code.
this: bpm = 7200 / pCount
to this: bpm = 3600 / pCount

My results are:

Press button. Wait. Press again.
Count = 12
BPM = 300

If you still say that 7200 is correct. I beg of you to teach me why. I am not being mean here, just learning, trying to understand everything that is being put out here.

3. Tracy Allen said...

The existing routine counts for 1/2 of a cycle of your 555 input, whereas it looks to me that you probably want to count for a full cycle.

It starts counting when the button is "released" and stops counting when it is next "pressed". That is 1/2 cycle. And that may explain why you need 3600/pcount instead of 7200/pcount. Also, since 555 oscillators are usually not symmetrical output, more time in one state than the other, that 3600 would not be right on either, so that might explain your "+10".

That will have the effect of waiting until the button is pressed and released, then counting the + half cycle, then the - half cycle. The counting ends when the button is released a second time. The system then waits for the button to be pressed and released again before it starts counting. That is, the alternate program skips every other cycle of your 3hz button input.

I'm puzzled why your experiment yielded such scattered reults. Was that also from the 3hz 555 oscillator, or was it from a real finger pressing a button? The 555 should not bounce. If it is a real pushbutton, you can deal with that using an RC circuit in parallel with the button, or by a software test outside the main counting loop, where it will not limit your counting speed.
The one that had VERY scattered results was an acutal button. And I will havta deal with the bounce issue in circuit I guess. You say it can be dealt with OUTSIDE the main counting loop.? I would imagine that any software that will deal with my bouncing button, will affect the counting.? Due to the BUTTON command using up time to do its work?

So wait. This program, it only counts from LAST BUTTON RELEASE to NEXT BUTTON PRESS?
So I am acutally loosing some timing in there.?
If I need to count every hz, then I need to reprogram it to count from LAST BUTTON RELEASE to NEXT BUTTON RELEASE right? Or is that what you had just said? LOL.. and gave me the program for... heh...

Post Edited (BPM) : 6/28/2005 5:15:49 AM GMT

4. after reading your code, and message a few more times, you did say that. GREAT! so thats why I was all wack! I didn't realize the code wasn't counting for the full cycle button release to button release. (I am not that good at understanding programs yet)

I do havta say, after being "all about hardware" I am pushed into the software realm without the EDGE that is associated with learning a language.
I love it, what a great way to help teach microprocessors and programming.

5. I tried out your code tracy, and it works without me changing the 7200. GREAT, (now I get to compare the two codes and learn exactly what is going on between them heh)

I thank you very much for all your help, you too Jon!

I have attached the working code.

Heres my results after a bit more design tweaking.
I raised the HZ to 240. Hoping for a bit more accuracy on counting. Not sure if it will help.
And obviously I changed the divisor to 14400.
I know I still need a debouncer...

BPM = 123
BPM = 129
BPM = 124
BPM = 126
BPM = 133
BPM = 129
BPM = 128
BPM = 133
BPM = 123
BPM = 129
BPM = 124
BPM = 127
BPM = 127
BPM = 124
BPM = 128
BPM = 120
BPM = 126
BPM = 119
BPM = 125
BPM = 129
BPM = 128
BPM = 127
BPM = 126
BPM = 125
BPM = 138
BPM = 129

But thats pretty good!

I am guessing my target bpm was 128.
Testing this with a steady, 4hz signal, resulted in the following.
The average being 240. :)
BPM = 240
BPM = 236
BPM = 236
BPM = 244
BPM = 240
BPM = 240
BPM = 236
BPM = 236
BPM = 236
BPM = 244
BPM = 240
BPM = 236
BPM = 240
BPM = 240
BPM = 240
BPM = 244
BPM = 240
BPM = 240
BPM = 240
BPM = 236
BPM = 236
BPM = 236
BPM = 244
BPM = 240
BPM = 240
BPM = 240
BPM = 240
BPM = 236
BPM = 240
BPM = 240

6. Now mabee I should actually build the BO-BOT, I have the kit... Just didn't do it. Heh, I had other evil plans in mind for my stamp2 (like a BPM tool)

7. I would like to continue on the BPM, but the next step i think is to debounce the button. and I need an external circuit for that?
Then I need to display the bpm (external circuit)
etc.. I must wait for my stuff to get here.
Then comes the issue of me only having a BS2.
My external circuits prolly require some elaborate subroutine to communicate to them. Untill the parts get here I guess I can't do much.

8. I searched for PCF8483 on BOTH mouser.com and digikey and NO parts were found that describe some kind of counter.

digikey showed me a 0.027µF capacitor when searching on "PCF 8483"
and nothing when searching on "PCF8483"

mouser showed 4 semiconductor results...
two were RS-485/422 Interface ICs
one was a 4-BIT BIN FULL ADDER
and the other was a Driver IC.

The ever elusive PCF8483 hunt continues!

could I debounce with SCHMITT TRIGGER LOGIC?
Or some other way?

9. The part mentioned was pcf8583.

regards peter

10. Thanks for the corrected part #

11. Can you define for me what you mean by beats-per-minute?· When I run your code I get exactly double what I think I should, though looking at you code the results are correct (though not matching my input).
If I press the button every six seconds is this not 10 beats per minute?· When I run your code as is I get 20 if there is six seconds between button presses.
There will be a treshold where the instruction cycle won't be able to keep up with your input; I'd suggest that 120 Hz is probably pretty close to it in high-level PBASIC.· Of course, if you port this over to the SX using SX/B then it's a different story ... though SX/B does not offer th convenience of 16-bit math.

BPM said...
I tried out your code tracy, and it works without me changing the 7200. GREAT, (now I get to compare the two codes and learn exactly what is going on between them heh)

I thank you very much for all your help, you too Jon!

I have attached the working code.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

12. Yeh, counting for 6 seconds with an input of 240 hz should yield 6*240=1440 counts. And 14400/1440 = 10 beats per minute. I don't see offhand where the discrepancy lies in the setup wrt BPM's result.

I think the limit for count frequency with this routine may go as high as 300 hertz even with a BS2.
There is still some optimization that could be applied. For example, the statement
LOOP UNTIL (startBtn=pressed) ' pressed defined as =0
is within the loop and the loop will run significantly faster with
LOOP WHILE startBtn ' loop while startBtn=1, using WHILE construct and leaving off the =
Less transparent for self documentation, granted, but faster.
If I get a chance I'll run a little test to compare techniques, how fast they can go.

BPM could get an extra decimal point in the result, using the formula,
BPM = 14400/pcount *10 + (14400//pcount * 10 / pcount)
debug dec BPM/10,".",dec1 BPM

that gives one extra decimal point over simply
BPM = 14400/pcount
e.g., 10.3 BPM instead of 10.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com

13. I misse the part where he changed to 240 Hz...· I think I'll bow out of this thread; I don't seem to be smart enough to understand what's wanted or contribute anything useful.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

14. Please don't bow out, Jon . No one here will ever attribute to you a lack of smarts! Quite quite the contrary. The problem goal under consideration is ambiguous and developing, so there is a lot of second guessing going on.

I did test the attached program, which has three possible methods around a #SELECT#CASE directive. It counts square wave on p0 during a 1 second interval that p1 is high. (The p1 1 second high gating signal is generated by a second Stamp, and the p0 frequency input to be counted is generated by an Extech process calibrator.)

Method 1: The BS2pe counted without error up to 400 hertz but failed at 480 hertz. On a BS2p, it counted up to 800 hertz, but failed at 1200. (The Extech calibrater has only discrete steps, with nothing between 400 and 480 nor between 800 and 1200).

Method 2: This is code optimized method 1, using the LOOP WHILE startBtn instead of LOOP UNTIL (startBtn=pressed) within the main loop. On a BS2pe that could count up to 800 hertz without error and on a BS2p up to 1200 hertz.

Method 3: This is the code using XOR bit manipulation I posted earlier, but with the same optimization as method 2. On the BS2pe it counted ccorrectly up to 400 hertz, and on a BS2p, ujp to 800 hertz. So it is indeed slower than Jon's approach with the IF-THEN logic. I still like this method, because it is less modal, and thus easier to add additional parallel processing.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com

15. Jon Williams (Parallax) said...
I misse the part where he changed to 240 Hz... I think I'll bow out of this thread; I don't seem to be smart enough to understand what's wanted or contribute anything useful.

LOL you not smart?

The problem is, I am constantly changing my parameters and requirements. And I am asking multiple questions one after another.
I am being very confusing, and I appologise for it.

For instance, I am learning how to drive a dual 7seg display using a 74LS47. (stamp2 ----> BCD(with common anode lines) -----> 74ls47 ----> 7segment)
I have searched and found your code

Code:
```Pins = decVal / 10 * 16
Pins = decVal // 10 | Pins```

I still dont understand what the HECK this says. LOL. But I am searching the help and slowly putting it together.
:)

16. To start with, that code you reference is for the BS1 (I can tell because PINS is a BS1 reserved word).· But let me see if I can explain because you can sustitute OUTH (P8..P15) on the BS2, like this:

OUTD = decVal / 10
OUTC = decVal // 10

The first line divides decVal by 10, so the 10s digit gets output to OUTD (P12..P15, which would connect to your 74LS47 pins A..D).· The second line uses the modulus (//) operator which returns the remainder of a division.· Let's say that decVal is 25: 25 dvidied by 10 is 2, with 5 left over (remainder).· So 5 (%0101) would be output OUTC (P8..P11).

That said, it's actually easier with the BS2's DIG opertor -- it returns the digit in the specific position of a number.· So you can do this:

OUTD = bpm DIG 1··· ' get 10s (101) digit
OUTC = bpm DIG 0··· ' get 1s (100)·digit

But didn't you say somewhere you wanted three digits?· If yes and you can squeeze your Hz input and button(s) into P0..P3, then you can use the OUTB, OUTC, and OUTD pin groups like this:

OUTD = bpm DIG 2··· ' get 100s (102)·digit
OUTC = bpm DIG 1··· ' get 10s (101) digit
OUTB = bpm DIG 0··· ' get 1s (100)·digit

Make sense?

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

17. GREAT it makes 100% sense!

I can see where having an I2C device to decode the digits comes in handy now. Just 3 digits and I am already using 75% of my out pins.

If I have digit displays that have common anodes, couldn't I use the same 4 out pins for all 3 digits(74ls47 inputs), and then just use 3 more pins to BLANK the other digits, then flashing the digit that I am sending to my output?

So, send number to all 3 74ls47's, but two of the 47's keep BLANK on. And the other 47 turn it off.
And so on for the other two digits.

OUTB = bpm DIG getDig ' get digit 0, 1, 2 (i would use a, For getDig = 0 to 3)
OUTC = blank DIG blankDig 'get blank mode of 3 digits, 000, or 111. But if I do this, it will convert the digit to BCD, So I need to figure out which BCD numbers will send the proper blank signals. Easy...

This way I am still using alot, but now 7 pins for 3 digits. I am sure theres some catch to doing this tho, and look forward to your reply! :)

18. To share the outputs with multiple 47s you end up multiplexing -- not easy to do in PBASIC and the results will not be satisfying. I would use three 74HC595 output shift registers that are daisy-chained. With three pins and a few lines of code you would end up with 24 additional digital outputs, enough to handle your 7-segment·displays without worry.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Jon Williams
Applications Engineer, Parallax

19. Tell me what you think of this. It works really good. It uses 1 - 74ls47. And 3 transistors. (1 for each common anode).
To add any number of digits, only requires 1 additional line per digit. (so 1 transistor, and one pinout per digit)

Using this method, you could drive up to 12 digits? (with no leftover pins)
I don't have any artifacts or shadow in any of my digits AT ALL! (in total darkness)
To blank each digit, I cut off the power to the digit using the transistor.

Actually I am amazed at how easy it is to add more digits.

But at the same time, this 3 digit 7-segment BCD out display takes up 7 pins.

Code:
```' {\$STAMP BS2}
' {\$PBASIC 2.5}

number    VAR    Word
digit     VAR    Word

DIRS = %1111111

Main:

number = 159

DO
FOR digit = 0 TO 2
SELECT digit

CASE 0
OUTB = 000                 ' blank all displays
OUTA = number DIG digit    ' load 1's digit in 74ls47
OUTB = 001                 ' turn on 1's display.

CASE 1
OUTB = 000                 ' blank all displays
OUTA = number DIG digit    ' load 10's digit in 74ls47
OUTB = 010                 ' turn on 10's display.

CASE 2
OUTB = 000                 ' blank all displays
OUTA = number DIG digit    ' load 100's digit in 74ls47
OUTB = 100                 ' turn on 100's display.

ENDSELECT
NEXT
LOOP```

Obviously this method isn't efficient, or pin conserving, but it has taught me alot about displaying digits.

20. I am sure your laughing at that....
Its definely not efficient. uhhh dont ask why I included all that select case crap.. LOL

This works exactly the same

Code:
```Display_Digits:

OUTA = bpm DIG 0           ' load 1's digit in 74ls47
OUTB = 001                 ' turn on 1's display.
PAUSE 1                    ' let em burn!
OUTB = 000                 ' blank all displays

OUTA = bpm DIG 1           ' load 10's digit in 74ls47
OUTB = 010                 ' turn on 10's display.
PAUSE 1                    ' let em burn!
OUTB = 000                 ' blank all displays

OUTA = bpm DIG 2           ' load 100's digit in 74ls47
OUTB = 100                 ' turn on 100's display.
PAUSE 1                    ' let em burn!
OUTB = 000                 ' blank all displays

RETURN```