My third attempt at using an Arduino to make a master clock with dividers and multipliers.
This is a good beginners circuit.
My earlier attempts are here:
You can of course just buy a clock multiplier / divider, but where's the fun in that.
i'M USING a basic Arduino Uno
The OLED communicates via i2c
Pin | Wiring to Arduino Uno |
Vin | 5V |
GND | GND |
SCL | A5 |
SDA | A4 |
The POT is wired thus:
centre (wiper) to A0
Right to GND
Left to 5V
The pot supplies an analog voltage which is converted into a digital
signal by the Arduino's ADCs.
Maybe an encoder would be better used??
The 4 LEDs
Cathode to gnd via 220 ohm resistors
Anode to pins 8, 9, 10, 11. I played around with the delay function, but the Millis function works much better.
I'm not a coder so if you can suggest any improvements, let me know.
Feel free to hack & improve the code.
The code:
// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
/*
This is part of a project to build a Synth master clock module with multipliers and dividers
Hopefully will add MIDI later.
jondent808@gmail.com
https://djjondent.blogspot.com/2018/03/arduino-index.html
*/
#include <SPI.h>#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
const int ledPin = 8;// the number of the LED pin 8
int ledState = LOW; // ledState used to set the LED 8
const int ledPin9 = 9;// the number of the LED pin 9
int ledState9 = LOW; // ledState used to set the LED 9
const int ledPin10 = 10;// the number of the LED pin 10
int ledState10 = LOW; // ledState used to set the LED 10
const int ledPin11 = 11;// the number of the LED pin 11
int ledState11 = LOW; // ledState used to set the LED 11
#define MIN_BPM 20 /*write here the min BPM that you want */
#define MAX_BPM 300 /* write here the max BPM that you want */
#define POT A0 // the potentiometer connects to analog pin A0
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Variables
int bpm;
unsigned long previousMillis = 0; // will store last time LED was updated
unsigned long previousMillis9 = 0; // will store last time LED9 was updated
unsigned long previousMillis10 = 0; // will store last time LED10 was updated
unsigned long previousMillis11 = 0; // will store last time LED11 was updated
const long interval = 60000; // interval at which to blink (milliseconds)
const long interval2 = 30000; // interval * 2
const long interval4 = 15000; // interval * 4
const long interval8 = 7500; // interval * 8
void setup() {
// set the digital pin as output:
pinMode(ledPin, OUTPUT);
pinMode(ledPin9, OUTPUT);
pinMode(ledPin10, OUTPUT);
pinMode(ledPin11, OUTPUT);
digitalWrite(ledPin,ledState);// set initial state of pin 8 LED
digitalWrite(ledPin9,ledState9);// set initial state of pin 9 LED
digitalWrite(ledPin10,ledState10);// set initial state of pin 10 LED
digitalWrite(ledPin11,ledState11);// set initial state of pin 11 LED
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C
display.clearDisplay(); // Clear the buffer.
}
void loop() {
bpm = map(analogRead(POT), 0, 1023, MIN_BPM, MAX_BPM);
display.clearDisplay();
display.setTextSize(3);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println(bpm);
display.setTextSize(2);
display.setTextColor(WHITE);
display.println(" BPM");
display.display();
unsigned long currentMillis = millis();
unsigned long currentMillis9 = millis();
unsigned long currentMillis10 = millis();
unsigned long currentMillis11 = millis();
if (currentMillis - previousMillis >= interval/bpm) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED 8 is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// set the LED 8 with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
// **********************************
if (currentMillis9 - previousMillis9 >= interval2/bpm) {
// save the last time you blinked the LED
previousMillis9 = currentMillis9;
// if the LED 9 is off turn it on and vice-versa:
if (ledState9 == LOW) {
ledState9 = HIGH;
} else {
ledState9 = LOW;
}
// set the LED 9 with the ledState of the variable:
digitalWrite(ledPin9, ledState9);
}
// ********************************************
if (currentMillis10 - previousMillis10 >= interval4/bpm) {
// save the last time you blinked the LED
previousMillis10 = currentMillis10;
// if the LED 10 is off turn it on and vice-versa:
if (ledState10 == LOW) {
ledState10 = HIGH;
} else {
ledState10 = LOW;
}
// set the LED 10 with the ledState of the variable:
digitalWrite(ledPin10, ledState10);
}
//*******************************************
if (currentMillis11 - previousMillis11 >= interval8/bpm) {
// save the last time you blinked the LED
previousMillis11 = currentMillis11;
// if the LED 11 is off turn it on and vice-versa:
if (ledState11 == LOW) {
ledState11 = HIGH;
} else {
ledState11 = LOW;
}
// set the LED 11 with the ledState of the variable:
digitalWrite(ledPin11, ledState11);
}
}
// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
---------------------------------
-------------------------------------
Hi there. I'm enjoying reading about your experiments.
ReplyDeleteIn terms of things to think about with your code, here are a few ideas of things you could consider:
* analogRead can be slow, so it might be worth only reading it once in a while rather than every time the loop() runs. But if you aren't worried about particularly fast counting frequencies, it is probably not an issue worth bothering about.
* similarly with updating the display. You might get a faster loop updating the display on a different pass to reading the pot for example, but again only if that is important to you.
* you could actually use a timer interrupt yourself to take your counter handling out of your loop completely and give it a more accurate "tick" if you wanted (the Arduino millis() code does this itself). The TimerOne library might help here (I talk about it a bit here: https://diyelectromusic.wordpress.com/2020/06/25/arduino-r2r-digital-audio-part-2/).
* you could use arrays of counters/values to save cutting and pasting the timer code and then work through them one at a time in your loop.
* you could think about how to abstract all the timer/led handling into its own function which takes a parameter to decide which led/counter to service.
* If you are always planning to output to the LEDS as a binary counted sequence (1,2,4,8) then another option might be to write directly to the Arduino's GPIO pins with a single counter value. IO pins 8,9,10,11 are the first four bits of "PORTB" of the ATMega328, so you could set them or clear them directly by writing a 4-bit value to PORTB directly for example (see: https://www.arduino.cc/en/Reference/PortManipulation).
Just a few ideas! Apologies if you already knew all this, I wasn't sure what your starting point for knowledge was given your "I am not a coder" comment :)
I did some experimenting with Arduino for frequency generation, which is not dissimilar to what you are doing. I managed to get 12 tones playing at different frequencies from one Uno in the end!
If you are interested, there are details of how I did it here: https://diyelectromusic.wordpress.com/2021/02/05/arduino-tone-polyphony/
Best wishes,
Kevin
Hello Kevin, Thanks for your awesome suggestions.
DeleteI am definitely just a beginner, so do value your suggestions very much. I will certainly try using the timerOne library.
I was also thinking of adding the tone function -- maybe as a simple tuner ??
Anyway, if you do have any other ideas do let me know.
I'll up date the blog as I go along. Cheers jono
"you could use arrays of counters/values to save cutting and pasting the timer code and then work through them one at a time in your loop."
ReplyDeleteGreat idea Kevin.
"If you are always planning to output to the LEDS as a binary counted sequence (1,2,4,8) then another option might be to write directly to the Arduino's GPIO pins with a single counter value."
I plan to not fix the output of the leds to binary. I would still like them to be connected to the clock. Maybe some odd divisions or I might add a random function somewhere ??