HIDE NAV

Microcontroller Unit Lab 5

BiPolar Stepper Motor Control

Using a Step-Direction Board with
CPU step signal & Pulse Width Modulation signal



Summary

Use a microcontoller to provide a step & direction control siginal to a bipolar stepper motor driver board.

Setup 

  a.  Setup Dual Voltage (12v / 5v) Power Circuit using a 5v Regulator.

  b.  Solder Stepper Motor Wires onto 4 pin Male Header.

  c.  Wire Microcontroller, Stepper Driver and Stepper Motor.

Pt. 1  Repeated CPU-timed sequences

  a.  Create a repeated control sequence that verifies repeatable movement.

  b.  Determine a practical upper limit of pulse rate (i.e. rotational speed).

  c.  Determine the effects of microstep settings on accuracy and maximum speed.

Pt. 2  Add three buttons - speed up, speed down and direction change.

Pt. 3  Replace the CPU timing with Pulse Width Modulation control where the PWM freqency controls the motor speed.



Required Equipment and Supplies

- NEMA 17 Stepper Motor - datasheet

- A4988 Bipolar Stepper Driver Board - pinout diagramIC Datasheet

- LM7805 or LM323 5V Regulator LM7805 datasheetLM323 datasheet

- Rasperry Pi Pico with Headers - pinout diagram

- Momentary Switch (Push Button) [x3]

- 15kΩ Resistor [x3]

- USB Micro Cable

- Breadboard

- Cables and 22ga wire as needed



Example Code For Pt. 1


/// A CPU timed sequence of repeating movements
#include "pico/stdlib.h"

const uint STEP = 17;
const uint DIR = 16;
uint PERIOD = 1500;

int main() {
// setup and  initialize
	gpio_init(STEP);
	gpio_init(DIR);
  gpio_set_dir(STEP,GPIO_OUT);
  gpio_set_dir(DIR,GPIO_OUT);

// primary loop
	while (true) {
		gpio_put(DIR, 0);
		//1/4 turn
		for(int i = 0; i < 200; i++){
			//single pulse @ 200 Hz
			//  200Hz = 5ms = 5000 us
			gpio_put(STEP, 1);
			sleep_us(100);
			gpio_put(STEP, 0);
			sleep_us(PERIOD-100);
			}
		sleep_ms(1000);

		gpio_put(DIR, 1);
		//1/4 turn
		for(int i = 0; i < 200; i++){
			gpio_put(STEP, 1);
			sleep_us(100);
			gpio_put(STEP, 0);
			sleep_us(PERIOD-100);
		}
		sleep_ms(1000);

	}
}


Example Code For Pt. 2


/// A CPU timed demonstration using three buttons 
#include "pico/stdlib.h"

const uint STEP = 17;
const uint DIR = 16;

const uint BTN_SPEED_UP = 20;
const uint BTN_SPEED_DN = 19;
const uint BTN_MODE = 18;

const uint STEP_PERIOD_MAX = 10000;
const uint STEP_PERIOD_MIN = 1500;
const uint STEP_PERIOD_INC = 500;

uint period;
int mode = 0; // 0 stop, 1 forward, 2 stop, 3 reverse
const uint DEBOUNCE_DELAY = 150;

void check_buttons();
void step(uint per, int n_steps);

