Go Down

Topic: Comandare ventola PWM con LIN BUS (Read 2866 times) previous topic - next topic

PM68

Jun 05, 2018, 01:54 pm Last Edit: Jun 08, 2018, 02:26 pm by PM68
Ciao a tutti,
sono un novizio di Arduino e non ho nessuna base di informatica. Ho bisogno di un grosso aiuto.
Devo comandare una ventola PWM leggendo i comandi da una rete LIN Bus.
Ho trovato qui sul forum un codice che legge la LIN BUS, ho identificato i numeri che corrispondono alla velocità della ventola e il codice che fa girare le ventole a 3 velocità.

Dovrei mettere assieme le due cose:

-quando legge sulla LIN il n° 76 comandare la ventola al 75% PWM
-quando legge sulla LIN il n° 75 comandare la ventola al 50% PWM
-quando legge sulla LIN il n° 74 comandare la ventola al 25% PWM
-quando legge sulla LIN il n° 7F la ventola è ferma

Il codice originale che utilizzo per leggere la LIN con un Arduino DUE l'ho preso dalla discussione "LIN Bus communication Uno to Due".
Il codice per comandare la ventola l'ho preso dall'esempio della libreria "pwm01.h".
Di seguito il codice ibrido che ho messo assieme con scarsi risultati. Come ho anticipato non ho basi di informatica.

Code: [Select]

//  CODICE PER RILEVAZIONE EVENTI SU LINBUS e COMANDO VENTOLE
//Due project, Receive

#include <SerialSniffer.h>
#include <lin_stack.h>
#include <pwm01.h>

const int PIN_TXE = 18;
const int PIN_CS = 2;
word VentPin = 3;

uint8_t rxByte[4];

void setup() {

  pinMode(PIN_CS, OUTPUT);
  pinMode(VentPin, OUTPUT);
  digitalWrite(PIN_CS, HIGH);
  pwm25kHzBegin();

  Serial1.begin(9600, SERIAL_8E1); //LIN Serial Rx, 8E1 is BMW iBus standard
  //Serial.begin(9600); //debug serial
  //Serial.println("Due debug Comms");

  delay(100);
}

void loop() {
  while (Serial1.available()) {
    delay(5);
    byte actuallyRead = Serial1.readBytes(rxByte, 8); //Read UP TO 8 bytes
    if (actuallyRead > 0)
    {
      for (uint8_t i = 0; i < actuallyRead; i++)
      {
        Serial.println(rxByte[i], HEX);
      }
    }
    if (rxByte == 74)
    { pwmDuty(59); // 75% (range = 0-79 = 1.25-100%)
      delay (5000);
    }
    if (rxByte == 75)
    { pwmDuty(39); // 50% (range = 0-79 = 1.25-100%)
    delay (5000);
    }
    if (rxByte == 76)
    { pwmDuty(19); // 25% (range = 0-79 = 1.25-100%)
    delay (5000);
    }
   
  }

  void loop() {
    pwmDuty(19); // 25% (range = 0-79 = 1.25-100%)
    delay(5000);
    pwmDuty(39); // 50% (range = 0-79 = 1.25-100%)
    delay (5000);
    pwmDuty(59); // 75% (range = 0-79 = 1.25-100%)
    delay (5000);
  }

  void pwm25kHzBegin() {
    TCCR2A = 0;                               // TC2 Control Register A
    TCCR2B = 0;                               // TC2 Control Register B
    TIMSK2 = 0;                               // TC2 Interrupt Mask Register
    TIFR2 = 0;                                // TC2 Interrupt Flag Register
    TCCR2A |= (1 << COM2B1) | (1 << WGM21) | (1 << WGM20);  // OC2B cleared/set on match when up/down counting, fast PWM
    TCCR2B |= (1 << WGM22) | (1 << CS21);     // prescaler 8
    OCR2A = 79;                               // TOP overflow value (Hz)
    OCR2B = 0;
  }

  void pwmDuty(byte ocrb) {
    OCR2B = ocrb;                             // PWM Width (duty)
  }

gpb01

... beh ... usa una semplice struttura switch/case e assegni il valore del PWM in funzione del valore LIN ricevuto :)

Guglielmo
Search is Your friend ... or I am Your enemy !

PM68

Grazie Guglielmo!
Sembra perfetta per quello che devo fare.
Questa sera provo.

Mauro

gpb01

#3
Jun 06, 2018, 02:28 pm Last Edit: Jun 06, 2018, 02:28 pm by gpb01
>PM68:   ti ricordo che in conformità al regolamento, punto 7, devi editare il tuo post (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More -> Modify che si trova in basso a destra del tuo post) e racchiudere il codice all'interno dei tag CODE (... sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra).

