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