int main() {
// setup and  initialize
	gpio_init(STEP);
	gpio_set_dir(STEP,GPIO_OUT);

	gpio_init(DIR);
  gpio_set_dir(DIR,GPIO_OUT);

	gpio_init(BTN_MODE);
	gpio_set_dir(BTN_MODE, GPIO_IN);

	gpio_init(BTN_SPEED_UP);
	gpio_set_dir(BTN_SPEED_UP, GPIO_IN);

	gpio_init(BTN_SPEED_DN);
	gpio_set_dir(BTN_SPEED_DN, GPIO_IN);

	period = (STEP_PERIOD_MAX - STEP_PERIOD_MIN)/2;

// primary loop
	while (true) {
		check_buttons();
		step(period, 20);
	}
}


	void check_buttons(){

		if (gpio_get(BTN_MODE) == 0) {
			mode++;
			if(mode > 3) mode = 0;
			if(mode == 1) gpio_put(DIR, 1); // mode 1 is forward
			if(mode == 3) gpio_put(DIR, 0); // mode 3 is reverse
			sleep_ms(DEBOUNCE_DELAY); //debounce delay
			return;
		}

		if (gpio_get(BTN_SPEED_UP) == 0) {
			period -= STEP_PERIOD_INC;
			if(period < STEP_PERIOD_MIN) period = STEP_PERIOD_MIN;
			sleep_ms(DEBOUNCE_DELAY); //debounce delay
			return;
		}

		if(gpio_get(BTN_SPEED_DN) == 0) {
			period += STEP_PERIOD_INC;
			if(period > STEP_PERIOD_MAX) period = STEP_PERIOD_MAX;
			sleep_ms(DEBOUNCE_DELAY); //debounce delay
			return;
		}
	}

	void step(uint per, int n_steps){
		if(n_steps < 0) return;
		if(mode == 1 || mode == 3) {
				//take n steps
			for(int i = 0; i < n_steps; i++){
				gpio_put(STEP, 1);
				sleep_us(100);
				gpio_put(STEP, 0);
				sleep_us(per-100);
			}
		}
	}



Example Code For Pt. 3


/// A PWM timed demonstration using three buttons
#include "pico/stdlib.h"
#include "hardware/pwm.h"

const uint STEP = 17;
const uint DIR = 16;

const uint BTN_SPEED_UP = 20;
const uint BTN_SPEED_DN = 19;
const uint BTN_MODE = 18;

const uint WRAP_MAX = 60000u;
const uint WRAP_MIN = 20000u;
const uint WRAP_INC = 2500u;

uint16_t wrap = 35000u;
int mode = 0; // 0 stop, 1 forward, 2 stop, 3 reverse
const uint DEBOUNCE_DELAY = 150;

void pin_setup();
void check_buttons();
void pwm_step();

int main() {
	// setup and  initialize
	pin_setup();
	// primary loop
	while (true) {
		check_buttons();
		pwm_step();
	}
}


void pin_setup() {

	//pwm on this pin. Start in off position
	gpio_set_function(STEP, GPIO_FUNC_PWM);
	pwm_set_enabled(pwm_gpio_to_slice_num(STEP), true);
	pwm_set_gpio_level(STEP,0);

	gpio_init(DIR);
	gpio_set_dir(DIR,GPIO_OUT);

	gpio_init(BTN_MODE);
	gpio_set_dir(BTN_MODE, GPIO_IN);

	gpio_init(BTN_SPEED_UP);
	gpio_set_dir(BTN_SPEED_UP, GPIO_IN);

	gpio_init(BTN_SPEED_DN);
	gpio_set_dir(BTN_SPEED_DN, GPIO_IN);
}




void check_buttons(){

	if (gpio_get(BTN_MODE) == 0) {
		mode++;
		if(mode > 3) mode = 0;
		if(mode == 1) gpio_put(DIR, 1); // mode 1 is forward
		if(mode == 3) gpio_put(DIR, 0); // mode 3 is reverse
		sleep_ms(DEBOUNCE_DELAY); //debounce delay
		return;
	}

	if (gpio_get(BTN_SPEED_UP) == 0) {
		wrap -= WRAP_INC;
		if(wrap < WRAP_MIN) wrap = WRAP_MIN;
		sleep_ms(DEBOUNCE_DELAY); //debounce delay
		return;
	}

	if(gpio_get(BTN_SPEED_DN) == 0) {
		wrap += WRAP_INC;
		if(wrap > WRAP_MAX) wrap = WRAP_MAX;
		sleep_ms(DEBOUNCE_DELAY); //debounce delay
		return;
	}
}


void pwm_step() {
	uint8_t int_divider = 10;
	uint8_t frac_divider = 0;  //divider fraction not used
	pwm_set_wrap(pwm_gpio_to_slice_num(STEP), wrap);
	pwm_set_clkdiv_int_frac(pwm_gpio_to_slice_num(STEP), int_divider, frac_divider);
	if(mode == 1 || mode == 3){
		pwm_set_gpio_level(STEP,1000);
	} else {
		pwm_set_gpio_level(STEP,0);
	}
}