Log in

View Full Version : encoder vs. motor


stephenthe1
09-12-2004, 15:38
I have a robot with a mechanical encoder attatched to an arm with a motor to lift the arm.

the encoder is at 50 resolution
the arm motor is attatched to pwm_02
the encoder is attatched to rc_dig_in06
I calculated that the encoder will "click" or turn on and off 10.7 times for the distance I need.(the encoder is 50 resolution).

basically I need the source so the motor attatched to pwm_02 will stop once the encoder "ticks" 10.7 (or eleven) times. Please keep it simple. I don't have time to go through a tutorial right now. thank you so much for the help.

oh yeah, it would be nice If I could have the arm lift at the touch of a trigger on a joystick attatched to p1_sw_trig. and have the arm go back down at the touch of the trigger again. does the operator interface controller provide a way to simply shut everything down immediately in the event of a disaster?
please help.
thanks,
Stephen

Mike Betts
09-12-2004, 15:52
Stephen,

I think it would be best for you to attempt to write this code yourself. It is very simple (count to 11)...

If you post your code, I'm sure that one of us will critique it for you before you load it into a robot.

Regards,

Mike

stephenthe1
09-12-2004, 15:54
can you look at this and tell me if you see any errors.


//the encoder is at 50 resolution
//the arm motor is attatched to pwm_02
//the encoder is attatched to rc_dig_in06
unsigned int encoder;
if (p2_sw_trig == 1)
pwm_02 = 220;
if (rc_dig_in06 == 1)
encoder = encoder + 1;
if (encoder == 11)
pwm_02 = 128;

Mark McLeod
09-12-2004, 16:04
can you look at this and tell me if you see any errors.


//the encoder is at 50 resolution
//the arm motor is attatched to pwm_02
//the encoder is attatched to rc_dig_in06
unsigned int encoder;
if (p2_sw_trig == 1)
pwm_02 = 220;
if (rc_dig_in06 == 1)
encoder = encoder + 1;
if (encoder == 11)
pwm_02 = 128;
Couple of problems, such as,
"encoder" needs to be static or a global, so it retains it's value from call to call.
The check on rc_dig_in06 will increment "encoder" more often than every "tick"
"encoder" might shoot right past 11 and keep going.

But first what model encoder are you using?

seanwitte
09-12-2004, 16:05
can you look at this and tell me if you see any errors.


//the encoder is at 50 resolution
//the arm motor is attatched to pwm_02
//the encoder is attatched to rc_dig_in06
unsigned int encoder;
if (p2_sw_trig == 1)
pwm_02 = 220;
if (rc_dig_in06 == 1)
encoder = encoder + 1;
if (encoder == 11)
pwm_02 = 128;


You only want to increment the encoder variable when rc_dig_in06 goes from 0-1 or from 1-0 (pick one). So you need to keep track of the previous value and the current value, then increment only when when it changes.

Mike Betts
09-12-2004, 16:05
can you look at this and tell me if you see any errors.


//the encoder is at 50 resolution
//the arm motor is attatched to pwm_02
//the encoder is attatched to rc_dig_in06
unsigned int encoder;
if (p2_sw_trig == 1)
pwm_02 = 220;
if (rc_dig_in06 == 1)
encoder = encoder + 1;
if (encoder == 11)
pwm_02 = 128;


Stephen,

A good start.

