Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Concurrent threads on a pic?

Status
Not open for further replies.

HakBot

New Member
Hi,

I'm kinda new to microcontrollers and I've got some code going that controls 1 hobby servo via a delay loop that controls the pulse width. What I want to do is drive serveral servos now from the same pic. I was thinking I could just use concurrently running threads and run each servo from a thread. Is it possible to do threads on a pic? If so, can anyone point me to an example?

If threads are not possible, what is the standard way of running multiple servos on the same board? My chip, the pic18f4550 has 16 digital outputs so in theory I can run up to 16 servos from this board.
 
What language are you using?

How much resolution do you have or do you need per step between the 1.0-msec and 2.0-msec pulse range?

What's the oscillator frequency to the core on your '4550?

Mike
 
The simple answer is timer interrupts, but as Mike asks it depends on what resolution you're wanting, and the clock speed you're using.

Another question is what else is it doing?, depending on that you may simply be able to run the 16 servos using delay loops, in sequential order.
 
Mike,

Im using C and the the C18 compiler from Microchip. I do not know what resolution between steps I really need. I would like the servos to operate the same as they would on a standard r/c transmitter/receiver. As of now, I am driving one servo. I pass in a value in the range of 120-240 to give me the desired pulse width. Im using the following: Delay100TCYx(120) = 1ms, Delay100TCYx(240) = 2ms (found in delays.h). 120 steps seem fine and I would be happy if I could still get this but more steps would be nice! :D Also, Im using a 20MHz crystal.

Nigel,

The pic is going to be doing nothing else but driving the servos, a dedicated servo controller. My original idea was to drive the servos sequentially like you mentioned but wont this cause a problems if all 16 servos take 2ms pulses? Right now I have the 1-2ms pulses being sent every 20ms. This works fine for one servo but 16 *could* cause a 36ms period.
 
Nigel's idea of consecutive/sequential time delay functions is incredibly clever and intuitive. Simply execute 16 consecutive 1-msec time delays, one for each of your PWM outputs, then delay for an additional 4-msecs before starting over. Way to go Nigel. Staggering the 1 to 2-msec processing for each output is simple, elegant, and insightful.

