Creative Inspire T7900 – Digitale volume en bass regeling

Toon hier Uw afgeronde projecten aan anderen.
Gebruikers-avatar
Berichten: 15
Geregistreerd: 25 Jul 2014, 14:38
Woonplaats: Deventer

Creative Inspire T7900 – Digitale volume en bass regeling

Berichtdoor DomoticX » 14 Jul 2016, 19:24

Even een projectje...de Creative Inspire T7900 is een 7.1 speakerset, na verloop van jaren is mijn volumeknop haperig, in de zin dat het soms van heel zacht naar heel hard gaat, maar echter is het nu helemaal gebeurd, dus op naar de digitale oplossing!

Hier draait het om, de afstandsbediening van de T7900:
Creative-Inspire-T7900-Afstandsbediening.jpg
Creative-Inspire-T7900-Afstandsbediening.jpg (15.36 KiB) 9762 keer bekeken


Het idee wat ik in gedachten heb is door middel van 2 rotary encoders, een OLED display, Arduino MEGA en 2 digitale potmeters (MCP41050) de afstandsbediening (MS0720B) “aan te sturen”.
Een paar avonden later is het gelukt, vooral het stoeien met goede uitlezing van de rotary encoders was een puzzel (werkt nu perfect met interrupts), maar het slokt 2 interrupts op per encoder, dus op de UNO kan je maar 1 encoder aansluiten, daarvoor heb ik de MEGA gebruikt!

Dit project is een voorbeeld voor als mensen met het zelfde idee lopen om met digitale potmeters te werken.

Principe:
De rotary encoders worden uitgelezen en de waarden worden verwerkt en doorgegeven naar de digitale potmeters MCP41050, tevens wordt er een display aangestuurd, zodat je visueel ook kan zien op welke waarde je zit, de BASS instelling wordt opgeslagen in het EEPROM, deze blijft bewaard na het uitzetten, dit omdat de bass instelling eenmaal ingesteld, weinig wordt aangepast.

Schema:
Creative Inspire T7900 - Digitale volume en bass regeling fritzing.png
Creative Inspire T7900 - Digitale volume en bass regeling fritzing.png (71.48 KiB) 9762 keer bekeken


Praktijk:
Creative Inspire T7900 - Digitale volume en bass regeling prototype.jpg
Creative Inspire T7900 - Digitale volume en bass regeling prototype.jpg (48.36 KiB) 9762 keer bekeken


Script:


cpp code
// Script om de potmeters van een Creative T7900 set te vervangen door
// digitale potmeters en OLED scherm met rotary encoders.
//
// Changelog:
//
// v1.0.0 (2016-07-14)
// Initial release door S. Ebeltjes @ DomoticX.nl

// U8glib Bibliotheek importeren
#include "U8glib.h"
// U8glib Bibliotheek configureren voor het juiste display
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST); // Dev 0, Fast I2C / TWI

#include <SPI.h>
byte address = 0x11;
int CS1 = 53;
int CS2 = 49;

// BASS instelling wordt opgeslagen in het EEPROM geheugen
#include <EEPROM.h> // eeprom bibliotheek inladen
int EepromAdres2 = 0; // Het adres in de EEPROM (0-511 byte)

// Encoder pins configureren.
int pinEnc1A = 2; // Encoder 1 pin A
int pinEnc1B = 3; // Encoder 1 pin B
int pinEnc2A = 19; // Encoder 2 pin A
int pinEnc2B = 18; // Encoder 2 pin B

static byte abOud; // Initialiseer status.
volatile int teller1 = 0; // rotatie teller 1.
volatile int teller2 = 0; // rotatie teller 2.
int teller1_oud = 1; // oude rotatie teller 1.
int teller2_oud = 1; // oude rotatie teller 2.

// Potmeter1 instellingen.
int potmeter1;
// Mapwaarden voor potmeter1 tbv arduino map()
int BitResPot1 = 254; // 8-bit = 254, 7 bit = 127.
int MaxResPot1 = 200; // Encoder stapjes tot maximaal VOLUME.

// Potmeter2 instellingen.
int potmeter2;
// Mapwaarden voor potmeter2 tbv arduino map()
int BitResPot2 = 254; // 8-bit = 254, 7 bit = 127.
int MaxResPot2 = 200; // Encoder stapjes tot maximaal BASS (Max. 254 ivm EEPROM opslag)

// Waarden voor variabel getal reserveren.
enum {BufSize=6};
char teller1Str[BufSize];
char teller2Str[BufSize];

void setup() {
// Encoder pinnen instellen.
pinMode(pinEnc1A, INPUT);
pinMode(pinEnc1B, INPUT);
pinMode(pinEnc2A, INPUT);
pinMode(pinEnc2B, INPUT);
// Chip Select (CS) pinnen instellen voor MCP41xxx.
pinMode(CS1, OUTPUT);
pinMode(CS2, OUTPUT);

// Interrupts instellen (pin hoog-laag verandering).
// Interrupt 0 = Pin 2 op de Arduino MEGA.
// Interrupt 1 = Pin 3 op de Arduino MEGA.
// Interrupt 4 = Pin 19 op de Arduino MEGA.
// Interrupt 5 = Pin 18 op de Arduino MEGA.
attachInterrupt(0, pinActie1, CHANGE); // Encoder 1.
attachInterrupt(1, pinActie1, CHANGE); // Encoder 1.
attachInterrupt(4, pinActie2, CHANGE); // Encoder 2.
attachInterrupt(5, pinActie2, CHANGE); // Encoder 2.

// Begin SPI interface
SPI.begin();

// Lettertype instellen voor u8glib.
u8g.setFont(u8g_font_5x8);

// Stel potmeter1 (VOLUME) in bij opstarten.
digitalPot1Write(potmeter1);

// Stel potmeter2 (BASS) in bij opstarten (haal ook de waarde uit de EEPROM)
teller2 = EEPROM.read(EepromAdres2);
potmeter2 = map(teller2, 0, MaxResPot2, 0, BitResPot2); // Map de volume van 0-255 voor de potmeter2 (MCP41xxx)
digitalPot2Write(potmeter2); // Stel potmeter2 in (MCP41xxx).
}

void loop() {
// IF loop wanneer er aan een encoder is gedraaid.
if ((teller1_oud != teller1) || (teller2_oud != teller2)) {
teller1_oud = teller1;
teller2_oud = teller2;

snprintf(teller1Str, BufSize, "%d", potmeter1); // Converteer de "potmeter1" INT naar STR (tbv OLED scherm)
snprintf(teller2Str, BufSize, "%d", potmeter2); // Converteer de "potmeter2" INT naar STR (tbv OLED scherm)

// OLED scherm loop.
u8g.firstPage();
do {
u8g.drawStr(0, 10, "VOLUME <");
u8g.drawStr(40, 10, teller1Str); // print "teller2" tekst.
u8g.drawStr(55, 10, ">");
u8g.drawStr(0, 42, "BASS <");
u8g.drawStr(40, 42, teller2Str); // print "teller2" tekst.
u8g.drawStr(55, 42, ">");

u8g.setColorIndex(0); // zet kleur negatief (pixel uit).
u8g.drawBox(0, 14, 128, 16); // Teken een rechthoek, 0px vanaf links, 14px van boven, 128px breed, 16px hoog.
u8g.drawBox(0, 46, 128, 16); // Teken een rechthoek, 0px vanaf links, 46px van boven, 128px breed, 16px hoog.

int bar1 = map(teller1, 0, MaxResPot1, 1, 126);
int bar2 = map(teller2, 0, MaxResPot2, 1, 126);
u8g.setColorIndex(1); // zet de kleur positief (pixel aan).

// Bar Volume.
u8g.drawFrame(0, 14, 126, 16); // Teken een frame, 0px vanaf links, 14px van boven, 126px breed, 16px hoog.
u8g.drawBox(0, 14, bar1, 16); // Teken een rechthoek, 0px vanaf links, 14px van boven, 128px breed, 16px hoog.

// Bar Bass.
u8g.drawFrame(0, 46, 126, 16); // Teken een frame, 0px vanaf links, 14px van boven, 126px breed, 16px hoog.
u8g.drawBox(0, 46, bar2, 16); // Teken een rechthoek, 0px vanaf links, 46px van boven, 128px breed, 16px hoog.
} while( u8g.nextPage() );

}
}

