Forum: Mikrocontroller und Digitale Elektronik CAN bus message, stm32f407


von Korke (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!

Ich habe bei deiner Umsetzung einer Aufgabe ein Problem.

Hier ein Fragment von meinem Code. In der Textdatei im Anhang ist er 
komplett:

void CAN1_RX0_IRQHandler (void)
{
      CAN_Receive(CAN1, CAN_FIFO0, &RxMsg);

      if (counter1 == 10)
          {

                                      TxMsg.StdId = 0x11D;
                                            TxMsg.ExtId = 0;
                                      TxMsg.DLC = 1;
                                      TxMsg.IDE = CAN_ID_STD;
                                      TxMsg.RTR = CAN_RTR_DATA;

                                       // send  number of received 
messages
                                      TxMsg.Data[0] = counter2;


                                            CAN_Transmit(CAN1, &TxMsg);
                                       GPIO_ToggleBits(GPIOD,GPIO_Pin_12);

                                        }

      if(RxMsg.StdId == 0x67)
        {
              counter1++;
        }

      else if(RxMsg.StdId == 0x52)
        {
               counter2++;
        }
}

// end of fragment



Ich will eine Nachricht mit bestimmten Inhalt senden, sobald ich die 
Nachricht mit der ID 0x67 zehnmal empfangen habe.

Mit dem CANalyzer konnte ich bisher noch nicht das entsprechende 
Resultat erzielen. Wie kann ich sicherstellen, dass ich genau 10 
messages zähle, abreche und dann keine weitere 0x67 Nachricht beim neuen 
Zählanlauf übersehe (mit dem Raussenden der Nachricht würde eventuell 
eine 11. (die neue erste msg des Folgezyklus) Nachricht übersehen.

Kann mir jemand Tipps geben oder hat ähnliche Probleme bereits gelöst?

Danke, Gruß
Korke

von Stefan K. (stefan64)


Lesenswert?

Dein ISR empfängt erstmal 10 Msgs mit (RxMsg.StdId == 0x67). Bei der 10. 
dieser Msgs passiert noch: garnichts.

Erst NACH der 10. msg wird JEDE empfangene msg eine Antwort erzeugen. 
Dies passiert so lange, bis eine 11. msg mit (RxMsg.StdId == 0x67) 
empfangen wird. Diese wird noch einmal eine Antwort senden, danach wird 
aber (counter1 > 10) und damit wird nie wieder eine AntwortMsg 
verschickt (korrekter: erst nach 2^32 empfangenen msgs).

Gruß, Stefan

von Stefan K. (stefan64)


Lesenswert?

Deine Counter sind zwar 32 Bit breit definiert:
1
uint32_t counter1 = 0;    // counter for message 1
Deine msg versendet davon aber nur 8 Bit:
1
TxMsg.Data[0] = counter2;

Gruß, Stefan

von Bastian W. (jackfrost)


Lesenswert?

Hi,

Wenn du die CAN Nachricht erst auf die ID 0x67 prüfst , dann den Zähler 
erhöhst. Mit dem Zähler kannst du dann den Rest einer Division durch 
nehmen und den auf
1
if((counter1 % 10) == 0)

prüfen. Damit sollte es gehen , wenn sende Puffer und Empfangspuffer 
getrennt sind. Welche ID hat deine Antwort ? Wenn die größer als 0x67 
ist kann theoretisch die Nachtichten der IDs <= 0x67 deine Antwort 
überschreiben.

Gruß JackFrost

von Stefan K. (stefan64)


Lesenswert?

Bastian W. schrieb:
> Wenn die größer als 0x67
> ist kann theoretisch die Nachtichten der IDs <= 0x67 deine Antwort
> überschreiben.

Nein, bei CAN werden keine msgs überschrieben. Die msg mit der 
niedrigeren Priorität wird bei gleichzeitigem Sendeversuch später 
gesendet bzw. wiederholt.

Die höchste Priorität hat beim CAN-Bus eine msg mit der Priorität 0x00.

Gruß, Stefan

von Korke (Gast)


Lesenswert?

Ich würde nun das probieren. Leider komme ich aber erst morgen wieder an 
CANalyzer:


void CAN1_RX0_IRQHandler (void)
{
      CAN_Receive(CAN1, CAN_FIFO0, &RxMsg);

      if ((counter1 % 10) == 0)
          {

                                      TxMsg.StdId = 0x11D;
                                      TxMsg.ExtId = 0;
                                      TxMsg.DLC = 1;
                                      TxMsg.IDE = CAN_ID_STD;
                                      TxMsg.RTR = CAN_RTR_DATA;

                                       // send  number of received
messages
                                      TxMsg.Data[0] = counter2;


                                            CAN_Transmit(CAN1, &TxMsg);
                                       GPIO_ToggleBits(GPIOD,GPIO_Pin_12);

                                        }

      if(RxMsg.StdId == 0x67)
        {
              counter1++;
        }

      else if(RxMsg.StdId == 0x52)
        {
               counter2++;
        }
}

// end of fragment


Ich habe bezüglich den 8 Bit, die die Message höchstens versenden kann, 
leider keinen Schimmer, wie ich darangehen soll. Wenn ich über die 2^8 
hinaus bin, sehe ich ein, dass es dann ohnehin nicht mehr funktioniert.

von Stefan K. (stefan64)


Lesenswert?

So wie Du das machst, wird die Antwort-msg immer dann geschickt, wenn 
counter1 durch 10 teilbar ist.
Zusätzlich: Da zuerst die Abfrage "durch 10 teilbar" und danach 
"counter1++" kommt, geschieht das erst bei der 11. empfangenen 0x67-msg!

Du willst aber nur dann die Antwort senden, wenn die empfangene msg eine 
(RxMsg.StdId == 0x67) ist UND der counter durch 10 teilbar ist.

Also:
1
  if(RxMsg.StdId == 0x67)
2
  {
3
    counter_0x67++;
4
5
    if ((counter_0x67 % 10) == 0)
6
    {
7
      // todo: Antwort-msg auf 0x67 senden
8
      // todo: Led togglen
9
    }
10
  }
11
12
  if(RxMsg.StdId == 0x52)
13
  {
14
    counter_0x52++;
15
16
    if ((counter_0x52 % 10) == 0)
17
    {
18
      // todo: Antwort-msg auf 0x52 senden
19
      // todo: Led togglen
20
    }
21
  }

Ich habe mal Deine counter umbenannt, dann ist der Zusammenhang 
intuitiver.

Korke schrieb:
> Ich habe bezüglich den 8 Bit, die die Message höchstens versenden kann,
> leider keinen Schimmer, wie ich darangehen soll. Wenn ich über die 2^8
> hinaus bin, sehe ich ein, dass es dann ohnehin nicht mehr funktioniert.

Du kannst Deine uint32_t counter (4 Byte) entweder in TxMsg.Data[0] bis 
TxMsg.Data[3] speichern.
Wenn Du nicht weisst, wie das geht, dann kannst Du immer noch Deine 
counter-Definition auf uint8_t ändern. Dann läuft der Counter zwar 
schneller über, aber das Programm ist formal richtiger ...

Viele Grüße, Stefan

: Bearbeitet durch User
von Korke (Gast)


Lesenswert?

Vielen Dank für die Erklärung, Stefan!

von Korke (Gast)


Lesenswert?

Ist es eventuell besser die Variablen, die global deklariert sind, in 
die main zu packen?

Was wäre ein Grund dafür? - Wir konnten nur antworten, dass wir es 
bisher immer so gemacht haben.

von Jörg M. (derlang)


Lesenswert?

Korke schrieb:
> Ist es eventuell besser die Variablen, die global deklariert sind, in
> die main zu packen?
>
> Was wäre ein Grund dafür? - Wir konnten nur antworten, dass wir es
> bisher immer so gemacht haben.

Autsch, ich hoffe mal nicht an einer Uni. Mein Prof hätte mich bei so 
einer Antwort aus dem Kurs geschmissen mit der Empfehlung nächstes Jahr 
erneut zu belegen...

Denk mal nach, Stichwort Gültigkeitsbereich

Gehört zum allerersten Grundstoff.

von Stefan K. (stefan64)


Lesenswert?

Probier es einfach aus.

Die Variablen, die Du in der main() definierst, sind in der ISR nicht 
bekannt. Das wird also nicht funktionieren, der Compiler wird Dir einen 
Error bringen.

Die eigendliche Domäne globaler Variablen ist die Kommunikation zwischen 
Interrupts und dem "normalen" Programm.

Viele Grüße, Stefan

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.