Program digital IO to PWM?

Hi Guys,

I am very new to programming and to vex. I would like to turn a digital output into a pwm output that will control an external H-bridge running a dc motor. The pwm from the motor\servo ports duty cycle is too short so that is why I am not using that. I need to program a pwm with a duty cycle from 0 to 100% and have it controlled by a stick on the vex transmitter.
Thanks for any help in advance.

JK

The Vex controller isn"t set up for this. You might want to look at using a RC type speed controller or a victor speed controller. This a current thread on using a victor with a vex controller.

OK. Thanks for the help.

I think he’s talking about using the digital IO port to directly drive the H-bridge instead of using a signal port on a Victor.

To do this on a VEX controller, you have to be aware that you’ve got a limited duty cycle in Operator Control mode. This runs an underlying C file in the default code that is called “user_routines.c”. This runs every 18.5 milliseconds (ms), which gives you a frequency of approximately 55 Hz. PWM signals usually run at around 1000 times that, 50 kHz, because of the inefficiency of running it much slower. The autonomous mode code, “user_routines_fast.c” runs at around 400 Hz on average with out much of a processing load, but fluctuates wildly depending on what kind of code you’re running in it, and so is not suitable for precision timing operations. If you’ve done BEST, the BRAIN runs motors at 100 Hz, and even that draws more power than necessary, so I think Gdeaver is right about this, it’s not an ideal application of the VEX microcontroller, as 55 Hz will draw lots of extra power, and the motor will not be very responsive.

If you still want to try it, here’s the brief run-through of PWM power signals. As it sounds like you know, PWM is not about varying the voltage to control the power of the motor, but instead varying the application time of full voltage to the motor. That gives you a much simpler control program, much simpler circuitry, and happens to have the added bonus of giving you more power and torque from the motor, as you’re always operating it at its peak efficiency voltage, just in short bursts. Now there is a downside, and that is the induction of the coils in the motor is a bit of a problem for PWM control, because the short bursts of power in quick succession cause a back-current to come out of the motor that can be quite powerful, and spikes in between the PWM crests. You have to have a fairly large capacitor wired to the H-bridge to absorb these spikes so the back current doesn’t destroy your transistors. But you can’t have too large a capacitor, because the increased capacitance can counteract itself and cause the capacitor to explode. Just keep this in mind while building your H-bridge, and DO THE CALCULATIONS.

The code for driving a PWM power signal is fairly basic, and there are a couple of ways to do it. One way is by counting clock cycles. Since the user_routines.c code is always run consistently at a regulated 18.5 ms cycle (unless you have lots of printf() statements, which kill the processor time), you can run it on a fairly regular timing scheme. You can have an iteration counter, i, that holds the number of cycles, and when it reaches a certain number, you send a pulse and count again. You’d also have a variable, p, that holds the amount of power you want to go to the motor. The timing depends on the precision of your counter. A basic 127-point precision counter would go like this:


int i;
unsigned char p;

while(1) {
    if(GetOIAInput(1, 2) >127) p=(GetOIAInput(1, 2) - 127); //p = right joystick Y axis forward value
    else p=0;

    for(i=0; i<(127-p); i++) SetDigitalOutput(1, 0); //Set digIO port 1 to 0 for the off period
    for(i=0; i<p; i++) SetDigitalOutput(1, 1); //Set digIO port 1 to 1 for the on period
}

However, on the VEX microcontroller, this would amount to a period of 2.35 seconds, which is nowhere NEAR fast enough to get the thing to move. The second way is to let the controller do the counting on its internal clock and you just provide the power. For this to work at a reasonable speed, you have to add a variable to hold the system time in microseconds. This is an unsigned long integer type on the VEX microcontroller (32 bits), so you declare the variable as “unsigned long”.


unsigned char p;
unsigned long time;

while(1) {
    if(GetOIAInput(1, 2) >127) p=(GetOIAInput(1, 2) - 127);
    else p=0;

    time=GetUsClock();
    while((GetUsClock()-time)<(100-p)) SetDigitalOutput(1, 0);
    time=GetUsClock();
    while((GetUsClock()-time)<p) SetDigitalOutput(1, 1);
}