In pratica, tutto il tuo codice dovrà trovarsi racchiuso tra due tag: [code] _il _tuo_ codice_ [/code] così da non venire interpretato e non dare adito alla formazione di caratteri indesiderati o cattiva formattazione del testo. Grazie.

Guglielmo
Search is Your friend ... or I am Your enemy !

PM68

#4
Jun 07, 2018, 11:56 pm Last Edit: Jun 08, 2018, 12:05 am by PM68
Grazie Guglielmo per le istruzioni.
Avevo cercato di inserire il codice correttamente ma non ci sono riuscito.
Ora ci riprovo.

Ho modificato il codice inserendo la struttura switch case come mi hai suggerito però mi da questo errore che mi sembra avere capito dipende dalla costante inByte che ho provato a mettere "char" invece di "int" ma non gli piace:
 
Code: [Select]

jump to case label [-fpermissive]
 


 Il mio codice è questo:
 
Code: [Select]

//  Arduino DUE
//  CODICE PER RILEVAZIONE EVENTI SU LINBUS  e COMANDO VENTOLE

#include <SerialSniffer.h>
#include <lin_stack.h>
#include <DuePWM.h>

#define PWM_FREQ1  20000
#define PWM_FREQ2  20000

DuePWM pwm( PWM_FREQ1, PWM_FREQ2 );
#define PIN_TXE 1
#define PIN_CS 2
#define FAULT_PIN 9
uint8_t rxByte[4];

void setup() {
  pinMode(PIN_CS, OUTPUT);
  pinMode(FAULT_PIN, OUTPUT);
  digitalWrite(PIN_CS, HIGH);
  digitalWrite(FAULT_PIN, HIGH);
  Serial1.begin(9600, SERIAL_8E1); //LIN Serial Rx, 8E1 is BMW iBus standard
  pwm.setFreq1( PWM_FREQ1 );
  pwm.setFreq2( PWM_FREQ2 );
  pwm.pinFreq1( 6 );  // Pin 6 freq set to "pwm_freq1" on clock A
  pwm.pinFreq2( 7 );  // Pin 7 freq set to "pwm_freq2" on clock B
}

void loop() {
  if (Serial1.available() > 0) {
    char inByte = Serial1.read();

    switch (inByte) {
      case '74': //quando legge "74" sulla serial1
        uint32_t pwm_duty = 190; // 75% duty cycle
        pwm.pinDuty( 6, pwm_duty );  // 75% duty cycle on Pin 12
        break;
      case '75': //quando legge "75" sulla serial1
        uint32_t pwm_duty = 127; // 50% duty cycle
        pwm.pinDuty( 6, pwm_duty );  // 50% duty cycle on Pin 12
        break;
      case '76': //quando legge "76" sulla serial1
        uint32_t pwm_duty = 63; // 25% duty cycle
        pwm.pinDuty( 6, pwm_duty );  // 25% duty cycle on Pin 12
        break;
      case '7F': //quando legge "7F" sulla serial1
        pwm.stop(6);
        break;

    }
  }
}

PM68

Ho risolto, mancavano alcune parentesi graffe.

gpb01

#6
Jun 08, 2018, 02:40 pm Last Edit: Jun 08, 2018, 02:41 pm by gpb01
Mmm ... sicuro di quei "case" ? ? ?

inByte conterrà, dopo la lettura dalla seriale 1 byte (1 carattere) mentre tu stai facendo dei "case" con un insieme di due caratteri (es. '7F', ovvero un numero a 16 bit).

Ho invece idea che tu devi confrontare, visto i numeri che indichi, con valori esadecimali, che si rappresentano con lo 0x davanti ovvero 0x74, 0x75, 0x76 e 0x7F che occupano 1 byte (1 carattere) come tu ricevi.

Guglielmo
Search is Your friend ... or I am Your enemy !

PM68

#7
Jun 09, 2018, 12:39 am Last Edit: Jun 09, 2018, 12:40 am by PM68
Grazie di tutti i consigli Guglielmo, ho corretto.
Ora volevo provarlo dandogli i comandi da monitor seriale, ho cambiato da "Serial1" a "Serial" ,  non mi da nessun errore di compilazione, però la ventola parte alla massima velocità e qualsiasi cosa scrivo sul monitor seriale non cambia niente. Ho provato a scrivere sia 74 che 0x74 o 7F o 0x7F inoltre essendo di default "pwm.stop" mi aspetto che se non do comandi dovrebbe stare ferma.
Mi puoi dire cosa sbaglio?
Code: [Select]

