Impostare luminosità display MAX72xx tramite pot

Buongiorno.
Ho 4 max72xx,che mi visualizzano lo spettro sonoro (FFT).
Il fatto è che vorrei impostare la luminosità dei display tramite un potenziometro.

Il valore che deve cambiare con il pot è questo:

mx.control(MD_MAX72XX::INTENSITY, 20)

Mentre questo è il codice del programma:

#include <arduinoFFT.h>
#include <MD_MAX72xx.h>
#include <SPI.h>

#define SAMPLES 64            //Must be a power of 2
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW   // Set display type  so that  MD_MAX72xx library treets it properly
#define MAX_DEVICES  4   // Total number display modules
#define CLK_PIN   13  // Clock pin to communicate with display
#define DATA_PIN  11  // Data pin to communicate with display
#define CS_PIN    10  // Control pin to communicate with display
#define  xres 32      // Total number of  columns in the display, must be <= SAMPLES/2
#define  yres 8       // Total number of  rows in the display


int MY_ARRAY[] = {128, 128, 192, 224, 240, 248, 252, 254, 255}; // default = standard pattern
int MY_MODE_1[] = {0, 128, 192, 224, 240, 248, 252, 254, 255}; // standard pattern
int MY_MODE_2[] = {0, 128, 64, 32, 16, 8, 4, 2, 1}; // only peak pattern
int MY_MODE_3[] = {0, 128, 192, 160, 144, 136, 132, 130, 129}; // only peak +  bottom point
int MY_MODE_4[] = {128, 128, 192, 224, 240, 248, 252, 254, 255}; // one gap in the top , 3rd light onwards 0, 128, 192, 160, 208, 232, 244, 250, 253
int MY_MODE_5[] = {0, 1, 3, 7, 15, 31, 63, 127, 255}; // standard pattern, mirrored vertically


double vReal[SAMPLES];
double vImag[SAMPLES];
char data_avgs[xres];

int yvalue;
int displaycolumn , displayvalue;
int peaks[xres];
const int buttonPin = 5;    // the number of the pushbutton pin
int state = HIGH;             // the current reading from the input pin
int previousState = LOW;   // the previous reading from the input pin
int displaymode = 1;
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers


MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);   // display object
arduinoFFT FFT = arduinoFFT();                                    // FFT object



void setup() {

  ADCSRA = 0b11100101;      // set ADC to free running mode and set pre-scalar to 32 (0xe5)
  ADMUX = 0b00000000;       // use pin A0 and external voltage reference
  pinMode(buttonPin, INPUT);
  mx.begin();           // initialize display
  mx.control(MD_MAX72XX::INTENSITY, 20); //luminosità display
  delay(500);            // wait to get reference voltage stabilized
}

void loop() {
  // ++ Sampling
  for (int i = 0; i < SAMPLES; i++)
  {
    while (!(ADCSRA & 0x10));       // wait for ADC to complete current conversion ie ADIF bit set
    ADCSRA = 0b11110101 ;               // clear ADIF bit so that ADC can do next operation (0xf5)
    int value = ADC - 512 ;                 // Read from ADC and subtract DC offset caused value
    vReal[i] = value / 6;                   // Copy to bins after compressing
    vImag[i] = 0;
  }
  // -- Sampling


  // ++ FFT
  FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_NUTTALL, FFT_FORWARD);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
  // -- FFT


  // ++ re-arrange FFT result to match with no. of columns on display ( xres )
  int step = (SAMPLES / 2) / xres;
  int c = 0;
  for (int i = 0; i < (SAMPLES / 2); i += step)
  {
    data_avgs[c] = 0;
    for (int k = 0 ; k < step ; k++) {
      data_avgs[c] = data_avgs[c] + vReal[i + k];
    }
    data_avgs[c] = data_avgs[c] / step;
    c++;
  }
  // -- re-arrange FFT result to match with no. of columns on display ( xres )


  // ++ send to display according measured value
  for (int i = 0; i < xres; i++)
  {
    data_avgs[i] = constrain(data_avgs[i], 0, 80);          // set max & min values for buckets
    data_avgs[i] = map(data_avgs[i], 0, 80, 0, yres);        // remap averaged values to yres
    yvalue = data_avgs[i];

    peaks[i] = peaks[i] - 1;  // decay by one light
    if (yvalue > peaks[i])
      peaks[i] = yvalue ;
    yvalue = peaks[i];
    displayvalue = MY_ARRAY[yvalue];
    displaycolumn = 31 - i;
    mx.setColumn(displaycolumn, displayvalue);              // for left to right
  }
  // -- send to display according measured value

  displayModeChange ();         // check if button pressed to change display mode
}