// Wanneer een interrupt heeft plaatsgevonden, lees de input pinnen, bereken nieuwe status, pas de telling aan.
void pinActie1() {
enum { upMask = 0x66, downMask = 0x99 };
byte abNieuw = (digitalRead(pinEnc1A) << 1) | digitalRead(pinEnc1B);
byte criteria = abNieuw^abOud;
if (criteria==1 || criteria==2) {
if (upMask & (1 << (2*abOud + abNieuw/2)))
teller1--; // tel naar boven.
else teller1++; // tel naar beneden.
}
if (teller1 < 0) { teller1 = 0; }
if (teller1 > MaxResPot1) { teller1 = MaxResPot1; }

potmeter1 = map(teller1, 0, MaxResPot1, 0, BitResPot1); // Map de volume van 0-255 voor de potmeter1.
digitalPot1Write(potmeter1); // Stel potmeter1 in.
abOud = abNieuw; // bewaar nieuwe status.
}

// Wanneer een interrupt heeft plaatsgevonden, lees de input pinnen, bereken nieuwe status, pas de telling aan.
void pinActie2() {
enum { upMask = 0x66, downMask = 0x99 };
byte abNieuw = (digitalRead(pinEnc2A) << 1) | digitalRead(pinEnc2B);
byte criteria = abNieuw^abOud;
if (criteria==1 || criteria==2) {
if (upMask & (1 << (2*abOud + abNieuw/2)))
teller2--; // tel naar boven.
else teller2++; // tel naar beneden.
}
if (teller2 < 0) { teller2 = 0; }
if (teller2 > MaxResPot2) { teller2 = MaxResPot2; }

potmeter2 = map(teller2, 0, MaxResPot2, 0, BitResPot2); // Map de volume van 0-255 voor de potmeter2.
digitalPot2Write(potmeter2); // Stel potmeter2 in.

// Sla waarde op in EEPROM geheugen (BASS veranderdt niet veel)
EEPROM.write(EepromAdres2, teller2);

abOud = abNieuw; // bewaar nieuwe status.
}

// Stel de waarde in voor de MCP41xxx chip.
int digitalPot1Write(int value) {
digitalWrite(CS1, LOW);
SPI.transfer(address);
SPI.transfer(value);
digitalWrite(CS1, HIGH);
}

// Stel de waarde in voor de MCP41xxx chip.
int digitalPot2Write(int value) {
digitalWrite(CS2, LOW);
SPI.transfer(address);
SPI.transfer(value);
digitalWrite(CS2, HIGH);
}


Nu het Kastje nog....

Video's volgen (moet nog monteren etc)

Ps. voor grotere afbeeldingen kijk hier: http://domoticx.com/creative-inspire-t7900-digitale-volume-en-bass-regeling/
Maatwerk in: Domotica - Automatisering - Elektronica - 3D printing - Software ontwikkeling
Website / Webshop / Knowledge Center / Facebook (like de pagina en blijf op de hoogte!)

Advertisement

Gebruikers-avatar
Berichten: 5043
Geregistreerd: 13 Mei 2013, 20:57
Woonplaats: Heemskerk

Re: Creative Inspire T7900 – Digitale volume en bass regelin

Berichtdoor nicoverduin » 15 Jul 2016, 07:47

Leuk hobby projectje!!
Je kan toch de pinChangeInt library gebruiken? Dan kun je een int op elke pin krijgen.
Verder zijn er nog wel wat mogelijkheden om de code wat netter en efficiënter te maken zoals een functie voor schrijven naar de potmeters, 1 functie voor de pin acties en een aparte functie voor het display.
Docent HBO Technische Informatica, Embedded ontwikkelaar & elektronicus
http://www.verelec.nl

Berichten: 4064
Geregistreerd: 16 Okt 2013, 14:31
Woonplaats: s hertogenbosch

Re: Creative Inspire T7900 – Digitale volume en bass regelin

Berichtdoor shooter » 15 Jul 2016, 16:48

Ook voor jou geld, houd de interupts kort, ofwel zet alleen een positie++ als de Bpin LOW is en positie-- als de Bpin High is.
de rest zoals overshoot gewoon in een loopfunctie doen.

is het een audiosignaal of wellicht een analoog regelsignaal dat naar een versterker gaat.
wel leuk ja, ik druk op een volumeknopje op mijn toetsenbord. haha
paul deelen
shooter@home.nl

Gebruikers-avatar
Berichten: 15
Geregistreerd: 25 Jul 2014, 14:38
Woonplaats: Deventer

Re: Creative Inspire T7900 – Digitale volume en bass regelin

Berichtdoor DomoticX » 15 Jul 2016, 19:24

@nico
Ik heb zoveel libraries gebruikt en getest voor encoders...echter geen één werkt goed!, veelal zijn ze "polling" en moeten in de loop(), dat is echt een afrader want je kan niets meer in de loop() kwijt of je pulsen worden niet meer goed geteld.
Code heb ik al aangepast, zie onder.

@shooter
Het is een analoog regelsignaal naar de active sub, waar de versterker etc in zit, er lopen geen grote stromen.

TODO:
- VOLUME MUTE toevoegen doormiddel van pushbutton in encoder
- Creative flash logo

Code: Alles selecteren
// Script om de potmeters van een Creative T7900 set te vervangen door
// digitale potmeters en OLED scherm met rotary encoders.
//
// v1.0.1 (2016-07-15)
// Code cleanup en kleine aanpassingen.

#include "U8glib.h" // U8glib Bibliotheek importeren.
// U8glib Bibliotheek configureren voor het juiste display.
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST); // Dev 0, Fast I2C / TWI

#include <SPI.h> // SPI bibliotheke inporteren.
byte address = 0x11;
int CS1 = 53; // ChipSelect pin voor potmeter1.
int CS2 = 49; // ChipSelect pin voor potmeter2.

// BASS instelling wordt opgeslagen in het EEPROM geheugen.
#include <EEPROM.h> // eeprom bibliotheek inladen.
int EepromAdres = 0; // Het adres in de EEPROM (0-511 byte).

// Encoder pins configureren.
int pinEnc1A = 2;   // Encoder 1 pin A.
int pinEnc1B = 3;   // Encoder 1 pin B.
int pinEnc2A = 19;  // Encoder 2 pin A.
int pinEnc2B = 18;  // Encoder 2 pin B.

// Grafische variabelen.
int bar1;
int bar2;

static byte abOud;        // Initialiseer status.
volatile int teller1 = 0; // rotatie teller 1.
volatile int teller2 = 0; // rotatie teller 2.
int teller1_oud = 1;      // oude rotatie teller 1.
int teller2_oud = 1;      // oude rotatie teller 2.

