Hallo!
Ich schreibe meine Programme in Basic und habe gerade ein Problem.
Habe eine Platine mit 2x MCP2515, die als Gateway funktioniert.
Der µC läuft mit 16Mhz, MCPs laufen auch mit 16Mhz. SPI 1Mhz.
Can 500kb/s. Ca. 40% ausgelastet.
Habe manchmal das Problem, dass die Firmware sporadisch stehenbleibt.
Bewusst reproduzieren konnte ich das nicht.
Ich vermute es liegt an meinem Programmablauf.
Ich kann leider kein Quellcode hier posten, deswegen schreibe ich mein
Ablauf.
µC initialisieren
nicht beschaltete Pins aus Ausgang setzen
Interrupts konfigirieren. INT0 1. MCP2515
1. MCP2515 initialisieren (nur zum Lesen)
2. MCP2515 initialisieren (nur zum Senden)
DO
IF A = 1 then (Leitung INT0 ist mit dem INT Pin vom MCP2515 verbunden)
Empfangsbuffer erkennen (in welchem Buffer die Nachriegt liegt)
Wenn die Nachricht im Buffer0 liegt
Daten Buffer0 auslesen und 1:1 mit dem 2. MCP Senden (Sendebuffer
0)
Wenn die Nachricht im Buffer1 liegt
Daten Buffer1 auslesen und 1:1 mit dem 2. MCP Senden (Sendebuffer
1)
Wenn die Nachricht im Buffer0 UND Buffer1 liegt
Daten Buffer0 auslesen und 1:1 mit dem 2. MCP Senden (Sendebuffer
0)
Daten Buffer1 auslesen und 1:1 mit dem 2. MCP Senden (Sendebuffer
1)
A = 0 (Alles quasi abgearbeitet)
end if
LOOP
INT0:
A = 1 (Wenn Empfangsinterrupt ausgelöst wurde, Variable A auf 1 setzen,
in DO-LOOP dann weiter verarbeiten)
Return
An sich funktioniert das Programm wie geschmiert.
Kann Stundenlang laufen ohne Probleme.
ABER, ab und zu habe ich sporadische Ausfälle, wo ich Reset drücken
muss.
Meine Vermutung:
Wenn Nachricht empfangen wurde, wird die Variable A auf 1 gesetzt.
Wenn Alles abgearbeitet wurde, wird die Variable A wieder auf 0
zurückgesetzt.
ABER, was passiert, wenn mein Programm in der Do-Loop-Schleife gerade
z.B. die Nachricht verschickt UND gerade eine NEUE NACHRICHT eintrifft,
wird die Variable A nun wieder auf 1 gesetzt.
Das merke ich ja nicht, und arbeite meine DO-LOOP Schleife zu Ende
ab,und setze die Variable wieder auf 0 (obwohl eine Neue Nachricht da
ist).
Die neue Nachricht wird nicht ausgelesen, weil A = 0 ist, und Interrupt
vom MCP2515 wird auch nicht gelöscht, weil er erst beim Auslesen
gelöscht wird.
Tja, währen ich den Post geschrieben habe, habe ich mein Problem auch
erkannt.
Ist plausibel, oder?
Biete um Bestätigung.
Gruß
Ralf
Ich würde A im Int immer um 1 erhöhen und die Schleife in der Main
solange ausführen wie a>0 ist. A dann natürlich nach jedem Durchlauf
nicht auf 0 setzen sondern um 1 verringern.
Gruß
Thomas
Thomas H. schrieb:> Ich würde A im Int immer um 1 erhöhen und die Schleife in der Main> solange ausführen wie a>0 ist. A dann natürlich nach jedem Durchlauf> nicht auf 0 setzen sondern um 1 verringern.
Falls der µC ein AVR ist, dann sollte die Variable A auf jeden Fall nur
8bit breit sein und mit volatile deklariert werden. Es kann sonst zu
Problemen kommen, wenn A im Interrupt-Handler verändert wird.
Gruß Chris
@Christoph H.
Habe da Basic gelesen und ging davon aus das Basic das selbst schon
berücksichtigt. Kenne nur Bascom und da ist es so ;)
Aber klar kommt auch auf den µC an, könnte ja auch ein PIC sein und da
kenne ich mich mit Basic Dialekten nicht aus.
Gruß
Thomas
Das Problem ist, ich habe nur einen Versuch.
Ich muss die Platinen bald ausliefern, und die sollen stabil laufen.
Falls ich das später umflashen muss, fallen Kosten an umd die Situation
an sich ist dann auch schlecht.
Die Idee mit :
>A im Int immer um 1 erhöhen ...nach jedem Durchlauf nicht auf 0 setzen >sondern
um 1 verringern.
finde ich gut, habe aber etwas Angst, dass es sich wieder etwas
verhacken kann. Weil es kann u.U. sein, dass ich die falschen Daten
auslese, weil diese nicht aktuell sind.
Wie wäre es mit:
A nicht am Ende auf 0 setzen, sondern sofort am Anfang:
DO
IF A = 1 then (Leitung INT0 ist mit dem INT Pin vom MCP2515 verbunden)
A = 0
Empfangsbuffer erkennen (in welchem Buffer die Nachriegt liegt)
...
alles erledigen
...
LOOP
Kann das so stabil laufen?
Es ist nicht so schlimm, wenn eine Nachricht verloren geht.
VIEL schlimmer ist es, wenn die Daten (Bytes) falsch ausgelesen und
gesendet werden, oder das Programm einfach stehen bleibt.
Danke
Gruß
Ralf
Wenn Nachrichten ruhig verloren gehen können könntest du auch nach
IF A=1 THEN
den Interrupt abschalten und am Ende vor dem
END IF
wieder aktivieren, dann sollte es egal sein wo du A innerhalb der IF
THEN ... END IF auf 0 setzt.
Gruß
Thomas
Glaube nicht, dass es funktioniert.
Der Interrupt reagiert auf fallende Flanke.
Wenn ich vor End if Interrupt wieder aktiviere, dann ist der Pin bereits
auf LOW. So stehe ich immer noch beim alten Problem.
Ich glaube ich mache es doch mit A++ und in der DO-Loop A--.
Kann da etwas schief gehen?
Gruß
Hallo Ralf,
ich würde beides probieren denn wenn der INT Low ist beim wieder
aktivieren ist das ja kein Flankenwechsel nach Low, erst müsste die
Leitung ja wieder auf High und dann nach Low wechseln um einen Int
auszulösen.
Aber wie gesagt könnte beides gehen, einfach probieren.
Um welchen controller handelt es sich denn nun eigentlich?
Gruß
Thomas
Handelt sich um AVR und Bascom.
Werde mal probieren, den Fehler zu reproduzieren, wo ich nun weiß wie es
zustande kommt.
Kann dann die beiden Varianten ausprobieren und gucken, was hilft.
Danke für die Beteiligung.
Gruß
>terrupt auf fallende Flanke ist ganz schlecht. Setz ihn auf low-level.
Dann kann ich ja ganz ohne Interrupts arbeiten, oder?
Etwa so:
PinX.x = Input
DO
IF PINx.x = 0 then (Wenn MCP Int Pin auf LOW ist)
Empfangsbuffer erkennen (in welchem Buffer die Nachriegt liegt)
...
alles erledigen
...
LOOP
Spricht da was gegen?
Danke
Nein, nicht drauf verzichten.
Wahrscheinlich ist bei dir folgendes Szenario:
1. Interrupt kommt, du liest den MCP aus. Bevor du alles gelesen hast
können in der Zwischenzeit aber weitere Interrupts gekommen sein, d.h.
die Int-Leitung bleibt low, und du bekommst nie wieder eine Flanke.
Also levelgesteuerter Interrupt. Ist noch ein weiterer anhängig, springt
der MC direkt nach Verlassen der ISR wieder in die ISR und versucht den
nächsten zu bearbeiten.