#include <DuePWM.h>

#define PWM_FREQ1  20000
#define PWM_FREQ2  20000
char inByte ;

DuePWM pwm( PWM_FREQ1, PWM_FREQ2 );

void setup() {

  Serial.begin(9600);
  pwm.setFreq1( PWM_FREQ1 );
  pwm.setFreq2( PWM_FREQ2 );
  pwm.pinFreq1( 6 );  // Pin 6 freq set to "pwm_freq1" on clock A
  pwm.pinFreq2( 7 );  // Pin 7 freq set to "pwm_freq2" on clock B
}

void loop()
{
  if (Serial.available() > 0)
  {
    inByte = Serial.read();
    switch (inByte)
    {
      case 0x74: //quando legge "74" sulla serial1
        { uint32_t pwm_duty = 190; // 75% duty cycle
          pwm.pinDuty( 6, pwm_duty );  // 75% duty cycle on Pin 6
          delay (5000);
          break;
        }
      case 0x75: //quando legge "75" sulla serial1
        { uint32_t pwm_duty = 127; // 50% duty cycle
          pwm.pinDuty( 6, pwm_duty );  // 50% duty cycle on Pin 6
          delay (5000);
          break;
        }
      case 0x76: //quando legge "76" sulla serial1
        { uint32_t pwm_duty = 63; // 25% duty cycle
          pwm.pinDuty( 6, pwm_duty );  // 25% duty cycle on Pin 6
          delay (5000);
          break;
        }
      case 0x7F:
        { pwm.stop( 6 );
          delay (5000);
          break;
        }

      default:
        {
          pwm.stop( 6 );
        }
    }
  }
}

gpb01

Che semplicemente NON puoi usare il monitor seriale ...
... il monitor seriale invia quello che scrivi in ASCII e qiuindi, se scrivi 74, NON invia il codice 0x74, ma invia DUE caratteri ASCII uno per il 7 che è 0x37 ed uno per il 4, che è 0x34. Idem per il resto.

Se vuoi usare il monitor seriale, devi temporaneamente modificare il codice è mettere, al posto di quei codici esadecimali, ad esempio delle lettere ... 'A', 'B', 'C', 'D' ... così quando premi una lettera viene inviata solo quella e riesci a leggerla ;)

Guglielmo
Search is Your friend ... or I am Your enemy !

PM68

Sei un grande Guglielmo! Con la seriale funziona.

Ora lo provo nella vecchia versione collegato alla LIN dell'auto.

Grazie
Mauro


PM68

#10
Jun 17, 2018, 04:17 pm Last Edit: Jun 17, 2018, 04:18 pm by PM68
Buongiorno a tutti,
proseguendo con i miei rilievi mi sono accorto che i frame che rilevavo sulla lin bus non erano completi perchè la velocità di trasmissione non è 9600 ma 19200.
Corretto il tutto i codici che attivano le ventole sono formati da più byte e inseriti nel mio codice mi da un errore di sintassi:"expected ':' before numeric constant".
Mi potete aiutare per la scrittura corretta? Di seguito il mio codice:

Code: [Select]


//  CODICE PER RILEVAZIONE EVENTI SU LINBUS LEXUS e COMANDO VENTOLE PWM

#include <DuePWM.h>

#define PIN_TXE 18
#define PIN_CS 2
uint8_t rxByte[8];

#define PWM_FREQ1  20000
#define PWM_FREQ2  20000
uint32_t pwm_duty = 0;
byte inByte;

DuePWM pwm( PWM_FREQ1, PWM_FREQ2 );

void setup() {
  pinMode(PIN_TXE, OUTPUT);
  pinMode(PIN_CS, OUTPUT);
  digitalWrite(PIN_TXE, HIGH);
  digitalWrite(PIN_CS, HIGH);
  Serial1.begin(19200, SERIAL_8E1); //LIN Serial Rx, 8E1 is BMW iBus standard
  pwm.setFreq1( PWM_FREQ1 );
  pwm.setFreq2( PWM_FREQ2 );
  pwm.pinFreq1( 6 );  // Pin 6 freq set to "pwm_freq1" on clock A
  pwm.pinFreq2( 7 );  // Pin 7 freq set to "pwm_freq2" on clock B
}

