You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
5.5 KiB
C

/** @file encoder.c
* @date 2014-12-04
* @author Frank Klee
* @brief Drehencoder Library
*
* Basisroutinen zum Abfragen eines Drehencoders mittels Polling.
* Quelle: https://www.mikrocontroller.net/articles/Drehgeber
*
* @brief Formatierungen und Umbenennungen der Funktionen
* @author Tom, DL7BJ
* @date 2023-03-23
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include "encoder.h"
int8_t DrehgeberPosition; ///< akt. Drehencoderposition
int8_t DrehgeberMax = 127; ///< maximaler Wert des Drehgebers
int8_t DrehgeberMin = -127; ///< minimaler Wert des Drehgebers
volatile int16_t iButtonPressedCounter = 0; ///< Zähler für kurzen Tastendruck
volatile int16_t iButtonDebounceCycles = 0; ///< Zähler für Entprellung
volatile int16_t iButtonPressedLongCycles = 0; ///< Zähler für langen Tastendruck
volatile int8_t enc_delta; ///< Delta des Encoders bei Betätigung
static int8_t last; ///< letzter Wert des Encoders
typedef enum EButtonState
{
ButtonState_Unpressed, ///< Taster nicht gedrückt
ButtonState_Pressed, ///< Taster gedrückt
ButtonState_Hold, ///< Taster gehalten
ButtonState_Released ///< Taster geöffnet
}tEButtonState;
volatile tEButtonState buttonState = ButtonState_Unpressed;
volatile tEButtonPressedState buttonPressed = ButtonPressed_Unpressed;
/** @fn void EncoderInit(void)
* @brief Initialisierung des Drehencoders und der Startwerte
* @param none
* @retval none
*/
void EncoderInit(void)
{
int8_t new;
new = 0;
if(PHASE_A)
new = 3;
if(PHASE_B)
new ^= 1;
last = new;
enc_delta = 0;
iButtonDebounceCycles = BUTTON_DEBOUNCETIME_MS;
iButtonPressedLongCycles = BUTTON_PRESSEDLONG_MS;
}
/** @fn void EncoderPolling(void)
* @brief EncoderPolling
*
* Abfrage des Drehencoders und des Tasters
* Wird vom Timer 0 aufgerufen
*
* @param none
* @retval none
*/
void EncoderPolling(void)
{
int8_t new, diff;
new = 0;
if(PHASE_A) new = 3;
if(PHASE_B) new ^= 1;
diff = last - new;
if(diff & 1) {
last = new;
enc_delta += (diff & 2) - 1;
}
switch(buttonState)
{
case ButtonState_Unpressed:
if(BUTTONPRESSED) buttonState = ButtonState_Pressed;
break;
case ButtonState_Pressed:
buttonState = ButtonState_Hold;
break;
case ButtonState_Hold:
iButtonPressedCounter++;
if(iButtonPressedCounter >= iButtonDebounceCycles && (! BUTTONPRESSED))
{
buttonState = ButtonState_Released;
if(buttonPressed != ButtonPressed_Long)
buttonPressed = ButtonPressed_Short;
}
if(iButtonPressedCounter >= iButtonPressedLongCycles)
{
buttonState = ButtonState_Released;
buttonPressed = ButtonPressed_Long;
}
break;
case ButtonState_Released:
iButtonPressedCounter = 0;
if(!BUTTONPRESSED)
buttonState = ButtonState_Unpressed;
break;
}
}
#if defined (SingleStep)
int8_t EncodeRead(void)
{
int8_t val;
cli();
val = enc_delta;
enc_delta = 0;
sei();
return val;
}
#elif defined (TwoStep)
int8_t EncodeRead(void)
{
int8_t val;
cli();
val = enc_delta;
enc_delta = val & 1;
sei();
return val >> 1;
}
#elif defined (FourStep)
int8_t EncodeRead(void)
{
int8_t val;
cli();
val = enc_delta;
enc_delta = val & 3;
sei();
return val >> 2;
}
#endif
/** @fn int8_t EncoderRead(char Ueberlauf)
* @brief Liest die akt. Position des Drehencoders
*
* @param Ueberlauf größer +127, -127
* @retval Aktuelle Position des Drehencoders
*/
int8_t EncoderRead(char Ueberlauf)
{
DrehgeberPosition += EncodeRead();
if(DrehgeberPosition > DrehgeberMax)
{
if(Ueberlauf)
DrehgeberPosition = DrehgeberPosition - DrehgeberMax + DrehgeberMin - 1;
else
DrehgeberPosition = DrehgeberMax;
}
if(DrehgeberPosition < DrehgeberMin)
{
if(Ueberlauf)
DrehgeberPosition = DrehgeberPosition + DrehgeberMax - DrehgeberMin + 1;
else
DrehgeberPosition = DrehgeberMin;
}
return(DrehgeberPosition);
}
/** @fn void EncoderWrite(int8_t EncoderPos)
* @brief Setzt die aktuelle Position des Drehencoders
*
* @param EncoderPos - die Position des Drehencoders
* @retval none
*/
void EncoderWrite(int8_t EncoderPos)
{
DrehgeberPosition = EncoderPos;
}
/** @fn void EncoderMinMax(int8_t EncoderMin, int8_t EncoderMax)
* @brief Setzt den minimalen und maximalen Bereich des Drehencoders
*
* @param EncoderMin minimaler Wert des Drehencoders
* @param EncoderMax maximaler Wert des Drehencoders
* @retval none
*/
void EncoderMinMax(int8_t EncoderMin, int8_t EncoderMax)
{
DrehgeberMin = EncoderMin;
DrehgeberMax = EncoderMax;
if(DrehgeberPosition > DrehgeberMax) DrehgeberPosition = DrehgeberMax;
if(DrehgeberPosition < DrehgeberMin) DrehgeberPosition = DrehgeberMin;
}
/** @fn tEButtonPressedState EncoderGetButtonState(void)
* @brief Liefert den Status des Tasters vom Drehencoder
*
* @param none
* @retval tEButtonPressedState
*/
tEButtonPressedState EncoderGetButtonState(void)
{
tEButtonPressedState retVal = buttonPressed;
buttonPressed = ButtonPressed_Unpressed;
return retVal;
}