/// simple project using Arduino UNO and 128x64 OLED Display to display a menu
// Menueauswahl mit Drehencoder
// 1.3" OLED als SPI (nicht I2C),
// Freigabetaste
// Umschaltung auf Manuell mit Beschleunigung
// geschrieben für Arduino NANO
// Ausgänge müssen angepasst werden, stimmen hier im WOKWI nicht (wg I2C Display)
// Überprüfung 451 und 461
//modified by W. Knoth
/*----------------------------------------------------------------------------*/
// ----------------- DAC ------------------------------------------------------//
#include <Adafruit_MCP4725.h> // MCP4725 library from adafruit
const int I2C_ADDR = 0x62;
Adafruit_MCP4725 dac; //MCP4725;
// ----------------------Adafruit 1.3" -----------------------------------------//
//#include <Adafruit_SH1106.h>
//#define OLED_RESET 4
//Adafruit_SH1106 display(OLED_RESET);
// -----------------------------------------------------------------------------//
#include <Wire.h>
#include "TimerOne.h"
TimerOne timer1;
// ----------------- U8G ---------------------------------------------------
#include "U8glib.h"
//U8GLIB_SSD1306_128X64 u8g(13, 11, 8, 9, 10); // SPI connection
//U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST); // Dev 0, Fast I2C / TWI
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST); // Fast I2C / TWI
//U8GLIB_SSD1306_128X64 u8g(13, 11, 8, 9, 10); // SPI connection
// ------------------- U8G2 ------------------------------------------------
//#include <U8g2lib.h>
//#include <MUIU8g2.h>
//#include <U8x8lib.h>
//U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); // initialization for the used OLED display
//0.96
//U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); //OLED
//U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); // OLED
// 1,3 Zoll SH1106
//U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); // OLED
//#define I2C_ADDRESS 0x70
// CLK=13, DIN=11, CE=8, DC=9, RST=10
// GND > GND
// VCC > 5V für NOKIA 3,3V
// SCL > A5 >13
// SDA > A4 >11
// RES >10
// DC > 9
// CS > 8
// *** CONNECTIONS ***
// CLK=13, DIN=11, CE=8, DC=9, RST=10
// for SPI connection, use this wiring:
// N5110 LCD from left:
// #1 RST - Pin 10
// #2 CS/CE - Pin 8
// #3 DC - Pin 9
// #4 MOSI/DIN - Pin 11
// #5 SCK/CLK - Pin 13
// #6 VCC 3.3V
// #7 LIGHT
// #8 GND
// all the arrays below are generated from images using image2cpp website
// scroll down to see the actual code
// 'icon_battery', 16x16px
const unsigned char bitmap_icon_battery_empty [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 'icon_battery', 16x16px
const unsigned char bitmap_icon_battery_full [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x40, 0x04, 0x5b, 0x66, 0x5b, 0x66,
0x5b, 0x66, 0x40, 0x04, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 'icon_battery', 16x16px
const unsigned char bitmap_icon_battery_empty_2 [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 384)
const unsigned char* bitmap_icons[3] = {
bitmap_icon_battery_empty,
bitmap_icon_battery_full,
bitmap_icon_battery_empty_2,
};
// 'scrollbar_background', 8x64px
const unsigned char bitmap_scrollbar_background [] PROGMEM = {
0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00
};
// 'item_sel_outline', 128x21px
const unsigned char bitmap_item_sel_outline [] PROGMEM = {
0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0
};
// ------------------ end generated bitmaps from image2cpp ---------------------------------
const int ENCODER_CLK = 2; // PinA // Used for generating interrupts using CLK signal
const int ENCODER_DT = 3; // PinB // Used for reading DT signal
const int ENCODER_BTN = 6; // PinSW // Used for the push button switch
const int pageCount = 4; // Anzahl Pages
const int LED_PIN13 = 13;
const int Hupe = 12;
const int LED = 11;
const int tasterPin = 10;
const int button_less = 8;
const int button_more = 9;
boolean down = false;
boolean A = false;
boolean Taste = false;
boolean Stop = false;
//int B;
int icon = 0;
int button_select_clicked = 0; // same as above
int ONOFF = 0;
int item_selected = 0; // which item in the menu is selected
int item_sel_previous; // previous item - used in the menu screen to draw the item before the selected one
int item_sel_next; // next item - used in the menu screen to draw next item after the selected one
int current_screen = 0; // 0 = menu, 1 = screenshot, 2 = qr
int dac_ADC;
int dac_volt;
int i;
int btn = 0;
int p = 0;
int progress = 0;
int Poti = 0;
int counter = 0;
char buffer[32]; // helper buffer to construct a string to be displayed
int Automatic = 1;
/*------------------------ Menue --------------------------------------------------------*/
const int NUM_ITEMS = 13; // number of items in the list and also the number of screenshots and screenshots with QR codes (other screens)
const int MAX_ITEM_LENGTH = 20; // maximum characters for the item name
char menu_items [NUM_ITEMS] [MAX_ITEM_LENGTH] = { // array with item names
{ "1.5 V" },
{ "3.2 V" },
{ "3.7 V" },
{ "4.2 V" },
{ "4.8 V" },
{ "5.0 V" },
{ "6.0 V" },
{ "12.0 V" },
{ "13.8 V" },
{ "15.0 V" },
{ "24.0 V" },
{ "30.0 V" },
{ "Var." }
// { " "}
};
/*---------------------- Ende Menu ------------------------------------------------------------*/
// note - when changing the order of items above, make sure the other arrays referencing bitmaps
// also have the same order, for example array "bitmap_icons" for icons, and other arrays for screenshots and QR codes
// ------------------------------------------------------------------
// SETUP SETUP SETUP SETUP SETUP SETUP SETUP
// ------------------------------------------------------------------
void setup() {
Serial.begin(9600);
timer1.initialize(1000000); // 1 Sekunde
timer1.attachInterrupt(timer_isr);
//**************** DAC einspannen *****************************************
// intialize MCP4725 DAC
dac.begin(I2C_ADDR); //(0x62)
//***************** Ende DAC ***********************************************
u8g.setColorIndex(1); // set the color to white
pinMode(ENCODER_CLK, INPUT);
pinMode(ENCODER_DT, INPUT);
attachInterrupt(digitalPinToInterrupt(ENCODER_CLK), readEncoder, FALLING);
delay(500);
pinMode(ENCODER_BTN, INPUT_PULLUP);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(LED_PIN13, OUTPUT);
pinMode(Hupe, OUTPUT);
pinMode(tasterPin, INPUT_PULLUP);
pinMode(button_less, INPUT_PULLUP);
pinMode(button_more, INPUT_PULLUP);
pinMode(LED, OUTPUT);
}
// Updated by the ISR (Interrupt Service Routine)
volatile int virtualPosition = 50;
// ------------------------------------------------------------------
// INTERRUPT INTERRUPT INTERRUPT INTERRUPT INTERRUPT
// ------------------------------------------------------------------
void readEncoder() {
A = true;
int dtValue = digitalRead(ENCODER_DT);
// progress = dtValue;
// ---------------------------------------------------------------
// test von Rotary_Encoder_Sketch_2
// ---------------------------------------------------------------
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = millis();
// If interrupts come faster than 5ms, assume it's a bounce and ignore
if (interruptTime - lastInterruptTime > 1000) {
if (digitalRead(ENCODER_DT) == LOW)
{
// virtualPosition-- ; // Could be -5 or -10
down = false;
}
else {
// virtualPosition++ ; // Could be +5 or +10
down = true;
}
// Restrict value from 0 to +100
virtualPosition = min(100, max(0, virtualPosition));
// Keep track of when we were here last (no more than every 5ms)
lastInterruptTime = interruptTime;
}
delay(10000); // muss ! 10000
progress = virtualPosition;
}
//----------------------------- Mainroutine -----------------------------------
// -------------- loop loop loop loop ---------------------------
// ----------------------------------------------------------------------------
void loop() {
//------------- OnOFF toggle --------------------------------------------------
if (digitalRead(tasterPin) == LOW) {
ONOFF = !ONOFF;
digitalWrite(LED, ONOFF);
delay(20);
while (!digitalRead(tasterPin));
}
if (icon == 0) {
ONOFF = 0;
digitalWrite(LED, ONOFF);
}
//-------------- Ende OnOFF ---------------------------------------------------
//------------------------- Mittelbutton --------------------------------------
if (Poti == 0) {
if ((digitalRead(ENCODER_BTN) == LOW) && (button_select_clicked == 0)) {
//button_select_clicked = 1; // set button to clicked to only perform the action once
Taste = true;
icon = 1;
}
if ((digitalRead(ENCODER_BTN) == LOW) && (button_select_clicked == 1)) {
Taste = false; // false
}
}
// **************************************************************************
/*-------------------- ab hier neu einpflegen ------------------------------*/
// MENU SCREEN
if ((down == false) && (A == true)) {
//up button clicked - jump to previous menu item
item_selected = item_selected + 1; // select previous item -1
A = false; // set button to clicked to only perform the action once
icon = 0;
if (item_selected >= NUM_ITEMS) {
//last item was selected, jump to first menu item
item_selected = 0;
}
}
else if ((down == true) && (A == true)) {
//down button clicked - jump to next menu item
item_selected = item_selected - 1; // +1 select next item
A = false; // set button to clicked to only perform the action once
icon = 0;
if (item_selected < 0) {
//if first item was selected, jump to last item
item_selected = NUM_ITEMS - 1;
}
}
if ((down == true) && (A == true)) { // unclick
A = 0;
button_select_clicked = 0;
}
if ((down == false) && (A == true)) { // unclick
A = 0;
button_select_clicked = 0;
}
if ((Taste == true) && (button_select_clicked == 0)) { // select button clicked, jump between screens
button_select_clicked = 1; // set button to clicked to only perform the action once
icon = 1;
if (current_screen == 0) {
current_screen = 1; // menu items screen --> screenshots screen
}
//else if (current_screen == 1) {current_screen = 2;} // screenshots screen --> qr codes screen
else {
current_screen = 0; // qr codes screen --> menu items screen
}
current_screen = 0;
}
if ((Taste == false) && (button_select_clicked == 1)) { // unclick
button_select_clicked = 0;
}
// set correct values for the previous and next items
item_sel_previous = item_selected - 1;
if (item_sel_previous < 0) {
item_sel_previous = NUM_ITEMS - 1;
} // previous item would be below first = make it the last
item_sel_next = item_selected + 1;
if (item_sel_next >= NUM_ITEMS) {
item_sel_next = 0;
} // 0 next item would be after last = make it the first
//------------------------------------------------------------------------------
//------------------- first page -----------------------------------------------
//-------------------------------------------------------------------------------
u8g.firstPage(); // required for page drawing mode for u8g library
do {
// selected item background
u8g.drawBitmapP(0, 22, 128 / 8, 21, bitmap_item_sel_outline);
// draw previous item as label
u8g.setFont(u8g_font_6x12); // 7x14
u8g.drawStr(25, 15, menu_items[item_sel_previous]);
// draw selected item as label in bold font
u8g.setFont(u8g_font_6x12); //7x14B
u8g.drawStr(25, 15 + 20 + 2, menu_items[item_selected]);
if (icon == 1) {
u8g.drawBitmapP( 4, 24, 16 / 8, 16, bitmap_icons[1]); // Icon wird gesetzt
digitalWrite(LED_PIN13, HIGH);
digitalWrite(Hupe, HIGH);
delay((100));
digitalWrite(Hupe, LOW);
//------------ DAC setzen ----------------
if (item_selected == 0) {
i = 205; //4096 / 30 * 1.5 * 1.026;
}
if (item_selected == 1) {
i = 437; //4096 / 30 * 3.2 * 1.012;
}
if (item_selected == 2) {
i = 505; //4096 / 30 * 3.7 * 1.010;
}
if (item_selected == 3) {
i = 579; // 4.2
}
if (item_selected == 4) {
i = 655; //4096 / 30 * 4.8;
}
if (item_selected == 5) {
i = 683; //4096 / 30 * 5.0;
}
if (item_selected == 6) {
i = 819; //4096 / 30 * 6.0;
}
if (item_selected == 7) {
i = 1638; //4096 / 30 * 12.0;
}
if (item_selected == 8) {
i = 1884; //4096 / 30 * 13.8;
}
if (item_selected == 9) {
i = 2048; //4096 / 30 * 15.0;
}
if (item_selected == 10) {
i = 3277; //4096 / 30 * 24.0;
}
if (item_selected == 11) {
i = 4095; //4096 / 30 * 30.0;
}
if ((item_selected == 12) && (Poti == 0)) {
//Stop = false;
//i = 0; // Var.
Poti = 1;
Automatic = 1;
}
//--------------------- ab hier neu -------------------
if (((Poti == 1)) && (Stop == false)) { //(((Poti == 1)) && (Stop == false)) {
if ((digitalRead(ENCODER_DT) == HIGH) && (Automatic == 1)) {
virtualPosition++ ; // Could be 0 or 4095
//Serial.println("auto 1");
}
}
///*
// -----------------test
if (digitalRead(button_more) == 0) {
virtualPosition++;
Automatic = 0;
if ((virtualPosition) > 4095) {
virtualPosition = 4095;
}
}
if (digitalRead(button_less) == 0) {
virtualPosition--;
Automatic = 0;
if ((virtualPosition) < 0) {
virtualPosition = 0;
}
}
//*/
//Serial.println(virtualPosition);
// ----------------test ende
virtualPosition = min(4095, max(0, virtualPosition)); // 1000,
progress = virtualPosition / 4;
if ((digitalRead(ENCODER_BTN) == LOW)) { //&& (button_select_clicked == 0)) {
button_select_clicked = 1; // set button to clicked to only perform the action once
Taste = true; //false;
Stop = !Stop; //false;
//Serial.println(Stop);
delay(50);
}
dac.setVoltage(i, false);
//Serial.println(i);
//---------------------
if ((Poti == 1) && (Stop == false)) {
;
u8g.setColorIndex(1); // white color
u8g.drawBox(2, 28, map(progress, 0, 1023, 0, 124), 10); // actual gauge fill, remapped from 0-1023 to 0-124 (maximum rectangle size)
dac.setVoltage(i, false);
//Serial.print("Poti1**");
//Serial.println(i);
// bis hier ok
//-----------------
//sprintf(buffer, "---->", i); // construct a string with the progress variable
sprintf(buffer, " DAC: %d%", i); // construct a string with the progress variable
u8g.drawStr(20, 53, buffer); // display the string 33 , 53
//-----------------
}
if ((digitalRead(ENCODER_BTN) == LOW) && (Poti == 1)) {
;
Poti = 0;
u8g.drawBox(2, 28, map(0, 0, 1023, 0, 124), 10); // actual gauge fill, remapped from 0-1023 to 0-124 (maximum rectangle size)
}
if (item_selected != 12) {
Poti = 0;
}
i = virtualPosition;
}
// ---------------------------------------
// --------------- Ende icon = 1 ------------------------------------
if (icon == 0) {
u8g.drawBitmapP( 4, 24, 16 / 8, 16, bitmap_icons[0]); // Icon wird gelöscht
digitalWrite(LED_PIN13, LOW);
Poti = 0;
//digitalWrite(Hupe, LOW);
// -------------- DAC setzen AUS ------------------------
i = 0;
dac.setVoltage(i, false);
//-------------------------------------------------------
}
// draw next item as label
u8g.setFont(u8g_font_6x12); // 7x14
u8g.drawStr(25, 15 + 20 + 20 + 2 + 2, menu_items[item_sel_next]);
// draw scrollbar background
u8g.drawBitmapP(128 - 8, 0, 8 / 8, 64, bitmap_scrollbar_background);
// draw scrollbar handle
u8g.drawBox(125, 64 / NUM_ITEMS * item_selected, 3, 64 / NUM_ITEMS);
if (Poti == 1) {
u8g.drawBox(2, 28, map(progress, 0, 1023, 0, 124), 10); // actual gauge fill, remapped from 0-1023 to 0-124 (maximum rectangle size)
}
}
while ( u8g.nextPage() ); // required for page drawing mode with u8g library
}
//------------------------------Ende void loop ---------------------------------------
void timer_isr(void) {
if (digitalRead(button_more) == 0) {
//Serial.println("Hallo");
virtualPosition = virtualPosition + 100;
}
if (digitalRead(button_less) == 0) {
//Serial.println("Hallo");
//virtualPosition = virtualPosition - 100;
}
}
//------------------------------Ende Timer loop ---------------------------------------