View previous topic :: View next topic |
Author |
Message |
iso9001
Joined: 02 Dec 2003 Posts: 262
|
Timing and Ouput Question (need code help) |
Posted: Tue Dec 16, 2003 4:18 am |
|
|
I have this digital hall effect sensor that is hooked up to a processor that reads the pulses of a rotating shaft. I changed the shaft size and number of gears on this shaft and now the processor gets the wrong rpm of the shaft. I need to make this processor think i'm still using the old shaft...
Problem is the Signal wire on the sensor is getting 5V *FROM* the processor and not the other way around (sensor sending out low pulses). It looks to be that the processor is monitoring the 5V its sending out, whenever a gear tooth goes by it grounds out the signal wire, the processor sees this, and thus knows counts that gear
Anyone have any ideas on how to do this for all freqs from 0-2000Hz...
The only thing I have right now is:
Code: |
...do other things
while(1) {
delay_us(half_of_freq);
output_low(PIN_XX); //(ground the pin)
delay_us(half_of_freq);
output_float(PIN_XX);
}
// i THINK this is what float does, replace w/ high if needed
|
Serious problem is that I have OTHER things this chip has to do as well as the hall sensor fooling. Is this a job for interupts? Its not important if the other pieces of code get slightly interupted.
Any Ideas ?
edit: I just realized I have to read the lows on this signal at 2khz (max) and repeatedly ground out a pin at 5kHz max... At the same time... I'm losing faith that I can do this fast enough...
btw: What happends when you have 2 interupts occur at the exact same time ? is there a buffer or does one not get reconized ? |
|
|
rwyoung
Joined: 12 Nov 2003 Posts: 563 Location: Lawrence, KS USA
|
|
Posted: Tue Dec 16, 2003 9:01 am |
|
|
Most 3-wire hall-effect sensors are VDD, SIGNAL and GROUND.
VDD is your system's VDD (typically +5V but depending on the sensor some will work down to +2.5V and lower). Same as the PIC is using.
SIGNAL is the output from the sensing element inside the package. This could be a latched line or a simple open-collector output. You mention that you are watching gear teeth on a shaft so I'm assuming this isn't a latching sensor. Put a pull-up resistor of at least 10K from SIGNAL to VDD. Depending on the electrical noise your system will encounter you can probably use a higher value to reduce current consumption but start with a 10K.
GROUND is your digital ground, same as the PIC is using.
Sometimes these pulses are pretty sloppy with slow edges or multiple small transitions on the edge as it rises or falls. It is a good idea to buffer the signal with a gate with lots of hysteresis like a 74HC14. Most of the PICs input pins have hystresis built it so that may not be necessary.
I would use the CCP1 or CCP2 input to read the pulse. You would configure the CCP1 or CCP2 interrupt for edge trigger. Also you need to configure your TIMER1 to run at some reasonably high speed all the time. The speed needs to be high enough to get you the resolution you need but not so high as to overflow more than once between pulses. If you are trying to use TIMER1 for other things in your system, compromises will be necessary.
Some sample code (snipped from another project so I won't guarantee that I didn't forget to copy a line or that it will work at all for you)
I was using a PIC16F73A and several interrupts. The #priority line helped me minimize problems. You can miss interrupts, so since the signal I was using to drive the external interrupt and CCP1 were the most important to me, they were first. Incoming RS232 data and the internal ADC were the least important so they are last.
Code: |
#priority EXT, CCP1, CCP2, RDA, AD
// declared as global data
unsigned int16 pulses; // Hall-Effect sensor input counter
unsigned int16 oldccp2; // last read of CCP_2 register
// these belong in your initialization routine:
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); // 333.3ns resolution (12MHz xtal)
setup_ccp2(CCP_CAPTURE_RE); // interrupt on rising edge
pulses = 0;
oldccp2 = 0;
enable_interrupts(INT_CCP2); // interrupt on CCP2 rising edge
enable_interrupts(global);
//
#int_CCP2
CCP2_isr()
{
pulses = CCP_2 - oldccp2;
oldccp2 = CCP_2;
}
|
Now each count of "pulses" is worth 333.33ns because my xtal frequency was 12MHz and I'm letting TIMER1 run full speed (12MHz = 83.33ns period & TIMER1 maximum speed is 4 times the crystal period - that pesky data sheet again) With a 1MHz external osc you would have 4us resolution at maximum timer frequency. But don't expect to be able to reliably measure a 250kHz output. What would be more reasonable as an upper limit would be 2.5kHz. There your 4us is worth about 1%.
In your code you now have a value for pulses that is updating in the background without requiring you to do anything.
Like I said above, I've cut out lots of other code so there are no sanity tests of "pulses", my system was only working with a very limited range of expected pulse periods. Also I didn't show filtering code that took out some of the jitter in my "pulses" value. An excercise left for the reader but there have been lots of old posts in the forum about simple digital filtering tricks. _________________ Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month! |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Dec 16, 2003 9:22 am |
|
|
How much are you trying to change the orginal signal by? I assume that this is a fixed rate and that you are just trying to compensate for changing a gear or something. |
|
|
iso9001
Joined: 02 Dec 2003 Posts: 262
|
|
Posted: Tue Dec 16, 2003 12:04 pm |
|
|
Rob I havn't even gotten a chance yet to really read your post yet,
Mark, its a VERY Variable rate. I need to be reading in a 0-2000Hz signal and sending out a (~) 0-5000Hz signal.
Problem I see is that I nee to be gounding the signal out quick to simulate a pulse... That along with the other things I have going on here... Well, I'm starting to get worried its going to skip interupts or be so busy counting them that it will miss when someone presses a button or such.
I'm going to do some more testing then get back on here. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Tue Dec 16, 2003 1:00 pm |
|
|
So are you saying that you are doing a 2.5x multiplier?
Something like if the input is:
0 then output is 0
1Hz then output is 2.5Hz
500Hz then output is 1.25KHz
1KHz then output is 2.5KHz
ect.. |
|
|
iso9001
Joined: 02 Dec 2003 Posts: 262
|
|
Posted: Tue Dec 16, 2003 2:38 pm |
|
|
Mark,
Almost... Its not going to be 2.5x... but I'm certain it will be a linear coefficient. I think I went from ~100 small gears to 4 large ones... Maybe somthing like 25.8543x or whatnot...
(I know, my REAL values are from 0-500 in and 0-5000 out, I figure if I can read 2000 in AND output 5000 at the same time I'de be more then happy)
I found that the % of the 'wave' (remember I'm really just grounding short intervals to simulate a hall effect sensor) is like 49%. But I found that it doesnt matter to me at all. The only thing I care about is make the freq of the grounds even to what the processor is expecting...
I've never worked with interupts, but I read a little about em and saw that there is a L_to_H that would work well to count the pulses from the original sensor. That priority thing is cool. ButI'm not sure how to temporary gound a pin every X seconds to make a 'proper' freq. Not sure how to use the RTCC/Timer0 interupt
All that PLUS monitor for two switches and when either become active send output to a pin. Which if needed, can be delayed for a few ticks |
|
|
iso9001
Joined: 02 Dec 2003 Posts: 262
|
|
Posted: Tue Dec 16, 2003 11:16 pm |
|
|
rwyoung just got done reading your post... not understnading fully yet... but working on it.
I tested my gounding out w/o interupts and it worked. I got the rotations to read various values by changing the delay_us...
Now to work on the interupts.
I figured I'll need one interupt happening every .250seconds (or so) that is always counting *unique* low pulses. Then after every .250 I take that total number, multiply by my coeff. and then output THAT using an interupt that is based off a timer, but the time it delays the pulses (ie: setting the freq) will change every .250 seconds... get ?
Why am I going to need filtering??? I've got a pretty reliable hall sensor, a pic that will only count on the L_to_H event (no double counting the same pulse)... Where does it get messed up ? |
|
|
rwyoung
Joined: 12 Nov 2003 Posts: 563 Location: Lawrence, KS USA
|
|
Posted: Wed Dec 17, 2003 7:33 am |
|
|
iso9001 wrote: | Why am I going to need filtering??? I've got a pretty reliable hall sensor, a pic that will only count on the L_to_H event (no double counting the same pulse)... Where does it get messed up ? |
You may not need to filter but I have implemented it in the past.
The microprocessor has its own clock and everything it does is synchronous to that clock. Interrupts from the outside world are usually asynchronous to the clock.
I could have a counting resolution of 250ns in my microcontroller but an interrupt that happens at 3.333us or some number that is not an even multiple of my counting resolution. That means that one time I might get a count of 13 and maybe the next time I get a count of 14.
If I set up my code to average for filter several counts and I kept bobbling between 13 & 14 counts I might get the equivalent of 13.5 counts out of my filter. Actually for my example of 250ns and 3.333us I'd probably get one count of 14 for every 2 times I read 13. (13+13+14)/3 = 13.33 counts.
This was in a motor controller where I was reading shaft speed from a hall-effect sensor. Using a PID (Proportional, Integral, Differential) control scheme it naturally filters the sensing data. The result is a smoother transition between speeds and the code wasn't trying to make major changes to the motor speed with each control cycle. That makes for a jerky and sometimes noisy control.
In your system, only if there are runt pulses from the hall-effect sensor that aren't stopped by the hysteresis of the PIC input pin would I begin to worry about filtering in the analog sense. If you can't get enough resolution and you can tolerate the longer time to calculate speed then you can filter the digital data.
Now that you are completely confused, don't worry about implementing any filtering in your pulse counting interrupt. The best thing you can do for your design is start with a simple drawing and flowchart made with pencil and paper. Doing a lot of ad-hoc design and trying to understand every response you get here will probably waste more time than you save. The best thing I can tell you is apply the KISS principle. _________________ Rob Young
The Screw-Up Fairy may just visit you but he has crashed on my couch for the last month! |
|
|
iso9001
Joined: 02 Dec 2003 Posts: 262
|
|
Posted: Wed Dec 17, 2003 9:48 pm |
|
|
rwyoung, no man, that all pretty perfect sense. It didnt untill i read the runt pulses part, that cleared it up.
I tried looking for interupt code emaples today and it didnt go so well...
I know i'l need one to count pulses, but I also need one to... um how should I say this, make another interupt to make a variable timed interupt or um... So:
////////////////////////////////////////////////////////////////////////////
Lets say my new gear is turning at 200Hz, where the original gear would be at 5000 (ie: the old gear had 25 teeth on it, new one has 4 large ones)
I know I will need one interupt to read in when X signal is grounded... so thats H_to_L... That will be my hall sensor reader, I'l need it to count pulses++ at each unique low. easy-ish.
My plan then is to have another interupt timed, lets say somthing like every 1 second (not a reletivly fast value or anything)... This interupt takes 'pulses', times my coefficient (25.0 or so) then modifies the next interupt which is...
This last one actually takes the final_pulses number and spaces it over an equall time that is 'set' by the middle interupt. (ie: That middle interupt sees 10pulses times 25 == 2500 then sets this interupt be on a timer of whatever it takes to evenly space out 2500 pusles
Does that make sense to anyone? Is there a better way to do this? If this will work my next problem is that this is the code i have so far:
Code: |
ENABLE_INTERRUPTS(INT_EXT, INT_TIMER1, INT_TIMER2);
EXT_INT_EDGE(H_TO_L);
|
|
|
|
iso9001
Joined: 02 Dec 2003 Posts: 262
|
Ok, I got a BIT more... |
Posted: Wed Dec 17, 2003 11:48 pm |
|
|
I've been reading a ton of old forum stuff and making really slow progress. But maybe this will make it easier to get help on.
It looks like there is one ext. interupt pin (B0 on the 16F872), I thats cool I think I only need one thing to be monitored w/ an interupt.
(all written for a 1 Mhz clock... its all i got right now)
Code: |
void main() {
enable_interrupts(INT_EXT);
ext_int_edge( H_TO_L );
enable_interrupts(INT_TIMER1);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
set_timer0(7812);
//0.000016 * 8 = 0.000128 s
// 1/T1 == 7812.5
...
|
Code: |
//This is supposed to count when a gear goes by
//I'm not sure what edge_detect_isr() is, where
//is that defined? Or can I name that anything ?
#int_ext
edge_detect_isr() {
pulses++;
} |
Code: |
#int_TIMER1
TIMER1_isr() {
<do somthing here to reset my fake/modified hall sensor output>
}
}
//This should reset my output every 1 sec
//I'm not sure exactly how to go about spacing
//out the pulses as output evenly over the sample
//period (in my code example - 1 second)
//remember the code 'shouldnt' have any delays
//anytime i spend delaying is time I'm not checking
//or monitoring other things in the code (minor stuff)
|
Is ANY of this kinda right ? |
|
|
iso9001
Joined: 02 Dec 2003 Posts: 262
|
hello ? |
Posted: Sat Dec 20, 2003 1:02 am |
|
|
I'm not having much luck really understanding interupts... I got my code to kinda work, but i know it doesnt work right, but I cant follow where i goes wrong.
Is what I have kind-of-sort-of-somwhat right ??? Is there any sites I could read about interups in C for PIC ??? |
|
|
|