KANN keine Temperaturdaten übertragen

Ich habe an einem CAN-Bus-Projekt gearbeitet. Es ist ein Projekt aus dem Buch Advanced Micro Controller Projects von Dogan. Es ist ein CAN-Bus-Projekt für Temperatursensoren. Wie Sie wissen, kann das Projekt nicht simuliert werden, da MCP2551 nicht in Proteus verfügbar ist, also habe ich es gemäß dem Schaltplan im Buch in Hardware implementiert.

Geben Sie hier die Bildbeschreibung ein

Ich habe die Schaltung auf zwei Steckbrettern mit einem CAN-Bus aus Twisted Pairs implementiert. Ich habe PIC18F458 mit seinem eingebauten CAN-Modul verwendet. Die Länge des Busses beträgt weniger als 500 cm. Als ich es getestet habe, zeigte es nur die Willkommensnachricht auf dem LCD. Ich habe den Code für die Übertragung von Zeichen getestet. Es hat funktioniert, aber für die Temperatur werden keine Daten angezeigt.

Hier ist der Code des Kollektorknotens.

//unsigned char Can_Init_Flags, Can_Send_Flags,dt,len, Can_Rcv_Flags;
unsigned short init_flag, send_flag,len, read_flag;volatile int dt;
char SJW, BRP, Phase_Seg1, Phase_Seg2, Prop_Seg, txt[4];
long id, mask;
int bitvalue;
float vout, temperature; int flag;

#define d portb.b0

void adc_setting()
{
  adcon0 = 0x00;
  adcon1 = 0x80;
  intcon = 0xc0;
  pie1.adie = 1;
  pir1.adif = 0;
}

void interrupt()
{
  if (pir1.adif)
  {
    pir1.adif = 0;
    adcon0.adon = 0;
    flag = 1;
    adcon0.adon = 1;
    adcon0.go_done = 1;
  }
}

void main()
{
  //Portc=0x08;
  TRISA = 0xFF; // PORTA are inputs
  //TRISB = 0x08; // RB2 is output, RB3 is input
  //
  // Configure A/D converter
  //
  //ADC_Init();
  adc_setting();
  adcon0.adon = 1;
  adcon0.go_done = 1;


  //ADCON1 = 0x80;
  //
  // CAN BUS Timing Parameters
  //
  SJW = 1;
  BRP = 1;
  Phase_Seg1 = 6;
  Phase_Seg2 = 7;
  BRP = 1;
  Prop_Seg = 6;

  init_flag= _CAN_CONFIG_SAMPLE_THRICE &
             _CAN_CONFIG_PHSEG2_PRG_ON &
             _CAN_CONFIG_STD_MSG &
             _CAN_CONFIG_DBL_BUFFER_ON &
             _CAN_CONFIG_VALID_XTD_MSG &
             _CAN_CONFIG_LINE_FILTER_OFF;
              send_flag  = _CAN_TX_PRIORITY_0 &
              _CAN_TX_XTD_FRAME &
              _CAN_TX_NO_RTR_FRAME;
               read_flag=0;

     //
     // Initialise CAN module
     //
  CANInitialize(SJW, BRP, Phase_Seg1, Phase_Seg2, Prop_Seg,init_flag );
  //
  // Set CAN CONFIG mode
  //
  CANSetOperationMode(_CAN_MODE_CONFIG,0xFF);
  mask = -1;
  //
  // Set all MASK1 bits to 1's
  //
  CANSetMask(_CAN_MASK_B1, mask, _CAN_CONFIG_XTD_MSG);
  //
  // Set all MASK2 bits to 1's
  //
  CANSetMask(_CAN_MASK_B2, mask, _CAN_CONFIG_XTD_MSG);
  //
  // Set id of filter B1_F1 to 500
  //
  CANSetFilter(_CAN_FILTER_B1_F1,500,_CAN_CONFIG_XTD_MSG);
  //
  // Set CAN module to NORMAL mode
  //
  CANSetOperationMode(_CAN_MODE_NORMAL, 0xFF);

  // Program loop. Read the temperature from analog temperature sensor

  while(1) // Endless loop
  {
    //
    // Wait until a request is received
    //
    dt = 0;
    while (!dt) dt = CANRead (&id, i, &len, read_flag);
    if (id == 500 && i[0]=='T')
    {
      if (flag==1)
      {
        bitvalue = (adresh<<8)+adresl;
        vout = bitvalue * 0.00488;
        temperature = vout / 0.0100;

        i[0] = temperature;
        id = 3; // Identifier
        CANWrite (id, i, 1, send_flag); // send temperature
      }
    }
  }
}

