refactor v1

This commit is contained in:
2025-01-10 13:53:27 +01:00
parent 09c7107a07
commit 285ec4b38d
52 changed files with 79 additions and 21 deletions

View File

@@ -0,0 +1,54 @@
# Source and include
BUILD_DIR=build
SRCS=$(wildcard src/*.c)
OBJS=$(SRCS:%.c=build/%.o)
INC=-I ./inc
# MCU configuration
# Set MCU type, clock frequency and programmer
MCU=atmega8
CLOCK_FREQ=16000000
PROG_STR=usbasp
# Compiler flags
CFLAGS=-std=c11 -Wall -Wextra -Werror -mmcu=$(MCU) -DF_CPU=$(CLOCK_FREQ)
OPT_FLAGS=-O3 -g -DDEBUG
# Compiler and utility tools
OBJCOPY=avr-objcopy
CC=avr-gcc
# Project configuration
PROJ_NAME=sflap_controller_fw
PROJ_BLD=$(BUILD_DIR)/$(PROJ_NAME)
# Rules
all: $(PROJ_BLD).elf
$(PROJ_BLD).elf: $(OBJS)
$(CC) -o $@ $^ $(INC) $(CFLAGS) $(OPT_FLAGS) $(MCU_FLAGS)
$(OBJCOPY) -j .text -j .data -O ihex $@ $(PROJ_BLD).hex
$(OBJCOPY) -j .text -j .data -O binary $@ $(PROJ_BLD).bin
build/%.o: %.c
mkdir -p build/src
$(CC) -c -o $@ $(INC) $(CFLAGS) $(OPT_FLAGS) $(MCU_FLAGS) $<
release: OPT_FLAGS=-O2 -DNDEBUG
release: $(PROJ_BLD).elf
fuse:
avrdude -c $(PROG_STR) -p $(MCU) -U lfuse:w:0xDF:m -U hfuse:w:0xCA:m -B 125kHz
flash:
avrdude -c $(PROG_STR) -p $(MCU) -U flash:w:$(PROJ_BLD).hex:i
flash-debug:
avrdude -c $(PROG_STR) -p $(MCU) -U flash:w:$(PROJ_BLD).elf:e
clean:
rm -rf build
.PHONY = clean, release, flash, flash-debug

View File

@@ -0,0 +1,162 @@
#include "mctrl.h"
#include "rcount.h"
#include "rs485.h"
#include <avr/io.h>
#include <avr/wdt.h>
#include <stdlib.h>
#include <util/delay.h>
/*
* PD0 -> BUS_RX
* PD1 -> BUS_TX
* PD2 -> BUS_DIR (0=RECV/1=SEND)
*
* PD3 -> SENSOR_IN
*
* PC0-3 -> MOTOR CTRL
*/
uint16_t address = 0x0000;
int16_t calib_offset = 0x0000;
void eeprom_write_c(uint16_t address, uint8_t data) {
// disable interrupt
cli();
while (EECR & (1 << EEWE))
; // wait until previous write is done
EEAR = address;
EEDR = data;
EECR |= (1 << EEMWE); // enable Master Write Enable
EECR |= (1 << EEWE); // write one
sei();
}
uint8_t eeprom_read_c(uint16_t address) {
while (EECR & (1 << EEWE))
; // wait until previous write is done
EEAR = address;
EECR |= (1 << EERE); // read one
return EEDR;
}
#define CONF_CONST_OKAY (uint8_t)0xAA
#define CONF_ADDR_OKAY 0x0004
#define CONF_ADDR_ADDR 0x0000
#define CONF_ADDR_OFFSET 0x0002
void initialSetup() {
wdt_disable();
if (eeprom_read_c(CONF_ADDR_OKAY) == CONF_CONST_OKAY) {
uint8_t addrL = eeprom_read_c(CONF_ADDR_ADDR);
uint8_t addrH = eeprom_read_c(CONF_ADDR_ADDR + 1);
address = addrL | (addrH << 8);
uint8_t offsetL = eeprom_read_c(CONF_ADDR_OFFSET);
uint8_t offsetH = eeprom_read_c(CONF_ADDR_OFFSET + 1);
calib_offset = offsetL | (offsetH << 8);
} else {
eeprom_write_c(CONF_ADDR_ADDR, (uint8_t)0x00);
eeprom_write_c(CONF_ADDR_ADDR + 1, (uint8_t)0x00);
eeprom_write_c(CONF_ADDR_OFFSET, (uint8_t)0x00);
eeprom_write_c(CONF_ADDR_OFFSET + 1, (uint8_t)0x00);
eeprom_write_c(CONF_ADDR_OKAY, CONF_CONST_OKAY);
}
}
void readCommand() {
char *payload = malloc(64);
uint8_t payload_len = sfbus_recv_frame(address, payload);
if (payload_len > 0) {
// read command byte
uint8_t opcode = *payload;
// parse commands
if (opcode == (uint8_t)0x10) {
// 0x1O = Set Digit
uint8_t targetDigit = *(payload + 1);
mctrl_set(targetDigit, 0);
} else if (opcode == (uint8_t)0x11) {
// 0x11 = Set Digit (full rotation)
uint8_t targetDigit = *(payload + 1);
mctrl_set(targetDigit, 1);
} else if (opcode == (uint8_t)0xF0) {
// 0xFO = READ EEPROM
uint8_t bytes = 5;
char *msg = malloc(bytes + 1);
*msg = 0xAA;
for (uint16_t i = 1; i < (uint16_t)bytes + 1; i++) {
*(msg + i) = eeprom_read_c(i - 1);
}
_delay_ms(2);
sfbus_send_frame(0xFFFF, msg, bytes + 1);
free(msg);
} else if (opcode == (uint8_t)0xF1) {
// 0xF1 = WRITE EEPROM
eeprom_write_c(CONF_ADDR_OKAY, (char)0xFF);
for (uint16_t i = 0; i < 4; i++) {
eeprom_write_c(i, *(payload + 1 + i));
}
eeprom_write_c(CONF_ADDR_OKAY, CONF_CONST_OKAY);
// respond with readout
uint8_t bytes = 5;
char *msg = malloc(bytes + 1);
*msg = 0xAA;
for (uint16_t i = 1; i < (uint16_t)bytes + 1; i++) {
*(msg + i) = eeprom_read_c(i - 1);
}
_delay_ms(2);
sfbus_send_frame(0xFFFF, msg, bytes + 1);
free(msg);
// now use new addr
uint8_t addrL = eeprom_read_c(CONF_ADDR_ADDR);
uint8_t addrH = eeprom_read_c(CONF_ADDR_ADDR + 1);
address = addrL | (addrH << 8);
} else if (opcode == (uint8_t)0xF8) {
// 0xF8 = Get Status
char *msg = malloc(7);
*msg = getSts();
uint16_t voltage = getVoltage();
*(msg + 2) = (voltage >> 0) & 0xFF;
*(msg + 1) = (voltage >> 8) & 0xFF;
uint32_t counter = rc_getCounter();
*(msg + 6) = (counter >> 0) & 0xFF;
*(msg + 5) = (counter >> 8) & 0xFF;
*(msg + 4) = (counter >> 16) & 0xFF;
*(msg + 3) = (counter >> 24) & 0xFF;
_delay_ms(2);
sfbus_send_frame(0xFFFF, msg, 7);
free(msg);
} else if (opcode == (uint8_t)0xFE) {
// 0xFE = PING
char msg = 0xFF;
_delay_ms(2);
sfbus_send_frame(0xFFFF, &msg, 1);
} else if ((opcode & (uint8_t)0xFE) == (uint8_t)0x20) {
// 0x20 = poweroff; 0x21 is poweron
uint8_t state = opcode & (uint8_t)0x01;
mctrl_power(state);
} else if (opcode == (uint8_t)0x30) {
// 0x30 = reset
do {
wdt_enable(WDTO_15MS);
for (;;) {
}
} while (0);
} else {
// invalid opcode
char msg = 0xEE;
_delay_ms(2);
sfbus_send_frame(0xFFFF, &msg, 1);
}
}
free(payload);
}
int main() {
initialSetup();
rs485_init();
mctrl_init();
while (1 == 1) {
readCommand();
}
}

View File

@@ -0,0 +1,242 @@
#include "mctrl.h"
// Motor driver steps definition. Reverse for direction change.
uint8_t motor_steps[4] = {
0b00000001,
0b00000010,
0b00000100,
0b00001000,
};
uint8_t step_index = 0; // cuurent index in motor_steps
uint8_t target_flap = 0; // target flap
uint16_t absolute_pos = 0; // absolute position in steps
uint16_t rel_offset = 1400; // offset of '0' flap relative to home
uint16_t steps_since_home = 0; // steps since last home signal
// homing util variables
uint8_t homing = 0; // current homing step
uint8_t lastSens = 0; // home sonsor signal from last tick
// counter for auto powersaving
uint8_t ticksSinceMove = 0;
// value to goto after the current target_flap is reached. 255 = NONE.
uint8_t afterRotation = 255;
int16_t *delta_err;
// error and status flags
uint8_t sts_flag_errorTooBig = 0; // last home signal too early or too late
uint8_t sts_flag_noHome = 0; // no home signal detected. Wheel stuck
uint8_t sts_flag_fuse = 0; // blown fuse detcted
uint8_t sts_flag_pwrdwn = 0; // device is powered down by controller
uint8_t sts_flag_failsafe = 0; // device is powered down for safety reasons
uint8_t sts_flag_busy = 0; // device is busy
// voltage monitoring variables
uint16_t currentVoltage = 0; // current ADC reading
uint8_t currentFaultReadings = 0; // ticks with faulty readings (too many will
// trip pwrdwn and sts_flag_fuse)
// initialize motor controller
void mctrl_init() {
DDRC = 0x0F; // set all pins as outputs
PORTC = 0x00; // set all to LOW
DDRD &= ~(1 << PD3); // PD3 is input
PORTD |= (1 << PD3); // PD3 pullup
// setup adc
ADMUX = 0x07; // Aref, ADC7
ADCSRA =
(1 << ADEN) | (1 << ADSC) | (1 << ADPS1); // Enable ADC, Start first
// reading No frerunning, 8MHz
while ((ADCSRA & (1 << ADSC)) > 0)
; // wait until first reading is complete,
// to avoid error flag on first tick!
// setup timer for ISR
TCCR1A = 0;
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // CTC und Prescaler 64
OCR1A = 480; // 8.000.000 / 64 / 1000 für 1ms
OCR1A = 580; // 8.000.000 / 64 / 1000 für 1ms
// OCR1A = 450; // 8.000.000 / 64 /
// 1000 für 1ms
TIMSK = 1 << OCIE1A; // Timerinterrupts aktivieren
homing = 1;
delta_err = malloc(ERROR_DATASETS * sizeof(uint16_t));
_delay_ms(1000);
sei();
}
// call when critical fail. Powers down motor and sets flags
void failSafe() {
sts_flag_failsafe = 1;
PORTC = 0x00;
}
// read voltage non blocking (called every tick)
void readVoltage() {
currentVoltage = ADC; // read last measurement
ADMUX = 0x07; // select ADC7
ADCSRA |= (1 << ADSC); // trigger next reading
if (currentVoltage < 128) { // if voltage is too low, fuse is probably broken
currentFaultReadings++;
if (currentFaultReadings > 20) { // too many fault readings trigger failSafe
sts_flag_fuse = 1;
failSafe();
}
}
}
// MAIN service routine. Called by timer 1
ISR(TIMER1_COMPA_vect) {
readVoltage(); // read and check voltage
if (sts_flag_pwrdwn == 1 || sts_flag_failsafe == 1) {
return;
} // if sts_flag_pwrdwn, STOP!
if (steps_since_home >
STEPS_PRE_REV * 1.5) { // check if home is missing for too long
// home missing error. Wheel probably stuck or power fail
sts_flag_noHome = 1;
failSafe();
} else if (homing == 1) { // Homing procedure 1. step: move out of home
if ((PIND & (1 << PD3)) > 0) {
homing = 2;
} else {
mctrl_step();
}
} else if (homing == 2) { // Homing procedure 2. step: find magnet
mctrl_step();
if ((PIND & (1 << PD3)) == 0) {
homing = 3;
steps_since_home = 0;
absolute_pos = rel_offset;
incrementCounter();
}
} else if (homing == 3) { // Homing procedure 3. step: find magnet
if (absolute_pos <= 0) {
homing = 0;
absolute_pos = rel_offset;
}
mctrl_step();
absolute_pos--;
} else { // when no failsafe is triggered and homing is done
// calculate target position
uint16_t target_pos = (target_flap * STEPS_PRE_FLAP) + rel_offset;
if (target_pos >= STEPS_PRE_REV) {
target_pos -= STEPS_PRE_REV;
}
if (absolute_pos != target_pos) {
// if target position is not reached, move motor
ticksSinceMove = 0;
mctrl_step();
absolute_pos++;
if (absolute_pos >= STEPS_PRE_REV) {
absolute_pos -= STEPS_PRE_REV;
}
// detect home position
if ((PIND & (1 << PD3)) == 0) {
if (lastSens == 0) {
// new home transition
int16_t errorDelta =
(absolute_pos > (STEPS_PRE_REV / 2) ? absolute_pos - STEPS_PRE_REV
: absolute_pos);
sts_flag_errorTooBig =
(errorDelta > 30) || (errorDelta < -30) ? 1 : 0;
// storeErr(errorDelta);
absolute_pos = 0;
steps_since_home = 0;
// increment rotations counter
incrementCounter();
}
lastSens = 1;
} else {
lastSens = 0;
}
} else { // if target position is reached
if (afterRotation < 55) { // if after rotation is set, apply it as new target
target_flap = afterRotation;
afterRotation = 255;
} else if (ticksSinceMove < 2) { // if motor has not been moved
sts_flag_busy = 0;
} else if (ticksSinceMove < 50) { // if motor has not been moved
ticksSinceMove++;
} else { // power off after 50 ticks
// PORTC = 0x00; // turn off stepper
}
}
}
rc_tick(); // process counter tick, non-blocking
}
// TODO
void storeErr(int16_t error) {
int16_t *delta_err_tmp = malloc(ERROR_DATASETS * sizeof(uint16_t));
memcpy(delta_err, delta_err_tmp + sizeof(uint16_t),
((ERROR_DATASETS - 2) * sizeof(uint16_t)));
memcpy(&error, delta_err_tmp, sizeof(uint16_t));
free(delta_err);
delta_err = delta_err_tmp;
}
// TODO
void getErr(int16_t *error) {
memcpy(delta_err, error, (ERROR_DATASETS * sizeof(uint16_t)));
}
// return status flag
uint8_t getSts() {
uint8_t status = sts_flag_errorTooBig; // bit 0: delta too big
status |= sts_flag_noHome << 1; // bit 1: no home found
status |= sts_flag_fuse << 2; // bit 2: fuse blown
status |= sts_flag_pwrdwn << 4; // bit 4: device powered down
status |= sts_flag_failsafe << 5; // bit 5: failsafe active
status |= sts_flag_busy << 6; // bit 6: failsafe active
if ((PIND & (1 << PD3)) == 0) {
status |= (1 << 3);
}
return status;
}
// return voltage
uint16_t getVoltage() { return currentVoltage; }
// set target flap
void mctrl_set(uint8_t flap, uint8_t fullRotation) {
sts_flag_busy = 1;
if (fullRotation == 0) {
target_flap = flap;
// if (absolute_pos < STEPS_ADJ) {
// absolute_pos += STEPS_PRE_REV;
// }
// absolute_pos -= STEPS_ADJ;
} else {
target_flap = (target_flap + (STEPS_PRE_FLAP - 1)) % STEPS_PRE_FLAP;
afterRotation = flap;
}
}
// trigger home procedure
void mctrl_home() { homing = 1; }
// trigger home procedure
void mctrl_power(uint8_t state) {
if (state == 0) {
sts_flag_pwrdwn = 1;
PORTC = 0x00;
}else{
sts_flag_pwrdwn = 0;
PORTC = motor_steps[step_index];
}
}
// do stepper step (I/O)
void mctrl_step() {
step_index++;
steps_since_home++;
if (step_index > 3) {
step_index = 0;
}
PORTC = motor_steps[step_index];
}

View File

@@ -0,0 +1,36 @@
#pragma once
#define MP_A PC0
#define MP_B PC1
#define MP_C PC2
#define MP_D PC3
#define STEPS_PRE_REV 2025
#define STEPS_PRE_FLAP 45
#define STEPS_ADJ 0 // added per flap to compensate for motor power down
#define AMOUNTFLAPS 45
#define ERROR_DATASETS 8
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "rcount.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
void mctrl_init();
void mctrl_step();
void mctrl_set(uint8_t flap, uint8_t fullRotation);
void getErr(int16_t* error);
uint8_t getSts();
uint16_t getVoltage();
void mctrl_power(uint8_t state);
#ifdef __cplusplus
}
#endif // __cplusplus