void displayModeChange() {
  int reading = digitalRead(buttonPin);
  if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) // works only when pressed

  {

    switch (displaymode) {
      case 1:    //       move from mode 1 to 2
        displaymode = 2;
        for (int i = 0 ; i <= 8 ; i++ ) {
          MY_ARRAY[i] = MY_MODE_2[i];
        }
        break;
      case 2:    //       move from mode 2 to 3
        displaymode = 3;
        for (int i = 0 ; i <= 8 ; i++ ) {
          MY_ARRAY[i] = MY_MODE_3[i];
        }
        break;
      case 3:    //     move from mode 3 to 4
        displaymode = 4;
        for (int i = 0 ; i <= 8 ; i++ ) {
          MY_ARRAY[i] = MY_MODE_4[i];
        }
        break;
      case 4:    //     move from mode 4 to 5
        displaymode = 5;
        for (int i = 0 ; i <= 8 ; i++ ) {
          MY_ARRAY[i] = MY_MODE_5[i];
        }
        break;
      case 5:    //      move from mode 5 to 1
        displaymode = 1;
        for (int i = 0 ; i <= 8 ; i++ ) {
          MY_ARRAY[i] = MY_MODE_1[i];
        }
        break;
    }

    lastDebounceTime = millis();
  }
  previousState = reading;
}

Ciao.
Io farei così

  • collego il pot ad un pin analogico
  • leggo il valore del pot
  • faccio una map per portare il valore entro il range accettato dalla funzione
  • chiamo la funzione
    mx.control(MD_MAX72XX::INTENSITY, val-pot)

Ciao!
Grazie della risposta.
Ecco,il mio problema è fare il map per il valore min max

sai che range di valori accetta la libreria?

Io ho provato con minimo 0.1 e max 20,e li ha accettati

zonalimitatore:
Io ho provato con minimo 0.1 e max 20,e li ha accettati

SE, come suppongo, tu stia usando QUESTA libreria, beh guarda che basta studiare la documentazione (... e quella è una delle poche librerie ben documentate) per vedere QUALI valori sono ammessi e ... quelli che hai dato tu NON vanno bene ...

Il metodo control() usato come lo hai usato tu, accetta due parametri, ed il secondo è di tipo 'int'. Nel tuo caso il controllo che vai a modificare è INTENSITY (primo parametro) ed il secondo è il valore dell'intensità che va da 0 a MAX_INTENSITY

Il valore di MAX_INTENSITY lo si trova invece QUI e vale 0xf ovvero 15, quindi ... puoi impostare 16 livelli di luminosità, da 0 a 15.

Quindi, come vedi, c'è tutto, basta cercare e studiare bene la documentazione ... ::slight_smile:

Guglielmo

gpb01:
SE, come suppongo, tu stia usando QUESTA libreria, beh guarda che basta studiare la documentazione (... e quella è una delle poche librerie ben documentate) per vedere QUALI valori sono ammessi e ... quelli che hai dato tu NON vanno bene ...

Il metodo control() usato come lo hai usato tu, accetta due parametri, ed il secondo è di tipo 'int'. Nel tuo caso il controllo che vai a modificare è INTENSITY (primo parametro) ed il secondo è il valore dell'intensità che va da 0 a MAX_INTENSITY

Il valore di MAX_INTENSITY lo si trova invece QUI e vale 0xf ovvero 15, quindi ... puoi impostare 16 livelli di luminosità, da 0 a 15.

Quindi, come vedi, c'è tutto, basta cercare e studiare bene la documentazione ... ::slight_smile:

Guglielmo

Grazie mille.Si è proprio quella,ma io non sono riuscito a trovare quel parametro esadecimale (forse perchè cercavo un numero)!!!
Comunque non ho capito,in che senso dici che è sbagliato?Per il massimo di 20?

zonalimitatore:
Comunque non ho capito,in che senso dici che è sbagliato?Per il massimo di 20?

... se hai visto la documentazione quel parametro è :

  1. un INTERO (e non un numero decimale)

  2. può andare da 0 a MAX_INTENSITY ovvero da 0 a 15

... vedi un po' tu ... ::slight_smile:

Guglielmo

Esatto,dalla documentazione è come dici tu,ma nella pratica, se io imposto 0.1 è proprio il minimo.
Se imposto 0.2 aumenta leggermente la luminosità. Quindi nella pratica accetta anche i decimali

zonalimitatore:
Esatto,dalla documentazione è come dici tu,ma nella pratica, se io imposto 0.1 è proprio il minimo.
Se imposto 0.2 aumenta leggermente la luminosità. Quindi nella pratica accetta anche i decimali

Sicuro che non stai usando un'altra libreria? Perché se un parametro è dichiarato 'int' NON gli puoi passare un 'float' senza che il compilatore ti indichi qualche cosa ...
... NON hai visto warning o segnalazioni in fase di compilazione ?

Guglielmo

gpb01:
Sicuro che non stai usando un'altra libreria? Perché se un parametro è dichiarato 'int' NON gli puoi passare un 'float' senza che il compilatore ti indichi qualche cosa ...
... NON hai visto warning o segnalazioni in fase di compilazione ?

Guglielmo

No,nessun warn....adesso controllo bene che libreria sia

E' proprio quella da te indicata,versione 3.3.0

zonalimitatore:
No,nessun warn ...

... vero, vengono dati solo se si passa in compilazione il parametro -Wconversion ... ::slight_smile:

In ogni caso, ho riguardato i sorgenti e ovunque quel parametro è dichiarato 'int' quindi, per quello che vedo, un float viene trocato ad un intero ed il suo valore intero viene assegnato alla funzione.

Il metodo control() che richiami tu, a sua volta chiama il metodo controlHardware() ... che vuole un intero:

