Skip to content

Commit 225cf7c

Browse files
committed
Stripped-down testing program for rotary encoders
1 parent 818a017 commit 225cf7c

File tree

2 files changed

+275
-3
lines changed

2 files changed

+275
-3
lines changed

encoder_test/encoder_test.ino

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
////////// Configuration consts //////////
2+
3+
// These are the RLB board connections to Arduino analog input pins.
4+
// S1/PL13 = Reset
5+
// S2/PL5 = A1
6+
// S3/PL6 = A0
7+
// S4/PL7 = A6
8+
// S5/PL8 = A3
9+
// S6/PL9 = A2
10+
// S7/PL14 = A7
11+
// A6-A7 are analog-only pins that aren't as responsive and require a physical pullup resistor (1K to +5V).
12+
13+
// What input is associated with each control?
14+
const byte mainAdjA = A1; //main up/down buttons or rotary encoder - must be equipped
15+
const byte mainAdjB = A0;
16+
const byte mainAdjType = 2;
17+
18+
////////// Function prototypes, global consts and vars //////////
19+
20+
// Hardware inputs
21+
//unsigned long inputSampleLast = 0; //millis() of last time inputs (and RTC) were sampled
22+
//const byte inputSampleDur = 50; //input sampling frequency (in ms) to avoid bounce
23+
//unsigned long inputLast = 0; //When a button was last pressed / knob was last turned
24+
//unsigned long inputLast2 = 0; //Second-to-last of above
25+
//byte btnCurHeld = 0; //Button hold thresholds: 0=none, 1=unused, 2=short, 3=long, 4=set by btnStop()
26+
bool mainRotLast[2] = {0,0}; //last state of main rotary encoder inputs
27+
void initInputs(); //Set pinModes for inputs; capture initial state of knobs (rotary encoders, if equipped).
28+
void checkInputs(); //Run at sample rate. Calls checkBtn() for each eligible button and ctrlEvt() for each knob event.
29+
bool readInput(byte pin); //Does analog or digital read depending on which type of pin it is.
30+
//void checkBtn(byte btn); //Calls ctrlEvt() for each button event
31+
//void btnStop(); //Stops further events from a button until it's released, to prevent unintended behavior after an event is handled.
32+
void checkRot(byte rotA, byte rotB, bool last[], bool triggerEvent);
33+
34+
// Display formatting
35+
byte displayNext[6] = {15,15,15,15,15,15}; //Internal representation of display. Blank to start. Change this to change tubes.
36+
37+
// Hardware outputs
38+
//This clock is 2x3 multiplexed: two tubes powered at a time.
39+
//The anode channel determines which two tubes are powered,
40+
//and the two SN74141 cathode driver chips determine which digits are lit.
41+
//4 pins out to each SN74141, representing a binary number with values [1,2,4,8]
42+
byte binOutA[4] = {2,3,4,5};
43+
byte binOutB[4] = {6,7,8,9};
44+
//3 pins out to anode channel switches
45+
byte anodes[3] = {11,12,13};
46+
void initOutputs();
47+
float fadeMax = 5.0f;
48+
float fadeStep = 1.0f;
49+
int displayLast[6]={11,11,11,11,11,11}; //What is currently being displayed. We slowly fade away from this.
50+
float displayNextFade[6]={0.0f,0.0f,0.0f,0.0f,0.0f,0.0f}; //Fading in displayNext values
51+
float displayLastFade[6]={8.0f,8.0f,8.0f,8.0f,8.0f,8.0f}; //Fading out displayLast values
52+
unsigned long setStartLast = 0; //to control flashing
53+
void cycleDisplay(); //Run on every "clock cycle" to keep multiplexing going.
54+
void setCathodes(byte decValA, byte decValB);
55+
void decToBin(bool binVal[], byte i);
56+
57+
58+
////////// Includes and main code control //////////
59+
// #include <EEPROM.h>
60+
// #include <Wire.h>
61+
// #include <RTClib.h>
62+
// RTC_DS1307 rtc;
63+
64+
void setup(){
65+
//Serial.begin(57600);
66+
//Wire.begin();
67+
//rtc.begin();
68+
//if(!rtc.isrunning()) rtc.adjust(DateTime(2017,1,1,0,0,0)); //TODO test
69+
initOutputs();
70+
initInputs();
71+
//initEEPROM(readInput(mainSel)==LOW);
72+
//debugEEPROM();
73+
//setCaches();
74+
}
75+
76+
void loop(){
77+
//Things done every "clock cycle"
78+
//checkRTC(); //if clock has ticked, decrement timer if running, and updateDisplay
79+
checkInputs(); //if inputs have changed, this will do things + updateDisplay as needed
80+
//doSetHold(); //if inputs have been held, this will do more things + updateDisplay as needed
81+
cycleDisplay(); //keeps the display hardware multiplexing cycle going
82+
}
83+
84+
85+
////////// Control inputs //////////
86+
void initInputs(){
87+
//TODO are there no "loose" pins left floating after this? per https://electronics.stackexchange.com/q/37696/151805
88+
pinMode(A0, INPUT_PULLUP);
89+
pinMode(A1, INPUT_PULLUP);
90+
pinMode(A2, INPUT_PULLUP);
91+
pinMode(A3, INPUT_PULLUP);
92+
//4 and 5 used for I2C
93+
pinMode(A6, INPUT); digitalWrite(A6, HIGH);
94+
pinMode(A7, INPUT); digitalWrite(A7, HIGH);
95+
//If using rotary encoders, capture their initial state
96+
if(mainAdjType==2) checkRot(mainAdjA,mainAdjB,mainRotLast,false);
97+
//if(altAdjType==2) checkRot(altAdjA,altAdjB,altRotLast,false);
98+
}
99+
100+
void checkInputs(){
101+
// TODO can all this if/else business be defined at load instead of evaluated every sample?
102+
//if(millis() >= inputSampleLast+inputSampleDur) { //time for a sample
103+
//inputSampleLast = millis();
104+
//potential issue: if user only means to rotate or push encoder but does both?
105+
//checkBtn(mainSel); //main select
106+
//if(mainAdjType==2)
107+
checkRot(mainAdjA,mainAdjB,mainRotLast,true); //main rotary encoder
108+
//else {
109+
//checkBtn(mainAdjA); checkBtn(mainAdjB);//main adj buttons
110+
//}
111+
//if(altSel!=0) checkBtn(altSel); //alt select (if equipped)
112+
//if(altAdjType==2) checkRot(altAdj,altRotLast,true); //alt rotary encoder (if equipped)
113+
//else
114+
//if(altAdjType==1) { checkBtn(altAdjA); checkBtn(altAdjB); } //alt adj buttons
115+
//} //end if time for a sample
116+
}
117+
bool readInput(byte pin){
118+
if(pin==A6 || pin==A7) return analogRead(pin)<100?0:1; //analog-only pins
119+
else return digitalRead(pin);
120+
}
121+
122+
word numMoves = 0;
123+
void checkRot(byte rotA, byte rotB, bool last[], bool triggerEvent){
124+
//Changes in rotary encoders.
125+
//When an encoder has changed, will call ctrlEvt(ctrl,1)
126+
//mimicking an up/down adj button press
127+
//TODO do we need to watch the rotation direction w/ last2[] to accommodate for inputs changing faster than we sample?
128+
//if(btnCur==0) { //only do if a button isn't pressed
129+
bool newA = readInput(rotA);
130+
bool newB = readInput(rotB);
131+
//if(newA != last[0] && triggerEvent) ctrlEvt(newA==last[1] ? rotA : rotB, 1);
132+
//If A changed, we'll pretend B didn't - see TODO above
133+
//else if(newB != last[1] && triggerEvent) ctrlEvt(newB==last[0] ? rotB : rotA, 1);
134+
135+
if(newA!=last[0] || newB!=last[1]) {
136+
numMoves++;
137+
//Big tubes: show the number of moves we've had
138+
editDisplay(numMoves,0,3,false);
139+
//Small tubes: show the state of each of the encoder's pins
140+
editDisplay(newA,4,4,false);
141+
editDisplay(newB,5,5,false);
142+
}
143+
144+
last[0] = newA;
145+
last[1] = newB;
146+
//}//end if button isn't pressed
147+
}//end checkRot
148+
149+
150+
151+
////////// Display data formatting //////////
152+
// void updateDisplay(){
153+
// //Run as needed to update display when the value being shown on it has changed
154+
// //(Ticking time and date are an exception - see checkRTC() )
155+
// //This formats the new value and puts it in displayNext[] for cycleDisplay() to pick up
156+
// if(fnSet) { //setting
157+
// //little tubes:
158+
// if(fn==255) editDisplay(fnSet, 4, 5, false); //setup menu: current option key
159+
// else blankDisplay(4, 5); //fn setting: blank
160+
// //big tubes:
161+
// if(fnSetValMax==1439) { //value is a time of day
162+
// editDisplay(fnSetVal/60, 0, 1, EEPROM.read(optsLoc[4])); //hours with leading zero
163+
// editDisplay(fnSetVal%60, 2, 3, true);
164+
// } else editDisplay(fnSetVal, 0, 3, false); //some other type of value
165+
// }
166+
// else { //fn running
167+
// switch(fn){
168+
// //case 0: //time taken care of by checkRTC()
169+
// //case 1: //date taken care of by checkRTC()
170+
// case 2: //alarm
171+
// case 3: //timer
172+
// break;
173+
// }
174+
// }
175+
// } //end updateDisplay()
176+
177+
void editDisplay(word n, byte posStart, byte posEnd, bool leadingZeros){
178+
//Splits n into digits, sets them into displayNext in places posSt-posEnd (inclusive), with or without leading zeros
179+
//If there are blank places (on the left of a non-leading-zero number), uses value 15 to blank tube
180+
//If number has more places than posEnd-posStart, the higher places are truncated off (e.g. 10015 on 4 tubes --> 0015)
181+
word place;
182+
for(byte i=0; i<=posEnd-posStart; i++){
183+
//place = int(pow(10,i)); TODO PROBLEM: int(pow(10,2))==99 and int(pow(10,3))==999. Why??????????
184+
switch(i){
185+
case 0: place=1; break;
186+
case 1: place=10; break;
187+
case 2: place=100; break;
188+
case 3: place=1000; break;
189+
default: break;
190+
}
191+
displayNext[posEnd-i] = (i==0&&n==0 ? 0 : (n>=place ? (n/place)%10 : (leadingZeros?0:15)));
192+
}
193+
} //end editDisplay()
194+
void blankDisplay(byte posStart, byte posEnd){
195+
for(byte i=posStart; i<=posEnd; i++) displayNext[i]=15;
196+
} //end blankDisplay();
197+
198+
199+
////////// Hardware outputs //////////
200+
void initOutputs() {
201+
for(byte i=0; i<4; i++) { pinMode(binOutA[i],OUTPUT); pinMode(binOutB[i],OUTPUT); }
202+
for(byte i=0; i<3; i++) { pinMode(anodes[i],OUTPUT); }
203+
pinMode(10, OUTPUT); //Alarm signal pin
204+
}
205+
206+
void cycleDisplay(){
207+
bool dim = 0;//(opts[2]>0?true:false); //Under normal circumstances, dim constantly if the time is right
208+
// if(fnSet>0) { //but if we're setting, dim for every other 500ms since we started setting
209+
// if(setStartLast==0) setStartLast = millis();
210+
// dim = 1-(((millis()-setStartLast)/500)%2);
211+
// } else {
212+
// if(setStartLast>0) setStartLast=0;
213+
// }
214+
215+
//Anode channel 0: tubes #2 (min x10) and #5 (sec x1)
216+
setCathodes(displayLast[2],displayLast[5]); //Via d2b decoder chip, set cathodes to old digits
217+
digitalWrite(anodes[0], HIGH); //Turn on tubes
218+
delay(displayLastFade[0]/(dim?4:1)); //Display for fade-out cycles
219+
setCathodes(displayNext[2],displayNext[5]); //Switch cathodes to new digits
220+
delay(displayNextFade[0]/(dim?4:1)); //Display for fade-in cycles
221+
digitalWrite(anodes[0], LOW); //Turn off tubes
222+
223+
if(dim) delay(fadeMax/1.5);
224+
225+
//Anode channel 1: tubes #4 (sec x10) and #1 (hour x1)
226+
setCathodes(displayLast[4],displayLast[1]);
227+
digitalWrite(anodes[1], HIGH);
228+
delay(displayLastFade[1]/(dim?4:1));
229+
setCathodes(displayNext[4],displayNext[1]);
230+
delay(displayNextFade[1]/(dim?4:1));
231+
digitalWrite(anodes[1], LOW);
232+
233+
if(dim) delay(fadeMax/1.5);
234+
235+
//Anode channel 2: tubes #0 (hour x10) and #3 (min x1)
236+
setCathodes(displayLast[0],displayLast[3]);
237+
digitalWrite(anodes[2], HIGH);
238+
delay(displayLastFade[2]/(dim?4:1));
239+
setCathodes(displayNext[0],displayNext[3]);
240+
delay(displayNextFade[2]/(dim?4:1));
241+
digitalWrite(anodes[2], LOW);
242+
243+
if(dim) delay(fadeMax*0.75);
244+
245+
// Loop thru and update all the arrays, and fades.
246+
for( byte i = 0 ; i < 6 ; i ++ ) {
247+
if( displayNext[i] != displayLast[i] ) {
248+
displayNextFade[i] += fadeStep;
249+
displayLastFade[i] -= fadeStep;
250+
251+
if( displayNextFade[i] >= fadeMax ){
252+
displayNextFade[i] = 0.0f;
253+
displayLastFade[i] = fadeMax;
254+
displayLast[i] = displayNext[i];
255+
}
256+
}
257+
}
258+
} //end cycleDisplay()
259+
260+
void setCathodes(byte decValA, byte decValB){
261+
bool binVal[4]; //4-bit binary number with values [1,2,4,8]
262+
decToBin(binVal,decValA); //have binary value of decVal set into binVal
263+
for(byte i=0; i<4; i++) digitalWrite(binOutA[i],binVal[i]); //set bin inputs of SN74141
264+
decToBin(binVal,decValB);
265+
for(byte i=0; i<4; i++) digitalWrite(binOutB[i],binVal[i]); //set bin inputs of SN74141
266+
} //end setCathodes()
267+
268+
void decToBin(bool binVal[], byte i){
269+
//binVal is a reference (modify in place) of a binary number bool[4] with values [1,2,4,8]
270+
if(i<0 || i>15) i=15; //default value, turns tubes off
271+
binVal[3] = int(i/8)%2;
272+
binVal[2] = int(i/4)%2;
273+
binVal[1] = int(i/2)%2;
274+
binVal[0] = i%2;
275+
} //end decToBin()

sixtube_lm/sixtube_lm.ino

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -504,9 +504,6 @@ void updateDisplay(){
504504
break;
505505
}
506506
}
507-
// if(tinkercad) {
508-
// for(int i=0; i<6; i++) { if(q[i]>9) Serial.print("-"); else Serial.print(q[i],DEC); if(i==1||i==3) Serial.print("."); } Serial.println();
509-
// }
510507
} //end updateDisplay()
511508

512509
void editDisplay(word n, byte posStart, byte posEnd, bool leadingZeros){

0 commit comments

Comments
 (0)