// Potmeter1 instellingen:
int potmeter1;
// Mapwaarden voor potmeter1 tbv arduino map().
int BitResPot1 = 254;   // 8-bit = 254, 7 bit = 127.
int MaxResPot1 = 200;  // Encoder stapjes tot maximaal VOLUME.

// Potmeter2 instellingen:
int potmeter2;
// Mapwaarden voor potmeter2 tbv arduino map().
int BitResPot2 = 254; // 8-bit = 254, 7 bit = 127.
int MaxResPot2 = 200; // Encoder stapjes tot maximaal BASS (Max. 254 ivm EEPROM opslag).

// Waarden voor variabel getal reserveren.
enum {BufSize=5};
char teller1Str[BufSize];
char teller2Str[BufSize];

void setup() {
  // Encoder pinnen instellen.
  pinMode(pinEnc1A, INPUT);
  pinMode(pinEnc1B, INPUT);
  pinMode(pinEnc2A, INPUT);
  pinMode(pinEnc2B, INPUT);
  // Chip Select (CS) pinnen instellen voor MCP41xxx potmeters.
  pinMode(CS1, OUTPUT);
  pinMode(CS2, OUTPUT);

  // Interrupts instellen (pin hoog-laag verandering).
  // Interrupt 0 = Pin 2  op de Arduino MEGA.
  // Interrupt 1 = Pin 3  op de Arduino MEGA.
  // Interrupt 4 = Pin 19 op de Arduino MEGA.
  // Interrupt 5 = Pin 18 op de Arduino MEGA.
  attachInterrupt(0, pinActie1, CHANGE); // Encoder 1.
  attachInterrupt(1, pinActie1, CHANGE); // Encoder 1.
  attachInterrupt(4, pinActie2, CHANGE); // Encoder 2.
  attachInterrupt(5, pinActie2, CHANGE); // Encoder 2.
 
  SPI.begin(); // Begin SPI interface
  u8g.setFont(u8g_font_5x8); // Lettertype instellen voor u8glib.

  // Stel potmeter1 (VOLUME) in bij opstarten.
  digitalPotWrite(CS1, potmeter1);
 
  // Stel potmeter2 (BASS) in bij opstarten (haal ook de waarde uit de EEPROM).
  teller2 = EEPROM.read(EepromAdres);
  potmeter2 = map(teller2, 0, MaxResPot2, 0, BitResPot2); // Map de volume van 0-255 voor de potmeter2 (MCP41xxx).
  digitalPotWrite(CS2, potmeter2); // Stel potmeter2 in (MCP41xxx).
}


void loop() {
  // IF loop wanneer er aan een encoder is gedraaid.
  if ((teller1_oud != teller1) || (teller2_oud != teller2)) {
    teller1_oud = teller1; teller2_oud = teller2; // Reset tellers.

    // OLED scherm loop.
    u8g.firstPage(); 
    do { SchermUpdate(); } while( u8g.nextPage() );
  }
}


// Scherm update
void SchermUpdate() {
  u8g.drawStr(0, 10, "VOLUME <"); u8g.drawStr(40, 10, teller1Str); u8g.drawStr(55, 10, ">"); // Print VOLUME teller tekst.
  u8g.drawStr(0, 42, "BASS   <"); u8g.drawStr(40, 42, teller2Str); u8g.drawStr(55, 42, ">"); // Print BASS teller tekst.
 
  u8g.setColorIndex(0);            // zet kleur negatief (pixel uit).
  u8g.drawBox(0, 14, 126, 16);     // Teken een rechthoek, 0px vanaf links, 14px van boven, 126px breed, 16px hoog.
  u8g.drawBox(0, 46, 126, 16);     // Teken een rechthoek, 0px vanaf links, 46px van boven, 126px breed, 16px hoog.
  u8g.setColorIndex(1);            // zet de kleur positief (pixel aan).
     
   // Bar VOLUME.
  int bar1 = map(teller1, 0, MaxResPot1, 1, 126); // Map de waarden voor grafische bar1.
  u8g.drawFrame(0, 14, 126, 16);   // Teken een frame, 0px vanaf links, 14px van boven, 126px breed, 16px hoog.     
  u8g.drawBox(0, 14, bar1, 16);    // Teken een rechthoek, 0px vanaf links, 14px van boven, (int) breed, 16px hoog.

  // Bar BASS.
  int bar2 = map(teller2, 0, MaxResPot2, 1, 126); // Map de waarden voor grafische bar2.
  u8g.drawFrame(0, 46, 126, 16);   // Teken een frame, 0px vanaf links, 14px van boven, 126px breed, 16px hoog.   
  u8g.drawBox(0, 46, bar2, 16);    // Teken een rechthoek, 0px vanaf links, 46px van boven, (int) breed, 16px hoog.
}


// Wanneer een interrupt heeft plaatsgevonden, lees de input pinnen, bereken nieuwe status, pas de telling aan.
void pinActie1() {
  enum { upMask = 0x66, downMask = 0x99 };
  byte abNieuw = (digitalRead(pinEnc1A) << 1) | digitalRead(pinEnc1B);
  byte criteria = abNieuw^abOud;
  if (criteria==1 || criteria==2) {
    if (upMask & (1 << (2*abOud + abNieuw/2)))
      teller1--;    // tel naar boven.
    else teller1++; // tel naar beneden.
  }
 
  // Limiteer het bereik van teller1.
  if (teller1 < 0) { teller1 = 0; }
  if (teller1 > MaxResPot1) { teller1 = MaxResPot1; }
 
  potmeter1 = map(teller1, 0, MaxResPot1, 0, BitResPot1); // Map de volume van 0-255 voor de potmeter1.
  digitalPotWrite(CS1, potmeter1); // Stel potmeter2 in.
  snprintf(teller1Str, BufSize, "%d", potmeter1);  // Converteer de "potmeter1" INT naar STR (tbv OLED scherm).
  abOud = abNieuw; // bewaar nieuwe status.
}


// Wanneer een interrupt heeft plaatsgevonden, lees de input pinnen, bereken nieuwe status, pas de telling aan.
void pinActie2() {
  enum { upMask = 0x66, downMask = 0x99 };
  byte abNieuw = (digitalRead(pinEnc2A) << 1) | digitalRead(pinEnc2B);
  byte criteria = abNieuw^abOud;
  if (criteria==1 || criteria==2) {
    if (upMask & (1 << (2*abOud + abNieuw/2)))
      teller2--;    // tel naar boven.
    else teller2++; // tel naar beneden.
  }
 
  // Limiteer het bereik van teller2.
  if (teller2 < 0) { teller2 = 0; }
  if (teller2 > MaxResPot2) { teller2 = MaxResPot2; }

  potmeter2 = map(teller2, 0, MaxResPot2, 0, BitResPot2); // Map de volume van 0-255 voor de potmeter2.
  digitalPotWrite(CS2, potmeter2); // Stel potmeter2 in.
  snprintf(teller2Str, BufSize, "%d", potmeter2);  // Converteer de "potmeter2" INT naar STR (tbv OLED scherm).
  abOud = abNieuw; // bewaar nieuwe status.

  // Sla waarde op in EEPROM geheugen (BASS veranderd niet veel)
  EEPROM.write(EepromAdres, teller2);
}

// Stel de waarde in voor de MCP41xxx chip.
int digitalPotWrite(int chip, int value) {
  digitalWrite(chip, LOW);
  SPI.transfer(address);
  SPI.transfer(value);
  digitalWrite(chip, HIGH);
}