void MD_MAX72XX::controlHardware(uint8_t dev, controlRequest_t mode, int value)
// control command is for the devices, translate internal request to device bytes
// into the transmission buffer
{
  uint8_t opcode = OP_NOOP;
  uint8_t param = 0;

  // work out data to write
  switch (mode)
  {
    case SHUTDOWN:
      opcode = OP_SHUTDOWN;
      param = (value == OFF ? 1 : 0);
      break;

    case SCANLIMIT:
      opcode = OP_SCANLIMIT;
      param = (value > MAX_SCANLIMIT ? MAX_SCANLIMIT : value);
      break;

    case INTENSITY:
      opcode = OP_INTENSITY;
      param = (value > MAX_INTENSITY ? MAX_INTENSITY : value);
      break;

    case DECODE:
      opcode = OP_DECODEMODE;
      param = (value == OFF ? 0 : 0xff);
      break;

    case TEST:
      opcode = OP_DISPLAYTEST;
      param = (value == OFF ? 0 : 1);
      break;

    default:
      return;
  }

... questo è quanto, poi ... fai come credi, io ti dico che devi passare un valore intero compreso tra 0 e MAX_INTENSITY.

Guglielmo

Già....ok vedo se riesco a farlo controllare.Grazie

>zonalimitatore: Quando si quota un post, NON è necessario riportarlo (inutilmente) tutto; bastano poche righe per far capire di cosa si parla ed a cosa ci si riferisce, inoltre, se si risponde al post immediatamente precedente, normalmente NON è necessario alcun "quote" dato che è sottinteso. :slight_smile:

Gli utenti da device "mobile" (piccoli schermi) ringrazieranno per la cortesia :wink:

Guglielmo

P.S.: Ho eliminato io il "quote" dal tuo post qui sopra :wink:

Ok,no problem,grazie.

Ho provato,ma sicuramente sbaglio qualcosa:

  int valpot = analogRead(pinPotenziometro);
 mx.control(MD_MAX72XX::INTENSITY, valpot);

Quando leggi un pin analogico ottieni un valre che va da 0 a 1023 ... come pensi di poterlo dare direttamente in pasto ad un qualche cosa che accetta da 0 a 15 ? ? ? :o

Devi usare la funzione map() per rimappare i valori che vanno da 0 a 1023 in valori che vanno da 0 a 15.

Guglielmo

...o, più semplicemente, dividere per 64:

   da:           avrai:
  0 a  63          0
 64 a 127          1
128 a 191          2
192 a 255          3
256 a 319          4
320 a 383          5
384 a 447          6
448 a 511          7
512 a 575          8
576 a 639          9
640 a 703         10
704 a 767         11
768 a 831         12
832 a 895         13
896 a 959         14
960 a 1023        15

Quindi metti nel loop:

mx.control(MD_MAX72XX::INTENSITY, analogRead(pinPotenziometro)/64);

o, meglio:

unsigned long t_potRead;

loop()
{
if(millis()-t_potRead>200)
  {
  t_potRead=millis();
  mx.control(MD_MAX72XX::INTENSITY, analogRead(pinPotenziometro)/64);
  }
...
}

In questo modo la lettura e l'impostazione vengono eseguite solo 5 volte al secondo. Ovviamente ciò ha un senso solo se, come sarebbe auspicabile, il loop gira alla velocità della luce o quasi... :slight_smile:

ecco,io avevo provato mx.control(MD_MAX72XX::INTENSITY, analogRead(pinPotenziometro)/64); che avrebbe dovuto restituirmi circa 15 valori....Ma non funzionava

Poi provo come dice Datman

SU CHE SCHEDA STAI LAVORANDO?...
Te lo chiedo perché per la prima volta ho usato una ESP82666 D1 mini e ho scoperto che c'è un po' di confusione sui pin... :frowning:

Nano,niente esp

Caricando questo codice,il display si illumina "standard" (la metà),ma non ho niente di funzionante,nel il controllo della luminosità,il pulsante cambia modo display,e la visualizzazione dello spettro.
Sicuramente avrò sbagliato qualcosa io

#include <arduinoFFT.h>
#include <MD_MAX72xx.h>
#include <SPI.h>

#define SAMPLES 64            //Must be a power of 2
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW   // Set display type  so that  MD_MAX72xx library treets it properly
#define MAX_DEVICES  4   // Total number display modules
#define CLK_PIN   13  // Clock pin to communicate with display
#define DATA_PIN  11  // Data pin to communicate with display
#define CS_PIN    10  // Control pin to communicate with display
#define  xres 32      // Total number of  columns in the display, must be <= SAMPLES/2
#define  yres 8       // Total number of  rows in the display

int pinPotenziometro  = A4;


int MY_ARRAY[] = {128, 128, 192, 224, 240, 248, 252, 254, 255}; // default = standard pattern
int MY_MODE_1[] = {0, 128, 192, 224, 240, 248, 252, 254, 255}; // standard pattern
int MY_MODE_2[] = {0, 128, 64, 32, 16, 8, 4, 2, 1}; // only peak pattern
int MY_MODE_3[] = {0, 128, 192, 160, 144, 136, 132, 130, 129}; // only peak +  bottom point
int MY_MODE_4[] = {128, 128, 192, 224, 240, 248, 252, 254, 255}; // one gap in the top , 3rd light onwards 0, 128, 192, 160, 208, 232, 244, 250, 253
int MY_MODE_5[] = {0, 1, 3, 7, 15, 31, 63, 127, 255}; // standard pattern, mirrored vertically


double vReal[SAMPLES];
double vImag[SAMPLES];
char data_avgs[xres];

int yvalue;
int displaycolumn , displayvalue;
int peaks[xres];
const int buttonPin = 5;    // the number of the pushbutton pin
int state = HIGH;             // the current reading from the input pin
int previousState = LOW;   // the previous reading from the input pin
int displaymode = 1;
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers
unsigned long t_potRead;

MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);   // display object
arduinoFFT FFT = arduinoFFT();                                    // FFT object
int valpot = analogRead(pinPotenziometro);


