MobaTools.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. #ifndef MOBATOOLS_H
  2. #define MOBATOOLS_H
  3. /*
  4. MobaTools.h - a library for model railroaders
  5. Author: fpm, fpm@mnet-mail.de
  6. Copyright (c) 2017 All right reserved.
  7. MobaTools V1.0
  8. (C) 11-2017 fpm fpm@mnet-online.de
  9. History:
  10. V1.0 11-2017 Use of Timer 3 if available ( on AtMega32u4 and AtMega2560 )
  11. V0.9 03-2017
  12. Better resolution for the 'speed' servo-paramter (programm starts in compatibility mode)
  13. outputs for softleds can be inverted
  14. MobaTools run on STM32F1 platform
  15. V0.8 02-2017
  16. Enable Softleds an all digital outputs
  17. V0.7 01-2017
  18. Allow nested Interrupts with the servos. This allows more precise other
  19. interrupts e.g. for NmraDCC Library.
  20. A4988 stepper driver IC is supported (needs only 2 ports: step and direction)
  21. Library to drive the Stepper Motor 28BYJ-48
  22. connected to SPI (MOSI,CLK,SS) Interface via shift register
  23. or 4 pins directly
  24. This library is free software; you can redistribute it and/or
  25. modify it under the terms of the GNU General Public
  26. License as published by the Free Software Foundation; either
  27. version 2.1 of the License, or (at your option) any later version.
  28. This library is distributed in the hope that it will be useful,
  29. but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  31. Lesser General Public License for more details.
  32. You should have received a copy of the GNU General Public
  33. License along with this library; if not, write to the Free Software
  34. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  35. */
  36. /* 08-02-17 start of implementing STM32 support
  37. 03-02-17 / V0.8 Softleds now working on all digital outputs
  38. 02-11-16 / (V0.7) Updating Stepper driver:
  39. - stepper motor can be connected ba means of a4988 stepper motor driver IC
  40. this uses only 2 pins: STEP and DIRECTION
  41. */
  42. #include <inttypes.h>
  43. #include <Arduino.h>
  44. #ifndef __AVR_MEGA__
  45. #ifndef __STM32F1__
  46. #error "Only AVR AtMega or STM32F1 processors are supported"
  47. #endif
  48. #endif
  49. #ifdef __STM32F1__
  50. #include <libmaple/timer.h>
  51. #include <libmaple/spi.h>
  52. #endif
  53. #define Servo2 Servo8 // Kompatibilität zu Version 01 und 02
  54. //defines used in user programs
  55. #define HALFSTEP 1
  56. #define FULLSTEP 2
  57. #define A4988 3 // using motordriver A4988
  58. #define NOSTEP 0 // invalid-flag
  59. #define NO_OUTPUT 0
  60. #ifdef __AVR_MEGA__
  61. #define PIN8_11 1
  62. #define PIN4_7 2
  63. #endif
  64. #define SPI_1 3
  65. #define SPI_2 4
  66. #define SPI_3 5
  67. #define SPI_4 6
  68. #define SINGLE_PINS 7
  69. #define A4988_PINS 8
  70. // for formatted printing to Serial( just like fprintf )
  71. // you need to define txtbuf with proper length to use this
  72. #define SerialPrintf( ... ) sprintf( txtbuf, __VA_ARGS__ ); Serial.print( txtbuf );
  73. //#define FIXED_POSITION_SERVO_PULSES
  74. ////////////////// END OF 'PUBLIC' PARAMETERS ////////////////////////////////////////////////
  75. ////////////////////////////////////////////////////////////////////////////////////////////////////
  76. // internal defines
  77. #ifdef __AVR_MEGA__
  78. // defines only for ATMega
  79. #define FAST_PORTWRT // if this is defined, ports are written directly in IRQ-Routines,
  80. // not with 'digitalWrite' functions
  81. #define TICS_PER_MICROSECOND (clockCyclesPerMicrosecond() / 8 ) // prescaler is 8 = 0.5us
  82. #elif defined __STM32F1__
  83. //defines only for STM32
  84. #define TICS_PER_MICROSECOND (clockCyclesPerMicrosecond() / 36 ) // prescaler is 36 = 0.5us
  85. #endif
  86. // defines for the stepper motor
  87. #define MAX_STEPPER 4 //
  88. #define MIN_STEPTIME 800 // minimum steptime between 2 steps
  89. #define CYCLETIME 200 // Irq-periode in us. Step time is an integer multiple
  90. // of this value
  91. #define CYCLETICS CYCLETIME*TICS_PER_MICROSECOND
  92. // defines for soft-leds
  93. #define MAX_LEDS 16 // Soft On/Off defined for compatibility reasons. There is no fixed limit anymore.
  94. // defines for servos
  95. #define MINPULSEWIDTH 700 // don't make it shorter
  96. #define MAXPULSEWIDTH 2300 // don't make it longer
  97. #ifdef FIXED_POSITION_SERVO_PULSES
  98. #define MAX_SERVOS 8
  99. #else
  100. #define OVLMARGIN 280 // Overlap margin ( Overlap is MINPULSEWIDTH - OVLMARGIN )
  101. #define OVL_TICS ( ( MINPULSEWIDTH - OVLMARGIN ) * TICS_PER_MICROSECOND )
  102. #define MARGINTICS ( OVLMARGIN * TICS_PER_MICROSECOND )
  103. #define MAX_SERVOS 16
  104. #endif
  105. #define MINPULSETICS MINPULSEWIDTH * TICS_PER_MICROSECOND
  106. #define MAXPULSETICS MAXPULSEWIDTH * TICS_PER_MICROSECOND
  107. #define OFF_COUNT 50 // if autoOff is set, a pulse is switched off, if it length does not change for
  108. // OFF_COUNT cycles ( = OFF_COUNT * 20ms )
  109. #define FIRST_PULSE 100 // first pulse starts 200 tics after timer overflow, so we do not compete
  110. // with overflow IRQ
  111. #define SPEED_RES 4 // All position values in tics are multiplied by this factor. This means, that one
  112. // 'Speed-tic' is 0,125 µs per 20ms cycle. This gives better resolution in defining the speed.
  113. // Only when computing the next interrupt time the values are divided by this value again to get
  114. // the real 'timer tics'
  115. ///////////////////////////////////////////////////////////////////////////////////////////////
  116. //
  117. typedef struct { // portaddress and bitmask for direkt pin set/reset
  118. uint8_t* Adr;
  119. uint8_t Mask;
  120. } portBits_t;
  121. /////////////////////////////////////////////////////////////////////////////////
  122. // global stepper data ( used in ISR )
  123. typedef struct {
  124. volatile long stepCnt; // nmbr of steps to take
  125. volatile int8_t patternIx; // Pattern-Index of actual Step (0-7)
  126. int8_t patternIxInc; // halfstep: +/-1, fullstep: +/-2, A4988 +3/-3/
  127. // sign defines direction
  128. uint16_t cycSteps; // nbr of IRQ cycles per step ( speed of motor )
  129. uint16_t rCycSteps; // nbr of IRQ cycles per step during start/stop ramp
  130. uint16_t rStepDec; // count of steps until decrementing cycle ( during start ramp )
  131. volatile uint16_t cycCnt; // counting cycles until cycStep
  132. volatile long stepsFromZero; // distance from last reference point ( always as steps in HALFSTEP mode )
  133. // in FULLSTEP mode this is twice the real step number
  134. uint8_t output :6 ; // PORTB(pin8-11), PORTD (pin4-7), SPI0,SPI1,SPI2,SPI3, SINGLE_PINS, A4988_PINS
  135. uint8_t activ :1;
  136. uint8_t endless :1; // turn endless
  137. #ifdef FAST_PORTWRT
  138. portBits_t portPins[4]; // Outputpins as Portaddress and Bitmask for faster writing
  139. #else
  140. uint8_t pins[4]; // Outputpins as Arduino numbers
  141. #endif
  142. uint8_t lastPattern; // only changed pins are updated ( is faster )
  143. } stepperData_t ;
  144. typedef union { // used output channels as bit and uint8_t
  145. struct {
  146. uint8_t pin8_11 :1;
  147. uint8_t pin4_7 :1;
  148. uint8_t spi1 :1;
  149. uint8_t spi2 :1;
  150. uint8_t spi3 :1;
  151. uint8_t spi4 :1;
  152. };
  153. uint8_t outputs;
  154. } outUsed_t;
  155. ////////////////////////////////////////////////////////////////////////////////////
  156. // global servo data ( used in ISR )
  157. typedef struct servoData_t {
  158. struct servoData_t* prevServoDataP;
  159. uint8_t servoIx :6 ; // Servo number
  160. uint8_t on :1 ; // True: create pulse
  161. uint8_t noAutoff :1; // don't switch pulses off automatically
  162. int soll; // Position, die der Servo anfahren soll ( in Tics ). -1: not initialized
  163. volatile int ist; // Position, die der Servo derzeit einnimt ( in Tics )
  164. int inc; // Schrittweite je Zyklus um Ist an Soll anzugleichen
  165. uint8_t offcnt; // counter to switch off pulses if length doesn't change
  166. #ifdef FAST_PORTWRT
  167. uint8_t* portAdr; // port adress related to pin number
  168. uint8_t bitMask; // bitmask related to pin number
  169. #endif
  170. uint8_t pin ; // pin
  171. } servoData_t ;
  172. //////////////////////////////////////////////////////////////////////////////////
  173. // global data for softleds ( used in ISR )
  174. // the PWM pulses are created together with stepper pulses
  175. //
  176. // table of pwm-steps for soft on/off in CYCLETIME units ( bulb simulation). The last value means pwm cycletime
  177. //14ms cycletime
  178. //const uint8_t iSteps[] = { 2, 3 , 4, 6, 8, 11, 14, 17, 21, 25, 30, 36, 43, 55, 70 };
  179. //16ms cycletime ( 60Hz )
  180. //const uint8_t iSteps[] = {2, 8 ,14 ,20, 25,30, 35, 39, 43, 47, 50, 53, 56, 58, 60, 62, 64,66,68,70,72,73,74,75,76,78,79,80 };
  181. const uint8_t iSteps[] = {9, 16 ,23 ,29, 35,41, 45, 49, 53, 56, 59, 62, 64, 66, 68, 70, 71,72,73,74,75,76,77,77,78,78,79,80 };
  182. // 20ms cycletime ( 50Hz )
  183. //const uint8_t iSteps[] = { 2,4, 6, 9, 12, 15, 20, 25, 30, 35, 40, 45,50,55,65,80,100 };
  184. #define LED_STEP_MAX (sizeof(iSteps) -1)
  185. #define LED_CYCLE_MAX (iSteps[LED_STEP_MAX])
  186. #define LED_PWMTIME (iSteps[LED_STEP_MAX] / 5) // PWM refreshrate in ms
  187. // todo: dies gilt nur bei einer CYCLETIME von 200us (derzeit default)
  188. typedef struct ledData_t { // global led values ( used in IRQ )
  189. struct ledData_t* nextLedDataP; // chaining the active Leds
  190. struct ledData_t** backLedDataPP; // adress of pointer, that points to this led (backwards reference)
  191. int8_t speed; // > 0 : steps per cycle ( more steps = more speed )
  192. // < 0 : cycles per step ( more cycles = less speed )
  193. // 0: led is inactive (not attached)
  194. // uint8_t invert=false; // false: ON ist HIGH, true: ON is LOW
  195. int8_t aStep; // actual step (brightness)
  196. int8_t aCycle; // actual cycle ( =length of PWM pule )
  197. int8_t stpCnt; // counter for PWM cycles on same step (for low speed)
  198. uint8_t actPulse; // PWM pulse is active
  199. uint8_t state; // actual state: steady or incementing/decrementing
  200. #define NOTATTACHED 0
  201. #define STATE_OFF 1 // using #defines here is a little bit faster in the ISR than enums
  202. #define STATE_ON 2
  203. #define ACTIVE 3 // state >= ACTIVE means active in ISR routine
  204. #define INCFAST 3
  205. #define DECFAST 4
  206. #define INCSLOW 5
  207. #define DECSLOW 6
  208. #define INCLIN 7
  209. #define DECLIN 8
  210. volatile uint8_t invFlg;
  211. #ifdef FAST_PORTWRT
  212. portBits_t portPin; // Outputpin as portaddress and bitmask for faster writing
  213. #else
  214. uint8_t pin; // Outputpins as Arduino numbers
  215. #endif
  216. } ledData_t;
  217. //////////////////////////////////////////////////////////////////////////////
  218. class Stepper4
  219. {
  220. private:
  221. uint8_t stepperIx; // Index in Structure
  222. int stepsRev; // steps per full rotation
  223. long stepsToMove; // from last point
  224. uint8_t stepMode; // FULLSTEP or HALFSTEP
  225. uint8_t minCycSteps; // minimum time between 2 steps without ramp
  226. // ramp starts with this speed if wanted speed ist faster
  227. uint8_t minrCycSteps; // absolute minimum time between 2 steps even with ramp
  228. static outUsed_t outputsUsed;
  229. long getSFZ(); // get step-distance from last reference point
  230. void initialize(int,uint8_t,uint8_t);
  231. public:
  232. Stepper4(int steps); // steps per 360 degree in FULLSTEP mode
  233. Stepper4(int steps, uint8_t mode );
  234. // mode means HALFSTEP or FULLSTEP
  235. Stepper4(int steps, uint8_t mode, uint8_t minStepTime ); // min StepTim in ms
  236. uint8_t attach( uint8_t,uint8_t,uint8_t,uint8_t); //single pins definition for output
  237. uint8_t attach( uint8_t stepP, uint8_t dirP); // Port for step and direction in A4988 mode
  238. uint8_t attach(uint8_t outArg); // stepMode defaults to halfstep
  239. uint8_t attach(uint8_t outArg, uint8_t* );
  240. // returns 0 on failure
  241. void detach(); // detach from output, motor will not move anymore
  242. void write(long angle); // specify the angle in degrees, mybe pos or neg. angle is
  243. // measured from last 'setZero' point
  244. void write(long angle, uint8_t factor); // factor specifies resolution of parameter angle
  245. // e.g. 10 means, 'angle' is angle in .1 degrees
  246. void writeSteps( long stepPos );// Go to position stepPos steps from zeropoint
  247. void setZero(); // actual position is set as 0 angle (zeropoint)
  248. int setSpeed(int rpm10 ); // Set movement speed, rpm*10
  249. void doSteps(long count); // rotate count steps. May be positive or negative
  250. // angle is updated internally, so the next call to 'write'
  251. // will move to the correct angle
  252. void rotate(int8_t direction ); // rotate endless until 'stop',
  253. void stop(); // stops moving immediately
  254. uint8_t moving(); // returns the remaining way to the angle last set with write() in
  255. // in percentage. '0' means, that the angle is reached
  256. // 255 means the motor is rotating endlessly
  257. long read(); // actual angle from zeropoint (setZero)
  258. long readSteps(); // actual distance to zeropoint in steps
  259. uint8_t attached();
  260. };
  261. ////////////////////////////////////////////////////////////////////////////////////////
  262. class Servo8
  263. {
  264. private:
  265. int16_t lastPos; // startingpoint of movement
  266. uint8_t pin;
  267. uint8_t angle; // in degrees
  268. uint8_t min16; // minimum pulse, 16uS units (default is 34)
  269. uint8_t max16; // maximum pulse, 16uS units, (default is 150)
  270. servoData_t servoData; // Servo data to be used in ISR
  271. public:
  272. Servo8();
  273. uint8_t attach(int pin); // attach to a pin, sets pinMode, returns 0 on failure, won't
  274. // position the servo until a subsequent write() happens
  275. uint8_t attach( int pin, bool autoOff ); // automatic switch off pulses with constant length
  276. uint8_t attach(int pin, int pos0, int pos180 ); // also sets position values (in us) for angele 0 and 180
  277. uint8_t attach(int pin, int pos0, int pos180, bool autoOff );
  278. void detach();
  279. void write(int); // specify the angle in degrees, 0 to 180. Values obove 180 are interpreted
  280. // as microseconds, limited to MaximumPulse and MinimumPulse
  281. void setSpeed(int); // Set Movement speed, the higher the faster
  282. // Zero means no speed control (default)
  283. void setSpeed(int,bool); // Set compatibility-Flag (true= compatibility with version V08 and earlier)
  284. #define HIGHRES 0
  285. #define SPEEDV08 1
  286. uint8_t moving(); // returns the remaining Way to the angle last set with write() in
  287. // in percentage. '0' means, that the angle is reached
  288. uint8_t read(); // current position in degrees (0...180)
  289. int readMicroseconds();// current pulsewidth in microseconds
  290. uint8_t attached();
  291. void setMinimumPulse(uint16_t); // pulse length for 0 degrees in microseconds, 700uS default
  292. void setMaximumPulse(uint16_t); // pulse length for 180 degrees in microseconds, 2300uS default
  293. };
  294. //////////////////////////////////////////////////////////////////////////////////////////////
  295. class SoftLed
  296. { // Switch leds on/off softly.
  297. //
  298. public:
  299. SoftLed();
  300. uint8_t attach(uint8_t pinArg, uint8_t invArg = false ); // Led-pin with soft on
  301. void riseTime( int ); // in millisec - falltime is the same
  302. void on(); //
  303. void off(); //
  304. void write( uint8_t ); // is ON or OFF
  305. void write( uint8_t time, uint8_t type ); //whether it is a linear or bulb type
  306. void toggle( void );
  307. private:
  308. void mount( uint8_t state );
  309. ledData_t ledData;
  310. uint8_t setpoint;
  311. #define OFF 0
  312. #define ON 1
  313. uint8_t ledType; // Type of lamp (linear or bulb)
  314. #define LINEAR 0
  315. #define BULB 1
  316. uint8_t ledIx;
  317. uint8_t ledValid; // Flag that this is a valid instance
  318. #define LEDVALID 0x55
  319. uint8_t ledSpeed; // speed with IRQ based softleds
  320. };
  321. ////////////////////////////////////////////////////////////////////////////////////////////
  322. // Timermanagement
  323. class EggTimer
  324. {
  325. public:
  326. EggTimer();
  327. void setTime( long);
  328. bool running();
  329. long getTime();
  330. private:
  331. bool active;
  332. long endtime;
  333. };
  334. #endif