I’ve never actually tried it this way, so the precision may not actually be as good as you’d think. Using the system microsecond clock should force the code to run in user_routines_fast.c, and since you’re using the microsecond clock, the timing should be accurate, but if it doesn’t, make p an unsigned integer and start multiplying p by powers of 10. This will decrease the theoretical accuracy, and ironically therefore increase the practical accuracy. By using a 127 us period, you end up with a theoretical frequency of 7.87 kHz. This is way faster than the VEX controller can think, but depending on the precision you need from the motor, it may actually be good enough

However, either of these methods are still very time-dependent. If you have a bunch of printf() statements in the code, they won’t work, because they slow down the processor cycles so much. In the second method, you’d have to do some pretty clever code to get more than one motor to work at a time, because it would require parallel processing to run several of the counters simultaneously to run more than one motor, and none of the PIC 8-bit (or even 16-bit) controllers come anywhere close to being able to support that. If there’s any thread() emulation, it would seriously slow down the controller and cause it to not work. Again, I reiterate that yes, it would be better to get a motor controller than make your own code on a VEX. If you’re fairly good at electronics and programming, you could actually get yourself a small microcontroller (something along the lines of an ATMEGA8 from Atmel, or you could possibly find a dedicated motor controller chip) and use one to control each separate H-Bridge from the PWM pulse from the motor ports on the VEX, but this then gets into some hard calculations on save current levels and capacitor values.

Another alternative is the VEX motor controller. You could wire one up to the H-bridge with some diodes and completely avoid any advanced programming. They’re $10, and save you a lot of headache. This is the same board that is inside the VEX motors, and output a PWM power signal. They can be found at the bottom of this page.

Sorry for the long post, I hope it can help you with anything.

The PIC18F8520 actually has several hardware counter-compare modules which are connected to the first four motor ports. These can be used to generate a high resolution PWM signal from 0% duty to 100% duty at high frequencies (I think I used 40kilohertz). Since hardware is taking care of this, after you set a value your code can continue to do anything else and the signal will continue to be generated until it is told otherwise.

I attached some code that I used to drive an h-bridge motor controller via this method.

CustomPWM.c (4 KB)
CustomPWM.h (317 Bytes)


CustomPWM.c (4 KB)
CustomPWM.h (317 Bytes)

For those who are not familiar with MPLAB, the CustomPWM.c code was meant to be part of a project in MPLAB. For those curious in getting a working project you need to download the full project from VEX’s software downloads.
http://www.vexrobotics.com/docs/VexCode_def_2008.zip

Once you have MPLAB opened, add the source files for CustomPWM.c & CustomPWM.h

Thanks for posting this awesome code !!! Kevin Watson also has some great interfacing examples, Kevin's FRC Code Repository but this is only for FRC 2008 & 2007 systems.

Thanks a lot for the code and the info on where it should be used. I will try to get it done without having to bother you guys much. Thank you very much.

JK

OK. I have MPLAB install along with C18 and the loader. I figured out how to use them and I added the custompwm files to the vexusercode then I downloaded to the vex controller but it did not change the pwm. ( I am watching the pwm with a scope.) So, I did some more research and found out how to use the DDT. With the DDT I can get the type of pwm I am looking for out of motor port 1 but I still can not get it to work with the tx and the user code. Please remember that I am brand new to programming so there may be something very simple I am missing.
Thanks so much for the help.

JK

Just started with the default code myself last night.

Did you call the functions in CustomPWM.c from anywhere in user_routines.c or user_routines_fast.c? Uncalled functions are pretty, but don’t do anything. You should call these functions from either Process_Data_From_Local_IO in user_routines_fast.c or Process_Data_From_Master_uP in user_routines.c. Remember that the former will execute very quickly (on the order of a few hundred kilohertz), but the processing speed will fluctuate widely, and the latter will execute once every 18.5 ms. I don’t know what kind of precision H-bridge application you’re planning on running, but an 18.5 ms speed update rate should be plenty. Even though the update rate is “slow”, the PWM speed is still quite fast at 40 kHz.

This code gives you 0% to 100% duty cycle in the motor slots 1-3 controlled by the corresponding joystick channels.
I hope this helps. :]

PWMcontrol.zip (230 KB)


PWMcontrol.zip (230 KB)