View File

@@ -0,0 +1,45 @@
#include "rcount.h"
uint8_t rc_eeprom_write_c(uint16_t address, uint8_t data) {
// disable interrupt
if (EECR & (1 << EEWE)) { return 1; }
EEAR = address;
EEDR = data;
EECR |= (1 << EEMWE); // enable Master Write Enable
EECR |= (1 << EEWE); // write one
return 0;
}
uint8_t rc_eeprom_read_c(uint16_t address) {
while (EECR & (1 << EEWE))
; // wait until previous write is done
EEAR = address;
EECR |= (1 << EERE); // read one
return EEDR;
}
uint32_t counter = (uint32_t)0xFFFFFFFF;
uint8_t counter_phase = 5;
void rc_tick() {
if (counter == (uint32_t)0xFFFFFFFF) { counter = rc_getCounter(); }
if (counter_phase < 5) {
cli();
if (rc_eeprom_write_c(0x100 + counter_phase, ((counter >> (counter_phase * 8)) & 0xFF)) == 0) {
counter_phase++;
}
sei();
}
}
void incrementCounter() {
counter++;
counter_phase = 0;
}
uint32_t rc_getCounter() {
uint32_t counter = rc_eeprom_read_c(0x100);
counter |= ((uint32_t)rc_eeprom_read_c(0x101) << 8);
counter |= ((uint32_t)rc_eeprom_read_c(0x102) << 16);
counter |= ((uint32_t)rc_eeprom_read_c(0x103) << 24);
return counter;
}