void loop()
{
  if (Serial1.available() > 0)
  {
    inByte = Serial.read();
    switch (inByte)
    {
      case 0x0 0x60 0xFE 0x0: //quando legge la sequenza "0 60 FE 0" sulla seriale
        { pwm_duty = 60; // 75% duty cycle
          pwm.pinDuty( 6, pwm_duty );  // 75% duty cycle on Pin 6
          break;
        }
      case 0x0 0x66 0xFE 0x0: //quando legge la sequenza "0 66 FE 0" sulla seriale
        { pwm_duty = 130; // 50% duty cycle
          pwm.pinDuty( 6, pwm_duty );  // 50% duty cycle on Pin 6
          break;
        }
      case 0x0 0x78 0xFE 0x0: //quando legge la sequenza "0 78 FE 0" sulla seriale
        { pwm_duty = 200; // 25% duty cycle
          pwm.pinDuty( 6, pwm_duty );  // 25% duty cycle on Pin 6
          break;
        }

      default:
        { pwm_duty = 255; // 0% duty cycle
          pwm.pinDuty( 6, pwm_duty );  // 0% duty cycle on Pin 6
          break;
        }
    }
  }
}

Patrick_M

lo switch confronta 1 numero  (int o char) quindi confronta il valore attuale di inByte che non può essere contemporaneamente 0 60 fe 0 che sono 4 byte
inoltre la sintassi del case non prevede quella scrittura



per inserire (lo sketch) il programma, dall'IDE clicca modifica, clicca copia per il forum poi vieni qui e incolla nel tuo post (ctrl+v) ;)

gpb01

#12
Jun 17, 2018, 04:54 pm Last Edit: Jun 17, 2018, 04:54 pm by gpb01
Il while/case vuole UNA sola costante numerica, quindi scordati una sitassi come quella che hai scritto.

Secondo me, la strada più semplice e rivecere dalla seriale in una "macchina a stati finiti" in cui avanzo nei vari "stati" mano mano che ricevo i byte corretti e, quando una sequenza è stata completamente identificata, faccio quello che devo fare.

Guglielmo

P.S.: Patrick_M mi ha parzialmente anticipato. :)
Search is Your friend ... or I am Your enemy !

PM68

Grazie del suggerimento, mi sono documentato su cosa vuol dire "macchina a stati finiti" e mi sono guardato parecchi esempi però sono bloccato.

Diciamo che il mio primo stato è il codice che rileva dalla Lin Bus una "sbrodolata" di byte concatenati. Qui sotto li ho incolonnati per chiarezza partendo dal 66 66 :

66 66 9E 0
66 66 78 1E 0 1E 0 E0 0 E0 0 0 FE E6 0 0 E0 0
66 66 E0 1E 0 6 60 80  18 18 60 86 0 0
66 66 9E 0 1E 0 0 0 0 0 0 E0 0
66 66 FE E6 0
66 66 6 0 0 0 0 0 0 60 FE 0 66 18 60 86 0
66 66 78 1E 0 1E 0 E0 0 E0 0 0 0 0 0 0 E0 FE 0
66 66 E0 1E 0 6 60 80 18 66 FE 0
66 66 9E 0 1E F8 0 0 0 0 0 0 E0 E0 0 0 FE E6 0
66 66 6 80 0 0 0 0 0 0 80  18 18 60 86 0
66 66 F8 78 1E 0 1E 0 E0 0 0 0 0 0 0 0 E0 0
66 66 1E 0 6 60 80 18 0 0 0 0 66 FE 0
66 66 9E 0 1E 0 0 0 0 0 1E 0 E0 0 E0 0 0 FE E6 0
66 66 6 98 0 1E 0 6 60 80  18 18 60 86 0
66 66 78 1E 0 1E 9E 0 1E 0 0 0 0 0 0 E0 0
66 66 E0 1E 0 6 80 0 0 0 0 0 0 66 FE 0

Nascosti tra questi byte ci sono le sequenze che mi interessano es. 0 60 FE 0 oppure 0 66 FE 0.

Il secondo stato penso dovrebbe essere rilevare il passaggio delle sequenze che mi interessano e salvarle in una variabile di stato ...ma non so come fare.
Mi potete aiutare?

Grazie in anticipo

Standardoil

Mi fai una grande cortesia?
riparti da capo con lo spiegare "cosa" vuoi fare, e non "come" lo vuoi fare?
qualche idea credo di averla, ma....
Prima legge di Nelson (che sono io): Se vuoi il mio aiuto dimostrami almeno che hai letto il nostro "aiutateCi ad aiutarVi"

Non bado a studenti, che copino altrove

Tu hai problema-Io ti domando-Tu non mi rispondi: vuol dire che non ti serve più

Go Up