Working on a project to control a MC-2100 treadmill motor controller with a Uno.
This requires a 20hz PWM signal that We have working beautifully.
The problem occurs after the duty cycle has been set to anything above 0 and then returned to 0 the MC-2100 will not respond to any further input until the Arduino has been restarted.
Research has shown this is a safety feature of the MC-2100 called "soft start" that prevents the treadmill from restarting at a previously set speed. This issue is described in this video:
In the video he is using one of those cheap function generators to generate the signal to control the treadmill motor. To get around the soft start feature he simply turns off/on the function generator to get it to work again. Note that Power to the MC-2100 is not cycled only power to the function generator is cycled.
In my code I use the reset function to restart the Arduino and that does work, but I would like to find a solution that doesn't require a full reset. Since the only connection's between the 2 are 12v Power and ground from the MC-2100 thru a buck converter set at 7v powering the Arduino. and the PWM wire. I thought that setting the pinMode to INPUT might fool the MC-2100 into thinking it had been reset. But this did not work.
Is there a way to fool the MC-2100 into thinking the Arduino was reset without actually resetting it?
Edit: Forgot the code:
// ================= LCD ================
// https://github.com/duinoWitchery/hd44780
#include <Wire.h>
#include <hd44780.h> // main hd44780 header -
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header
// declare lcd object: auto locate & auto config expander chip
hd44780_I2Cexp lcd;
static constexpr uint8_t LCD_ROWS = 4;
static constexpr uint8_t LCD_COLS = 20;
// ================= KEYPAD ================
#include <Keypad.h>
const byte ROW_NUM = 4;
const byte COLUMN_NUM = 4;
char keys[ROW_NUM][COLUMN_NUM] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
byte pin_rows[ROW_NUM] = { 13, 12, 11, 9 };
byte pin_column[COLUMN_NUM] = { 8, 7, 6, 5 };
Keypad keypad = Keypad(makeKeymap(keys), pin_rows, pin_column, ROW_NUM, COLUMN_NUM);
// ================= CONSTANTS ================
constexpr uint8_t PWM_PIN = 10;
constexpr int TACHO_PIN = 2; // Constants should be all capitol letter's <<<<<
constexpr uint16_t MAX_DUTY = 5300; // 85% of TOP_COUNT
// ================= VARIABLES ================
uint16_t maxTargetDuty = 1000;
uint16_t targetDuty = 0;
uint16_t oldTargetDuty = 0;
int rpm;
// ================= Millis() Timing VARIABLES ================
unsigned long currentTime = 0; // can be used for several timers update it every loop
unsigned long displayStartTime = 0; // used to start/restart the timer
unsigned long displayInterval = 1000; // How often to update the display
unsigned long tachoStartTime = 0;
unsigned long tachoInterval = 1000;
// ================= Interrupt Service Routine For Tacho ================
volatile unsigned long counter = 0; // Counter variable for revolutions
void IRS_RpmCounter() {
counter++;
}
void(* resetFunc) (void) = 0;//declare reset function at address 0
// ================================================================
// * setup() *
// ================================================================
void setup() {
// Interrupt for Tacho
attachInterrupt(digitalPinToInterrupt(TACHO_PIN), IRS_RpmCounter, FALLING);
// Initializes timer 1 to produce a 20 hz pwm on Pin 10
pinMode(PWM_PIN, OUTPUT);
init20hzPWM();
// Initialize Display
lcd.begin(LCD_COLS, LCD_ROWS);
lcd.backlight(); // added turn on LCD backlight
lcd.setCursor(0, 0); // added move LCD cursor to column 0 row 0
lcd.print(" Uno Treadmill"); // added display Uno Treadmill on LCD display
delay(2000); // added wait 2 seconds before continuing
} // End setup()
// ================================================================
// * loop() *
// ================================================================
void loop() {
char key = keypad.getKey();
switch (key) {
case 'A': // Apply the desired duty cycle to start machine
pinMode(PWM_PIN, OUTPUT);
applyDutyCycle();
break;
case 'B': // Stop the machine.... currently by restarting the Arduino
resetFunc(); //call reset
//targetDuty = 0;
//applyDutyCycle();
break;
case 'C': // Small increase in duty cycle applied immediatly
targetDuty += 25;
applyDutyCycle();
break;
case 'D': // Small decrease in duty cycle applied immediatly
targetDuty -= 25;
applyDutyCycle();
break;
default: // Collect input data for duty cycle
byte numKey = key - '0';
if (numKey >= 0 && numKey <= 9) {
targetDuty = targetDuty * 10 + numKey;
}
break;
}
currentTime = millis();
updateRPM();
if (currentTime - displayStartTime >= displayInterval) {
displayStartTime = currentTime; // restarts timer
updateDisplay();
}
} // End loop()
// ================================================================
// * updateRPM() *
// ================================================================
void updateRPM() {
unsigned long tempCount;
if (currentTime - tachoStartTime >= tachoInterval) {
tachoStartTime = currentTime;
noInterrupts();
tempCount = counter;
counter = 0;
interrupts();
rpm = tempCount * 60; // Calculate RPM
}
}
// ================================================================
// * updateDisplay() *
// ================================================================
void updateDisplay() {
lcd.setCursor(0, 0);
lcd.print("Set Dutycycle: ");
lcd.print(targetDuty);
lcd.setCursor(0, 1);
lcd.print("Current RPM: ");
lcd.print(rpm);
lcd.setCursor(0, 2);
lcd.print("Duty Cycle: ");
lcd.print(oldTargetDuty);
lcd.setCursor(0, 3);
lcd.print("A to start B to stop");
} // End updateDisplay()
// ================================================================
// * applyDutyCycle() *
// ================================================================
void applyDutyCycle() {
// Constrain targetDuty within range
if (targetDuty > maxTargetDuty) {
targetDuty = maxTargetDuty;
}
oldTargetDuty = targetDuty;
uint16_t dutyCycle = map(targetDuty, 0, maxTargetDuty, 0, MAX_DUTY);
static uint16_t oldDutyCycle;
if (oldDutyCycle != dutyCycle) {
oldDutyCycle = dutyCycle;
// setting OCR1x applies dutyCycle
OCR1B = dutyCycle;
}
} // End applyDutyCycle()
// ================================================================
// * init20hzPWM() *
// * Set up Timer1 for 20hz phase correct PWM output on pin 10 *
// ================================================================
void init20hzPWM() {
// Desired Clock Divider Value
constexpr uint16_t PRESCALER = 64;
// Desired Frequncy in Herz
constexpr uint16_t FREQUENCY = 20;
// Formula to determine the TOP value, which sets the frequency
// The result must be a unsigned 16 bit integer to be valid (more info needed)
constexpr uint16_t TOP_COUNT = F_CPU / PRESCALER / FREQUENCY / 2;
// Set Compare Output Mode(set OC1B(pin 10) on compare match @TOP, clear OC1B @BOTTOM)
TCCR1A |= (1 << COM1A0);
TCCR1A |= (1 << COM1B1);
// Set Prescaler(Clock Divided by 64)
TCCR1B |= (1 << CS10) | (1 << CS11);
// Set Waveform Mode(Mode 9 Phase and Frequency correct using OCR1A for TOP)
TCCR1A |= (1 << WGM10);
TCCR1B |= (1 << WGM13);
// Set Frequency (20Hz)
OCR1A = TOP_COUNT;
// Set Dutycycle
OCR1B = 0;
} // End init20hzPWM()
// End Program
EDIT2: I should add that the Tach is a work in progrees and the tach wire is not currently hooked up.

