From 9fb4efc5ace02192df7287cdbe567056fe25e1fe Mon Sep 17 00:00:00 2001 From: Reed Nightingale Date: Sun, 19 Jan 2020 22:49:59 -0800 Subject: [PATCH 1/5] Move encoder functions to their own file --- encoder.cpp | 72 ++++++++++++++++++++++++++ encoder.h | 4 ++ ubitx_ui.cpp | 142 --------------------------------------------------- 3 files changed, 76 insertions(+), 142 deletions(-) create mode 100644 encoder.cpp create mode 100644 encoder.h diff --git a/encoder.cpp b/encoder.cpp new file mode 100644 index 0000000..c5bc049 --- /dev/null +++ b/encoder.cpp @@ -0,0 +1,72 @@ +/* + * 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); +} + +/* + * 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 +} + +/* + * 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); +} + +int enc_read(void) { + int8_t ret = enc_count; + enc_count = 0; + return int(ret); +} \ No newline at end of file diff --git a/encoder.h b/encoder.h new file mode 100644 index 0000000..5176684 --- /dev/null +++ b/encoder.h @@ -0,0 +1,4 @@ +#pragma once + +void enc_setup(void); +int enc_read(void); \ No newline at end of file diff --git a/ubitx_ui.cpp b/ubitx_ui.cpp index 624705f..6f11eb7 100644 --- a/ubitx_ui.cpp +++ b/ubitx_ui.cpp @@ -541,148 +541,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()); From 755b2214f941b14faf2c17e92cd568841c6fc7c0 Mon Sep 17 00:00:00 2001 From: Reed Nightingale Date: Sun, 19 Jan 2020 22:53:00 -0800 Subject: [PATCH 2/5] Add missing includes to compile --- encoder.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/encoder.cpp b/encoder.cpp index c5bc049..5c994fc 100644 --- a/encoder.cpp +++ b/encoder.cpp @@ -1,3 +1,9 @@ +#include +#include + +#include "ubitx.h"//Pin definitions + + /* * SmittyHalibut's encoder handling, using interrupts. Should be quicker, smoother handling. */ From 4aea1b7126ab2c84c4e6590e32fed247e631041d Mon Sep 17 00:00:00 2001 From: Reed Nightingale Date: Sun, 19 Jan 2020 22:54:42 -0800 Subject: [PATCH 3/5] Slightly change centering. Appears to ride a tiny bit high because it leaves room for below-line characters, like gjpqy --- nano_gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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); } From 13f109c8b3b4149a37d6729d2d72e6d97219db83 Mon Sep 17 00:00:00 2001 From: Reed Nightingale Date: Tue, 21 Jan 2020 01:13:36 -0800 Subject: [PATCH 4/5] First pass at a momentum function --- encoder.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++---------- encoder.h | 2 +- 2 files changed, 61 insertions(+), 14 deletions(-) diff --git a/encoder.cpp b/encoder.cpp index 5c994fc..9caa45c 100644 --- a/encoder.cpp +++ b/encoder.cpp @@ -1,23 +1,30 @@ #include #include +#include "encoder.h" #include "ubitx.h"//Pin definitions +//Normal encoder state +uint8_t prev_enc = 0; +int8_t enc_count = 0; -/* - * SmittyHalibut's encoder handling, using interrupts. Should be quicker, smoother handling. - */ -int8_t enc_count; -uint8_t prev_enc; +//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); +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) { +ISR (PCINT1_vect) +{ uint8_t cur_enc = enc_state(); if (prev_enc == cur_enc) { //Serial.println("unnecessary ISR"); @@ -32,7 +39,8 @@ ISR (PCINT1_vect) { (prev_enc == 3 && cur_enc == 1) || (prev_enc == 1 && cur_enc == 0)) { - enc_count-=1; + enc_count -= 1; + enc_count_periodic -= 1; } //these transitions point to the enccoder being rotated clockwise else if ((prev_enc == 0 && cur_enc == 1) || @@ -40,7 +48,8 @@ ISR (PCINT1_vect) { (prev_enc == 3 && cur_enc == 2) || (prev_enc == 2 && cur_enc == 0)) { - enc_count+=1; + 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. @@ -69,10 +78,48 @@ void enc_setup(void) // 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) { - int8_t ret = enc_count; - enc_count = 0; - return int(ret); + 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 index 5176684..b3bd8a7 100644 --- a/encoder.h +++ b/encoder.h @@ -1,4 +1,4 @@ #pragma once void enc_setup(void); -int enc_read(void); \ No newline at end of file +int enc_read(void); From bbdd6840c908eacd97e3dbcf2d3c48c2f8dcc9f7 Mon Sep 17 00:00:00 2001 From: Reed Nightingale Date: Tue, 21 Jan 2020 01:37:09 -0800 Subject: [PATCH 5/5] Reduce setting step size, since momentum can get places faster --- setup.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.cpp b/setup.cpp index 14272f7..e933700 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, @@ -286,7 +286,7 @@ const SettingScreen_t ssTone PROGMEM = { SS_CW_TONE_T, SS_CW_TONE_A, 1, - 10, + 1, ssCwToneInitialize, ssCwToneValidate, ssCwToneChange, @@ -319,7 +319,7 @@ const SettingScreen_t ssCwSwitchDelay PROGMEM = { SS_CW_SWITCH_T, SS_CW_SWITCH_A, 1, - 100, + 10, ssCwSwitchDelayInitialize, ssCwSwitchDelayValidate, ssCwSwitchDelayChange,