View File

@@ -0,0 +1,13 @@
#include <avr/io.h>
#include <avr/interrupt.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
void incrementCounter();
uint32_t rc_getCounter();
void rc_tick();
#ifdef __cplusplus
}
#endif // __cplusplus

View File

@@ -0,0 +1,86 @@
#include "rs485.h"
void rs485_init() {
// init I/O
DDRD &= ~(1 << PD0); // BUS_DIR & TX is OUTPUT
DDRD |= (1 << PD2) | (1 << PD1); // BUS_DIR & TX is OUTPUT
PORTD &= 0x07; // clear PD0-PD4
// init UART
UBRRH = (BAUDRATE >> 8);
UBRRL = BAUDRATE; // set baud rate
UCSRB |= (1 << TXEN) | (1 << RXEN); // enable receiver and transmitter
UCSRC |= (1 << URSEL) | (1 << UCSZ0) | (1 << UCSZ1); // 8bit data format
}
void dbg(char data) {
while (!(UCSRA & (1 << UDRE)))
;
UDR = data;
}
void rs485_send_c(char data) {
PORTD |= (1 << PD2); // set transciever to transmitt
while (!(UCSRA & (1 << UDRE)))
; // wait until buffer is empty
UCSRA = (1 << TXC); // clear transmit Complete bit
UDR = data;
while (!(UCSRA & (1 << TXC)))
; // wait until transmitt complete
PORTD &= ~(1 << PD2); // set transciever to transmitt
}
void rs485_send_str(char* data) {
for (unsigned int i = 0; i < sizeof(data); i++) {
rs485_send_c(data[i]);
}
}
char rs485_recv_c() {
while (!(UCSRA & (1 << RXC)))
;
; // wait while data is being received
return UDR;
}
// SFBUS Functions
uint8_t sfbus_recv_frame(uint16_t address, char* payload) {
while (rs485_recv_c() != '+') {} // Wwait for start byte
uint8_t frm_version = rs485_recv_c();
if (frm_version != 0) return 0;
uint8_t frm_length = rs485_recv_c();
uint8_t frm_addrL = rs485_recv_c();
uint8_t frm_addrH = rs485_recv_c();
uint16_t frm_addr = frm_addrL | (frm_addrH << 8);
if (frm_addr != address) return 0;
char* _payload = payload;
for (uint8_t i = 0; i < (frm_length - 3); i++) {
*_payload = rs485_recv_c();
_payload++;
}
if (rs485_recv_c() != '$') return -1;
return frm_length;
}
void sfbus_send_frame(uint16_t address, char* payload, uint8_t length) {
char framelen = length;
rs485_send_c(SFBUS_SOF_BYTE); // send startbyte 3 times
rs485_send_c(0); // send protocol version
rs485_send_c(framelen + 3); // send lentgh of remaining frame
rs485_send_c(address & 0xFF); // target address
rs485_send_c((address >> 8) & 0xFF);
while (framelen > 0) { // send payload
rs485_send_c(*payload);
payload++;
framelen--;
}
rs485_send_c(SFBUS_EOF_BYTE); // send end of frame byte
}