// Changelog:
//
// v1.0.1 (2016-07-15)
// Code cleanup en kleine aanpassingen.
//
// v1.0.0 (2016-07-14)
// Initial release door S. Ebeltjes @ DomoticX.nl
Maatwerk in: Domotica - Automatisering - Elektronica - 3D printing - Software ontwikkeling
Website / Webshop / Knowledge Center / Facebook (like de pagina en blijf op de hoogte!)

Berichten: 4064
Geregistreerd: 16 Okt 2013, 14:31
Woonplaats: s hertogenbosch

Re: Creative Inspire T7900 – Digitale volume en bass regelin

Berichtdoor shooter » 15 Jul 2016, 19:49

waarom zou een encoder software niet goed werken, natuurlijk boven 1 Mhz is het wel even opletten, maar zelfs dat kan met een encoder IC goed geregeld worden hoor.
en is het een echt audio signaal want dan moet je iets doen aan ontstoring en de draadjes een beetje netjes leggen want er is wel brom
als het een versterkersignaal is zou je een pwm kunnen gebruiken.
paul deelen
shooter@home.nl

Gebruikers-avatar
Berichten: 15
Geregistreerd: 25 Jul 2014, 14:38
Woonplaats: Deventer

Re: Creative Inspire T7900 – Digitale volume en bass regelin

Berichtdoor DomoticX » 19 Jul 2016, 21:09

Zo, even weer een paar avondjes bezig geweest, het begint er op te lijken, het was een uitdaging om een logo in XBM format te maken en in u8glib te laden, maar ik ben tevreden over het resultaat ;)

v1.1.0 (2016-07-19)
Toegevoegd: Creative Splashscreen.
Toegevoegd: Volume waarde nu ook opgelsagen in EEPROM.
Toegevoegd: MUTE functie (knop encoder1).
Bugfix: waarden bij opstarten worden nu weergegeven.

TODO:
IR bediening.
LDR autocontrast.

Arduino - Creative Audio project - MUTE.jpg
Arduino - Creative Audio project - MUTE.jpg (16.19 KiB) 9617 keer bekeken

Arduino - Creative Audio project - LOGO.jpg
Arduino - Creative Audio project - LOGO.jpg (18.03 KiB) 9617 keer bekeken


v1.1.0 schema:
Fritzing - Creative audio schema (code v1.1.0+).png
Fritzing - Creative audio schema (code v1.1.0+).png (84.63 KiB) 9617 keer bekeken


<< Voor grotere plaatjes kijk hier >>

v1.1.0 code:
Code: Alles selecteren
// Script om de potmeters van een Creative T7900 set te vervangen door
// digitale potmeters en OLED scherm met rotary encoders.
//
// v1.1.0 (2016-07-19)
// Toegevoegd: Creative Splashscreen.
// Toegevoegd: Volume waarde nu ook opgelsagen in EEPROM.
// Toegevoegd: MUTE functie (knop encoder1).
// Bugfix: waarden bij opstarten worden nu weergegeven.
//
// TODO:
// IR bediening.
// LDR autocontrast.

#include "U8glib.h" // U8glib Bibliotheek importeren.
// U8glib Bibliotheek configureren voor het juiste display.
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST); // Dev 0, Fast I2C / TWI

#include <SPI.h> // SPI bibliotheek importeren.
byte address = 0x11;
int CS1 = 53; // ChipSelect pin voor potmeter1.
int CS2 = 49; // ChipSelect pin voor potmeter2.

// BASS instelling wordt opgeslagen in het EEPROM geheugen.
#include <EEPROM.h> // EEPROM bibliotheek importeren.
int EepromAdres1 = 0; // Het adres voor de VOLUME in de EEPROM (0-511 byte).
int EepromAdres2 = 1; // Het adres voor de VOLUME in de EEPROM (0-511 byte).

// Encoder pins configureren.
int pinEnc1A = 2;   // Encoder 1 pin A.
int pinEnc1B = 3;   // Encoder 1 pin B.
int pinEnc1BUT = 4; // Encoder 1 drukknop.
int pinEnc2A = 19;  // Encoder 2 pin A.
int pinEnc2B = 18;  // Encoder 2 pin B.

// Grafische variabelen.
int bar1;
int bar2;

static byte abOud;        // Initialiseer status.
volatile int teller1 = 0; // rotatie teller 1.
volatile int teller2 = 0; // rotatie teller 2.
int teller1_oud = 1;      // oude rotatie teller 1.
int teller2_oud = 1;      // oude rotatie teller 2.
int mute;                 // MUTE waarde.

// Potmeter1 instellingen:
int potmeter1;
// Mapwaarden voor potmeter1 tbv arduino map().
int BitResPot1 = 255;   // 8-bit = 255, 7 bit = 127.
int MaxResPot1 = 200;  // Encoder stapjes tot maximaal VOLUME (Max. 254 ivm EEPROM opslag).

// Potmeter2 instellingen:
int potmeter2;
// Mapwaarden voor potmeter2 tbv arduino map().
int BitResPot2 = 255; // 8-bit = 255, 7 bit = 127.
int MaxResPot2 = 200; // Encoder stapjes tot maximaal BASS (Max. 254 ivm EEPROM opslag).

// Waarden voor variabel getal reserveren.
enum {BufSize=5};
char teller1Str[BufSize];
char teller2Str[BufSize];

// Creative logo 128x22 in XBM format.
static unsigned char creative_logo[] U8G_PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf0, 0x7f, 0xf0, 0xff, 0xc1, 0xff, 0x0f, 0xf0, 0xe0, 0xff, 0x8f, 0xe3, 0x01, 0x9e, 0xff, 0x1f,
0xf8, 0xff, 0xf0, 0xff, 0xc3, 0xff, 0x0f, 0xf0, 0xe0, 0xff, 0x8f, 0xc3, 0x01, 0x8e, 0xff, 0x1f,
0x3c, 0xe0, 0x70, 0x80, 0xc3, 0x01, 0x00, 0xf8, 0x01, 0x38, 0x80, 0xc3, 0x03, 0x8e, 0x03, 0x00,
0x1e, 0x00, 0x70, 0x80, 0xc3, 0x01, 0x00, 0xf8, 0x01, 0x38, 0x80, 0x83, 0x03, 0x87, 0x03, 0x00,
0x0e, 0x00, 0x70, 0x80, 0xc3, 0x01, 0x00, 0x9c, 0x03, 0x38, 0x80, 0x83, 0x03, 0x87, 0x03, 0x00,
0x0e, 0x00, 0x70, 0xe0, 0x03, 0xf0, 0x00, 0x9c, 0x03, 0x38, 0x80, 0x03, 0x87, 0x03, 0xe0, 0x00,
0x06, 0x00, 0x70, 0xf8, 0x01, 0xf0, 0x00, 0x0e, 0x07, 0x38, 0x80, 0x03, 0x87, 0x03, 0xe0, 0x00,
0x06, 0x00, 0x70, 0xf8, 0x00, 0xf0, 0x00, 0x0e, 0x07, 0x38, 0x80, 0x03, 0xce, 0x03, 0xe0, 0x00,
0x0e, 0x00, 0x70, 0x78, 0xc0, 0x01, 0x00, 0x06, 0x0e, 0x38, 0x80, 0x03, 0xce, 0x81, 0x03, 0x00,
0x0e, 0x00, 0x70, 0xf0, 0xc0, 0x01, 0x00, 0x07, 0x0e, 0x38, 0x80, 0x03, 0xfe, 0x81, 0x03, 0x00,
0x1e, 0xc0, 0x70, 0xe0, 0xc0, 0x01, 0x00, 0x03, 0x1e, 0x38, 0x80, 0x03, 0xfc, 0x80, 0x03, 0x00,
0x7c, 0xf0, 0x70, 0xe0, 0xc1, 0x01, 0x80, 0x03, 0x1c, 0x38, 0x80, 0x03, 0xfc, 0x80, 0x03, 0x00,
0xf8, 0xff, 0x70, 0xc0, 0xc3, 0xff, 0x8f, 0x03, 0x3c, 0x38, 0x80, 0x03, 0x78, 0x80, 0xff, 0x1f,
0xe0, 0x3f, 0x70, 0x80, 0xc3, 0xff, 0xcf, 0x01, 0x38, 0x38, 0x80, 0x03, 0x78, 0x80, 0xff, 0x1f,
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,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };


void setup() {
  // Encoder pinnen instellen.
  pinMode(pinEnc1A, INPUT);
  pinMode(pinEnc1B, INPUT);
  pinMode(pinEnc1BUT, INPUT);
  pinMode(pinEnc2A, INPUT);
  pinMode(pinEnc2B, INPUT);
  // Chip Select (CS) pinnen instellen voor MCP41xxx potmeters.
  pinMode(CS1, OUTPUT);
  pinMode(CS2, OUTPUT);
 
  digitalWrite(pinEnc1BUT, HIGH); // Zet encoder1 pin voor drukknop HOOG (pull-up weerstand).
 
  // Interrupts instellen (pin hoog-laag verandering).
  // Interrupt 0 = Pin 2  op de Arduino MEGA.
  // Interrupt 1 = Pin 3  op de Arduino MEGA.
  // Interrupt 4 = Pin 19 op de Arduino MEGA.
  // Interrupt 5 = Pin 18 op de Arduino MEGA.
  attachInterrupt(0, Enc1Draai, CHANGE); // Encoder 1.
  attachInterrupt(1, Enc1Draai, CHANGE); // Encoder 1.
  attachInterrupt(4, Enc2Draai, CHANGE); // Encoder 2.
  attachInterrupt(5, Enc2Draai, CHANGE); // Encoder 2.

  SPI.begin(); // Begin SPI interface
  u8g.setFont(u8g_font_5x8); // Lettertype instellen voor u8glib.
  //u8g.setContrast(3);
 
  // Stel potmeter1 (VOLUME) in bij opstarten.
  teller1 = EEPROM.read(EepromAdres1);
  potmeter1 = map(teller1, 0, MaxResPot1, 0, BitResPot1); // Map de volume van 0-255 voor de potmeter2 (MCP41xxx).
  digitalPotWrite(CS1, potmeter1);

  // Stel potmeter2 (BASS) in bij opstarten (haal ook de waarde uit de EEPROM).
  teller2 = EEPROM.read(EepromAdres2);
  potmeter2 = map(teller2, 0, MaxResPot2, 0, BitResPot2); // Map de volume van 0-255 voor de potmeter2 (MCP41xxx).
  digitalPotWrite(CS2, potmeter2); // Stel potmeter2 in (MCP41xxx).

  // Flash screen
  u8g.firstPage(); 
  do { SchermFlash(); } while( u8g.nextPage() );
  delay(4000);
 
  SchermUpdate();
}


void loop() {
  // IF loop wanneer er aan een encoder is gedraaid.
  if ((teller1_oud != teller1) || (teller2_oud != teller2)) {
    teller1_oud = teller1; teller2_oud = teller2; // Reset tellers.

    // OLED scherm loop.
    u8g.firstPage();
    do { SchermUpdate(); } while( u8g.nextPage() );
  }

  // Monitor of de knop van encoder1 is ingedrukt.
  if (!(digitalRead(pinEnc1BUT))) { Enc1Knop(); } // De knop is doorverbonden met GND en de pin wordt LAAG.
}


// Scherm update.
void SchermUpdate() {
  snprintf(teller1Str, BufSize, "%d", potmeter1);  // Converteer de "potmeter1" INT naar STR (tbv OLED scherm).
  snprintf(teller2Str, BufSize, "%d", potmeter2);  // Converteer de "potmeter2" INT naar STR (tbv OLED scherm).
 
  u8g.drawStr(0, 10, "VOLUME ["); u8g.drawStr(40, 10, teller1Str); u8g.drawStr(55, 10, "]"); // Print VOLUME teller tekst.
  u8g.drawStr(0, 42, "BASS   ["); u8g.drawStr(40, 42, teller2Str); u8g.drawStr(55, 42, "]"); // Print BASS teller tekst.
 
  u8g.setColorIndex(0);            // zet kleur negatief (pixel uit).
  u8g.drawBox(0, 14, 126, 16);     // Teken een rechthoek, 0px vanaf links, 14px van boven, 126px breed, 16px hoog.
  u8g.drawBox(0, 46, 126, 16);     // Teken een rechthoek, 0px vanaf links, 46px van boven, 126px breed, 16px hoog.
  u8g.setColorIndex(1);            // zet de kleur positief (pixel aan).
     
   // VOLUME bar.
  int bar1 = map(teller1, 0, MaxResPot1, 1, 126); // Map de waarden voor grafische bar1.
  u8g.drawFrame(0, 14, 126, 16);   // Teken een frame, 0px vanaf links, 14px van boven, 126px breed, 16px hoog.     
  u8g.drawBox(0, 14, bar1, 16);    // Teken een rechthoek, 0px vanaf links, 14px van boven, (int) breed, 16px hoog.

  if (mute == 1) {
    u8g.setScale2x2();                  // maak het lettertype 2x groter.
    u8g.drawStr(2, 14, "/// MUTE ///"); // print tekst.
    u8g.undoScale();                    // zet het lettertype weer terug.
  };

  // BASS bar.
  int bar2 = map(teller2, 0, MaxResPot2, 1, 126); // Map de waarden voor grafische bar2.
  u8g.drawFrame(0, 46, 126, 16);   // Teken een frame, 0px vanaf links, 14px van boven, 126px breed, 16px hoog.   
  u8g.drawBox(0, 46, bar2, 16);    // Teken een rechthoek, 0px vanaf links, 46px van boven, (int) breed, 16px hoog.
}

// Flashscreen.
void SchermFlash () {
  u8g.drawXBMP(1, 1, 128-1, 21, creative_logo); // info: hoogte -1
  u8g.setScale2x2(); // maak het lettertype 2x groter.
  u8g.drawStr(0, 25, "  [ T7900 ] "); // print tekst.
  u8g.undoScale(); // zet het lettertype weer terug.
}


// Wanneer een interrupt heeft plaatsgevonden, lees de input pinnen, bereken nieuwe status, pas de telling aan.
void Enc1Draai() {
  enum { upMask = 0x66, downMask = 0x99 };
  byte abNieuw = (digitalRead(pinEnc1A) << 1) | digitalRead(pinEnc1B);
  byte criteria = abNieuw^abOud;
  if (criteria==1 || criteria==2) {
    if (upMask & (1 << (2*abOud + abNieuw/2)))
      teller1--;    // tel naar boven.
    else teller1++; // tel naar beneden.
  }
 
  // Limiteer het bereik van teller1.
  if (teller1 <= 0) { teller1 = 0; mute = 1; }
  if (teller1 > 0) { mute = 0; }
  if (teller1 > MaxResPot1) { teller1 = MaxResPot1; }
 
  potmeter1 = map(teller1, 0, MaxResPot1, 0, BitResPot1); // Map de volume van 0-255 voor de potmeter1.
  digitalPotWrite(CS1, potmeter1); // Stel potmeter2 in.
  abOud = abNieuw; // bewaar nieuwe status.

  // Sla VOLUME waarde op in EEPROM geheugen.
  EEPROM.write(EepromAdres1, teller1);
}

