If you are using Arduino Uno/Nano with a 10-bit ADC the line sensors will not reach the threshold of 1500, as 1023 is the maximum value for 10-bit... which means your vehicle will only slow, and not stop. Maybe adjust the thresholds to 900 and 1000?
Left: 1023, Center: 1023, Right: 1023 Approaching line, slowing down...
Left: 1023, Center: 1023, Right: 1023 Approaching line, slowing down...
Left: 1023, Center: 1023, Right: 1023 Approaching line, slowing down...
But consider using digital line sensors, to indicate "LINE" or "NO LINE"... the 1023 steps of the analog reading probably will not change gradually, that is to say, there will not be a "75% line" or "33.3% line" but a "LINE" or "NO LINE"
diagram.json for wokwi.com
{
"version": 1,
"author": "Anonymous maker",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-arduino-nano", "id": "nano", "top": 4.8, "left": -0.5, "attrs": {} },
{ "type": "wokwi-potentiometer", "id": "pot1", "top": -1.3, "left": 172.6, "attrs": {} },
{ "type": "wokwi-potentiometer", "id": "pot2", "top": -1.3, "left": 249.4, "attrs": {} },
{ "type": "wokwi-potentiometer", "id": "pot3", "top": -1.3, "left": 326.2, "attrs": {} }
],
"connections": [
[ "pot1:GND", "nano:GND.1", "black", [ "v9.6", "h-57.6" ] ],
[ "nano:A0", "pot1:SIG", "green", [ "v19.2", "h153.6" ] ],
[ "pot1:VCC", "nano:5V", "red", [ "v28.8", "h-87.2" ] ],
[ "pot2:GND", "nano:GND.1", "black", [ "v9.6", "h-134.4" ] ],
[ "pot2:SIG", "nano:A1", "green", [ "v19.2", "h-230.8" ] ],
[ "pot2:VCC", "nano:5V", "red", [ "v28.8", "h-164" ] ],
[ "pot3:GND", "nano:GND.1", "black", [ "v9.6", "h-211.2" ] ],
[ "pot3:SIG", "nano:A2", "green", [ "v19.2", "h-298" ] ],
[ "pot3:VCC", "nano:5V", "red", [ "v28.8", "h-250.4" ] ]
],
"dependencies": {}
}
AFMotor.h for wokwi.com
// Adafruit Motor shield library
// copyright Adafruit Industries LLC, 2009
// this code is public domain, enjoy!
/*
* Usage Notes:
* For PIC32, all features work properly with the following two exceptions:
*
* 1) Because the PIC32 only has 5 PWM outputs, and the AFMotor shield needs 6
* to completely operate (four for motor outputs and two for RC servos), the
* M1 motor output will not have PWM ability when used with a PIC32 board.
* However, there is a very simple workaround. If you need to drive a stepper
* or DC motor with PWM on motor output M1, you can use the PWM output on pin
* 9 or pin 10 (normally use for RC servo outputs on Arduino, not needed for
* RC servo outputs on PIC32) to drive the PWM input for M1 by simply putting
* a jumber from pin 9 to pin 11 or pin 10 to pin 11. Then uncomment one of the
* two #defines below to activate the PWM on either pin 9 or pin 10. You will
* then have a fully functional microstepping for 2 stepper motors, or four
* DC motor outputs with PWM.
*
* 2) There is a conflict between RC Servo outputs on pins 9 and pins 10 and
* the operation of DC motors and stepper motors as of 9/2012. This issue
* will get fixed in future MPIDE releases, but at the present time it means
* that the Motor Party example will NOT work properly. Any time you attach
* an RC servo to pins 9 or pins 10, ALL PWM outputs on the whole board will
* stop working. Thus no steppers or DC motors.
*
*/
// <BPS> 09/15/2012 Modified for use with chipKIT boards
#ifndef _AFMotor_h_
#define _AFMotor_h_
#include <inttypes.h>
#if defined(__AVR__)
#include <avr/io.h>
//#define MOTORDEBUG 1
#define MICROSTEPS 16 // 8 or 16
#define MOTOR12_64KHZ _BV(CS20) // no prescale
#define MOTOR12_8KHZ _BV(CS21) // divide by 8
#define MOTOR12_2KHZ _BV(CS21) | _BV(CS20) // divide by 32
#define MOTOR12_1KHZ _BV(CS22) // divide by 64
#define MOTOR34_64KHZ _BV(CS00) // no prescale
#define MOTOR34_8KHZ _BV(CS01) // divide by 8
#define MOTOR34_1KHZ _BV(CS01) | _BV(CS00) // divide by 64
#define DC_MOTOR_PWM_RATE MOTOR34_8KHZ // PWM rate for DC motors
#define STEPPER1_PWM_RATE MOTOR12_64KHZ // PWM rate for stepper 1
#define STEPPER2_PWM_RATE MOTOR34_64KHZ // PWM rate for stepper 2
#elif defined(__PIC32MX__)
//#define MOTORDEBUG 1
// Uncomment the one of following lines if you have put a jumper from
// either pin 9 to pin 11 or pin 10 to pin 11 on your Motor Shield.
// Either will enable PWM for M1
//#define PIC32_USE_PIN9_FOR_M1_PWM
//#define PIC32_USE_PIN10_FOR_M1_PWM
#define MICROSTEPS 16 // 8 or 16
// For PIC32 Timers, define prescale settings by PWM frequency
#define MOTOR12_312KHZ 0 // 1:1, actual frequency 312KHz
#define MOTOR12_156KHZ 1 // 1:2, actual frequency 156KHz
#define MOTOR12_64KHZ 2 // 1:4, actual frequency 78KHz
#define MOTOR12_39KHZ 3 // 1:8, acutal frequency 39KHz
#define MOTOR12_19KHZ 4 // 1:16, actual frequency 19KHz
#define MOTOR12_8KHZ 5 // 1:32, actual frequency 9.7KHz
#define MOTOR12_4_8KHZ 6 // 1:64, actual frequency 4.8KHz
#define MOTOR12_2KHZ 7 // 1:256, actual frequency 1.2KHz
#define MOTOR12_1KHZ 7 // 1:256, actual frequency 1.2KHz
#define MOTOR34_312KHZ 0 // 1:1, actual frequency 312KHz
#define MOTOR34_156KHZ 1 // 1:2, actual frequency 156KHz
#define MOTOR34_64KHZ 2 // 1:4, actual frequency 78KHz
#define MOTOR34_39KHZ 3 // 1:8, acutal frequency 39KHz
#define MOTOR34_19KHZ 4 // 1:16, actual frequency 19KHz
#define MOTOR34_8KHZ 5 // 1:32, actual frequency 9.7KHz
#define MOTOR34_4_8KHZ 6 // 1:64, actual frequency 4.8KHz
#define MOTOR34_2KHZ 7 // 1:256, actual frequency 1.2KHz
#define MOTOR34_1KHZ 7 // 1:256, actual frequency 1.2KHz
// PWM rate for DC motors.
#define DC_MOTOR_PWM_RATE MOTOR34_39KHZ
// Note: for PIC32, both of these must be set to the same value
// since there's only one timebase for all 4 PWM outputs
#define STEPPER1_PWM_RATE MOTOR12_39KHZ
#define STEPPER2_PWM_RATE MOTOR34_39KHZ
#endif
// Bit positions in the 74HCT595 shift register output
#define MOTOR1_A 2
#define MOTOR1_B 3
#define MOTOR2_A 1
#define MOTOR2_B 4
#define MOTOR4_A 0
#define MOTOR4_B 6
#define MOTOR3_A 5
#define MOTOR3_B 7
// Constants that the user passes in to the motor calls
#define FORWARD 1
#define BACKWARD 2
#define BRAKE 3
#define RELEASE 4
// Constants that the user passes in to the stepper calls
#define SINGLE 1
#define DOUBLE 2
#define INTERLEAVE 3
#define MICROSTEP 4
/*
#define LATCH 4
#define LATCH_DDR DDRB
#define LATCH_PORT PORTB
#define CLK_PORT PORTD
#define CLK_DDR DDRD
#define CLK 4
#define ENABLE_PORT PORTD
#define ENABLE_DDR DDRD
#define ENABLE 7
#define SER 0
#define SER_DDR DDRB
#define SER_PORT PORTB
*/
// Arduino pin names for interface to 74HCT595 latch
#define MOTORLATCH 12
#define MOTORCLK 4
#define MOTORENABLE 7
#define MOTORDATA 8
class AFMotorController
{
public:
AFMotorController(void);
void enable(void);
friend class AF_DCMotor;
void latch_tx(void);
uint8_t TimerInitalized;
};
class AF_DCMotor
{
public:
AF_DCMotor(uint8_t motornum, uint8_t freq = DC_MOTOR_PWM_RATE);
void run(uint8_t);
void setSpeed(uint8_t);
private:
uint8_t motornum, pwmfreq;
};
class AF_Stepper {
public:
AF_Stepper(uint16_t, uint8_t);
void step(uint16_t steps, uint8_t dir, uint8_t style = SINGLE);
void setSpeed(uint16_t);
uint8_t onestep(uint8_t dir, uint8_t style);
void release(void);
uint16_t revsteps; // # steps per revolution
uint8_t steppernum;
uint32_t usperstep, steppingcounter;
private:
uint8_t currentstep;
};
uint8_t getlatchstate(void);
#endif
AFMotor.cpp for wokwi.com
// Adafruit Motor shield library
// copyright Adafruit Industries LLC, 2009
// this code is public domain, enjoy!
#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#if defined(__AVR__)
#include <avr/io.h>
#endif
#include "WProgram.h"
#endif
#include "AFMotor.h"
static uint8_t latch_state;
#if (MICROSTEPS == 8)
uint8_t microstepcurve[] = {0, 50, 98, 142, 180, 212, 236, 250, 255};
#elif (MICROSTEPS == 16)
uint8_t microstepcurve[] = {0, 25, 50, 74, 98, 120, 141, 162, 180, 197, 212, 225, 236, 244, 250, 253, 255};
#endif
AFMotorController::AFMotorController(void) {
TimerInitalized = false;
}
void AFMotorController::enable(void) {
// setup the latch
/*
LATCH_DDR |= _BV(LATCH);
ENABLE_DDR |= _BV(ENABLE);
CLK_DDR |= _BV(CLK);
SER_DDR |= _BV(SER);
*/
pinMode(MOTORLATCH, OUTPUT);
pinMode(MOTORENABLE, OUTPUT);
pinMode(MOTORDATA, OUTPUT);
pinMode(MOTORCLK, OUTPUT);
latch_state = 0;
latch_tx(); // "reset"
//ENABLE_PORT &= ~_BV(ENABLE); // enable the chip outputs!
digitalWrite(MOTORENABLE, LOW);
}
void AFMotorController::latch_tx(void) {
uint8_t i;
//LATCH_PORT &= ~_BV(LATCH);
digitalWrite(MOTORLATCH, LOW);
//SER_PORT &= ~_BV(SER);
digitalWrite(MOTORDATA, LOW);
for (i=0; i<8; i++) {
//CLK_PORT &= ~_BV(CLK);
digitalWrite(MOTORCLK, LOW);
if (latch_state & _BV(7-i)) {
//SER_PORT |= _BV(SER);
digitalWrite(MOTORDATA, HIGH);
} else {
//SER_PORT &= ~_BV(SER);
digitalWrite(MOTORDATA, LOW);
}
//CLK_PORT |= _BV(CLK);
digitalWrite(MOTORCLK, HIGH);
}
//LATCH_PORT |= _BV(LATCH);
digitalWrite(MOTORLATCH, HIGH);
}
static AFMotorController MC;
/******************************************
MOTORS
******************************************/
inline void initPWM1(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2A on PB3 (Arduino pin #11)
TCCR2A |= _BV(COM2A1) | _BV(WGM20) | _BV(WGM21); // fast PWM, turn on oc2a
TCCR2B = freq & 0x7;
OCR2A = 0;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 11 is now PB5 (OC1A)
TCCR1A |= _BV(COM1A1) | _BV(WGM10); // fast PWM, turn on oc1a
TCCR1B = (freq & 0x7) | _BV(WGM12);
OCR1A = 0;
#elif defined(__PIC32MX__)
#if defined(PIC32_USE_PIN9_FOR_M1_PWM)
// Make sure that pin 11 is an input, since we have tied together 9 and 11
pinMode(9, OUTPUT);
pinMode(11, INPUT);
if (!MC.TimerInitalized)
{ // Set up Timer2 for 80MHz counting fro 0 to 256
T2CON = 0x8000 | ((freq & 0x07) << 4); // ON=1, FRZ=0, SIDL=0, TGATE=0, TCKPS=<freq>, T32=0, TCS=0; // ON=1, FRZ=0, SIDL=0, TGATE=0, TCKPS=0, T32=0, TCS=0
TMR2 = 0x0000;
PR2 = 0x0100;
MC.TimerInitalized = true;
}
// Setup OC4 (pin 9) in PWM mode, with Timer2 as timebase
OC4CON = 0x8006; // OC32 = 0, OCTSEL=0, OCM=6
OC4RS = 0x0000;
OC4R = 0x0000;
#elif defined(PIC32_USE_PIN10_FOR_M1_PWM)
// Make sure that pin 11 is an input, since we have tied together 9 and 11
pinMode(10, OUTPUT);
pinMode(11, INPUT);
if (!MC.TimerInitalized)
{ // Set up Timer2 for 80MHz counting fro 0 to 256
T2CON = 0x8000 | ((freq & 0x07) << 4); // ON=1, FRZ=0, SIDL=0, TGATE=0, TCKPS=<freq>, T32=0, TCS=0; // ON=1, FRZ=0, SIDL=0, TGATE=0, TCKPS=0, T32=0, TCS=0
TMR2 = 0x0000;
PR2 = 0x0100;
MC.TimerInitalized = true;
}
// Setup OC5 (pin 10) in PWM mode, with Timer2 as timebase
OC5CON = 0x8006; // OC32 = 0, OCTSEL=0, OCM=6
OC5RS = 0x0000;
OC5R = 0x0000;
#else
// If we are not using PWM for pin 11, then just do digital
digitalWrite(11, LOW);
#endif
#else
#error "This chip is not supported!"
#endif
#if !defined(PIC32_USE_PIN9_FOR_M1_PWM) && !defined(PIC32_USE_PIN10_FOR_M1_PWM)
pinMode(11, OUTPUT);
#endif
}
inline void setPWM1(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2A on PB3 (Arduino pin #11)
OCR2A = s;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 11 is now PB5 (OC1A)
OCR1A = s;
#elif defined(__PIC32MX__)
#if defined(PIC32_USE_PIN9_FOR_M1_PWM)
// Set the OC4 (pin 9) PMW duty cycle from 0 to 255
OC4RS = s;
#elif defined(PIC32_USE_PIN10_FOR_M1_PWM)
// Set the OC5 (pin 10) PMW duty cycle from 0 to 255
OC5RS = s;
#else
// If we are not doing PWM output for M1, then just use on/off
if (s > 127)
{
digitalWrite(11, HIGH);
}
else
{
digitalWrite(11, LOW);
}
#endif
#else
#error "This chip is not supported!"
#endif
}
inline void initPWM2(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2B (pin 3)
TCCR2A |= _BV(COM2B1) | _BV(WGM20) | _BV(WGM21); // fast PWM, turn on oc2b
TCCR2B = freq & 0x7;
OCR2B = 0;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 3 is now PE5 (OC3C)
TCCR3A |= _BV(COM1C1) | _BV(WGM10); // fast PWM, turn on oc3c
TCCR3B = (freq & 0x7) | _BV(WGM12);
OCR3C = 0;
#elif defined(__PIC32MX__)
if (!MC.TimerInitalized)
{ // Set up Timer2 for 80MHz counting fro 0 to 256
T2CON = 0x8000 | ((freq & 0x07) << 4); // ON=1, FRZ=0, SIDL=0, TGATE=0, TCKPS=<freq>, T32=0, TCS=0; // ON=1, FRZ=0, SIDL=0, TGATE=0, TCKPS=0, T32=0, TCS=0
TMR2 = 0x0000;
PR2 = 0x0100;
MC.TimerInitalized = true;
}
// Setup OC1 (pin3) in PWM mode, with Timer2 as timebase
OC1CON = 0x8006; // OC32 = 0, OCTSEL=0, OCM=6
OC1RS = 0x0000;
OC1R = 0x0000;
#else
#error "This chip is not supported!"
#endif
pinMode(3, OUTPUT);
}
inline void setPWM2(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2A on PB3 (Arduino pin #11)
OCR2B = s;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 11 is now PB5 (OC1A)
OCR3C = s;
#elif defined(__PIC32MX__)
// Set the OC1 (pin3) PMW duty cycle from 0 to 255
OC1RS = s;
#else
#error "This chip is not supported!"
#endif
}
inline void initPWM3(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0A / PD6 (pin 6)
TCCR0A |= _BV(COM0A1) | _BV(WGM00) | _BV(WGM01); // fast PWM, turn on OC0A
//TCCR0B = freq & 0x7;
OCR0A = 0;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 6 is now PH3 (OC4A)
TCCR4A |= _BV(COM1A1) | _BV(WGM10); // fast PWM, turn on oc4a
TCCR4B = (freq & 0x7) | _BV(WGM12);
//TCCR4B = 1 | _BV(WGM12);
OCR4A = 0;
#elif defined(__PIC32MX__)
if (!MC.TimerInitalized)
{ // Set up Timer2 for 80MHz counting fro 0 to 256
T2CON = 0x8000 | ((freq & 0x07) << 4); // ON=1, FRZ=0, SIDL=0, TGATE=0, TCKPS=<freq>, T32=0, TCS=0; // ON=1, FRZ=0, SIDL=0, TGATE=0, TCKPS=0, T32=0, TCS=0
TMR2 = 0x0000;
PR2 = 0x0100;
MC.TimerInitalized = true;
}
// Setup OC3 (pin 6) in PWM mode, with Timer2 as timebase
OC3CON = 0x8006; // OC32 = 0, OCTSEL=0, OCM=6
OC3RS = 0x0000;
OC3R = 0x0000;
#else
#error "This chip is not supported!"
#endif
pinMode(6, OUTPUT);
}
inline void setPWM3(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0A on PB3 (Arduino pin #6)
OCR0A = s;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 6 is now PH3 (OC4A)
OCR4A = s;
#elif defined(__PIC32MX__)
// Set the OC3 (pin 6) PMW duty cycle from 0 to 255
OC3RS = s;
#else
#error "This chip is not supported!"
#endif
}
inline void initPWM4(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0B / PD5 (pin 5)
TCCR0A |= _BV(COM0B1) | _BV(WGM00) | _BV(WGM01); // fast PWM, turn on oc0a
//TCCR0B = freq & 0x7;
OCR0B = 0;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 5 is now PE3 (OC3A)
TCCR3A |= _BV(COM1A1) | _BV(WGM10); // fast PWM, turn on oc3a
TCCR3B = (freq & 0x7) | _BV(WGM12);
//TCCR4B = 1 | _BV(WGM12);
OCR3A = 0;
#elif defined(__PIC32MX__)
if (!MC.TimerInitalized)
{ // Set up Timer2 for 80MHz counting fro 0 to 256
T2CON = 0x8000 | ((freq & 0x07) << 4); // ON=1, FRZ=0, SIDL=0, TGATE=0, TCKPS=<freq>, T32=0, TCS=0; // ON=1, FRZ=0, SIDL=0, TGATE=0, TCKPS=0, T32=0, TCS=0
TMR2 = 0x0000;
PR2 = 0x0100;
MC.TimerInitalized = true;
}
// Setup OC2 (pin 5) in PWM mode, with Timer2 as timebase
OC2CON = 0x8006; // OC32 = 0, OCTSEL=0, OCM=6
OC2RS = 0x0000;
OC2R = 0x0000;
#else
#error "This chip is not supported!"
#endif
pinMode(5, OUTPUT);
}
inline void setPWM4(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0A on PB3 (Arduino pin #6)
OCR0B = s;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 6 is now PH3 (OC4A)
OCR3A = s;
#elif defined(__PIC32MX__)
// Set the OC2 (pin 5) PMW duty cycle from 0 to 255
OC2RS = s;
#else
#error "This chip is not supported!"
#endif
}
AF_DCMotor::AF_DCMotor(uint8_t num, uint8_t freq) {
motornum = num;
pwmfreq = freq;
MC.enable();
switch (num) {
case 1:
latch_state &= ~_BV(MOTOR1_A) & ~_BV(MOTOR1_B); // set both motor pins to 0
MC.latch_tx();
initPWM1(freq);
break;
case 2:
latch_state &= ~_BV(MOTOR2_A) & ~_BV(MOTOR2_B); // set both motor pins to 0
MC.latch_tx();
initPWM2(freq);
break;
case 3:
latch_state &= ~_BV(MOTOR3_A) & ~_BV(MOTOR3_B); // set both motor pins to 0
MC.latch_tx();
initPWM3(freq);
break;
case 4:
latch_state &= ~_BV(MOTOR4_A) & ~_BV(MOTOR4_B); // set both motor pins to 0
MC.latch_tx();
initPWM4(freq);
break;
}
}
void AF_DCMotor::run(uint8_t cmd) {
uint8_t a, b;
switch (motornum) {
case 1:
a = MOTOR1_A; b = MOTOR1_B; break;
case 2:
a = MOTOR2_A; b = MOTOR2_B; break;
case 3:
a = MOTOR3_A; b = MOTOR3_B; break;
case 4:
a = MOTOR4_A; b = MOTOR4_B; break;
default:
return;
}
switch (cmd) {
case FORWARD:
latch_state |= _BV(a);
latch_state &= ~_BV(b);
MC.latch_tx();
break;
case BACKWARD:
latch_state &= ~_BV(a);
latch_state |= _BV(b);
MC.latch_tx();
break;
case RELEASE:
latch_state &= ~_BV(a); // A and B both low
latch_state &= ~_BV(b);
MC.latch_tx();
break;
}
}
void AF_DCMotor::setSpeed(uint8_t speed) {
switch (motornum) {
case 1:
setPWM1(speed); break;
case 2:
setPWM2(speed); break;
case 3:
setPWM3(speed); break;
case 4:
setPWM4(speed); break;
}
}
/******************************************
STEPPERS
******************************************/
AF_Stepper::AF_Stepper(uint16_t steps, uint8_t num) {
MC.enable();
revsteps = steps;
steppernum = num;
currentstep = 0;
if (steppernum == 1) {
latch_state &= ~_BV(MOTOR1_A) & ~_BV(MOTOR1_B) &
~_BV(MOTOR2_A) & ~_BV(MOTOR2_B); // all motor pins to 0
MC.latch_tx();
// enable both H bridges
pinMode(11, OUTPUT);
pinMode(3, OUTPUT);
digitalWrite(11, HIGH);
digitalWrite(3, HIGH);
// use PWM for microstepping support
initPWM1(STEPPER1_PWM_RATE);
initPWM2(STEPPER1_PWM_RATE);
setPWM1(255);
setPWM2(255);
} else if (steppernum == 2) {
latch_state &= ~_BV(MOTOR3_A) & ~_BV(MOTOR3_B) &
~_BV(MOTOR4_A) & ~_BV(MOTOR4_B); // all motor pins to 0
MC.latch_tx();
// enable both H bridges
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
// use PWM for microstepping support
// use PWM for microstepping support
initPWM3(STEPPER2_PWM_RATE);
initPWM4(STEPPER2_PWM_RATE);
setPWM3(255);
setPWM4(255);
}
}
void AF_Stepper::setSpeed(uint16_t rpm) {
usperstep = 60000000 / ((uint32_t)revsteps * (uint32_t)rpm);
steppingcounter = 0;
}
void AF_Stepper::release(void) {
if (steppernum == 1) {
latch_state &= ~_BV(MOTOR1_A) & ~_BV(MOTOR1_B) &
~_BV(MOTOR2_A) & ~_BV(MOTOR2_B); // all motor pins to 0
MC.latch_tx();
} else if (steppernum == 2) {
latch_state &= ~_BV(MOTOR3_A) & ~_BV(MOTOR3_B) &
~_BV(MOTOR4_A) & ~_BV(MOTOR4_B); // all motor pins to 0
MC.latch_tx();
}
}
void AF_Stepper::step(uint16_t steps, uint8_t dir, uint8_t style) {
uint32_t uspers = usperstep;
uint8_t ret = 0;
if (style == INTERLEAVE) {
uspers /= 2;
}
else if (style == MICROSTEP) {
uspers /= MICROSTEPS;
steps *= MICROSTEPS;
#ifdef MOTORDEBUG
Serial.print("steps = "); Serial.println(steps, DEC);
#endif
}
while (steps--) {
ret = onestep(dir, style);
delay(uspers/1000); // in ms
steppingcounter += (uspers % 1000);
if (steppingcounter >= 1000) {
delay(1);
steppingcounter -= 1000;
}
}
if (style == MICROSTEP) {
while ((ret != 0) && (ret != MICROSTEPS)) {
ret = onestep(dir, style);
delay(uspers/1000); // in ms
steppingcounter += (uspers % 1000);
if (steppingcounter >= 1000) {
delay(1);
steppingcounter -= 1000;
}
}
}
}
uint8_t AF_Stepper::onestep(uint8_t dir, uint8_t style) {
uint8_t a, b, c, d;
uint8_t ocrb, ocra;
ocra = ocrb = 255;
if (steppernum == 1) {
a = _BV(MOTOR1_A);
b = _BV(MOTOR2_A);
c = _BV(MOTOR1_B);
d = _BV(MOTOR2_B);
} else if (steppernum == 2) {
a = _BV(MOTOR3_A);
b = _BV(MOTOR4_A);
c = _BV(MOTOR3_B);
d = _BV(MOTOR4_B);
} else {
return 0;
}
// next determine what sort of stepping procedure we're up to
if (style == SINGLE) {
if ((currentstep/(MICROSTEPS/2)) % 2) { // we're at an odd step, weird
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
}
else {
currentstep -= MICROSTEPS/2;
}
} else { // go to the next even step
if (dir == FORWARD) {
currentstep += MICROSTEPS;
}
else {
currentstep -= MICROSTEPS;
}
}
} else if (style == DOUBLE) {
if (! (currentstep/(MICROSTEPS/2) % 2)) { // we're at an even step, weird
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
} else {
currentstep -= MICROSTEPS/2;
}
} else { // go to the next odd step
if (dir == FORWARD) {
currentstep += MICROSTEPS;
} else {
currentstep -= MICROSTEPS;
}
}
} else if (style == INTERLEAVE) {
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
} else {
currentstep -= MICROSTEPS/2;
}
}
if (style == MICROSTEP) {
if (dir == FORWARD) {
currentstep++;
} else {
// BACKWARDS
currentstep--;
}
currentstep += MICROSTEPS*4;
currentstep %= MICROSTEPS*4;
ocra = ocrb = 0;
if ( (currentstep >= 0) && (currentstep < MICROSTEPS)) {
ocra = microstepcurve[MICROSTEPS - currentstep];
ocrb = microstepcurve[currentstep];
} else if ( (currentstep >= MICROSTEPS) && (currentstep < MICROSTEPS*2)) {
ocra = microstepcurve[currentstep - MICROSTEPS];
ocrb = microstepcurve[MICROSTEPS*2 - currentstep];
} else if ( (currentstep >= MICROSTEPS*2) && (currentstep < MICROSTEPS*3)) {
ocra = microstepcurve[MICROSTEPS*3 - currentstep];
ocrb = microstepcurve[currentstep - MICROSTEPS*2];
} else if ( (currentstep >= MICROSTEPS*3) && (currentstep < MICROSTEPS*4)) {
ocra = microstepcurve[currentstep - MICROSTEPS*3];
ocrb = microstepcurve[MICROSTEPS*4 - currentstep];
}
}
currentstep += MICROSTEPS*4;
currentstep %= MICROSTEPS*4;
#ifdef MOTORDEBUG
Serial.print("current step: "); Serial.println(currentstep, DEC);
Serial.print(" pwmA = "); Serial.print(ocra, DEC);
Serial.print(" pwmB = "); Serial.println(ocrb, DEC);
#endif
if (steppernum == 1) {
setPWM1(ocra);
setPWM2(ocrb);
} else if (steppernum == 2) {
setPWM3(ocra);
setPWM4(ocrb);
}
// release all
latch_state &= ~a & ~b & ~c & ~d; // all motor pins to 0
//Serial.println(step, DEC);
if (style == MICROSTEP) {
if ((currentstep >= 0) && (currentstep < MICROSTEPS))
latch_state |= a | b;
if ((currentstep >= MICROSTEPS) && (currentstep < MICROSTEPS*2))
latch_state |= b | c;
if ((currentstep >= MICROSTEPS*2) && (currentstep < MICROSTEPS*3))
latch_state |= c | d;
if ((currentstep >= MICROSTEPS*3) && (currentstep < MICROSTEPS*4))
latch_state |= d | a;
} else {
switch (currentstep/(MICROSTEPS/2)) {
case 0:
latch_state |= a; // energize coil 1 only
break;
case 1:
latch_state |= a | b; // energize coil 1+2
break;
case 2:
latch_state |= b; // energize coil 2 only
break;
case 3:
latch_state |= b | c; // energize coil 2+3
break;
case 4:
latch_state |= c; // energize coil 3 only
break;
case 5:
latch_state |= c | d; // energize coil 3+4
break;
case 6:
latch_state |= d; // energize coil 4 only
break;
case 7:
latch_state |= d | a; // energize coil 1+4
break;
}
}
MC.latch_tx();
return currentstep;
}