void setup() {

  ADCSRA = 0b11100101;      // set ADC to free running mode and set pre-scalar to 32 (0xe5)
  ADMUX = 0b00000000;       // use pin A0 and external voltage reference
  pinMode(buttonPin, INPUT);
  //pinMode (pinPotenziometro, INPUT);


  mx.begin();           // init  display
  //mx.control(MD_MAX72XX::INTENSITY, 1); //luminosità display
  delay(500);            // wait ref stab
}

void loop()

{
  // ++ Sampling
  for (int i = 0; i < SAMPLES; i++)
  {
    while (!(ADCSRA & 0x10));       // wait for ADC to complete current conversion ie ADIF bit set
    ADCSRA = 0b11110101 ;               // clear ADIF bit so that ADC can do next operation (0xf5)
    int value = ADC - 512 ;                 // Read from ADC and subtract DC offset caused value
    vReal[i] = value / 6;                   // Copy to bins after compressing
    vImag[i] = 0;
  }
  // -- Sampling


  // ++ FFT
  FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_NUTTALL, FFT_FORWARD);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
  // -- FFT


  // ++ re-arrange FFT result to match with no. of columns on display ( xres )
  int step = (SAMPLES / 2) / xres;
  int c = 0;
  for (int i = 0; i < (SAMPLES / 2); i += step)
  {
    data_avgs[c] = 0;
    for (int k = 0 ; k < step ; k++) {
      data_avgs[c] = data_avgs[c] + vReal[i + k];
    }
    data_avgs[c] = data_avgs[c] / step;
    c++;
  }
  // -- re-arrange FFT result to match with no. of columns on display ( xres )


  // ++ send to display according measured value
  for (int i = 0; i < xres; i++)
  {
    data_avgs[i] = constrain(data_avgs[i], 0, 80);          // set max & min values for buckets
    data_avgs[i] = map(data_avgs[i], 0, 80, 0, yres);        // remap averaged values to yres
    yvalue = data_avgs[i];

    peaks[i] = peaks[i] - 1;  // decay by one light
    if (yvalue > peaks[i])
      peaks[i] = yvalue ;
    yvalue = peaks[i];
    displayvalue = MY_ARRAY[yvalue];
    displaycolumn = 31 - i;
    mx.setColumn(displaycolumn, displayvalue);              // for left to right
  }


  {
    if (millis() - t_potRead > 200)
    {
      t_potRead = millis();
      mx.control(MD_MAX72XX::INTENSITY, analogRead(pinPotenziometro) / 64);
    }


    
    // -- send to display according measured value

    displayModeChange ();         // check if button pressed to change display mode


  }
}
void displayModeChange() {
  int reading = digitalRead(buttonPin);
  if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) // works only when pressed

  {

    switch (displaymode) {
      case 1:    //       move from mode 1 to 2
        displaymode = 2;
        for (int i = 0 ; i <= 8 ; i++ ) {
          MY_ARRAY[i] = MY_MODE_2[i];
        }
        break;
      case 2:    //       move from mode 2 to 3
        displaymode = 3;
        for (int i = 0 ; i <= 8 ; i++ ) {
          MY_ARRAY[i] = MY_MODE_3[i];
        }
        break;
      case 3:    //     move from mode 3 to 4
        displaymode = 4;
        for (int i = 0 ; i <= 8 ; i++ ) {
          MY_ARRAY[i] = MY_MODE_4[i];
        }
        break;
      case 4:    //     move from mode 4 to 5
        displaymode = 5;
        for (int i = 0 ; i <= 8 ; i++ ) {
          MY_ARRAY[i] = MY_MODE_5[i];
        }
        break;
      case 5:    //      move from mode 5 to 1
        displaymode = 1;
        for (int i = 0 ; i <= 8 ; i++ ) {
          MY_ARRAY[i] = MY_MODE_1[i];
        }
        break;
    }

    lastDebounceTime = millis();
  }
  previousState = reading;
}