// Wanneer de knop op encoder1 is ingedrukt.
void Enc1Knop() {
  if (mute == 0) {
    mute = 1;    // Zet MUTE waarde op 1 (vlag).
    teller1 = 0; // Zet volume waarde op 0.
  } else {
    mute = 0;    // Zet MUTE waarde op 0 (vlag).
    teller1 = EEPROM.read(EepromAdres1); // Haal de teller waarde op uit het geheugen.
  }
  potmeter1 = map(teller1, 0, MaxResPot1, 0, BitResPot1); // Map de volume van 0-255 voor de potmeter1.
  digitalPotWrite(CS1, potmeter1); // Stel potmeter2 in. 
 
  SchermUpdate(); // werk het scherm bij.
  delay(200); // wacht even voordat er weer gekeken wordt om de knop in te lezen.
}

// Wanneer een interrupt heeft plaatsgevonden, lees de input pinnen, bereken nieuwe status, pas de telling aan.
void Enc2Draai() {
  enum { upMask = 0x66, downMask = 0x99 };
  byte abNieuw = (digitalRead(pinEnc2A) << 1) | digitalRead(pinEnc2B);
  byte criteria = abNieuw^abOud;
  if (criteria==1 || criteria==2) {
    if (upMask & (1 << (2*abOud + abNieuw/2)))
      teller2--;    // tel naar boven.
    else teller2++; // tel naar beneden.
  }
 
  // Limiteer het bereik van teller2.
  if (teller2 < 0) { teller2 = 0; }
  if (teller2 > MaxResPot2) { teller2 = MaxResPot2; }

  potmeter2 = map(teller2, 0, MaxResPot2, 0, BitResPot2); // Map de volume van 0-255 voor de potmeter2.
  digitalPotWrite(CS2, potmeter2); // Stel potmeter2 in.
  abOud = abNieuw; // bewaar nieuwe status.

  // Sla BASS waarde op in EEPROM geheugen.
  EEPROM.write(EepromAdres2, teller2);
}

// Stel de waarde in voor de MCP41xxx chip.
int digitalPotWrite(int chip, int value) {
  digitalWrite(chip, LOW);
  SPI.transfer(address);
  SPI.transfer(value);
  digitalWrite(chip, HIGH);
}

// Changelog:
//
// v1.0.1 (2016-07-15)
// Code cleanup en kleine aanpassingen.
//
// v1.0.0 (2016-07-14)
// Initial release door S. Ebeltjes @ DomoticX.nl
Maatwerk in: Domotica - Automatisering - Elektronica - 3D printing - Software ontwikkeling
Website / Webshop / Knowledge Center / Facebook (like de pagina en blijf op de hoogte!)

Gebruikers-avatar
Berichten: 15
Geregistreerd: 25 Jul 2014, 14:38
Woonplaats: Deventer

Re: Creative Inspire T7900 – Digitale volume en bass regelin

Berichtdoor DomoticX » 30 Jul 2016, 09:15

Hallo allen, het project is nu klaar kwa functionaliteit, scherm wordt nu automatisch gedimd in licht/donker dmv LDR en er is IR functionaliteit toegevoegd om alles met een afstandsbediening te regelen...ik zal de behuizing tzt nog ontwerpen, maar voor nu erg tevreden.

Schema 1.2.0+
Fritzing - Creative audio schema (code v1.2.0+).png
Fritzing - Creative audio schema (code v1.2.0+).png (84.78 KiB) 9562 keer bekeken

Voor grotere plaatjes klik hier

Code v1.2.0 (2016-07-22)
cpp code
// Script om de potmeters van een Creative T7900 set te vervangen door
// digitale potmeters en OLED scherm met rotary encoders.
//
// v1.2.0 (2016-07-22)
// Toegevoegd: Autocontrast dmv LDR (2 waarden).
// Toegevoegd: IR bediending VOL+BASS+MUTE.
// Toegevoegd: Firmware versie in splashscreen.

char* versie = "1.2.0"; // laat deze firmware versie zien in het splashscreen.

#include "U8glib.h" // U8glib Bibliotheek importeren.
// U8glib Bibliotheek configureren voor het juiste display.
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST); // Dev 0, Fast I2C / TWI

// Digitale potmeters instellingen:
#include <SPI.h> // SPI bibliotheek importeren.
byte address = 0x11;
int CS1 = 53; // ChipSelect pin voor potmeter1.
int CS2 = 49; // ChipSelect pin voor potmeter2.

// BASS instelling wordt opgeslagen in het EEPROM geheugen.
#include <EEPROM.h> // EEPROM bibliotheek importeren.
int EepromAdres1 = 0; // Het adres voor de VOLUME in de EEPROM (0-511 byte).
int EepromAdres2 = 1; // Het adres voor de VOLUME in de EEPROM (0-511 byte).

// Encoder pins instellingen:
int pinEnc1A = 2; // Encoder 1 pin A.
int pinEnc1B = 3; // Encoder 1 pin B.
int pinEnc1BUT = 4; // Encoder 1 drukknop.
int pinEnc2A = 19; // Encoder 2 pin A.
int pinEnc2B = 18; // Encoder 2 pin B.

// LDR Sensor instellingen:
int LDRsensorPin = A0; // LDR Sensor pin.
int LDRsensorWaarde; // LDR sensor variabele.
unsigned long TimerLDR; // LDR timer.
int LDRdonkerwaarde = 400; // LDR waarde instellen voor donker (veelal 300-400)

// IR sensor instellingen:
#include <IRremote.h>
int IRsensorPin = 11; // IR Sensor pin.
IRrecv irrecv(IRsensorPin);
decode_results results;

// Potmeter1 instellingen:
int potmeter1;
// Mapwaarden voor potmeter1 tbv arduino map().
int BitResPot1 = 255; // 8-bit = 255, 7 bit = 127.
int MaxResPot1 = 200; // Encoder stapjes tot maximaal VOLUME (Max. 254 ivm EEPROM opslag).

// Potmeter2 instellingen:
int potmeter2;
// Mapwaarden voor potmeter2 tbv arduino map().
int BitResPot2 = 255; // 8-bit = 255, 7 bit = 127.
int MaxResPot2 = 200; // Encoder stapjes tot maximaal BASS (Max. 254 ivm EEPROM opslag).

// Grafische variabelen.
int bar1;
int bar2;
int contrast = 255; // 255 is maximaal contrast.

// Overige variabelen.
static byte abOud; // Initialiseer status.
volatile int teller1 = 0; // rotatie teller 1.
volatile int teller2 = 0; // rotatie teller 2.
int teller1_oud = 1; // oude rotatie teller 1.
int teller2_oud = 1; // oude rotatie teller 2.
int mute; // MUTE waarde.

// Waarden voor variabel getal reserveren.
enum {BufSize=5};
char teller1Str[BufSize];
char teller2Str[BufSize];