First of all, you have not initialized your counter (maybe this is done in your actual code... I don't know).

Second, what happens the next time through the loop? I'm assuming that you will want to perform this maneuver again and again (once again, I may be mistaken). For now, I will assume that this is a one shot deal...

Here is what I think will happen: When the encoder hits 11, the arm is turned off but the encoder micro-switch is still "closed". The count will increase to 12 and the arm will continue to travel. You might want the last test to be "encoder > 11"...

Does this make sense to you?

stephenthe1
09-12-2004, 16:23
we tried to keep the motor speed down so the encoder will read each tick before the program refreshes. so the motor doesn't "beat" the program before it reads the encoder.

//the encoder is at 50 resolution
//the arm motor is attatched to pwm_02
//the encoder is attatched to rc_dig_in06
static unsigned int encoder;
static unsigned int pressedornot;
if (p1_sw_trig == 1)
{
if (encoder <= 10)
{
pwm_02 = 150;
if (rc_dig_in06 == 1)
{
encoder = encoder + 1;
if (encoder > 10)
{
pwm_02 = 127;
}
}
}
}

Mark McLeod
09-12-2004, 16:37
Could work.

You still need to initialize "static unsigned int encoder= 0;" as Mike mentioned.

I still think you're going to count each encoder tick more than once and your arm will end up short of the expected position.

( I have to pickup my daughter and will check back later)

Mike Betts
09-12-2004, 16:51
we tried to keep the motor speed down so the encoder will read each tick before the program refreshes. so the motor doesn't "beat" the program before it reads the encoder.

//the encoder is at 50 resolution
//the arm motor is attatched to pwm_02
//the encoder is attatched to rc_dig_in06
static unsigned int encoder;
static unsigned int pressedornot;
if (p1_sw_trig == 1)
{
if (encoder <= 10)
{
pwm_02 = 150;
if (rc_dig_in06 == 1)
{
encoder = encoder + 1;
if (encoder > 10)
{
pwm_02 = 127;
}
}
}
}

Stephen,

You can see I attempted to reformat your code to make it more readable. Now you can see how your code nests...

I agree with Mark. I'm not worried about you missing an encoder ping but rather that you will get multiple hits at one ping.

You should consider implementing a state machine. Do you have a mentor on your team (what team are you with anyway?) who can teach you what a state machine is?

stephenthe1
09-12-2004, 18:51
thanks for the help and tips. I'll have to look into state machines. Today I was in a kind of hurry (which was probably obvious). but now I've got more time to think things through. Our team doesn't really have any mentors for programming. We never have, last year we had a wiz kid, and this year its kinda up to me and another guy. neither of us have much experience. I programmed with c#, but that was with Windows, which tends to behave much differently than a robot :yikes: . our team number is, I'm not sure. we're team "lugnut" though, from Ohio.

stephenthe1
09-12-2004, 18:54
Could work.

You still need to initialize "static unsigned int encoder= 0;" as Mike mentioned.

I still think you're going to count each encoder tick more than once and your arm will end up short of the expected position.

( I have to pickup my daughter and will check back later)
if I initialize it as zero, won't the program simply reset encoder to zero every time it rereads the code?

Mark McLeod
09-12-2004, 18:55
Our team doesn't really have any mentors for programming. We never have, last year we had a wiz kid, and this year its kinda up to me and another guy. neither of us have much experience. We'll be your mentors.;) There are quite a few of us to help you out.

if I initialize it as zero, won't the program simply reset encoder to zero every time it rereads the code?
That declaration only takes effect when the program starts. The use of "static" fixes it permanently in memory and that line will not get executed each time the routine is called. Without the "static" the variable would get initialized each time the routine is called.

stephenthe1
09-12-2004, 18:56
lol. great! yeah, this chiefdelphi site has been an awesome help.
well, the encoder is an EC202AXXX (with 50 resolution)

stephenthe1
09-12-2004, 19:33
so like with this code


//the encoder is at 50 resolution
//the arm motor is attatched to pwm_02
//the encoder is attatched to rc_dig_in06
static unsigned int encoder = 0;
if (p1_sw_trig == 1)
{
if (encoder <= 10)
{
pwm_02 = 254;
if (rc_dig_in06 == 1)
{
encoder = encoder + 1;
if (encoder > 10)
{
pwm_02 = 127;
}
}
}
}


I assigned a value of zero to encoder, however, every time the code is reread (every 30 milliseconds or something?), the value for encoder will be set back to zero, making its function useless. wish there was a way to make it so the thing didn't reread the code every amount of time, but rather go over it once and remember everything, and do everything from there. that's the way it is in most programming languages isn't it. anyway, do you see what I mean? or will it only assign the value of zero to it once and then when it reanalyzes the code, it will use the last assigned value. I don't think it works that way though.

Mike Betts
09-12-2004, 19:35
lol. great! yeah, this chiefdelphi site has been an awesome help.
well, the encoder is an EC202AXXX (with 50 resolution)

Steve,

What you have is not a mechanical encoder. It is an optical encoder made by CUI.

