Adjusting the speed of a motor with pulse-width modulation
All equipment working on direct current, also known as DC, require a constant input voltage. Within this category are many electronic components such as Lego™-motors and LEDs. The voltage of these components is typically within a certain range, but in general it can also be lowered. In the case of LEDs a lower voltage results in less light and by adjusting the input voltage of an electrical motor the rotational speed can be altered. The motor will then run slower or faster. The Dwengo library provides for this several useful functions. On this page we look into more detail how you can configure the PWM module of the PIC18F4550 yourself in order to easily adjust the speed of an electrical motor.
When a PWM signal with very high frequency is generated, the electrical motor perceives this as a constant high voltage. By adjusting the pulse-width or duty cycle of the PWM signal, the amplitude of the average voltage can be increased or decreased. Correspondingly the motor will run faster or slower. This is illustrated in the figure below. The same concept can be used to dim a LED for example.
To generate a PWM signal one can use interrupts or you can make use the build-in PWM module of the PIC18F4550.
Before you can configure the PWM, you need to load the necessary libraries.
#include <p18f4550.h> #include <timers.h> #include <delays.h> #include <pwm.h>
As always it is important to setup the configuration bits correctly. In this case CCP2MX plays an important role since we can use this to setup whether the PWM signal of the second PWM module is set on pin RC1 or on pin RB3. In the following example we set CCP2MX in such a way that the second PWM signal is on pin RC1. The signal of the first PWM module is always set on pin RC2, hence it does not need to be setup.
The configuration of the configuration bits becomes the following:
// Fuses configuration #pragma config PLLDIV = 5 // Divide by 5 (20 MHz oscillator input) #pragma config FOSC = HSPLL_HS // HS oscillator, PLL enabled, HS used by USB #pragma config IESO = OFF // Oscillator Switchover mode disabled #pragma config PWRT = OFF // PWRT disabled #pragma config BOR = OFF // Brown-out Reset enabled in hardware only (SBOREN is disabled) #pragma config WDT = OFF // HW Disabled - SW Controlled #pragma config WDTPS = 32768 // 1:32768 #pragma config MCLRE = ON // MCLR pin enabled; RE3 input pin disabled #pragma config LVP = OFF // Disable low-voltage programming #pragma config CCP2MX = ON // CCP2 multiplexed to RC1 and not to RB3 #pragma config PBADEN = OFF // PORB digital IO on powerup
The Dwengo board directly supports up to two electrical motors (M1 and M2 from the motor connector). For this four pins, RC1, RC2, RA4, RB3, from the microcontroller are used. All these pins have to be configures as outputs.
TRISAbits.TRISA4 = 0; TRISBbits.TRISB3 = 0; TRISCbits.TRISC1 = 0; TRISCbits.TRISC2 = 0;
In order to run a DC motor, you usually need two inputs. One of these inputs acts as the ground and the other input is de input voltage that determines the speed of the engine. So to run two motors we need to set two pins as ground.
PORTAbits.RA4 = 0; PORTBbits.RB3 = 0;
Beside the two pins that act as ground we need to set two pins that are used as the voltage input for the two motors. Since we want the robot to run faster and slower we must be able to setup these two voltages separately. As explained before we can do this by using a PWM signal for each of these pins. Since we need different PWM signals for each pin, we need two PWM modules. This is done with the functions OpenPWM1 and OpenPWM2. These functions require a argument that sets the period of the PWM signal according the following formula: PWM period = ( + 1) 4ToscT2Prescaler. In this case ** is the number we give to the function OpenPWM1 or OpenPWM2, Tosc is the period of the clock and is in our case equal to 1/48,000,000 seconds and T2Prescaler is a factor that allows us to slow down the timer timer2 that is used for the PWM modules. We chose to use a factor 4 (see further) to setup timer2 which results in a PWM period equal to 85.33 microseconds.
// PWM period = (0xFF + 1)*4*Tosc*T2Prescaler OpenPWM1(0xFF); // configuring PWM module 1 OpenPWM2(0xFF); // configuring PWM module 2
Next we setup timer2. This timer is used by the PWM modules to generate the PWM signal. We setup timer2 in such a way that it does not generate interrupts, that the prescaler is equal to a factor 4 which slows down timer2 with a factor 4 and a postscaler with factor 1 (without delay).
// Configuring timer 2 which provides timing for PWM // TIMER_INT_OFF: disable timer interrupt // T2_PS_1_4: Timer2 prescaling set to 4 // T2_POST_1_1: Timer2 postscaling set to 1 OpenTimer2(TIMER_INT_OFF & T2_PS_1_4 & T2_POST_1_1);
The speed of the motors can be adjusted by changing the pulse-width of the PWM signal. Setting the pulse-width is done with the function SetDCPWM1 for the first PWM module (motor 1) and the function SetDCPWM2 for the second PWM module (motor 2). These functions have one argument between 0 (pulse-width equal to 0, in other words no pulse) and 1023 (pulse-width equal to the PWM period, in order words the motor at full speed) that determines the pulse-width.
SetDCPWM1(1023); // sets PWM duty cycle 100% (full speed) SetDCPWM2(512); // sets PWM duty cycle 50% (medium speed)
- Type:

Your shopping cart