// Creative logo 128x22 in XBM format.
static unsigned char creative_logo[] U8G_PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf0, 0x7f, 0xf0, 0xff, 0xc1, 0xff, 0x0f, 0xf0, 0xe0, 0xff, 0x8f, 0xe3, 0x01, 0x9e, 0xff, 0x1f,
0xf8, 0xff, 0xf0, 0xff, 0xc3, 0xff, 0x0f, 0xf0, 0xe0, 0xff, 0x8f, 0xc3, 0x01, 0x8e, 0xff, 0x1f,
0x3c, 0xe0, 0x70, 0x80, 0xc3, 0x01, 0x00, 0xf8, 0x01, 0x38, 0x80, 0xc3, 0x03, 0x8e, 0x03, 0x00,
0x1e, 0x00, 0x70, 0x80, 0xc3, 0x01, 0x00, 0xf8, 0x01, 0x38, 0x80, 0x83, 0x03, 0x87, 0x03, 0x00,
0x0e, 0x00, 0x70, 0x80, 0xc3, 0x01, 0x00, 0x9c, 0x03, 0x38, 0x80, 0x83, 0x03, 0x87, 0x03, 0x00,
0x0e, 0x00, 0x70, 0xe0, 0x03, 0xf0, 0x00, 0x9c, 0x03, 0x38, 0x80, 0x03, 0x87, 0x03, 0xe0, 0x00,
0x06, 0x00, 0x70, 0xf8, 0x01, 0xf0, 0x00, 0x0e, 0x07, 0x38, 0x80, 0x03, 0x87, 0x03, 0xe0, 0x00,
0x06, 0x00, 0x70, 0xf8, 0x00, 0xf0, 0x00, 0x0e, 0x07, 0x38, 0x80, 0x03, 0xce, 0x03, 0xe0, 0x00,
0x0e, 0x00, 0x70, 0x78, 0xc0, 0x01, 0x00, 0x06, 0x0e, 0x38, 0x80, 0x03, 0xce, 0x81, 0x03, 0x00,
0x0e, 0x00, 0x70, 0xf0, 0xc0, 0x01, 0x00, 0x07, 0x0e, 0x38, 0x80, 0x03, 0xfe, 0x81, 0x03, 0x00,
0x1e, 0xc0, 0x70, 0xe0, 0xc0, 0x01, 0x00, 0x03, 0x1e, 0x38, 0x80, 0x03, 0xfc, 0x80, 0x03, 0x00,
0x7c, 0xf0, 0x70, 0xe0, 0xc1, 0x01, 0x80, 0x03, 0x1c, 0x38, 0x80, 0x03, 0xfc, 0x80, 0x03, 0x00,
0xf8, 0xff, 0x70, 0xc0, 0xc3, 0xff, 0x8f, 0x03, 0x3c, 0x38, 0x80, 0x03, 0x78, 0x80, 0xff, 0x1f,
0xe0, 0x3f, 0x70, 0x80, 0xc3, 0xff, 0xcf, 0x01, 0x38, 0x38, 0x80, 0x03, 0x78, 0x80, 0xff, 0x1f,
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,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };


void setup() {
// Encoder pinnen instellen.
pinMode(pinEnc1A, INPUT);
pinMode(pinEnc1B, INPUT);
pinMode(pinEnc1BUT, INPUT);
pinMode(pinEnc2A, INPUT);
pinMode(pinEnc2B, INPUT);
// Chip Select (CS) pinnen instellen voor MCP41xxx potmeters.
pinMode(CS1, OUTPUT);
pinMode(CS2, OUTPUT);

digitalWrite(pinEnc1BUT, HIGH); // Zet encoder1 pin voor drukknop HOOG (pull-up weerstand).

// Interrupts instellen (pin hoog-laag verandering).
// Interrupt 0 = Pin 2 op de Arduino MEGA.
// Interrupt 1 = Pin 3 op de Arduino MEGA.
// Interrupt 4 = Pin 19 op de Arduino MEGA.
// Interrupt 5 = Pin 18 op de Arduino MEGA.
attachInterrupt(0, Enc1Draai, CHANGE); // Encoder 1.
attachInterrupt(1, Enc1Draai, CHANGE); // Encoder 1.
attachInterrupt(4, Enc2Draai, CHANGE); // Encoder 2.
attachInterrupt(5, Enc2Draai, CHANGE); // Encoder 2.

SPI.begin(); // Start de SPI interface.
irrecv.enableIRIn(); // Start de IR ontvanger.

u8g.setFont(u8g_font_5x8); // Lettertype instellen voor u8glib.

// Stel potmeter1 (VOLUME) in bij opstarten.
teller1 = EEPROM.read(EepromAdres1);
potmeter1 = map(teller1, 0, MaxResPot1, 0, BitResPot1); // Map de volume van 0-255 voor de potmeter2 (MCP41xxx).
digitalPotWrite(CS1, potmeter1);

// Stel potmeter2 (BASS) in bij opstarten (haal ook de waarde uit de EEPROM).
teller2 = EEPROM.read(EepromAdres2);
potmeter2 = map(teller2, 0, MaxResPot2, 0, BitResPot2); // Map de volume van 0-255 voor de potmeter2 (MCP41xxx).
digitalPotWrite(CS2, potmeter2); // Stel potmeter2 in (MCP41xxx).

// Flash screen
SchermFlash();
delay(4000);

ContrastWaarde(); //Haal de contrastwaarde op.
SchermUpdate(); // Start het display met de balken.
}


void loop() {
// IF loop wanneer er aan een encoder is gedraaid.
if ((teller1_oud != teller1) || (teller2_oud != teller2)) {
teller1_oud = teller1; teller2_oud = teller2; // Reset tellers.
SchermUpdate(); // Werk het scherm bij als er aan een encoder is gedraaid.
}

// Monitor of de knop van encoder1 is ingedrukt.
if (!(digitalRead(pinEnc1BUT))) { Enc1Knop(); } // De knop is doorverbonden met GND en de pin wordt LAAG.

// Monitor om de 10 seconden de licht intensie via LDR om zo het contrast van het display in te stellen.
if (millis()-TimerLDR >= 10000UL) { // 10000UL = 10 sec.
ContrastWaarde(); // Run Subroutine.
TimerLDR = millis(); // Reset de timer.
}

// Monitor op ontvangen IR signalen.
if (irrecv.decode(&results)) {
translateIR();
irrecv.resume();
}

}

// Scherm update.
void SchermUpdate() {
u8g.firstPage();
do {
u8g.setContrast(contrast);

snprintf(teller1Str, BufSize, "%d", potmeter1); // Converteer de "potmeter1" INT naar STR (tbv OLED scherm).
snprintf(teller2Str, BufSize, "%d", potmeter2); // Converteer de "potmeter2" INT naar STR (tbv OLED scherm).

u8g.drawStr(0, 10, "VOLUME ["); u8g.drawStr(40, 10, teller1Str); u8g.drawStr(55, 10, "]"); // Print VOLUME teller tekst.
u8g.drawStr(0, 42, "BASS ["); u8g.drawStr(40, 42, teller2Str); u8g.drawStr(55, 42, "]"); // Print BASS teller tekst.

u8g.setColorIndex(0); // zet kleur negatief (pixel uit).
u8g.drawBox(0, 14, 126, 16); // Teken een rechthoek, 0px vanaf links, 14px van boven, 126px breed, 16px hoog.
u8g.drawBox(0, 46, 126, 16); // Teken een rechthoek, 0px vanaf links, 46px van boven, 126px breed, 16px hoog.
u8g.setColorIndex(1); // zet de kleur positief (pixel aan).

// VOLUME bar.
int bar1 = map(teller1, 0, MaxResPot1, 1, 126); // Map de waarden voor grafische bar1.
u8g.drawFrame(0, 14, 126, 16); // Teken een frame, 0px vanaf links, 14px van boven, 126px breed, 16px hoog.
u8g.drawBox(0, 14, bar1, 16); // Teken een rechthoek, 0px vanaf links, 14px van boven, (int) breed, 16px hoog.

if (mute == 1) {
u8g.setScale2x2(); // maak het lettertype 2x groter.
u8g.drawStr(2, 14, "/// MUTE ///"); // print tekst.
u8g.undoScale(); // zet het lettertype weer terug.
};

// BASS bar.
int bar2 = map(teller2, 0, MaxResPot2, 1, 126); // Map de waarden voor grafische bar2.
u8g.drawFrame(0, 46, 126, 16); // Teken een frame, 0px vanaf links, 14px van boven, 126px breed, 16px hoog.
u8g.drawBox(0, 46, bar2, 16); // Teken een rechthoek, 0px vanaf links, 46px van boven, (int) breed, 16px hoog.

} while( u8g.nextPage() );
}