Here is a spec sheet: EC202A050A2(S or T)D (http://rocky.digikey.com/WebLib/CUI%20Inc/Web%20data/EC202AxxxA2xD.pdf). As you can see, it comes in two flavors a horizontal or vertical mount.

More importantly, it has a quadrature output so that you can determine direction in your code.

Team 177 used a very similar device last year. I very, very strongly suggest that you download Kevin Watson's example code for optical encoders at http://kevin.org/frc/ and download the file edu_encoder.zip open it up and examine his code very carefully.

What Kevin did is for the edubot. You will have to do the same stuff to the RC code. However, over 50% of the work has been done for you.

It works like a charm. Trust me...

stephenthe1
09-12-2004, 19:38
Steve,

What you have is not a mechanical encoder. It is an optical encoder made by CUI.

Here is a spec sheet: EC202A050A2(S or T)D (http://rocky.digikey.com/WebLib/CUI%20Inc/Web%20data/EC202AxxxA2xD.pdf). As you can see, it comes in two flavors a horizontal or vertical mount.

More importantly, it has a quadrature output so that you can determine direction in your code.

Team 177 used a very similar device last year. I very, very strongly suggest that you download Kevin Watson's example code for optical encoders at http://kevin.org/frc/ and download the file edu_encoder.zip open it up and examine his code very carefully.

What Kevin did is for the edubot. You will have to do the same stuff to the RC code. However, over 50% of the work has been done for you.

It works like a charm. Trust me...
sweet. what a relief.

Mike Betts
09-12-2004, 19:41
Postscript:

Go to Optical Encoder Tutorial (http://zone.ni.com/devzone/conceptd.nsf/webmain/6E536D908B8D21B886256E62006E936A?opendocument&node=14330_US) and read the sections "Introduction To Encoders" and "Technical Overview".

I'm sure you will have questions... Post 'em here...

Mark McLeod
09-12-2004, 21:03
Continue in the direction Mike is sending you. I just want to address some of the previous outstanding questions.


I assigned a value of zero to encoder, however, every time the code is reread (every 30 milliseconds or something?), the value for encoder will be set back to zero, making its function useless. wish there was a way to make it so the thing didn't reread the code every amount of time, but rather go over it once and remember everything, and do everything from there. that's the way it is in most programming languages isn't it. anyway, do you see what I mean? or will it only assign the value of zero to it once and then when it reanalyzes the code, it will use the last assigned value. I don't think it works that way though.That is the way "static" works.

The statement “static unsigned int encoder = 0;” will only take effect at compile time, not while the code is running. It sort of nails the variable in place and sets it’s initial value only once.
The statement “unsigned int encoder = 0;” will take effect while the code is running. Every time the routine is entered the variable encoder will be “created” and assigned the value of 0.

Referring back to Sean’s comment earlier about only counting rc_dig_06 when it changes, not every pass through the code that it happens to equal 1…
The following is an example of only counting changes in rc_dig_06. This particular method actually doubles the resolution of your encoder as it counts both when it changes to 1 and when it changes to 0.


static char toggle=1; // Start as TRUE

if (toggle == rc_dig_in06) // Encoder has changed
{
toggle = !toggle;
encoder = encoder + 1;
}
This method that we’ve been discussing is called polling the input and works fine for slow changes like your arm movement. If the changes occur faster, such as an encoder on a wheel or motor shaft, then you should use interrupts. Interrupts basically are like a good poke in the controller whenever the encoder state changes, and will be discussed in Kevin’s paper.

Kevin Watson
10-12-2004, 01:35
Here is a spec sheet: EC202A050A2(S or T)D (http://rocky.digikey.com/WebLib/CUI%20Inc/Web%20data/EC202AxxxA2xD.pdf). As you can see, it comes in two flavors a horizontal or vertical mount.

More importantly, it has a quadrature output so that you can determine direction in your code.
Yes, this looks like a nice encoder.


Team 177 used a very similar device last year. I very, very strongly suggest that you download Kevin Watson's example code for optical encoders at http://kevin.org/frc/ and download the file edu_encoder.zip open it up and examine his code very carefully.
As the company that hosts my web server decided to change the IP on me, you may or may not be able to get a copy of the code at this time. It should start working soon as I just updated the DNS record on my end. If you need the code in the mean time, feel free to drop me a note and I'll send it to you.


What Kevin did is for the edubot. You will have to do the same stuff to the RC code. However, over 50% of the work has been done for you.
Yeah, I've been a real knuckle-head for not modifying the EDU-RC code to run on the FRC-RC. It's been on my to-do list for some time, but I just haven't had the time. I will, however, get it done before the kick-off.

-Kevin

Mr. Lim
10-12-2004, 02:36
I also highly recommend Kevin's code.

We used it on our FRC last year and it worked PERFECTLY. We also used it with a relatively low-resolution encoder, about 64 ticks per revolution.

Some advantages:
- Uses interrupts, so that you don't have to worry about missing your encoder ticks.
- Reads two quadrature outputs, so that you can detect which direction your encoder is spinning (increment your encoder variable when spun in one direction, decrement it in the other)

Things to look out for:
- The version I used had one interrupt per encoder, and interrupted only on rising edges
- This meant my encoder variable would only increase or decrease after about 4 encoder state changes, dividing my effective encoder resolution by 4
- This wasn't a BAD thing, in fact it was a very good exercise in learning, and implementing two interrupts per encoder, which interrupted on rising AND falling edges, and gave me back full encoder resolution

*hint: don't use two interrupts per encoder... to me external interrupts are more expensive than getting a higher resolution encoder. Last year, we had an interrupt or two to spare after we removed our IR after Pittsburgh. Next year, I know we WON'T have any spare external interrupts. I know it sounds crazy, maybe this advice comes a bit late, but buy an encoder with twice the resolution you expect to require.

It gave me a great opportunity to teach students about interrupts vs. polling, and the concepts of rising edges, falling edges and such. Even the whole concept of quadrature was quite interesting to them. Most didn't think it was that easy to figure out which way an encoder was spinning. In addition, we purchased an inexpensive mechanical encoder where we opened up the back, and you could physically see how the quadrature signal was generated with just a sweeping arm, and a few contacts.

I definitely learned a lot, and so did the students on 188.

Thanks Kevin for your code! We used your IR code too =), and were very successful in our empty gymnasium, but weren't so successful on the actual playing field.

-Shawn...

Mike Betts
10-12-2004, 10:08
...
As the company that hosts my web server decided to change the IP on me, you may or may not be able to get a copy of the code at this time. It should start working soon as I just updated the DNS record on my end
...
Your web site worked fine. The only thing I noticed is that I did not see a link to your FAQ.

...
Yeah, I've been a real knuckle-head for not modifying the EDU-RC code to run on the FRC-RC. It's been on my to-do list for some time, but I just haven't had the time. I will, however, get it done before the kick-off
...
IMHO, having a little work left for the student is a good thing. If they encounter problems in porting the code, they can always post here.

Thank you for your help.

Alan Anderson
10-12-2004, 10:46
Everybody has been focusing on the programming, but nobody has answered the other question:
...does the operator interface controller provide a way to simply shut everything down immediately in the event of a disaster?
If you don't already have a "competition dongle" to plug into the top port of your OI, make one now. One of the pins on the competition port will disable the robot, shutting off all its outputs. See the Competition Port Pinout Guide (http://www.innovationfirst.com/FIRSTRobotics/pdfs/Competition_Port_Pinout_Guide.PDF) on the Innovation First (http://www.innovationfirst.com/) web site.

A couple of weeks ago I put together a mini-dongle, with the "disable" toggle switch built into a plastic DB-15 connector housing (the extra channel access is wired to be permanently active, and autonomous control is not available). It's mostly going to be used when someone is working on the robot and doesn't want it to bite them if a joystick gets bumped. It'll also come in handy when we want to have multiple robots running at the same time.

Mike Betts
10-12-2004, 11:06
Alan,

Thank you for catching that.

I teach my team to pull the power plug or the tether (depending on how it is powered) to the OI to disable the robot. Also, when loading untested code, one team member is to have their hand on the 120 amp circuit breaker disconnect button until the code is verified.

The reason I do not have them use the dongle is that the connection is normally enabled (a broken wire enables the robot).

We use the dongle for autonomous mode testing only.

Kevin Watson
10-12-2004, 16:01
Shawn,


*hint: don't use two interrupts per encoder... to me external interrupts are more expensive than getting a higher resolution encoder. Last year, we had an interrupt or two to spare after we removed our IR after Pittsburgh. Next year, I know we WON'T have any spare external interrupts.Actually, the code only generates one interrupt per "tick". This is the desired behavior. If you want to count two edges per "tick" (which is a cool idea), you can modify the interrupt service routine to toggle the edge the interrupt is sensitive to. You could also just use interrupts 3-6, which are sensitive to both edges.


I know it sounds crazy, maybe this advice comes a bit late, but buy an encoder with twice the resolution you expect to require.
I'm not sure I would do this. You should do the math beforehand and get an encoder that isn't overkill. You should optimize in the direction of lower counts per revolution.


It gave me a great opportunity to teach students about interrupts vs. polling, and the concepts of rising edges, falling edges and such. Even the whole concept of quadrature was quite interesting to them. Most didn't think it was that easy to figure out which way an encoder was spinning. In addition, we purchased an inexpensive mechanical encoder where we opened up the back, and you could physically see how the quadrature signal was generated with just a sweeping arm, and a few contacts.
I definitely learned a lot, and so did the students on 188.Thanks. It really made my day reading this.


Thanks Kevin for your code! We used your IR code too =), and were very successful in our empty gymnasium, but weren't so successful on the actual playing field.Yeah, I've heard this more than a few times over the last eleven months <grin!>.

-Kevin

Kevin Watson
10-12-2004, 16:14
Your web site worked fine. The only thing I noticed is that I did not see a link to your FAQ.
It's at the top of this page: http://kevin.org/frc/2004


IMHO, having a little work left for the student is a good thing. If they encounter problems in porting the code, they can always post here. Unfortunatly, the interrupts I used in the code for the EDU-RC map to digital I/Os one and two on the FRC-RC, which overlap with the digital I/Os I used on the EDU-RC <DOH!>. This may not be obvious and may cause some confusion.

-Kevin

Mike Betts
10-12-2004, 19:26
...
Unfortunatly, the interrupts I used in the code for the EDU-RC map to digital I/Os one and two on the FRC-RC, which overlap with the digital I/Os I used on the EDU-RC <DOH!>. This may not be obvious and may cause some confusion...

Kevin,

Teams will have lots of I/O and interrupt requirements. They need to understand that there is not "one size fits all" and that different timers. interrupts, et cetera, act differently (eventually, you have to read the manual).

As to your previous statement, I can't get to your website at all now... Please let us know when everything is resolved. Your's is much to precious of a resource to be lost.

Once again, thank you for your guidance and support...

Kevin Watson
11-12-2004, 13:21
Yeah, I've been a real knuckle-head for not modifying the EDU-RC code to run on the FRC-RC. It's been on my to-do list for some time, but I just haven't had the time. I will, however, get it done before the kick-off.
Turns out that I had done a FRC-RC version of the encoder software last February, but didn't post it for some reason. If you'd like to test it before I can get a FRC-RC setup here at home, I've posted it here:

http://kevin.org/frc/frc_encoder.zip

and here:

http://robotics.jpl.nasa.gov/~kevinw/frc_encoder.zip

As I won't get a chance to test it for a few days, please let me know if you have problems with the code.

-Kevin

Kautz
15-12-2004, 19:18
Where do you wire the 5v and ground to pin 1 and 2 of the encoder. Pin 3&4 to the digital input /output?

Thanks I searched but do not fine anything.

Kevin Watson
15-12-2004, 19:30
Where do you wire the 5v and ground to pin 1 and 2 of the encoder. Pin 3&4 to the digital input /output?

Thanks I searched but do not fine anything.
Which encoder are you using?

-Kevin

Kautz
15-12-2004, 19:49
Which encoder are you using?

-Kevin
It is an optical encoder made by CUI.

EC202A050A2(S or T)D

Sorry about that

Kevin Watson
15-12-2004, 20:06
Where do you wire the 5v and ground to pin 1 and 2 of the encoder. Pin 3&4 to the digital input /output?

Thanks I searched but do not fine anything.
+5V goes to the middle PWM pin
Gnd goes to the outside PWM pin, where it's marked "Blk"
The A and B outputs go to the inside pins.

I don't remember which I/Os are used for the signals, but it will be documented in the readme.txt file and at the top of the encoder.c source file.

-Kevin

stephenthe1
16-12-2004, 15:36
+5V goes to the middle PWM pin
Gnd goes to the outside PWM pin, where it's marked "Blk"
The A and B outputs go to the inside pins.

I don't remember which I/Os are used for the signals, but it will be documented in the readme.txt file and at the top of the encoder.c source file.

-Kevin

did you mean that the +5V goes to the middle digital pin? the pwm's have an output of 7.5 volts right. and does the digital pin have an output of +5 volts?

Kevin Watson
16-12-2004, 16:59
did you mean that the +5V goes to the middle digital pin? the pwm's have an output of 7.5 volts right. and does the digital pin have an output of +5 volts?Yes, use the middle digital I/O pin, which is at +5V.

-Kevin

stephenthe1
16-12-2004, 18:32
in ifi_aliases.h, there is a reference to adc.h (#include <adc.h>). I looked in the directory with all the c and h, etc. files, and didn't find a file called adc.h. this is a problem, because the code won't compile with mplab untill I find out why it can't find that particular file. can I remove it from the ifi-aliases.h file?
this is the exact error message:
"E:\Robotics\defaultcode\FrcCode\ifi_aliases.h:18: unable to locate 'adc.h'"

Astronouth7303
16-12-2004, 18:56
This seems to occur frequently. Unless you didn't install MCC18 (which is a requirement), it should be there.

I believe adc.h is the first 'standard' include; so a misconfig is the most likely cause. Check to make sure MPLAB has the right include dir (by default it is C:\mcc18\h ).

Mark McLeod
16-12-2004, 23:04
this is the exact error message:
"E:\Robotics\defaultcode\FrcCode\ifi_aliases.h:18: unable to locate 'adc.h'"
More details are in this thread http://www.chiefdelphi.com/forums/showthread.php?t=24005&highlight=adc.h
or you can search for "adc.h" to get more hits.

stephenthe1
31-12-2004, 16:11
hi,
I've been going through a tutorial for using interrupts ("interrupts for dummies") and another one titled ("quadrature encoders"). this may be a vague question, I'm not sure. but what is "Port_B"? and what is "0xFF".
also, what are state machines (based on the current encoder position). are they used to determine what part of the "cycle" the encoder is going through.
lastly, just a thought, is does Port_B tell which of the 4 interrupts (4-7 was fired?), because these particular four are all identified under the "same name."
it seems that Port_B is used to reference interrupts 4-7, and then the 0xFF, where "FF" identifies which of those four ports was interrupted?
anything you can tell me to simplify this would be appreciated,
thanks,
Stephen P.

stephenthe1
31-12-2004, 16:26
also, if you could explain this segment of code.

#pragma code InterruptVectorLow = LOW_INT_VECTOR // put this code at address 0x18
void InterruptVectorLow (void)
{
_asm
goto InterruptHandlerLow // jump to InterruptHandlerLow(), below
_endasm
}
#pragma code

1: what is "#pragma"
2: what is the purpose of putting the "#" symbol in front of it
3: what are _asm and _endasm
thank you so much for the help,
Stephen.

Kevin Watson
31-12-2004, 18:15
Stephen,

I've been going through a tutorial for using interrupts ("interrupts for dummies") and another one titled ("quadrature encoders"). this may be a vague question,

No, they're great questions. I'll update the source code with additional documentation.


I'm not sure. but what is "Port_B"? and what is "0xFF".

Assuming you're referring to my code, here's a description of the three variables:

"Port_B" is a working copy of the input port where the state of the interrupt bits can be read. You need to take a snapshot because their value may change at any time. If, for example, interrupt 6 changes from a zero to a one and then quickly changes back to a zero before you get around to checking it's state, you're stuck servicing an interrupt without knowing which of the four inputs caused it. This is why I grab a copy of PORTB first off.

"Old_Port_B" is the state of the port the last time an interrupt was generated. Because four inputs are mapped to one interrupt, you need this information to determine which of the four inputs changed and caused the interrupt.

"Port_B_Delta" is the exclusive-or of the above two variables. The exclusive-or of two bits returns a one if the two bits are different, zero if they're the same. Later on, I check all four bits to see if they're a one, meaning that they've changed since the last interrupt was generated. You need to check each bit because one may have changed between the time another bit caused the current interrupt and the time you sampled PORTB. If you didn't do this, you might miss a valid interrupt-causing event, which is a really bad thing to happen.


...what are state machines (based on the current encoder position). are they used to determine what part of the "cycle" the encoder is going through.
Yes, exactly. A state machine is a construct that allows software (and hardware) to keep track of what's happened in the past. To use an analogy, it's kinda like Drew Barrymore's character in Fifty First Dates, who doesn't remember what happened the day before when she wakes-up the following morning. If she just left a note to herself each evening with her current marital state <unattached/dating/engaged/married>, she wouldn't have a problem the following morning <grin>. It's the same thing for software. By just changing the state variable (think Drew's note) before leaving a function, you'll be able to pick up where you left off the next time the function is called.


...lastly, just a thought, is does Port_B tell which of the 4 interrupts (4-7 was fired?), because these particular four are all identified under the "same name."
Yes, as I described above.


...and then the 0xFF, where "FF" identifies which of those four ports was interrupted?
If nothing is attached to the PORTB pins, their state will be read as all ones, the 0xFF is just my best guess of the state of PORTB when software starts execution. If you take a look at the Initialize_Interrupts( ) function, you'll see that I initialize Old_Port_B with the real state of PORTB just before I initialize the interrupt.

-Kevin

Kevin Watson
31-12-2004, 18:31
Stephen,


1: what is "#pragma"
A pragma tells the C pre-processor that what follows is a special note telling it to do something non-C language related. In this case, it tells the pre-processor (and later the linker) that you want this specific piece of code placed in a special place in memory reserved for interrupt service routines.


2: what is the purpose of putting the "#" symbol in front of it
This just indicates that this is a message for the C compiler pre-processor. Other examples are #include and #ifdef.


3: what are _asm and _endasm
This tells the C compiler that you want to insert raw assembly language within a C source file. In this case, we're just putting a jump instruction to the interrupt handler at the special location in memory where the CPU starts execution in response to an interrupt condition.

-Kevin

stephenthe1
01-01-2005, 11:24
I was reading about extern and static variables. I realize that it's considered bad coding technique to declare extern variables, because they are declared outside functions. however, I need this variable available to interrupts.c and user_routines_fast.c. however, I only want this variable to have its value assigned once. where should I place a variable that can be used in both these files, and have the variables value (unsigned int phase = 1000) assigned only once. I did search on google, but it doesn't exactly tell me about how the structure of the default code is set up to work with and where to put such a variable so it will be available to these particular files.
by the way, the purpose of the variable, is so when interrupt #1 fires, 1 is added to its value, and when interrupt #2 fires, 1 is subtracted from its value. the reason it needs to be available to user_routines_fast.c, is because that is where I want to place my functions, as it would be confusing to have the interrupts.c file running a function controlling the robot and a function in user_routines_fast.c controlling the robot as well.
thanks a lot,
Stephen.

Astronouth7303
01-01-2005, 11:50
I was reading about extern and static variables. I realize that it's considered bad coding technique to declare extern variables, because they are declared outside functions. however, I need this variable available to interrupts.c and user_routines_fast.c. however, I only want this variable to have its value assigned once. where should I place a variable that can be used in both these files, and have the variables value (unsigned int phase = 1000) assigned only once. I did search on google, but it doesn't exactly tell me about how the structure of the default code is set up to work with and where to put such a variable so it will be available to these particular files.

I don't know how it would be bad coding practice; any variable that needs to be accessable from 2 or more different functions must be declared globally.

The variable should be declared in one file and extern'd in all the others you need it in.

stephenthe1
01-01-2005, 20:17
where does mplab ide 7.00 send the mcc18.exe compiler file? I did the default settings for the entire installation. where is this at? keep in mind that I don't have a mcc18 folder in the root of the drive. the mplab files were installed into the program files folder. thanks, Stephen.

Kevin Watson
01-01-2005, 20:30
I don't know how it would be bad coding practice... Well, minimizing the number of global variables is desirable because you don't have any control over the scope of a global variable. I've been involved with a few flight projects where there weren't any globally defined variables in the flight source code.


...any variable that needs to be accessable from 2 or more different functions must be declared globally. No, this isn't true. You can pass a pointer to the variable in the function call.

stephenthe1
04-01-2005, 10:00
I've been using Kevin Watson's interrupt template code. I want to have a variable increment every time the interrupt fires. that's not a problem. however, is there a static variable type available that I can use between files? I'm not aware of such a thing. also, does the code in interrupts.c execute first, or the code in user_routines_fast.c go first? this affects whether I use the interrupts.c file to handle the motor speed or the user_routines_fast.c file to handle the speed of the motor. if the user routines file comes second, that would be the case where I need the variable. I'm willing to bet there's an easier way, but this is what I've come up with so far. I would use Kevin's template for encoders but it supports two encoders for the wheels, when I want to use the one we already have set up on digitals 1 and 2 with one motor. we'll probably have to use his eventually on the wheels in addition to this encoder.
thanks,
Stephen.

seanwitte
04-01-2005, 10:17
I've been using Kevin Watson's interrupt template code. I want to have a variable increment every time the interrupt fires. that's not a problem. however, is there a static variable type available that I can use between files? I'm not aware of such a thing. also, does the code in interrupts.c execute first, or the code in user_routines_fast.c go first? this affects whether I use the interrupts.c file to handle the motor speed or the user_routines_fast.c file to handle the speed of the motor. if the user routines file comes second, that would be the case where I need the variable. I'm willing to bet there's an easier way, but this is what I've come up with so far. I would use Kevin's template for encoders but it supports two encoders for the wheels, when I want to use the one we already have set up on digitals 1 and 2 with one motor. we'll probably have to use his eventually on the wheels in addition to this encoder.
thanks,
Stephen.

Declare the variable you want to share between files in a header file with the "extern" storage specifier. For example:

extern unsigned char MyVar;

In a source file that includes the header, define the actual variable:

unsigned char MyVar;

Any source files that use the header now have access to MyVar. I would declare all of your shared variables in one header file and define them all in one source file. To use them you just include the header in the source files where needed. Something like "sharedvars.h" and "sharedvars.c".

Astronouth7303
04-01-2005, 16:52
Declare the variable you want to share between files in a header file with the "extern" storage specifier. For example:

extern unsigned char MyVar;

In a source file that includes the header, define the actual variable:

unsigned char MyVar;


If the interupt fire enough, you will want to declare it volatile. ie,

/*** Variables.h ***/
volatile unsigned char MyVar = 0;

/*** MyCode.c ***/

extern volatile unsigned char MyVar;


This will cause it to not copy the value to a temporary storage location.

seanwitte
04-01-2005, 17:00
If the interupt fire enough, you will want to declare it volatile. ie,

/*** Variables.h ***/
volatile unsigned char MyVar = 0;

/*** MyCode.c ***/

extern volatile unsigned char MyVar;


This will cause it to not copy the value to a temporary storage location.

Correct, I forgot about about the volatile keyword. You need to swap the declarations in the two files though. The extern statement goes in .h and the declaration goes in .c.


/*** Variables.h ***/
extern volatile unsigned char MyVar;

/*** MyCode.c ***/
volatile unsigned char MyVar = 0;

stephenthe1
04-01-2005, 22:21
thanks guys!!! that clears that up.
do you know about the order the files are executed though? I need to know, because if I use interrupts in one file to control the speed of a motor, it needs to be read before the user_routines_fast.c file so that the variable's values (the extern one I was asking for help earlier) can be sent to that file.
do you see what I mean?
also, can I use the
volatile unsigned int my_int;
then assign its value to a static variable inside a method in another file?

(back to the question obout the file execution order) it would be really cool to be able to tell the controller to rescan the file (or whatever part of the .hex file it is) of course, it's better just to know which ones are done first and which are done last.
by the way, I feel dumb for asking this, but what's the difference between frc_rc and edu_rc.

Mike Betts
04-01-2005, 22:59
thanks guys!!! that clears that up.
do you know about the order the files are executed though? I need to know, because if I use interrupts in one file to control the speed of a motor, it needs to be read before the user_routines_fast.c file so that the variable's values (the extern one I was asking for help earlier) can be sent to that file.
do you see what I mean?
also, can I use the
volatile unsigned int my_int;
then assign its value to a static variable inside a method in another file?

(back to the question obout the file execution order) it would be really cool to be able to tell the controller to rescan the file (or whatever part of the .hex file it is) of course, it's better just to know which ones are done first and which are done last.
by the way, I feel dumb for asking this, but what's the difference between frc_rc and edu_rc.
1. Interrupts happen whenever interrupts happen. The only condition is that they must be enabled, This is typically performed in User_Initialization().

2. Your non-interrupt code executes from main () in main.c and follows whatever tortuous path you lead it on.

3. frc_rc is the full size controller that goes on our robots. edu_rc is the smaller controller for the Edubot.

stephenthe1
05-01-2005, 15:23
as I was looking at Kevin's encoder template, I was wandering how these particular variables are available to all files, as they aren't declared with the "extern" keyword.
examples:

long Get_Left_Encoder_Count(void); // call this to get the current left
// wheel's encoder count

long Get_Right_Encoder_Count(void); // call this to get the current right
// wheel's encoder count

void Set_Left_Encoder_Count(long); // call this to set the left wheel's
// encoder count

void Set_Right_Encoder_Count(long); // call this to set the right wheel's
// encoder count

void Left_Encoder_Int_Handler(void); // left wheel encoder interrupt handler

void Right_Encoder_Int_Handler(void); // right wheel encoder interrupt handler

do you see what I mean? this is pretty much the only thing keeping me from coding our encoder is understanding why this is. thanks. also, does anyone know an easy way to set up a third encoder easily with his code (attatched to dig_in_01 and dig_in_02 (plus setting them up as interrupts))? I'm semi-new, so I'm proned to mistakes. thanks again,
Stephen

Mike Betts
05-01-2005, 15:36
as I was looking at Kevin's encoder template, I was wandering how these particular variables are available to all files, as they aren't declared with the "extern" keyword.
examples:

long Get_Left_Encoder_Count(void); // call this to get the current left
// wheel's encoder count

long Get_Right_Encoder_Count(void); // call this to get the current right
// wheel's encoder count

void Set_Left_Encoder_Count(long); // call this to set the left wheel's
// encoder count

void Set_Right_Encoder_Count(long); // call this to set the right wheel's
// encoder count

void Left_Encoder_Int_Handler(void); // left wheel encoder interrupt handler

void Right_Encoder_Int_Handler(void); // right wheel encoder interrupt handler

do you see what I mean? this is pretty much the only thing keeping me from coding our encoder is understanding why this is. thanks. also, does anyone know an easy way to set up a third encoder easily with his code (attatched to dig_in_01 and dig_in_02 (plus setting them up as interrupts))? I'm semi-new, so I'm proned to mistakes. thanks again,
Stephen
Stephen,

All of your examples are of functions not variables...

stephenthe1
05-01-2005, 19:56
yeah, I soon realized that after posting. thanks for the tip though.

stephenthe1
06-01-2005, 18:39
beware, long question...

ok, I have a couple questions.
1: in Kevin's encoder template, he first uses the Get_Left_Encoder_Count function, and assigns its value to the "count" variable. then he uses the Get_Right_Encoder_Count function and assigns its return value to the "count" variable also. Then he runs the Set_Left_Encoder_Count function, and uses the "count" variable to assign the value of "count" to Left_Encoder_Count. then he uses the "count" variable to assign the value of "count" to Right_Encoder_Count. I don't understand how he can do this without confusing the value of "count" between the left and right encoders. any help would be appreciated.

2:when setting up digitals as low priority interrupts, what do I use to reference the different pins (1-6, or interrupts 2-7). I know the first one is INTCON3bits.INT2IP = 0. but I need confirmation that that one is correct, and what the other five are. I know that interrupts 3-6 (4-7) are ganged together. I would prefer to know how to address each one individually
if that can be done easily, if not, I can set them all as low priority interrupts. I think it'd be better to do the other way though, because I need to learn how to address each one individually.

3: similarly to question two, I need to know the names of the pins to set the "edge select" option. also, the names to clear the interrupt flag and to enable the interrupts. I found some of the info in the "interrupts for dummies tutorial," but I don't know how to address each one specifically. I can't be in the dark or guessing on any of this, because interrupts are very finicky.

thank you,
Stephen

Mike Betts
06-01-2005, 20:26
Stephen,

Find a good primer on C and read it. I highly recommend http://www.lysator.liu.se/c/bwk-tutor.html

Understand that I am not trying to be cruel... I just feel that you have not attempted to work things out for yourself. If Mr. Watson gave you all of the answers, what would you learn?

As it is, I feel he has given you too much.

I think back to my freshman days at college. A fellow student (I'll call him John) was hopelessly lost and in over his head. Another student gave him the program (it was a stack of punchcards for an IBM 360 mainframe). All John had to do was change the job card (the top card on the stack) and run his program...

John screwed it up and, after several hours, declared that he had changed all of the variable names and the program still didn't work!

John's problem was that he never read the material required by the professor and was too busy talking in class to pay attention.

Now to your situation. Your earlier post indicates that you have no real understanding of C. The variable count is a local variable inside of Get_Right_Encoder_Count and has nothing at all to do with the local variable count inside of Get_Left_Encoder_Count. Both functions return a number to the statement which called them.

Suppose I asked you to find out how many pennies Marsha has and then how many Bill has? You would go to Marsha and find out she has 3 pennies and report this to me. Then you would go to Bill hand find out he has 2 pennies and report it to me. The face that Marsha had 3 pennies does not influence the fact that Bill has two. I did not ask you to add then together... Just report.

The function Get_Right_Encoder_Count has no idea what other functions are available. It just reports the number of clicks that the right encoder has seen.

The last line of the function could have been written:

return(Right_Encoder_Count);

without any local variable... Does this make sense?

Bottom line: Mr. Watson's code works.

stephenthe1
06-01-2005, 22:07
your right there. it's just frustrating right now, because I understand the code so well, save that little thing and methods. however, my main problem was not that little variable, but the interrupt names ( the whole TRISBbits. etc. thing ), mainly for accessing the 3-6 interrupts. yeah, I'm the type of guy, who, when I understand it 100%, I can work magic, untill then, I'm in a ditch.
2 days till kickoff :yikes: excitement is bubbling.