PWM output 01 -- 1-msec total time
Turn output 01 on for #01's "on-delay" time
Turn output 01 off and delay for (1-msec minus #01's "on-time")

PWM output 02 -- 1-msec total time
Turn output 02 on for #02's "on-delay" time
Turn output 02 off and delay for (1-msec minus #02's "on-time")

~~~~~~~~~~~~

PWM output 16 -- 1-msec total time
Turn output 16 on for #16's "on-delay" time
Turn output 16 off and delay for (1-msec minus #16's "on-time")

PWM output last -- 4-msec total time
Simply delay for 4-msecs and start over

Regards, Mike
 

Attachments

  • PWM Sequential Outputs.JPG
    PWM Sequential Outputs.JPG
    21.8 KB · Views: 222
Last edited:
Oops. I goofed on that flow chart. I forgot about the minimum 1-msec on-time. Back to the drawing board for a new flow chart (grin).

Mike

<later>

How about this? Is this doable guys?

Period 01 (1-msec total)
Turn on Output 01 (on for entire 1-msec)
Delay 1-msec

Period 02 (1-msec total)
Turn on Output 02 (on for entire 1-msec)
Delay (Output 01 "on-time" minus 1-msec), turn off output 01
Delay (2-msecs minus Output 01 "on-time")

Period 03 (1-msec total)
Turn on Output 03 (on for entire 1-msec)
Delay (Output 02 "on-time" minus 1-msec), turn off output 02
Delay (2-msecs minus Output 02 "on-time")

~~~~~~~~~~

Period 16 (1-msec total)
Turn on Output 16 (on for entire 1-msec)
Delay (Output 15 "on-time" minus 1-msec), turn off output 15
Delay (2-msecs minus Output 15 "on-time")

Period 17 (1-msec total)
Delay (Output 16 "on-time" minus 1-msec), turn off output 16
Delay (2-msecs minus Output 16 "on-time")

Period 18-20 (3-msecs total)
Delay 3-msecs and start over
 

Attachments

  • PWM Sequence.JPG
    PWM Sequence.JPG
    24.9 KB · Views: 170
Last edited:
Mike,

That would work, but a hobby servos can pulse up to 2ms, making a total period of 36ms (if all servos were to pulse at 2ms). Id like to keep the 20ms period if at all possible. It seemed like the servos had more holding power at a 20ms period versus a 50ms period for example.

If I wanted to use this method and retain the 20ms period it seems like I could only control a max of 10 servos with this method.

Ah, you beat me to it....
 
Hopefully you've gone back and seen my addition. 16 Staggered and overlapping outputs that use 17-msecs of the overall repeating 20-msec period.

I'm not familiar with C but I suspect that code would work very well in a while procedure, wouldn't it? Period 01 and period 17 would be handled differently with a final 3-msec delay before repeating.

Mike
 
Last edited:
HakBot said:
Mike,

That would work, but a hobby servos can pulse up to 2ms, making a total period of 36ms (if all servos were to pulse at 2ms). Id like to keep the 20ms period if at all possible. It seemed like the servos had more holding power at a 20ms period versus a 50ms period for example.

It shouldn't make any difference?, the only drawback with 36mS instead of 20mS is that their response will be slightly slower, as they don't get the instructions quite as fast. Try it with a single channel, double the overall time to 40mS, and check the holding power - preferably with actual measurement rather than a 'feeling' - a piece of string and some weights should do the job!.

If I wanted to use this method and retain the 20ms period it seems like I could only control a max of 10 servos with this method.

If you want 20mS frame time yes, but the 20mS is designed simply from the maximum number of servo's for an RC model and the speed of response required. However, Mikes clever overlapped scheme reduces it more and makes it possible - at the expense of a little extra complication.
 
I remember looking at some *old* RC receiver schematics, and they tended to use a 4017 chip pretty much exactly as you are describing now. (It's probably also the reason why the timing pulses and RC update frequencies are setup as they are). The big plus is that if you use a 4017 (or some other shift register chip), you only tie up 2 IO's.

Staggering two sets so that the active edges don't overlap makes sense, and you should be able to drive 16 (20?) servos at 50Hz using only 3 IO's (reset/data line, 2 clock lines) and 2 extra shift-reg chips. Dumping this into an hardware timer interrupt would seem really worthwhile.
 
Last edited:
Mike,

Excellent! That makes sense now. I will implement it tonight.

Nigel,

I did not test the holding power with exact measuring equipment but I could notice a very big jump in holding power when I lowered my period from 50ms to 20ms. I could not move the servo by hand when it was set to 20ms but it was very easy to stop operation when at 50ms. I would not have thought that 30ms extra would have made a difference but it did, thats the reason im worried about not meeting the 20ms period. Ill give it a shot thought and let you know my findings.
 
Just an idea. Could you use a 1ms timer ISR and 16 counter bytes (one per pin), if byte is not 0, flip coresponding pin high, decrement the counter each time (if not 0). When zero flip the pin low and ignore it? Then feed the 16 bytes from you program, 20 is 20ms high then back to 0. Main program could track the delay times?

Or would this cause a power issue and why the delay routine is better?

Or you maybe need some blocking to let them get were they are going to?
 
Mike,

Sorry, forgot to mention this. The frame rate might not be exactly between 1-2ms. It could slightly more or less. Any ideas?
 
HakBot said:
Mike,

Sorry, forgot to mention this. The frame rate might not be exactly between 1-2ms. It could slightly more or less. Any ideas?
Really? And just when I thought I was getting a handle on how Servos work when I've never actually seen one (grin).

Please tell me why, I'm very curious.

Mike
 
This is only what I've heard from others in the forum but most servos operate outside of the advertised range to some degree. The pulse width may also vary slightly from brand to brand.

1-2ms will work, but I would like the user to be able to adjust this in the pc side app that will run the servos. Most of the applications/controllers I've seen allow the user to give the servo a pulse outside of the normal range.

Makes the code a litte more complicated.
 
mramos1 said:
Just an idea. Could you use a 1ms timer ISR and 16 counter bytes (one per pin), if byte is not 0, flip coresponding pin high, decrement the counter each time (if not 0). When zero flip the pin low and ignore it? Then feed the 16 bytes from you program, 20 is 20ms high then back to 0. Main program could track the delay times?

Or would this cause a power issue and why the delay routine is better?

Or you maybe need some blocking to let them get were they are going to?
No, he can't use 1-msec interrupts. He using 120 steps/msec which allows him to swing the servo 60 steps left (anti-clockwise) and 60 steps right (clockwise) of the center 1.5-msec pulse width servo position. You'd need 8.3-usec interrupts to provide the same resolution and then you might not have enough time in the ISR to tickle and toggle a counter and output.
 
HakBot said:
This is only what I've heard from others in the forum but most servos operate outside of the advertised range to some degree. The pulse width may also vary slightly from brand to brand.

1-2ms will work, but I would like the user to be able to adjust this in the pc side app that will run the servos. Most of the applications/controllers I've seen allow the user to give the servo a pulse outside of the normal range.

Makes the code a litte more complicated.
Yeah, that might complicate it a bit.

What's the range? Instead of going from 1.0-msec to 2.0-msec would you like to go from 0.8-msec to 2.2-msec? Still an overall 20-msec period?

Mike
 
Ok, how does this sound?

Here are the steps I was thinking to control 2 servos at once.

1. determine the smaller pulse width for the 2 servos
2. set both pins to high
3. delay the smaller of the 2 pulse widths
4. turn the pin off corresponding to the smaller pulse width
5. subtract the smaller pulse width from the larger pulse width and delay that much
6. repeat for the next set of 2 servos until 8 sets are performed

All together the total pulses should be shorter than 20ms. In my pc side code I will control this by setting the min pulse width to .5ms and the max to 2.5ms.

Something like this pusedo code:

if(delay1 > delay2){
pin1 = 1; pin2 = 1;
Delay(delay2);
pin2 = 0;
Delay(delay1-delay2)
pin1 = 0;
} else {
pin1 = 1; pin2 = 1;
Delay(delay1);
pin1 = 0;
Delay(delay2-delay1)
pin2 = 0;
}

I like this idea because it allows me to keep the interrupt timer in control of the overall period and have smaller or larger pulses. Does anyone forsee a problem with this code? I have a feeling that the extra logic will not effect the times by much (at least not enough to notice).
 
I think that should be ok since it is using an if else. If they are equal then it would go into the else block. The second Delay should get passed up. I know there will be a few clock ticks in between there but should that matter much when dealing with millisecond delays?

} else {
pin1 = 1; pin2 = 1;
Delay(delay1);
pin1 = 0;
Delay(delay2-delay1) <-----shouldnt wait if they are equal
pin2 = 0;
}
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top