Und hier ist der Code des Anzeigeknotens

float temperature; unsigned char i[8];

unsigned short init_flag, send_flag, dt, len, read_flag;

char SJW, BRP, Phase_Seg1, Phase_Seg2, Prop_Seg, txt[4];

long id, mask;

sbit LCD_RS at RC4_bit;

sbit LCD_EN at RC5_bit;

sbit LCD_D4 at RC0_bit;

sbit LCD_D5 at RC1_bit;

sbit LCD_D6 at RC2_bit;

sbit LCD_D7 at RC3_bit;

sbit LCD_RS_Direction at TRISC4_bit;

sbit LCD_EN_Direction at TRISC5_bit;

sbit LCD_D4_Direction at TRISC0_bit;

sbit LCD_D5_Direction at TRISC1_bit;

sbit LCD_D6_Direction at TRISC2_bit;

sbit LCD_D7_Direction at TRISC3_bit;

// End LCD module connections

void main()
{
    TRISC = 0; // PORTC are outputs (LCD)

    //TRISB = 0x08; // RB2 is output, RB3 is input

    //
    // CAN BUS Parameters

    SJW = 1;

    BRP = 1;

    Phase_Seg1 = 6;

    Phase_Seg2 = 7;

    Prop_Seg = 6;

    Init_Flags = _CAN_CONFIG_SAMPLE_THRICE &
                     _CAN_CONFIG_PHSEG2_PRG_ON &
                     _CAN_CONFIG_STD_MSG &
                     _CAN_CONFIG_DBL_BUFFER_ON &
                     _CAN_CONFIG_VALID_XTD_MSG &
                     _CAN_CONFIG_LINE_FILTER_OFF;
    Send_Flags = _CAN_TX_PRIORITY_0 &
                     _CAN_TX_XTD_FRAME &
                     _CAN_TX_NO_RTR_FRAME;

    Can_Rcv_Flags = 0;

    //
    //
    // Initialize CAN module
    //
    //

    CANInitialize(SJW, BRP, Phase_Seg1, Phase_Seg2, Prop_Seg, init_flag);

    // Set CAN CONFIG mode
    //

    CANSetOperationMode(_CAN_MODE_CONFIG, 0xFF);

    mask = -1;

    // Set all MASK1 bits to 1's

    CANSetMask(_CAN_MASK_B1, mask, _CAN_CONFIG_XTD_MSG);

    // Set all MASK2 bits to 1's
    //

    CANSetMask(_CAN_MASK_B2, mask, _CAN_CONFIG_XTD_MSG);

    //
    // Set id of filter B2_F3 to 3

    //

    CANSetFilter(_CAN_FILTER_B2_F3, 3, _CAN_CONFIG_XTD_MSG);

    //
    // Set CAN module to NORMAL mode
    //

    CANSetOperationMode(_CAN_MODE_NORMAL, 0xFF);


    // Configure LCD

    Lcd_init(); // LCD is connected to PORTC

    Lcd_Out(1,1,"CAN BUS"); // Display heading on LCD

    Delay_ms(1000); // Wait for 2 seconds


    //
    // Program loop. Read the temperature from Node:COLLECTOR and display

    // on the LCD continuously
    //
    while(1) // Endless loop
    {
        Lcd_Out(1,1,"Temp = "); // Display "Temp = "
        //
        // Send a message to Node:COLLECTOR and ask for data
        //
        i[0] = 'T'; // Data to be sent
        id = 500; // Identifier
        CANWrite(id, i, 1, send_flag); // Send 'T'
        //
        // Get temperature from node:COLLECT
        //
        dt = 0;
        while(!dt)
            dt = CANRead(&id, i, &len, &read_flag);

        if(id == 3)
        {
            temperature = i[0];
            ByteToStr(temperature,txt); // Convert to string
            Lcd_Out(1, 8, txt); // Output to LCD
            Delay_ms(1000); // Wait 1 second
        }
    }
}

