Perché il PWM non va a zero? (Ho preso l'oscilloscopio sbagliato! 😡)

Ciao a tutti

Mi sono reso conto con questo semplice programma che il PWM sul 9 non va a zero, ma rimane un impulso alto di 8us! Se escludo l'else if nella riga indicata, invece, arriva a zero! Perché?...

// pinPWM: 9
#include<avr/sleep.h>

uint8_t cont=0;
uint32_t t_cont;
uint32_t t_regolazione;
uint32_t p_clock=100000; // In us. 100 p_clock = 1 ciclo acceso/spento.
                       // 1.000=10Hz=0,1s; 10.000=1Hz=1s; 100.000=0,1Hz=10s.
                       // F[Hz] = 10.000/p_clock
bool fine=false;

void setup()
{
Serial.begin(115200);
}

void loop()
{
if(millis()-t_regolazione>=30000) // Ogni 30s.
  {
  t_regolazione=millis();
  if(p_clock<100000) p_clock*=1.2; // Rallenta del 20%.
  else fine=true;    
  }

if(micros()-t_cont>=p_clock)
  {
  cont+=1;
  t_cont=micros();
  if (cont>105) {cont=0;}
       if (cont<11) {analogWrite (9, cont);}
  else if (cont<51) {analogWrite (9, 6*(cont-9));}
  else if (cont<91) {analogWrite (9, 6*(91-cont)+8);}
  else if (cont<101){analogWrite (9, 100-cont);} // Se escludo questa, arriva a zero!
  else {analogWrite(9, 0);}
  }

if(fine==true && cont==0)
  {
  Sleep(); // Il ciclo è finito. Si può spegnere.
  }
}

Sul pin 6 fa la stessa cosa.

Perdonami, ma non sapendo esattamente cosa vuoi fare, quel listato mi lascia perplesso perché non è molto chiaro soprattutto per le indentazioni ma anche per le tanto graffe poco utili, e magari una descrizione di cosa vuoi ottenere sarebbe d'aiuto. Fai sempre per favore almeno Ctrl-T nell'IDE prima di postare.

Comuque a prima vista dato che pare che "cont" possa arrivare al massimo a 104 (perché una if e non fare modulo 105?), se commenti quell'"else if" ovviamente quando cont è maggiore di 91 andrà a fare l'ultima "else" che porta il PWM a zero. e lo mantiene per 13 cicli

Se non lo commenti, quando "cont" vale tra 91 e 100 il valore di quella if andrà tra 100-91 e 100-100 ossia da 9 fino a 0, per cui non mi torna che possa restarti un impulso (a meno che il tempo restante per qualche ragione non sia sufficiente per "vedere" il nuovo settaggio a zero). Ma non avendo chiaro cosa debba fare l'intero codice (in particolare il timer t_regolazione che "rallenta" il clock, non riesco ad immaginare per ora altro.

Sugli analogWrite? Le ho messe per disperazione, non riuscendo a capire perché non arrivasse a zero!

Il programma genera degli impulsi luminosi con accensione e spegnimento progressivi con una velocità che rallenta progressivamente (qui, per studiare il problema, ho usato un valore di p_clock molto alto, quindi è fortemente rallentato) e poi va in sleep,

// pinPWM: 9
#include<avr/sleep.h>

uint8_t cont=0;
uint32_t t_cont;
uint32_t t_regolazione;
uint32_t p_clock=100000; // In us. 100 p_clock = 1 ciclo acceso/spento.
                       // 1.000=10Hz=0,1s; 10.000=1Hz=1s; 100.000=0,1Hz=10s.
                       // F[Hz] = 10.000/p_clock
bool fine=false;

void setup()
{
Serial.begin(115200);
}

void loop()
{
if(millis()-t_regolazione>=30000) // Ogni 30s.
  {
  t_regolazione=millis();
  if(p_clock<100000) p_clock*=1.2; // Rallenta del 20%.
  else fine=true;    
  }

if(micros()-t_cont>=p_clock)
  {
  cont+=1;
  t_cont=micros();
  if (cont>105) cont=0; // cont va da 0 a 105.
  if      (cont< 11) analogWrite (9, cont);
  else if (cont< 51) analogWrite (9, 6*(cont-9));
  else if (cont< 91) analogWrite (9, 6*(91-cont)+8);
  else if (cont<101) analogWrite (9, 100-cont); // Se escludo questa, arriva a zero!
  else analogWrite(9, 0);
  }

if(fine==true && cont==0)
  {
  Sleep(); // Il ciclo è finito. Si può spegnere.
  }
}

void Sleep() // Va in Sleep, a basso consumo
  {
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Va in Sleep mode.
  sleep_enable();
  sleep_mode();
  }

Ah!...

The datasheet knows:

If the OCRnx is set equal to BOTTOM (0x0000) the output will be a narrow spike for each TOP+1 timer clock cycle.

Però analogWrite per il valore zero dovrebbe fare digitalWrite LOW, ma non funziona... Non funziona nemmeno se faccio io digitalWrite (6, LOW), nemmeno preceduto da pinMode (6, OUTPUT)!

Hm, ok ma non mi convince ancora... Se hai detto che commentando quella "else if" finale l'output resta a zero e non ricevi impulsi (in pratica "analogWrite(9, 0);" sembra funzionare), non mi sembra la stessa cosa. Di fatto quando "cont" va tra 91 e 100 dovrebbe arrivare a zero, esattamente come l'ultima "else", c'è qualcos'altro che mi manca di comprendere...
E poi se "p_clock" parte da 100.000, nella if() dei 30 secondi fai "if(p_clock<100000) p_clock*=1.2;" ma dato che p_clock vale già 100000 non moltiplicherà mai per 1.2, ma passerà per l'"else" e farà quindi finire il procedimento ("fine=true;"). Tra l'altro se anche moltiplicassi per 1.2, non diventerebbe mai minore di 100000 (varrebbe 120000, poi 144000 e così via).
Insomma, non capisco.

Lo so che magari non sono fatti miei, ma oltre a quelli ci sono anche altri particolari di cui non comprendo bene lo scopo, e mi incuriosisci...:wink:
Ad esempio tu qui mi sembra che faccia "count += 1;" ("++count" magari?) ossia conti quanti intervalli da 100.000 microsecondi sono passati, che corrispondono a 100 millisecondi: perché non usare millis()? E poi se "count" arriva a 104 ogni ciclo sono 10.4 secondi (circa), che poi teoricamente ogni 30 secondi "rallenti" ("allunghi") aggiungendo un 20% ad ogni ciclo (quindi 10.4 poi 12.48, poi 14.97...). Tutto questo ha uno scopo preciso che mi sfugge...:wink:

Si, ma parlo anche del resto dell'indentazione.
Per farti un esempio, l'ho riformattto con l'IDE oltre a qualche mio piccolo ritocco, in questo modo a me pare che si legga molto più facilmente:

// pinPWM: 9
#include <avr/sleep.h>

uint8_t cont = 0;
uint32_t t_cont;
uint32_t t_regolazione;
uint32_t p_clock = 100000;  // In us. 100 p_clock = 1 ciclo acceso/spento.
                            // 1.000=10Hz=0,1s; 10.000=1Hz=1s; 100.000=0,1Hz=10s.
                            // F[Hz] = 10.000/p_clock
bool fine = false;

void setup() {
  Serial.begin(115200);
}

void loop() {
  if (millis() - t_regolazione >= 30000)  { // Ogni 30s.
    t_regolazione = millis();
    if (p_clock < 100000) 
      p_clock *= 1.2;  // Rallenta del 20%.
    else 
      fine = true;
  }

  if (micros() - t_cont >= p_clock) {
    cont += 1;
    t_cont = micros();
    if (cont > 105) cont = 0;  // cont va da 0 a 105.
    if (cont < 11) analogWrite(9, cont);
    else if (cont < 51) analogWrite(9, 6 * (cont - 9));
    else if (cont < 91) analogWrite(9, 6 * (91 - cont) + 8);
    else if (cont < 101) analogWrite(9, 100 - cont); 
    else analogWrite(9, 0);
  }

  if (fine == true && cont == 0) {
    Sleep();  // Il ciclo è finito. Si può spegnere.
  }
}

void Sleep()  // Va in Sleep, a basso consumo
{
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // Va in Sleep mode.
  sleep_enable();
  sleep_mode();
}

Come ho scritto sopra, 100000 è un valore molto alto che ho messo per poter vedere bene sull'oscilloscopio che cosa accade. Normalmente parte da alcune migliaia, quindi per arrivare al valore finale impiega alcuni minuti.

Il funzionamento è questo:

Ogni p_clock incremento cont: se p_clock è 10000, cont viene incrementato ogni 10000us, cioè ogni 10ms, quindi 100 volte al secondo: in un secondo arriva a 100 (105 lo avevo messo per provare a prolungare il tempo di spegnimento) e poi ricomincia da zero. Qundi cont conta continuamente da 0 a 100 (o 105) e ricomincia.

Gli if / else if servono solo per realizzare una variazione di luminosità secondo una tabella che ho scritto in Excel.

Ogni 30 secondi, il periodo p_clock viene incrementato del 20%, rallentando l'accensione e lo spegnimento del LED.

Quando p_clock raggiunge 100000, appena cont torna a 0 (il LED si è spento) parte la funzione che mette in sleep.

E' uno degli innumerevoli stili di formattazione che possono essere impostati per il CTRL+T nel formatter.conf in (Arduino)\lib:

Mi sa che sto solo usando l'oscilloscopio sbagliato!!!
:face_with_symbols_on_mouth:

Vuoi dire che non indentare le righe che fanno parte di un blocco (funzione, if, eccetera) lasciandole tutte a sinistra in prima colonna è uno "stile di formattazione"?


Non voglio fare il "perfezionista", ma sto stile a me fa cag...:face_with_raised_eyebrow: :face_with_tears_of_joy:
PS: tra l'altro formatter.conf non esiste più nell'IDE 2, tu stai usando ancora l'1.8 quindi? :thinking: :smiling_face_with_sunglasses:

:open_mouth: in che senso?

Sì, uso l'1.8.
Che questo TDS1001B quando il segnale diventa piatto mantiene la traccia |¯|___ visualizzata per un secondo!!! Poi provo con il Rigol.

Sì. Guarda il sito Artistic Style.
In rete si trovano programmi con indentazioni diverse, ma l'importante è che ci sia una logica. Se, invece, le indentazioni e le graffe sono messe a caso, diventa veramente incomprensibile!

Non sono abituato a questa indentazione, ancora peggio lo stile condensato, quindi può essere che prendo lucciole per lanterne.

Visto che c'è Artistic e style vuole dire che l'uno vale l'altro è si tratta di una scelta di
stile personale e ognuno fa la sua.
Invece non c'è nulla di artistico e non è uno stile e c'è un solo modo per indentare, cioè quello più comprensibile all'essere umano, che non è di certo quello che usi.

Ciao.

Puoi fare una "controprova" con un generatore di segnale.
Comunque bello schifo il TDS...

C.V.D., il Rigol mostra il PWM che arriva fino a zero. :slight_smile:
Il TDS1001 è del 2005:

Avevo quello a portata di mano...

Vabbè, ma Rigol che batte Tektronix mi fa un po' specie... :roll_eyes:

Ciao, Ale.

Dai, adesso vedo con il Tektronix 468! :slight_smile:

Textronix si è rivalutata! Anche il 468 mostra il PWM fino a 0! :grin:
Vorrei vedere... E' analogico! :rolling_on_the_floor_laughing:

1 Like

Certamente. Ma magari quando posti qui credo che sia meglio se prima gli dai una passata con un IDE non "patchato" (puoi installare la 2.x anche solo per questo, ma poi magari ti viene voglia di usarla :smiling_face_with_sunglasses:) così vediamo le indentazioni "normali" e non quelle in stile "Salvador Dalì" che hai tu... :wink:

Comunque l'importante è se nel frattempo hai risolto (per i prossimi se possibile evita lo stile Dalì :smiling_face_with_halo:)

Sappi che ti invidio! Soprattutto la doppia base tempi.

:grin:
Per il 468 o per il Rigol?...


Questo però scommetto non ce l'hai!

Ciao, Ale.

1 Like

Il 468.

@speedyant Lo acquistai da carlo.rlo su ebay per 279€ nel dicembre 2020. Potresti chiedergli se te ne trova uno...