Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

See https://elliotmade.com/2020/06/26/treadmill-controller-reverse-engineering/


Speed to Byte Message:

MPHByte 1Byte 2Byte 3Byte 4Byte 5Byte 6Byte 7Measured RPM
0.002552412002210
0.5

0

00

255

FF

241

F1

2

02

0

00

161

A1

16

10


0.6025524120195201
0.7025524120230186
0.80255241218144
0.902552412142116
1.002552412176105332
1.1025524121111188
1.202552412114533
1.3025524121179197
1.4025524121213216
1.502552412124818
1.602552412226156
1.702552412260188
1.802552412294101
1.902552412212979
2.0025524122163171670
2.1025524122197182
2.202552412223182
2.30255241231043
2.40255241234411
2.502552412378210
2.60255241231128
2.7025524123147154
2.8025524123181186
2.902552412321599
3.00255241232492501016
3.10255241242896
3.202552412462132
3.302552412496229
3.402552412413070
3.502552412416587
3.6025524124199142
3.702552412423323
3.80255241251164
3.90255241254651
4.0025524125802121358
4.102552412511448
4.202552412514887
4.3025524125183130
4.402552412521738
4.5025524125251194
4.602552412629136
4.702552412664186
4.80255241269894
4.902552412613257
5.00255241261662211700
5.1025524126200121
5.2025524126235172
5.30255241271363
5.402552412747219
5.50255241278160
5.602552412711679
5.7025524127150236
5.8025524127184117
5.9025524127218172
6.00255241272531892042
6.102552412831135
6.202552412865230
6.3025524128992
6.402552412813454
6.5025524128164175
6.6025524128202118
6.702552412823686
6.802552412915112
6.902552412949234
7.002552412983512385
7.102552412911719
7.2025524129152158
7.3025524129186122
7.4025524129220103
7.5025524129254131
7.6025524121033132
7.702552412106793
7.80255241210101125
7.90255241210135222
8.00255241210170202725
8.102552412102049
8.20255241210238237
8.3025524121116132
8.402552412115181
8.502552412118576
8.60255241211119168
8.70255241211153118
8.802552412111885
8.90255241211222220
9.0025524121201053070
9.1025524121234141
9.20255241212101161
9.3025524121210369
9.40255241212137139
9.50255241212171127
9.6025524121220649
9.70255241212240235
9.8025524121318188
9.9025524121352156
10.00255241213871163414
10.10255241213121237
10.2025524121315578
10.30255241213173110
10.4025524121322492
10.502552412142210
10.6025524121436242
10.702552412147043
10.80255241214105131
10.9025524121413932
11.0025524121417303752
11.10255241214207217
11.2025524121424280
11.3025524121520195
11.402552412155439
11.5025524121588131
11.6025524121512386
11.7025524121515749
11.80255241215191213
11.90255241215225180
12.0025524121641193996


Arduino Code

Code Block
/*
 * Encoder on A2, A3 
 * Button on A1
 * MAX 485: 5v to DE, D8 to DI.  A and B to A and B of the treadmill controller
 * TM1637 display clock on 2, data on 3
 * Short out the middle "safety key" pins 
 * Take power from one of the treadmill controller pins (which one?)
 * Treadmill header has 8 pins (left to right, latch at the bottom):
 * 1 - 12v
 * 2 - 12v
 * 3 - A or B?
 * 4 - Safety switch
 * 5 - Safety switch
 * 6 - A or B?
 * 7 - Ground
 * 8 - Ground
*/




#include <AltSoftSerial.h>
//https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html

#include <SimpleTimer.h>
//https://github.com/jfturcot/SimpleTimer

#include <RotaryEncoder.h>
//http://www.mathertel.de/Arduino/RotaryEncoderLibrary.aspx
//https://github.com/mathertel/RotaryEncoder

#include "OneButton.h"
//https://github.com/mathertel/OneButton

#include <TM1637Display.h>
//https://github.com/avishorp/TM1637

#include <EEPROMex.h>
//https://github.com/thijse/Arduino-EEPROMEx

const int encoderButton = A1;
const int encoderA = A2;
const int encoderB = A3;
const int dispClock = 2; //D2
const int dispData = 3; //D3


AltSoftSerial ss;
SimpleTimer timer;
OneButton encoderButt(encoderButton, true);
RotaryEncoder encoder(A2, A3);
TM1637Display display1(dispClock, dispData);

bool halt = true;
int setSpeed = 0;
int curSpeed = 0; //ramp this up until it reaches the set speed
int savedSpeed = 0;
const int speedCount = 123;

