Action
Setting Up the PWM and Servo Control
#![allow(unused)]
fn main() {
const PWM_DIV_INT: u8 = 64;
const PWM_TOP: u16 = 46_874;
const TOP: u16 = PWM_TOP + 1;
const MIN_DUTY: u16 = (TOP as f64 * (2.5 / 100.)) as u16;
const HALF_DUTY: u16 = (TOP as f64 * (7.5 / 100.)) as u16;
const MAX_DUTY: u16 = (TOP as f64 * (12. / 100.)) as u16;
}
1. Set Up the PWM Slice and Channel
First, initialize the PWM slice and channel. You should have already done similar in the previous blinky section.
#![allow(unused)]
fn main() {
let mut pwm_slices = hal::pwm::Slices::new(pac.PWM, &mut pac.RESETS);
let pwm = &mut pwm_slices.pwm4;
}
2. Adjust for 50HZ frequency
Now, set the divisor and the top value to achieve a PWM frequency of 50Hz.
#![allow(unused)]
fn main() {
pwm.set_div_int(PWM_DIV_INT);
pwm.set_div_frac(0);
pwm.set_top(PWM_TOP);
pwm.enable();
}
3. Set Output Pin
Next, specify the GPIO pin where the PWM signal will be sent. We will use GPIO pin 9.
#![allow(unused)]
fn main() {
let servo = &mut pwm.channel_b;
servo.output_to(pins.gpio9);
}
4. Set Servo Position in a Loop
Finally, in the loop, we adjust the duty cycle which will control the servo’s position. We will move the servo to different positions (0°, 90°, and 180°) using the MIN_DUTY, HALF_DUTY, and MAX_DUTY values calculated earlier.
#![allow(unused)]
fn main() {
loop {
servo.set_duty_cycle(MIN_DUTY).unwrap(); // 0 degrees
timer.delay_ms(1000);
servo.set_duty_cycle(HALF_DUTY).unwrap(); // 90 degrees
timer.delay_ms(1000);
servo.set_duty_cycle(MAX_DUTY).unwrap(); // 180 degrees
timer.delay_ms(1000);
}
}
Full Code snippet
const PWM_DIV_INT: u8 = 64;
const PWM_TOP: u16 = 46_874;
const TOP: u16 = PWM_TOP + 1;
const MIN_DUTY: u16 = (TOP as f64 * (2.5 / 100.)) as u16;
const HALF_DUTY: u16 = (TOP as f64 * (7.5 / 100.)) as u16;
const MAX_DUTY: u16 = (TOP as f64 * (12. / 100.)) as u16;
#[hal::entry]
fn main() -> ! {
// Grab our singleton objects
let mut pac = hal::pac::Peripherals::take().unwrap();
// Set up the watchdog driver - needed by the clock setup code
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
// Configure the clocks
// The default is to generate a 125 MHz system clock
let clocks = hal::clocks::init_clocks_and_plls(
XTAL_FREQ_HZ,
pac.XOSC,
pac.CLOCKS,
pac.PLL_SYS,
pac.PLL_USB,
&mut pac.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
// The single-cycle I/O block controls our GPIO pins
let sio = hal::Sio::new(pac.SIO);
// Set the pins up according to their function on this particular board
let pins = hal::gpio::Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
sio.gpio_bank0,
&mut pac.RESETS,
);
// The delay object lets us wait for specified amounts of time (in
// milliseconds)
let mut timer = hal::Timer::new_timer0(pac.TIMER0, &mut pac.RESETS, &clocks);
// Init PWMs
let mut pwm_slices = hal::pwm::Slices::new(pac.PWM, &mut pac.RESETS);
// Configure PWM4
let pwm = &mut pwm_slices.pwm4;
pwm.set_div_int(PWM_DIV_INT);
pwm.set_div_frac(0);
pwm.set_top(PWM_TOP);
pwm.enable();
let servo = &mut pwm.channel_b;
servo.output_to(pins.gpio9);
loop {
servo.set_duty_cycle(MIN_DUTY).unwrap();
timer.delay_ms(1000);
servo.set_duty_cycle(HALF_DUTY).unwrap();
timer.delay_ms(1000);
servo.set_duty_cycle(MAX_DUTY).unwrap();
timer.delay_ms(1000);
}
}
Clone the existing project
You can clone (or refer) project I created and navigate to the servo folder.
git clone https://github.com/ImplFerris/pico2-rp-projects
cd pico2-projects/servo