Download free music MP3s on genuine quality, the world’s largest online music catalogue, powered by your scrobbles. Free listening, videos, photos, The world’s largest online music catalogue, powered by your scrobbles. Free listening, videos, photos, stats, charts, biographies and concerts. stats, charts, biographies and concerts.
Sunday, October 27, 2024
Arduino Euclidean Gate Sequencer – Part 3
This is another variant of my Arduino Euclidean Gate Sequencer this time using a rotary encoder and I2C display rather than a potentiometer for control. Part 1 covered all the theory and main functions of the code. Part 2 included some hard…
This is another variant of my Arduino Euclidean Gate Sequencer this time using a rotary encoder and I2C display rather than a potentiometer for control.
Part 1 covered all the theory and main functions of the code.
Part 2 included some hardware suggestions for connecting it to other devices.
Warning! I strongly recommend using old or second hand equipment for your experiments. I am not responsible for any damage to expensive instruments!
Switched Rotary Encoder - either a KY-040 module or an unmounted encoder.
128x64 OLED I2C SSD1306 display.
Optional: LEDs and associated (e.g. 220Ω or 1K) resistors.
Breadboard and jumper wires.
The Circuit
The above diagram shows how to connect two variants of rotary encoder. On the left is a common KY-040 switched encoder module. On the right is a common switched encoder directly connected to solderless breadboard. Only one encoder should be connected to D4, D5 with the switch on D6.
Note if it turns out the encoder is incrementing/decrementing values in the opposite way to what is expected, then usually the simplest thing to do is swap the IO pin assignments for the A and B connections in the code.
The diagram also shows how to connect a 128x64 I2C OLED display. These are the very common SSD1306 based displays. Note that the pinouts on these can vary with GND/VCC swapped or SCL/SDA swapped, but they must be connected to 5V, GND and A4 (SDA) and A5 (SCL).
The clock generator outputs are on D8-D13. I've not added an LED to D13 as it is wired to the internal LED, but that can be added too if required.
This expands on the original code that is fully described in part 1 here.
There are two main threads of code as follows:
10mS "tick" interrupt routine to ensure accurate GATE timings.
Back "loop" handling the encoder and display.
In order to ensure a responsive encoder the display is only updated when something actually needs to change.
Once again I've opted for Matthias Hertel's simple RotaryEncoder library which can be found here: https://github.com/mathertel/RotaryEncoder. I've found this seems to work best for me for the cheap encoders I tend to buy. One the correct encoder type has been found I've found this to be very reliable, especially when simply polling IO pins for an encoder. There is a little more on the rationale for choosing this library in a previous project here: Arduino MIDI Rotary Encoder Controller.
For the I2C display, I'm using the SSD1306 implementation of the Adafruit GFX library which can be found here:
All of these should be installable from the Arduino Library Manager.
The core principles of operation are as follows:
The display will show the tempo in beats per minute and which pattern is used for each of the 6 GATE outputs.
Clicking the encoder will change the focus between tempo and any of the six GATEs allowing them to be changed.
Note: although the tempo is in bpm the number of GATE pulses is actually running at 4 pulses per beat. This means that every 16-pulse sequence, regardless of pattern, will take 4 beats in time to run through.
This is the display I have. I've used a larger font for the tempo and underlining to show the active focus of the interface.
The display is managed by having lists of the coordinate points for "cursor" which map what I've used for positioning the text.
int cursor_x[GATES+1] = {10,30,50,70,90,110,20}; int cursor_y[GATES+1] = {60,60,60,60,60,60,35}; int cursor_l[GATES+1] = {12,12,12,12,12,12,54};
Then when the encoder triggers a change, the main interface code essentially runs the following algorithm:
IF encoder signals UP THEN IF focus is tempo THEN Increment the tempo ELSE Increment the selected GATE pattern ELSE IF encoder signals DOWN THEN IF focus is tempo THEN Decrement the tempo ELSE Decrement the selected GATE pattern
IF encoder switch is pressed Move focus on between GATES or over to tempo
I did wonder if the encoder should be polled in its own timer-driver routine. For performance, many people might enable hardware pin interrupts, but these are only available on pins 2 and 3 on an ATMega328. But as the interface loop is essentially not doing much else, it will poll the encoder pretty quickly (at least compared to the speed a person can turn it) and performance is further enhanced by only writing out to the display if something has actually changed.
There are three #defines for the encoder IO pins. If the encoder seems to be doing the opposite to what is expected, just swap over the pins for ENC_A and ENC_B.
#define ENC_A 4 #define ENC_B 5 #define ENC_SW 6
The display is assumed to have an I2C address of 0x3C but that can be changed. It is also built for a 128x64 display but a 128x32 display could also be used if the coordinates for the text and cursors mentioned previously are changed accordingly.
There are two sets of IO pin definitions in the code. One provides a consecutive set of GATES on D8-D13 and one uses D2,D3,D10-D13 to match the requirements of my Arduino Clock Generator Shield PCB.
int gatePins[GATES] = {13,12,11,10,3,2}; // PCB variant int gatePins[GATES] = {13,12,11,10,9,8}; // Consecutive pins
No comments:
Post a Comment