Die Temperatur wird überhaupt nicht angezeigt. Ich habe versucht, den Code ein paar Mal zu ändern, aber das Problem bleibt das gleiche. Ich habe den TX-Pin des Kollektorknotens auf einem digitalen Oszilloskop überprüft. Es zeigte nichts. Es überträgt keine Daten. Warum werden keine Daten übertragen?

Gibt es ein Problem mit meinem Code? Soll ich die Anforderungsbedingung im Übertragungsknoten entfernen und nur Daten in den zweiten Knoten schreiben und den Filter deaktivieren?

Wenn Sie Hilfe suchen, wäre ein guter Anfang, den Code so zu posten, wie Sie ihn geschrieben habenenter code here unsigned char temperature,i[8];
Sie haben eine Funktion namens interrupt(), aber es gibt keinen Hinweis darauf, dass sie mit einem tatsächlichen Hardware-Interrupt verbunden ist. Wenn diese Funktion nie ausgeführt wird, flagwird sie nie gesetzt und es wird nichts übertragen.

Antworten (3)

Ich habe die Schaltung auf zwei Steckbrettern mit einem CAN-Bus aus Twisted Pairs implementiert.

Sie müssen noch die Masse beider Mikrocontroller miteinander verbinden. CAN toleriert einige Gleichtaktvariationen der Busleitungen, aber sie können nicht willkürlich erdfrei sein. Anders ausgedrückt, Sie müssen die beiden Knoten mit drei Drähten verbinden, dem verdrillten Paar für die CANH- und CANL-Leitungen und einem Erdungsdraht.

Sir, meine Schaltung ist in Ordnung. Ich meine, ich habe den Knoten mit verdrillten Paaren verbunden. Und beide Knoten sind gemäß dem Schaltplan geerdet. Das LCD-Display zeigt die Begrüßungsnachricht, aber nicht die Temperatur. Ich denke, es gibt ein Problem mit dem Code. Der tx-Pin des ersten Knotens zeigt keine Spannung im digitalen Oszilloskop.
@Ammar Wenn Sie keine dedizierte Signalmasse verwenden, wird die Versorgungsmasse als Referenz verwendet. Bei einem hohen Potentialunterschied zwischen den Systemen wird es natürlich nicht funktionieren. Aber selbst wenn dies nicht der Fall ist, nehmen Sie alle Arten von EMI-Rauschen von der Versorgungsmasse auf.
Sir, ich habe denselben Code für die Übertragung von Zeichen getestet. Er hat funktioniert, zeigt aber keine Temperatur an. Ich weiß nicht, warum hier eine dedizierte Erdung benötigt wird? Die Schaltung ist auf zwei miteinander verbundenen Steckbrettern aufgebaut. Und die Länge des Busses beträgt weniger als 300 cm.Ich glaube nicht, dass es für eine solche Entfernung EMI geben wird
Funktioniert die eingebaute ADC-Funktion in diesem Projekt?

Dieser Code ergibt keinen Sinn:

    dt = 0;

    while(!dt);

        dt = CANRead(&id, b, &len, &Can_Rcv_Flags);

        if(id == 3)
        {
            temperature = b[0];

            ByteToStr(temperature,txt); // Convert to string

            Lcd_Out(1, 8, txt); // Output to LCD

            Delay_ms(1000); // Wait 1 second
        }
    }

Ich glaube, Sie werden von Ihrer eigenen Einrückung getäuscht. Die letzte geschweifte Klammer oben gehört zu for(;;)- da die while-Schleife keine geschweiften Klammern hat, hat sie nur eine leere ;Nullanweisung und keinen Schleifenkörper.

Die Linien dt = 0; while(!dt);sind also nutzlos, weil dt an dieser Stelle immer Null ist.

Du wolltest wahrscheinlich schreiben

while(!dt)
{
  dt = CANRead(&id, b, &len, &Can_Rcv_Flags);
}

Aus diesem Grund sollten Sie immer geschweifte Klammern nach jeder Steuer- oder Schleifenanweisung in Ihrem Code verwenden und niemals Semikolons in derselben Zeile wie eins platzieren. Gute Compiler warnen vor solchen Semikolons.


Andernfalls, wenn dies trotz der seltsamen Einrückung beabsichtigt war und es sich um dteine Variable handelt, die mit einer ISR geteilt wird, ist Ihr Code immer noch falsch, da dter nicht als deklariert wurde volatileund der Compiler ihn möglicherweise falsch optimiert. Sieh dir das an:

http://www.embedded.com/electronics-blogs/cole-bin/4418638/When-to-use---and-not-use---the-volatile-keyword

Ja, ich dachte auch, dass DT nicht im Code verwendet wird. Was ist der Zweck davon? Sie haben Recht mit der While-Schleife. Ich habe bereits Änderungen daran vorgenommen. Sie sprachen über das Schlüsselwort volatile. Mein Compiler mikroc gab es nicht irgendein Fehler. Sollte ich es nicht einfach entfernen?
@Ammar Der Hinweis zu Volatilität gilt nur, wenn die Variable von einem ISR verwendet wird. Wenn der gepostete Code der vollständige Code ist, dann trifft das hier nicht zu. Dennoch müssen Sie wissen, wie volatil funktioniert, wenn Sie eingebettete Software schreiben.
Sir, ich weiß nicht, ob es in der ISR verwendet wird. Aber DT wird nicht verwendet. Warum also nicht durch eine andere Variable ersetzen?
@Ammar Es wird hier eindeutig verwendet: dt = CANRead(.... Nur die Schleife ist falsch.
Sir, die Temperatur wird mit diesem Code nicht angezeigt. Was ist Ihrer Meinung nach das Problem? Können Temperaturdaten im Float- oder Char-Datentyp gesendet werden?

Ich vermute, dass eine dieser Nachrichten nicht richtig empfangen wird. Die Nachrichtenfilterung ist hier wichtig: Sie haben den Empfangsfilter so konfiguriert, dass beide Nachrichten, die Sie senden, erweiterte Typen sind (29-Bit-ID). Können Sie überprüfen, ob Sie die Nachrichten als erweiterte Frames senden und die CAN-Module mit aktivierten erweiterten Frames initialisiert werden? Ihr Code ist diesbezüglich nicht ganz selbsterklärend.

Standard- und erweiterte Nachrichten im CAN-Bus sind völlig unterschiedlich. Wenn Sie eine Standardnachricht mit der ID 5 senden und den Empfangsfilter so konfiguriert haben, dass erweiterte Nachrichten mit der ID 5 empfangen werden, erhalten Sie nichts.

Liege ich falsch oder initialisieren Sie das CAN-Modul des Displays mit nicht initialisiertem init_flag und senden die Nachrichten mit nicht initialisierten send_flag- Argumenten? Sie deklarieren Can_Init_Flags- und Can_Send_Flags- Variablen, die nicht definiert sind. Hier könnte es ein Problem geben.
Sir, ich habe eine Zeichenvariable zum Beispiel 'B' mit demselben Code übertragen. Es hat funktioniert, aber Temperaturdaten werden nicht auf dem LCD angezeigt.
Dies bedeutet, dass die Filter richtig konfiguriert sind
Wie finde ich heraus, ob die Filter in Standard- und erweiterten Frames aktiviert sind?
es sind init_flags, nicht CAN_init_flags. Es ist ein Fehler. Der Fehler liegt im Anzeigeknoten. Aber das Problem bleibt bestehen.
Sie haben also mindestens eine Nachricht erfolgreich gesendet und empfangen? In diesem Fall könnte das Problem in den Baudratenkonfigurationen liegen. Der CAN-Bus hat einen etwas kniffligen Fehlerbehandlungsmechanismus, der einen Knoten zum Schweigen bringt, der zu viele Fehler im Bus erkennt. hier ist ein Artikel über CAN-Fehlerbehandlung. Die Sache ist die, dass, wenn Phase_Seg1 und Phase_Seg2 so eingestellt sind, dass die Knoten Schwierigkeiten haben, Nachrichten zu empfangen oder zu senden, ihre Fehlerzähler steigen und sie schließlich im Bus-Off-Modus enden.
Du könntest den Bus mit einem Oszilloskop überprüfen. Wenn es scheint, dass beim Start einige. Nachrichten werden gesendet, aber dann hören die Knoten einfach auf zu senden, das Problem liegt möglicherweise in der Fehlerbehandlung.
Was sollte also getan werden, um zu verhindern, dass die Fehler den Bus stoppen?
Zuerst sollten Sie sicherstellen, ob das wirklich das Problem ist. CAN-Protokollstacks implementieren normalerweise Funktionen zum Abrufen von Status- oder Fehlerzählern.