// Flashscreen.
void SchermFlash () {
u8g.firstPage();
do {
u8g.drawXBMP(1, 1, 128-1, 21, creative_logo); // info: hoogte -1
u8g.setScale2x2(); // maak het lettertype 2x groter.
u8g.drawStr(0, 25, " [ T7900 ] "); // print tekst.
u8g.undoScale(); // zet het lettertype weer terug.
u8g.drawStr(50, 60, versie);
} while( u8g.nextPage() );
}


void ContrastWaarde() {
LDRsensorWaarde = analogRead(LDRsensorPin);
// map functie heeft niet veel nut, veel displays hebben maar 2 standen
contrast = 255; // Maximale Contrast/Helderheid.
if (LDRsensorWaarde < LDRdonkerwaarde) { contrast = 0; } // Minimale Contrast/Helderheid.
SchermUpdate(); // werk het scherm bij met de nieuwe contrast waarde.
}


void translateIR() { // Car Mp3 remote.
switch(results.value) {
case 0xFFE01F: // VOL- -> VOLUME omlaag
teller1 = teller1 - (MaxResPot1 / 20); // geeft 20 stapjes tot minimaal volume.
Teller1inst(); // Instellen van potmeter1.
break;

case 0xFFA857: // VOL+ -> VOLUME omhoog
teller1 = teller1 + (MaxResPot1 / 20); // geeft 20 stapjes tot maximaal volume.
Teller1inst(); // Instellen van potmeter1.
break;

case 0xFF906F: // EQ -> MUTE
Muteinst(); // MUTE instelling.
potmeter1 = map(teller1, 0, MaxResPot1, 0, BitResPot1); // Map de volume van 0-255 voor de potmeter1.
digitalPotWrite(CS1, potmeter1); // Stel potmeter2 in.
break;

case 0xFF22DD: // PREV -> BASS omlaag.
teller2 = teller2 - (MaxResPot2 / 20); // geeft 20 stapjes tot minimaal bass.
Teller2inst(); // Instellen van potmeter1.
break;

case 0xFF02FD: // NEXT -> BASS omhoog.
teller2 = teller2 + (MaxResPot2 / 20); // geeft 20 stapjes tot maximaal bass.
Teller2inst(); // Instellen van potmeter2.
break;
}
}


// Instellen van potmeter1.
void Teller1inst() {
// Limiteer het bereik van teller1.
if (teller1 <= 0) { teller1 = 0; mute = 1; }
if (teller1 > 0) { mute = 0; }
if (teller1 > MaxResPot1) { teller1 = MaxResPot1; }

potmeter1 = map(teller1, 0, MaxResPot1, 0, BitResPot1); // Map de volume van 0-255 voor de potmeter1.
digitalPotWrite(CS1, potmeter1); // Stel potmeter1 in.

// Sla VOLUME waarde op in EEPROM geheugen.
EEPROM.write(EepromAdres1, teller1);
}


// Instellen van potmeter2.
void Teller2inst() {
// Limiteer het bereik van teller2.
if (teller2 < 0) { teller2 = 0; }
if (teller2 > MaxResPot2) { teller2 = MaxResPot2; }

potmeter2 = map(teller2, 0, MaxResPot2, 0, BitResPot2); // Map de volume van 0-255 voor de potmeter2.
digitalPotWrite(CS2, potmeter2); // Stel potmeter2 in.

// Sla BASS waarde op in EEPROM geheugen.
EEPROM.write(EepromAdres2, teller2);
}

void Muteinst() {
if (mute == 0) {
mute = 1; // Zet MUTE waarde op 1 (vlag).
teller1 = 0; // Zet volume waarde op 0.
} else {
mute = 0; // Zet MUTE waarde op 0 (vlag).
teller1 = EEPROM.read(EepromAdres1); // Haal de teller waarde op uit het geheugen.
}
}

// Wanneer een interrupt heeft plaatsgevonden, lees de input pinnen, bereken nieuwe status, pas de telling aan.
void Enc1Draai() {
enum { upMask = 0x66, downMask = 0x99 };
byte abNieuw = (digitalRead(pinEnc1A) << 1) | digitalRead(pinEnc1B);
byte criteria = abNieuw^abOud;
if (criteria==1 || criteria==2) {
if (upMask & (1 << (2*abOud + abNieuw/2)))
teller1--; // tel naar boven.
else teller1++; // tel naar beneden.
}

Teller1inst(); // Instellen van potmeter1.
abOud = abNieuw; // bewaar nieuwe status.
}

// Wanneer de knop op encoder1 is ingedrukt.
void Enc1Knop() {
Muteinst(); // MUTE instelling.
potmeter1 = map(teller1, 0, MaxResPot1, 0, BitResPot1); // Map de volume van 0-255 voor de potmeter1.
digitalPotWrite(CS1, potmeter1); // Stel potmeter2 in.

SchermUpdate(); // werk het scherm bij.
delay(200); // wacht even voordat er weer gekeken wordt om de knop in te lezen.
}

// Wanneer een interrupt heeft plaatsgevonden, lees de input pinnen, bereken nieuwe status, pas de telling aan.
void Enc2Draai() {
enum { upMask = 0x66, downMask = 0x99 };
byte abNieuw = (digitalRead(pinEnc2A) << 1) | digitalRead(pinEnc2B);
byte criteria = abNieuw^abOud;
if (criteria==1 || criteria==2) {
if (upMask & (1 << (2*abOud + abNieuw/2)))
teller2--; // tel naar boven.
else teller2++; // tel naar beneden.
}

Teller2inst(); // Instellen van potmeter2.
abOud = abNieuw; // bewaar nieuwe status.
}

// Stel de waarde in voor de MCP41xxx chip.
int digitalPotWrite(int chip, int value) {
digitalWrite(chip, LOW);
SPI.transfer(address);
SPI.transfer(value);
digitalWrite(chip, HIGH);
}

// Changelog:
//
// v1.1.0 (2016-07-19)
// Toegevoegd: Creative Splashscreen.
// Toegevoegd: Volume waarde nu ook opgelsagen in EEPROM.
// Toegevoegd: MUTE functie (knop encoder1).
// Bugfix: waarden bij opstarten worden nu weergegeven.
//
// v1.0.1 (2016-07-15)
// Code cleanup en kleine aanpassingen.
//
// v1.0.0 (2016-07-14)
// Initial release door S. Ebeltjes @ DomoticX.nl
Maatwerk in: Domotica - Automatisering - Elektronica - 3D printing - Software ontwikkeling
Website / Webshop / Knowledge Center / Facebook (like de pagina en blijf op de hoogte!)

Terug naar Afgeronde projecten

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 5 gasten