diff --git a/encoder.cpp b/encoder.cpp new file mode 100644 index 0000000..9caa45c --- /dev/null +++ b/encoder.cpp @@ -0,0 +1,125 @@ +#include +#include + +#include "encoder.h" +#include "ubitx.h"//Pin definitions + +//Normal encoder state +uint8_t prev_enc = 0; +int8_t enc_count = 0; + +//Momentum encoder state +int16_t enc_count_periodic = 0; +int8_t momentum[3] = {0}; +static const uint16_t CALLBACK_PERIOD_MS = 200; +static const uint8_t MOMENTUM_MULTIPLIER = 1; + +uint8_t enc_state (void) +{ + return (digitalRead(ENC_A)?1:0 + digitalRead(ENC_B)?2:0); +} + +/* + * SmittyHalibut's encoder handling, using interrupts. Should be quicker, smoother handling. + * The Interrupt Service Routine for Pin Change Interrupts on A0-A5. + */ +ISR (PCINT1_vect) +{ + uint8_t cur_enc = enc_state(); + if (prev_enc == cur_enc) { + //Serial.println("unnecessary ISR"); + return; + } + //Serial.print(prev_enc); + //Serial.println(cur_enc); + + //these transitions point to the enccoder being rotated anti-clockwise + if ((prev_enc == 0 && cur_enc == 2) || + (prev_enc == 2 && cur_enc == 3) || + (prev_enc == 3 && cur_enc == 1) || + (prev_enc == 1 && cur_enc == 0)) + { + enc_count -= 1; + enc_count_periodic -= 1; + } + //these transitions point to the enccoder being rotated clockwise + else if ((prev_enc == 0 && cur_enc == 1) || + (prev_enc == 1 && cur_enc == 3) || + (prev_enc == 3 && cur_enc == 2) || + (prev_enc == 2 && cur_enc == 0)) + { + enc_count += 1; + enc_count_periodic += 1; + } + else { + // A change to two states, we can't tell whether it was forward or backward, so we skip it. + //Serial.println("skip"); + } + prev_enc = cur_enc; // Record state for next pulse interpretation +} + +/* + * Setup the encoder interrupts and global variables. + */ +void pci_setup(byte pin) { + *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin + PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt + PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group +} + +void enc_setup(void) +{ + enc_count = 0; + // This is already done in setup() ? + //pinMode(ENC_A, INPUT); + //pinMode(ENC_B, INPUT); + prev_enc = enc_state(); + + // Setup Pin Change Interrupts for the encoder inputs + pci_setup(ENC_A); + pci_setup(ENC_B); + + //Set up timer interrupt for momentum + TCCR1A = 0;//"normal" mode + TCCR1B = 3;//clock divider of 64 + TCNT1 = 0;//start counting at 0 + OCR1A = F_CPU * CALLBACK_PERIOD_MS / 1000 / 64;//set target number + TIMSK1 |= (1 << OCIE1A);//enable interrupt +} + +ISR(TIMER1_COMPA_vect) +{ + momentum[2] = momentum[1]; + momentum[1] = momentum[0]; + momentum[0] = enc_count_periodic; + enc_count_periodic = 0; +} + +int8_t min_momentum_mag() +{ + int8_t min_mag = 127; + for(uint8_t i = 0; i < sizeof(momentum)/sizeof(momentum[0]); ++i){ + int8_t mag = abs(momentum[i]); + if(mag < min_mag){ + min_mag = mag; + } + } + return min_mag; +} + +int enc_read(void) { + if(0 != enc_count){ + int16_t ret = enc_count; + int8_t s = (enc_count < 0) ? -1 : 1; + int8_t momentum_mag = min_momentum_mag(); + if(momentum_mag >= 20){ + ret += s*40; + } + else if(momentum_mag >= 5){ + ret += s*(20 + momentum_mag)/(20 - momentum_mag); + } + enc_count = 0; + return ret; + } + return 0; +} \ No newline at end of file diff --git a/encoder.h b/encoder.h new file mode 100644 index 0000000..b3bd8a7 --- /dev/null +++ b/encoder.h @@ -0,0 +1,4 @@ +#pragma once + +void enc_setup(void); +int enc_read(void); diff --git a/nano_gui.cpp b/nano_gui.cpp index 902f2ad..9efe8ec 100644 --- a/nano_gui.cpp +++ b/nano_gui.cpp @@ -238,7 +238,7 @@ void displayText(char *text, int x1, int y1, int w, int h, int color, int backgr uint16_t height_out; tft.getTextBounds(text,x1,y1,&x1_out,&y1_out,&width_out,&height_out,w); x1 += (w - ( (int32_t)width_out + (x1_out-x1)))/2; - y1 += (ubitx_font->yAdvance + h - ( (int32_t)height_out + (y1_out-y1)))/2; + y1 += (ubitx_font->yAdvance + h - ( (int32_t)height_out))/2; displayRawText(text,x1,y1,w,color,background); } diff --git a/setup.cpp b/setup.cpp index 7d666df..c87268f 100644 --- a/setup.cpp +++ b/setup.cpp @@ -180,7 +180,7 @@ const SettingScreen_t ssLocalOsc PROGMEM = { SS_LOCAL_OSC_T, SS_LOCAL_OSC_A, 1, - 875, + 50, ssLocalOscInitialize, ssLocalOscValidate, ssLocalOscChange, @@ -254,7 +254,7 @@ const SettingScreen_t ssTone PROGMEM = { SS_CW_TONE_T, SS_CW_TONE_A, 1, - 10, + 1, ssCwToneInitialize, ssCwToneValidate, ssCwToneChange, @@ -289,7 +289,7 @@ const SettingScreen_t ssCwSwitchDelay PROGMEM = { SS_CW_SWITCH_T, SS_CW_SWITCH_A, 1, - 100, + 10, ssCwSwitchDelayInitialize, ssCwSwitchDelayValidate, ssCwSwitchDelayChange, diff --git a/ubitx_ui.cpp b/ubitx_ui.cpp index dd5a8f3..7d320f0 100644 --- a/ubitx_ui.cpp +++ b/ubitx_ui.cpp @@ -553,148 +553,6 @@ void updateDisplay() { displayVFO(globalSettings.activeVfo); } - -/** - * The A7 And A6 are purely analog lines on the Arduino Nano - * These need to be pulled up externally using two 10 K resistors - * - * There are excellent pages on the Internet about how these encoders work - * and how they should be used. We have elected to use the simplest way - * to use these encoders without the complexity of interrupts etc to - * keep it understandable. - * - * The enc_state returns a two-bit number such that each bit reflects the current - * value of each of the two phases of the encoder - * - * The enc_read returns the number of net pulses counted over 50 msecs. - * If the puluses are -ve, they were anti-clockwise, if they are +ve, the - * were in the clockwise directions. Higher the pulses, greater the speed - * at which the enccoder was spun - */ - -/* -int enc_prev_state = 3; - -byte enc_state (void) { - //Serial.print(digitalRead(ENC_A)); Serial.print(":");Serial.println(digitalRead(ENC_B)); - return (digitalRead(ENC_A) == 1 ? 1 : 0) + (digitalRead(ENC_B) == 1 ? 2: 0); -} - - -int enc_read(void) { - int result = 0; - byte newState; - int enc_speed = 0; - - long stop_by = millis() + 200; - - while (millis() < stop_by) { // check if the previous state was stable - newState = enc_state(); // Get current state - -// if (newState != enc_prev_state) -// active_delay(20); - - if (enc_state() != newState || newState == enc_prev_state) - continue; - //these transitions point to the encoder being rotated anti-clockwise - if ((enc_prev_state == 0 && newState == 2) || - (enc_prev_state == 2 && newState == 3) || - (enc_prev_state == 3 && newState == 1) || - (enc_prev_state == 1 && newState == 0)){ - result--; - } - //these transitions point o the enccoder being rotated clockwise - if ((enc_prev_state == 0 && newState == 1) || - (enc_prev_state == 1 && newState == 3) || - (enc_prev_state == 3 && newState == 2) || - (enc_prev_state == 2 && newState == 0)){ - result++; - } - enc_prev_state = newState; // Record state for next pulse interpretation - enc_speed++; - active_delay(1); - } - //if (result) - // Serial.println(result); - return(result); -} -*/ - -/* - * SmittyHalibut's encoder handling, using interrupts. Should be quicker, smoother handling. - */ -int8_t enc_count; -uint8_t prev_enc; - -uint8_t enc_state (void) { - return (digitalRead(ENC_A)?1:0 + digitalRead(ENC_B)?2:0); -} - -/* - * Setup the encoder interrupts and global variables. - */ -void pci_setup(byte pin) { - *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin)); // enable pin - PCIFR |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt - PCICR |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group -} - -void enc_setup(void) { - enc_count = 0; - // This is already done in setup() ? - //pinMode(ENC_A, INPUT); - //pinMode(ENC_B, INPUT); - prev_enc = enc_state(); - - // Setup Pin Change Interrupts for the encoder inputs - pci_setup(ENC_A); - pci_setup(ENC_B); -} - -/* - * The Interrupt Service Routine for Pin Change Interrupts on A0-A5. - */ -ISR (PCINT1_vect) { - uint8_t cur_enc = enc_state(); - if (prev_enc == cur_enc) { - //Serial.println("unnecessary ISR"); - return; - } - //Serial.print(prev_enc); - //Serial.println(cur_enc); - - //these transitions point to the enccoder being rotated anti-clockwise - if ((prev_enc == 0 && cur_enc == 2) || - (prev_enc == 2 && cur_enc == 3) || - (prev_enc == 3 && cur_enc == 1) || - (prev_enc == 1 && cur_enc == 0)) - { - enc_count-=1; - } - //these transitions point to the enccoder being rotated clockwise - else if ((prev_enc == 0 && cur_enc == 1) || - (prev_enc == 1 && cur_enc == 3) || - (prev_enc == 3 && cur_enc == 2) || - (prev_enc == 2 && cur_enc == 0)) - { - enc_count+=1; - } - else { - // A change to two states, we can't tell whether it was forward or backward, so we skip it. - //Serial.println("skip"); - } - prev_enc = cur_enc; // Record state for next pulse interpretation -} - -int enc_read(void) { - int8_t ret = enc_count; - enc_count = 0; - return int(ret); -} - - - - void ritToggle(struct Button *button){ if(!globalSettings.ritOn){ ritEnable(GetActiveVfoFreq());