View File

@@ -0,0 +1,27 @@
#pragma once
//#define F_CPU 16000000UL
#define UART_BAUD 19200
#define BAUDRATE ((F_CPU) / (UART_BAUD * 16UL) - 1) // set baud rate value for UBRR
#define SFBUS_SOF_BYTE '+'
#define SFBUS_EOF_BYTE '$'
#include <avr/io.h>
#include <avr/interrupt.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
void dbg(char data);
void rs485_init(void);
void rs485_send_c(char data);
void rs485_send_str(char* data);
char rs485_recv_c(void);
uint8_t sfbus_recv_frame(uint16_t address, char* payload);
void sfbus_send_frame(uint16_t address, char* payload, uint8_t length);
#ifdef __cplusplus
}
#endif // __cplusplus

View File

@@ -0,0 +1,153 @@
#include <Stepper.h>
#define BAUDRATE 115200
#define STEPPERPIN1 11
#define STEPPERPIN2 10
#define STEPPERPIN3 9
#define STEPPERPIN4 8
#define STEPS 2038 //28BYJ-48 stepper, number of steps
#define HALLPIN 7 //Pin of hall sensor
#define AMOUNTFLAPS 45
#define ROTATIONDIRECTION 1 //-1 for reverse direction
#define OVERHEATINGTIMEOUT 2 //timeout in seconds to avoid overheating of stepper. After starting rotation, the counter will start. Stepper won't move again until timeout is passed
unsigned long lastRotation = 0;
//globals
int displayedLetter = 0; //currently shown letter
int desiredLetter = 0; //letter to be shown
const String letters[] = {" ", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "Ä", "Ö", "Ü", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ".", "-", "?", "!"};
Stepper stepper(STEPS, STEPPERPIN1, STEPPERPIN3, STEPPERPIN2, STEPPERPIN4); //stepper setup
bool lastInd1 = false; //store last status of phase
bool lastInd2 = false; //store last status of phase
bool lastInd3 = false; //store last status of phase
bool lastInd4 = false; //store last status of phase
float missedSteps = 0; //cummulate steps <1, to compensate via additional step when reaching >1
int currentlyrotating = 0; // 1 = drum is currently rotating, 0 = drum is standing still
int stepperSpeed = 10; //current speed of stepper, value only for first homing
int eeAddress = 0; //EEPROM address for calibration offset
int calOffset; //Offset for calibration in steps, stored in EEPROM, gets read in setup
int receivedNumber = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(BAUDRATE);
Serial.println("starting unit");
stepperSpeed = 17; //until homing is implemented
}
void loop() {
// put your main code here, to run repeatedly:
int calLetters[10] = {0, 26, 1, 21, 14, 43, 30, 31, 32, 39};
for (int i = 0; i < 10; i++) {
int currentCalLetter = calLetters[i];
rotateToLetter(currentCalLetter);
delay(5000);
}
}
//rotate to letter
void rotateToLetter(int toLetter) {
if (lastRotation == 0 || (millis() - lastRotation > OVERHEATINGTIMEOUT * 1000)) {
lastRotation = millis();
//get letter position
int posLetter = -1;
posLetter = toLetter;
int posCurrentLetter = -1;
posCurrentLetter = displayedLetter;
//int amountLetters = sizeof(letters) / sizeof(String);
#ifdef serial
Serial.print("go to letter: ");
Serial.println(letters[toLetter]);
#endif
//go to letter, but only if available (>-1)
if (posLetter > -1) { //check if letter exists
//check if letter is on higher index, then no full rotaion is needed
if (posLetter >= posCurrentLetter) {
#ifdef serial
Serial.println("direct");
#endif
//go directly to next letter, get steps from current letter to target letter
int diffPosition = posLetter - posCurrentLetter;
startMotor();
stepper.setSpeed(stepperSpeed);
//doing the rotation letterwise
for (int i = 0; i < diffPosition; i++) {
float preciseStep = (float)STEPS / (float)AMOUNTFLAPS;
int roundedStep = (int)preciseStep;
missedSteps = missedSteps + ((float)preciseStep - (float)roundedStep);
if (missedSteps > 1) {
roundedStep = roundedStep + 1;
missedSteps--;
}
stepper.step(ROTATIONDIRECTION * roundedStep);
}
}
else {
//full rotation is needed, good time for a calibration
#ifdef serial
Serial.println("full rotation incl. calibration");
#endif
//calibrate(false); //calibrate revolver and do not stop motor
//startMotor();
stepper.setSpeed(stepperSpeed);
for (int i = 0; i < posLetter; i++) {
float preciseStep = (float)STEPS / (float)AMOUNTFLAPS;
int roundedStep = (int)preciseStep;
missedSteps = missedSteps + (float)preciseStep - (float)roundedStep;
if (missedSteps > 1) {
roundedStep = roundedStep + 1;
missedSteps--;
}
stepper.step(ROTATIONDIRECTION * roundedStep);
}
}
//store new position
displayedLetter = toLetter;
//rotation is done, stop the motor
delay(100); //important to stop rotation before shutting of the motor to avoid rotation after switching off current
stopMotor();
}
else {
#ifdef serial
Serial.println("letter unknown, go to space");
#endif
desiredLetter = 0;
}
}
}
//switching off the motor driver
void stopMotor() {
lastInd1 = digitalRead(STEPPERPIN1);
lastInd2 = digitalRead(STEPPERPIN2);
lastInd3 = digitalRead(STEPPERPIN3);
lastInd4 = digitalRead(STEPPERPIN4);
digitalWrite(STEPPERPIN1, LOW);
digitalWrite(STEPPERPIN2, LOW);
digitalWrite(STEPPERPIN3, LOW);
digitalWrite(STEPPERPIN4, LOW);
#ifdef serial
Serial.println("Motor Stop");
#endif
currentlyrotating = 0; //set active state to not active
delay(100);
}
void startMotor() {
#ifdef serial
Serial.println("Motor Start");
#endif
currentlyrotating = 1; //set active state to active
digitalWrite(STEPPERPIN1, lastInd1);
digitalWrite(STEPPERPIN2, lastInd2);
digitalWrite(STEPPERPIN3, lastInd3);
digitalWrite(STEPPERPIN4, lastInd4);
}