Counting pulses without hanging code when no pulses are available?
eagletalontim
Posts: 1,399
I am working on reading a vehicle speed sensor that outputs a 5v square wave but have not been able to figure out how to keep the COG from hanging while waiting for a high or low signal if the vehicle is stopped. The only ways that I know how to read frequency is using the waitpeq function, the COUNT function in the BS2_Function, or with the JM_FREQIN function that I think uses the same thing. The problem with the JM_FREQIN function is I cannot call it faster than the frequency... meaning, if I get 1 pulse per second, I cannot call it ever 300ms like I need. The pulses could be anywhere from 1 per 1 second to 400 per 1 second. The waitpeq would do just that... wait. And the COUNT function could miss a few pulses that could make the readings inaccurate. Does anyone have any suggestions on what I could use to accomplish what I am trying to get done?
Comments
There are a variety of objects for capture pulses the poll the pin to see how long it stays in one state of the other. I have four quadrature encoder object that does this (the motor object has a bug but I think the encoder object works fine). I used JonnyMac's Nuts & Volts article as a guide (see column #6). You could use a simplified quadrature encoder type object to do what you want.
I'm sure there are other ways to do this I'm not thinking of, maybe someone else will chime in with some other options.
This is a possible solution.
Have an oscillator generate a steady, say, 5Hz square wave and using an XOR gate.
The tach signal on one input and the 5Hz on the other.
Assuming the tach outputs 0Hz to 400Hz.
The result will be 5Hz to 405Hz.
Once the measurement is made simply subtract 5Hz.
Basically with this scheme you never have no pulses to count.
A possible advantage is the measurement could be done quicker than once per second, possibly 5 per second although the resolution would be lower.
Duane J
-Phil
If there is a way to have a section of code that is only allowed to run for 1 second then "timeout", I could run a code that will count how long it takes to get lets say 3 pulses. If the 3 pulses take longer than 1 second, abort and set speed at 0.
From what I have seen, there would be a total of 16364 pulses per mile. This would mean that if the vehicle were traveling at 1 MPH, there would be 4.54 pulses per second? (16364 pulses / 60 minutes per hour / 60 seconds per minute).
So, is there a way to limit code to run in an allotted time and abort if time runs out?
How clean are those edges ? - Do you have a part number/link ?
As Phil mentioned in #4, you can use a Counter to increment on a Rise or Fall, so run one as a time-counter, and one as a edge-counter, and then check the changes however often you need to.
There is no stall : no sensor edges means the edge count holds, while the Time continues to increase.
Grab AN001 and search for POSEDGE and NEGEDGE
-Phil
Edit: What jmg said. Get the AppNote.
With slow pulses, you can run your own edge detection - you just compare two consecutive samples, and if they differ, then you check for Rising or Falling case, and on the one you want, you Increment a counter.
- but the hardware can do that for you, or are you already using both timers ?
Phil, are the counters you are talking about phsa and phsb? If so, yes they are being uses by the JM_FREQIN function for reading RPM. That function is working 100% perfect currently.
If I used Edge detection, would that not include using waitpeq or waitpne? Those both must wait for a high or low. If there is no change for 10 seconds, they will continue to wait. The problem I see with that is if I am driving 45 mph and slam on my brakes locking them up, the prop would continue to think I am traveling 45mph since the pulses stopped and no variable can be updated.... right?
Duane J
-Phil
I also made a pulse counter for my power logger that i use to track my current power usage. I wonder if it would be similar to what I am needing. Here is the code to the pulse counter for that project :
-Phil
I don't remember what resistors I have in place, but if I remember correctly, I used 2 10k resistors for that circuit. I was attempting to read the pulse generators from the transmission instead of the speed sensor which is apparently a reed switch from my research.
Peter
Mickster
P.S. 1uS is not going to work with Spin but something like 100uS should (right?)
It's no problem to go faster with the cog timing loop and I'm guessing that a cycle time of 10-20 microseconds/loop would be the limit (that's with execution of the pulse finding code and writing to hub RAM). The only caveat is that the duration of the pulse needs to be longer than the clock time - preferably twice as long to guarantee catching the pulse. Obviously your "clock" will overflow a lot faster in the 20 microsecond/loop case. Have you been writing code in Spin or PASM?
You need to create variables in your main program space.
Finally, you can launch the cog:
Easy-peazy.
To update every 200 milliseconds, I could simply change waitcnt(t += clkfreq) to waitcnt(t += clkfreq / 200)?
no. The system variable ClkFreq contains the number of clockticks that occure in one second. At 80 MHz these are 80 Million clockticks.
so waitcnt(t += clkfreq) waits for 80 Mio clockticks (which is one second
if you want to wait for 200 milliseconds. This is 1/5 second and the code is
waitcnt(t += clkfreq / 5)
As you are doing something for a vehicle. Is this project just some additional display or will the vehicle be controlled by this measurement?
Only in case the vehicle is conrolled by this thing:
If it is controlled I highly recommend to become an expert about programming in general and then become an expert about safety-requirements
and fail-safe mechanisms to avoid unexpexted behaviour whenever possible.
Again only in case the vehicle is CONTROLLED by this Huh !! Please can you tell me where and when this vehicle is driving that I can keep away from this area?
best regards Stefan
Top spin program should be HSPID_test and I've thrown in my modified version of Parallax Serial Terminal which had no feature to check for a character and give an indication that there wasn't one until I modified RxCheck to make it public.
The other thing that shocked me immensely is that there's no Go To in Spin!!!!! How can one write code without a branch or jump instruction??
My version of Firefox hangs when I attempt to upload an attachment so will try it from a far faster machine than my laptop.
That's better - opened a folder in <1 second. So enjoy. This program will wait forever for a pulse and time them when they occur. Maybe you can help me figure out the Spin sections of the code.
Also, this fragment - while keeping pin 4 as an input (default) - also sets bits 5 and 2 as outputs (cog location for DataMask is $24). Even with the # removed the muxz would actually set bit 4 as an output. ???
muxz dira, #DataMask should be muxz dira, #DataMask
It was entirely fortuitous that it worked. As soon as I finally saw Polar HR monitor data timed at 2 microsecond precision rolling up the screen, I assumed the program was fine. That error was a lapse into PDP-11 assembler mode. Still getting the hand of Propeller programming even though I've now been at it for a month.
As far as a 2 microsecond pulse coming in as 6 microseconds, I can't see any way of that happening, at least from the software perspective. The worst case execution of the loop, including hub writes, is <2 microseconds. The only way I can see that happening would be if there was enough capacitance on the input pin to stretch the pulse. How far apart were the 2 microsecond pulses spaced?
I'll have another look at the code in the morning to see if there's any other stupid errors there. I just took a chunk out of my Micromedic timer code and ramped up the frequency as far as I could. Hopefully it will be fast enough to reverse engineer what I suspect is an I2C device being driven in a very bizarre manner through a serial port.
And, sigh, you're right about the xor effects on the Z flag. 2 mistakes in 2 assembly instructions must be a new record for me. Updated code is:
xor TState, TState wz 'pulse state var = 0
muxnz dira, DataMask ' set bit4 to input '
Of course, it seems to work the same as the incorrect code and I'm glad you pointed out the errors I made as this coding error would have likely resulted in a very mysterious failure of the code to function if I added more instructions after the existing ones. The detailed Propeller documentation is quite explicit about the setting of the Z flag whereas the short summary sheet is ambiguous. Time to do a large volume printout of the manual.
Both the code with errors and the new code give 7820 as the duration of the Polar HR monitor receiver output pulse (or 15.64 msec). My previous code using a 1 msec timebase would return 14 or 15 msec for the duration of this pulse. Looking at the histogram of pulse widths for the Polar output pulse shows the width to vary by only +/- 2 microseconds.
Thanks again for spotting the errors - a good lesson that if code just happens to pass a quick screening doesn't mean it won't fail in future situations.
Apart from that, when the pulse lasts longer it levels out again. Which is good - in a way - but it's still something which shouldn't happen.