const byte b1[] = {0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16};
const byte b2[] = {0,161,195,230,8,42,76,111,145,179,213,248,26,60,94,129,163,197,231,10,44,78,112,147,181,215,249,28,62,96,130,165,199,233,11,46,80,114,148,183,217,251,29,64,98,132,166,200,235,13,47,81,116,150,184,218,253,31,65,99,134,164,202,236,15,49,83,117,152,186,220,254,33,67,101,135,170,204,238,16,51,85,119,153,188,222,0,34,101,103,137,171,206,240,18,52,87,121,155,173,224,2,36,70,105,139,173,207,242,20,54,88,123,157,191,225,4,20,54,88,123,157,191,225};
const byte b3[] = {221,16,201,186,144,116,105,188,33,197,216,18,156,188,101,79,171,182,82,43,11,210,8,154,186,99,250,96,132,229,70,87,142,23,64,51,212,48,87,130,38,194,136,186,94,57,221,121,172,63,219,60,79,236,117,172,189,135,230,2,54,175,118,86,112,234,51,19,158,122,103,131,132,93,125,222,20,9,237,132,81,76,168,118,5,220,105,141,161,69,139,127,49,235,188,156,116,237,78,110,92,210,242,43,131,32,0,217,80,195,39,131,86,49,213,180,119,195,39,131,86,49,213,180};
const int sfm[] = {0,262,314,366,418,471,523,575,628,680,732,785,837,889,941,994,1046,1098,1151,1203,1255,1308,1360,1412,1464,1517,1569,1621,1674,1726,1778,1831,1883,1935,1987,2040,2092,2144,2197,2249,2301,2355,2406,2458,2510,2563,2615,2667,2721,2772,2824,2878,2929,2981,3033,3087,3138,3190,3244,3295,3347,3401,3453,3504,3556,3610,3661,3713,3767,3818,3870,3924,3976,4027,4079,4133,4184,4236,4290,4342,4393,4447,4499,4550,4602,4656,4708,4759,4813,4865,4916,4970,5022,5074,5125,5179,5231,5282,5336,5388,5440,5493,5545,5597,5648,5702,5754,5805,5859,5911,5963,6016,6068,6120,6171,6225,6277,6329,6382,6434,6486,6539,6591,6643};

//eeprom memory locations
const int memAddress = 20;
const int memBase = 350;


void setup() {
  //interrupts for encoder
  PCICR |= (1 << PCIE1);    // This enables Pin Change Interrupt 1 that covers the Analog input pins or Port C.
  PCMSK1 |= (1 << PCINT10) | (1 << PCINT11);  // This enables the interrupt for pin 2 and 3 of Port C.
  //Serial.begin(9600);
  ss.begin(9600);
  timer.setInterval(100, sendSpeedPacket);
  encoderButt.attachClick(startStop);

  // Set Up EEPROM
  EEPROM.setMemPool(memBase, EEPROMSizeNano);

  //Load the stored speed value
  setSpeed = EEPROM.readInt(memAddress);

  display1.setBrightness(2);
  updateDisplay();
}

void loop() {
  // put your main code here, to run repeatedly:
  timer.run();
  encoderButt.tick();
  readEncoder();
  updateDisplay();
}

void sendSpeedPacket() {

  if(halt == true) { //send the stop packet
    ss.write((byte)0);
    ss.write((byte)255);
    ss.write((byte)241);
    ss.write((byte)2);
    ss.write((byte)0);
    ss.write((byte)0);
    ss.write((byte)221);
  }
  else { //send the current speed packet
    ss.write((byte)0);
    ss.write((byte)255);
    ss.write((byte)241);
    ss.write((byte)2);
    ss.write((byte)b1[curSpeed]);
    ss.write((byte)b2[curSpeed]);
    ss.write((byte)b3[curSpeed]);   
  }

  if (halt == true){
    curSpeed = 0;
  }

  if (curSpeed < setSpeed && halt == false) { //this ramps the sent speed up until it hits the set speed
    curSpeed++;
  }
  if (curSpeed > setSpeed && halt == false) { //this immediately reduces the sent speed to the set speed
    curSpeed = setSpeed;
  }

  //Serial.print(halt);
  //Serial.print(" ");
  //Serial.println(curSpeed);
  
}

void startStop () {
  halt = !halt;
  EEPROM.writeInt(memAddress, setSpeed); //save the speed every time the button is pushed... so that on next power up it is not zero
}

void readEncoder() {
  static int pos = 0;

  int newPos = encoder.getPosition();
      if (pos > newPos) {
        setSpeed = setSpeed - 1;
      }
      else if (pos < newPos) {
        setSpeed = setSpeed + 1;
      }
      pos = newPos; //--keep

      setSpeed = constrain(setSpeed, 0, speedCount);


}

ISR(PCINT1_vect) {
  encoder.tick(); // just call tick() to check the state.
}


void updateDisplay() {
  display1.showNumberDecEx(sfm[setSpeed], 0, true);  //Set time should always show on display 1
//  Serial.print("Minutes: ");
//  Serial.print(seconds / 60);
//  Serial.print("Seconds: ");
//  Serial.println(seconds & 60);
}

...