Microcontroller Unit Lab 5
Multiple Independant H-Bridge Motors
Organized by C Struct Variables with PWM Throttle
Code
Part 1 Library & Timed Sequence Demonstration.
h-bridge.h
#include "pico/stdlib.h"
#include "hardware/pwm.h"
#define HB_PWM_WRAP 499
#define HB_PWM_DIV 10
struct H_Bridge {
uint fwd_gp;
uint rev_gp;
};
enum H_Bridge_Mode {
STOP,
FORWARD,
REVERSE
};
void hb_pin_setup(struct H_Bridge hb);
void hb_set_duty(struct H_Bridge hb, enum H_Bridge_Mode m, float duty_set);
h-bridge.c
#include "h-bridge.h"
void hb_pin_setup(struct H_Bridge hb){
//forward pin
gpio_set_function(hb.fwd_gp, GPIO_FUNC_PWM);
int f_slice_num = pwm_gpio_to_slice_num(hb.fwd_gp);
pwm_set_enabled(f_slice_num, true);
pwm_set_wrap(f_slice_num, HB_PWM_WRAP);
pwm_set_clkdiv_int_frac(f_slice_num, HB_PWM_DIV, 0);
pwm_set_gpio_level(hb.fwd_gp, 0);
//reverse pin
gpio_set_function(hb.rev_gp, GPIO_FUNC_PWM);
int r_slice_num = pwm_gpio_to_slice_num(hb.rev_gp);
pwm_set_enabled(r_slice_num, true);
pwm_set_wrap(r_slice_num, HB_PWM_WRAP);
pwm_set_clkdiv_int_frac(r_slice_num, HB_PWM_DIV, 0);
pwm_set_gpio_level(hb.rev_gp, 0);
}
void hb_set_duty(struct H_Bridge hb, enum H_Bridge_Mode m, float duty_set){
if(duty_set > 1.0f) duty_set = 1.0f;
if(duty_set < 0.0f) duty_set = 0.0f;
switch(m) {
default:
case STOP:
pwm_set_gpio_level(hb.fwd_gp, 0);
pwm_set_gpio_level(hb.rev_gp, 0);
break;
case FORWARD:
pwm_set_gpio_level(hb.rev_gp, 0);
int f_level = duty_set * HB_PWM_WRAP;
pwm_set_gpio_level(hb.fwd_gp, f_level);
break;
case REVERSE:
pwm_set_gpio_level(hb.fwd_gp, 0);
int r_level = duty_set * HB_PWM_WRAP;
pwm_set_gpio_level(hb.rev_gp, r_level);
break;
}
}
main.c
#include "pico/stdlib.h"
#include "h-bridge.h"
struct H_Bridge hb_motor_left;
struct H_Bridge hb_motor_right;
int main() {
// setup & initialize
hb_motor_left.fwd_gp = 12;
hb_motor_left.rev_gp = 13;
hb_pin_setup(hb_motor_left);
hb_motor_right.fwd_gp = 14;
hb_motor_right.rev_gp = 15;
hb_pin_setup(hb_motor_right);
// primary loop
while (true) {
hb_set_duty(hb_motor_right, FORWARD, 0.85f);
hb_set_duty(hb_motor_left, FORWARD, .8f);
sleep_ms(1000);
hb_set_duty(hb_motor_right, STOP, 0.0f);
hb_set_duty(hb_motor_left, STOP, 0.0f);
sleep_ms(1000);
hb_set_duty(hb_motor_right, REVERSE, 0.90f);
hb_set_duty(hb_motor_left, REVERSE, 0.95f);
sleep_ms(1000);
hb_set_duty(hb_motor_right, STOP, 0.0f);
hb_set_duty(hb_motor_left, STOP, 0.0f);
sleep_ms(1000);
}
}
Code
Part 2 2wd Mode Select, No Speed Yet.
main.c
#include "pico/stdlib.h"
#include "h-bridge.h"
/*
//// BENCH
#define HB_L_FWD_GP 13
#define HB_L_REV_GP 12
#define HB_R_FWD_GP 14
#define HB_R_REV_GP 15
#define BTN_MODE_GP 22
*/
//// ACTUAL CAR
#define HB_L_FWD_GP 15
#define HB_L_REV_GP 14
#define HB_R_FWD_GP 13
#define HB_R_REV_GP 12
#define BTN_MODE_GP 18
// Buttons: speed up, speed down
#define POLL_DELAY_MS_FAST 10
#define POLL_DELAY_MS_SLOW 250
bool do_slow_delay = false;
struct H_Bridge hb_motor_left;
struct H_Bridge hb_motor_right;
enum Drive_Mode {
D_STOP,
D_FORWARD,
D_REVERSE,
D_ROTATE_L,
D_ROTATE_R
};
enum Drive_Mode drive_mode_last_active = D_STOP;
enum Drive_Mode drive_mode_current = D_STOP;
//TODO: speed/duty variables
// current, increment, min
//PROTOS
void app_pin_setup();
void app_check_buttons();
void app_mode_change();
void app_update_motors();
void app_poll_delay();
int main() {
// setup & initialize
hb_motor_left.fwd_gp = HB_L_FWD_GP;
hb_motor_left.rev_gp = HB_L_REV_GP;
hb_pin_setup(hb_motor_left);
hb_motor_right.fwd_gp = HB_R_FWD_GP;
hb_motor_right.rev_gp = HB_R_REV_GP;
hb_pin_setup(hb_motor_right);
app_pin_setup();
// primary loop
while (true) {
app_check_buttons();
app_update_motors();
app_poll_delay();
}
}
//IMPLEMENTS
void app_check_buttons(){
int mode_state = gpio_get(BTN_MODE_GP);
if(mode_state == 0) {
app_mode_change();
do_slow_delay = true;
}
}
void app_pin_setup(){
gpio_init(BTN_MODE_GP);
gpio_set_dir(BTN_MODE_GP, GPIO_IN);
gpio_pull_up(BTN_MODE_GP);
}
void app_mode_change() {
if(drive_mode_current != D_STOP) {
drive_mode_last_active = drive_mode_current;
drive_mode_current = D_STOP;
} else {
//the drive mode WAS stop
drive_mode_current = drive_mode_last_active + 1;
if(drive_mode_current > D_ROTATE_R) drive_mode_current = D_FORWARD;
}
}
void app_update_motors(){
switch(drive_mode_current){
default:
case D_STOP:
hb_set_duty(hb_motor_left, STOP, 0.0f);
hb_set_duty(hb_motor_right, STOP, 0.0f);
break;
case D_FORWARD:
hb_set_duty(hb_motor_left, FORWARD, 1.0f);
hb_set_duty(hb_motor_right, FORWARD, 1.0f);
break;
case D_REVERSE:
hb_set_duty(hb_motor_left, REVERSE, 1.0f);
hb_set_duty(hb_motor_right, REVERSE, 1.0f);
break;
case D_ROTATE_L:
hb_set_duty(hb_motor_left, REVERSE, 1.0f);
hb_set_duty(hb_motor_right, FORWARD, 1.0f);
break;
case D_ROTATE_R:
hb_set_duty(hb_motor_left, FORWARD, 1.0f);
hb_set_duty(hb_motor_right, REVERSE, 1.0f);
break;
}
}
void app_poll_delay() {
if (do_slow_delay) {
sleep_ms(POLL_DELAY_MS_SLOW);
do_slow_delay = false;
} else {
sleep_ms(POLL_DELAY_MS_FAST);
}
}