Hallo Leute,
ihr alle kennt sicher dieses Gefühl, ganz nah an der Lösung zu sein und
trotzdem wie blind keinen Fehler finden zu können? Hier bin ich eben
angelangt.
Die Variablen BDHighestFailureByte und CCHighestFailureByte sollen sich
nur erhöhen und niemals senken können (Maximum-Tracer)...
Die gehen jedoch entsprechend mit BDStableFailureByte bzw.
CCStableFailureByte mit, nicht nur rauf, auch runter!!!?
In den Funktionen, die ich hier aus Übersichtlichkeit-Gründen nicht
beigefügt habe, werden sie nicht verarbeitet; könnten auch nicht weil
sie ja nur in main deklariert sind.
Im gesamten Programm werden auch keine Pointer benützt.
Also ich finde hier keine Operation, die die BDHighestFailureByte und
CCHighestFailureByte Variablen erniedrigen können, egal was immer mit
allen anderen Variablen passieren
würde.
Und ihr?
Danke voraus für die Hilfe!
int main (void)
{ //############################################# Main program begin
#############################################
unsigned char EqualFailuresCounter=0x00; // For checking if the
failure is stable
unsigned char BDPreviousSingleFailureByte=0xFF; // For recording
the previous single failure byte
unsigned char CCPreviousSingleFailureByte=0xFF; // For recording
the previous single failure byte
unsigned char BDStableFailureByte=0x00; // Stable failure is
recorded when the single failure did not change 30 times
unsigned char CCStableFailureByte=0x00; // Stable failure is
recorded when the single failure did not change 30 times
unsigned char BDPreviousStableFailureByte=0xFF; // For recording
the previous stable failure byte
unsigned char CCPreviousStableFailureByte=0xFF; // For recording
the previous stable failure byte
unsigned char BDHighestFailureByte=0x00; // The highest failure
byte ever observed
unsigned char CCHighestFailureByte=0x00; // The highest failure
byte ever observed
OutputsInputsConfiguration ();
for(;;) { //############################ Endless loop begin
############################
TestPattern ();
LEDsFailureSignalisation ();
// Check if the single failure bytes changed since the last test
pattern loop run
if
((BDPreviousSingleFailureByte==BDSingleFailureByte)&(CCPreviousSingleFai
lureByte==CCSingleFailureByte))
{EqualFailuresCounter++;} // Increase the counter if the single
failure bytes did not change
else
{EqualFailuresCounter=0;} // Reset the counter if the single
failure bytes changed
BDPreviousSingleFailureByte=BDSingleFailureByte; // Record the
previous single failure byte for the next comparison
CCPreviousSingleFailureByte=CCSingleFailureByte; // Record the
previous single failure byte for the next comparison
if (EqualFailuresCounter>30) // If the single failure did not
change during the last 30 test pattern loop run...
{
EqualFailuresCounter=0; // Reset the counter
BDStableFailureByte=BDSingleFailureByte; // Take over the failure
as stable
CCStableFailureByte=CCSingleFailureByte; // Take over the failure
as stable
}
// Beep only once at a change of the stable failure, else too
loud:
if
((BDPreviousStableFailureByte!=BDStableFailureByte)|(CCPreviousStableFai
lureByte!=CCStableFailureByte))
{ // Do not beep at the highest failure byte
if
((BDStableFailureByte<BDHighestFailureByte)|(CCStableFailureByte<CCHighe
stFailureByte))
BeepForPassOrFail (); // Beep type is choosen inside of this
function due to the global variables BD- and CCSingleFailureByte
}
else _delay_ms(10); // Do not beep at equal stable
failures
BDPreviousStableFailureByte=BDStableFailureByte; // Record the
previous stable failure byte for the next comparison
CCPreviousStableFailureByte=CCStableFailureByte; // Record the
previous stable failure byte for the next comparison
if (BDStableFailureByte>BDHighestFailureByte) // Find out the
highest BDFailureByte ever seen
{BDHighestFailureByte=BDStableFailureByte;} // Find out the
highest BDFailureByte ever seen
if (CCStableFailureByte>CCHighestFailureByte) // Find out the
highest CCFailureByte ever seen
{CCHighestFailureByte=CCStableFailureByte;} // Find out the
highest CCFailureByte ever seen
PORTB=BDHighestFailureByte; // For debugging
_delay_ms(100);
PORTB=0x00;
_delay_ms(100);
PORTB=BDHighestFailureByte;
_delay_ms(100);
PORTB=0x00;
_delay_ms(100);
PORTB=BDHighestFailureByte;
_delay_ms(100);
PORTB=0x00;
_delay_ms(100);
} //############################ Endless loop end
############################
} //############################################# Main program end
#############################################
Wenn du für's Debugging nur einen Wert ausgibst, den aber dreimal, woher
kennst du dann die anderen Werte?
Erkennst du an irgendwas, dass das Programm neu gestartet wurde? Das ist
nämlich auch ein Weg, den Wert zu verringern.
Hallo,
ja, andere Werte verfolge ich jetzt nicht, aber wie geschrieben, egal
wie die anderen wären, können die besagten Variablen nicht erniedrigt
werden.
Der Rest vom Programm ist übrigens funktional ok.
& oder &&, was soll ich nehmen für diesen if? Sollte auch für die Frage
nicht relevant sein...
Michal schrieb:
> ja, andere Werte verfolge ich jetzt nicht, aber wie geschrieben, egal> wie die anderen wären, können die besagten Variablen nicht erniedrigt> werden.
Möglicherweise durch irgendwie ausgelösten aber nicht erkannten
Neustart.
Sind Interrupts im Spiel?
> & oder &&, was soll ich nehmen für diesen if? Sollte auch für die Frage> nicht relevant sein...
& | für Bitoperationen
&& || für logische Operationen wie hier.
Oder durch Programmfehler wie beispielsweise einen eingeschalteten aber
nicht definierten Interrupt, durch Stacküberlauf,...
Solltest irgendeine Erkennung dafür einbauen, um sicher zu gehen.
Beispielsweise am Anfang kurz mit anderer Frequenz blinken oder so.
Kommentier doch einfach mal die Zuweisungen wie "CCHighestFailureByte =
... " aus und schau, was die Werte austuen.
Kannst auch versuchen, Interrupts gezielt zu sperren, beim AVR geht das
mit CLI.
Um was für einen Prozessortyp handelt es sich? 8Bit?
Welcher Compiler?
Hallo,
ich verwende keine Interrupts.
Möchte euch das lesen vom ganzen Programm ersparen, oder wollt ihr euch
doch durchkämpfen?
Es ist ein Tester mehradrigen Kabel auf Open, Short und Verwechslung.
Ich programmiere einen ATmega8 mit einem AVRISP mkII vom AVRStudio mit
AVR GCC Plug-In.
Michal schrieb:
> Neustart vom Programm, das geht durch Reset z.B. durch Unterspannung?> Kaum vorstellbar...
Watchdog schon kontrolliert?
Gibt es irgendwelche Funktionen (außer main), die mit lokalen Variablen
arbeiten, insbesondere Arrays?
Hallo,
da ich vor halbem Jahr angefangen habe, programmiere ich noch am
einfachsten wie möglich.
Kein Watchdog, keine Interrupts, keine Pointer, nur elementares
"Blinken".
Hier der ganze Code für interessierte...
Die Frage ist: gibt es irgendwo eine Operation die BDHighestFailureByte
und
CCHighestFailureByte erniedrigen könnte?
Omg,
das du bei solchem Source irgendwo ne Macke reinhaust ist fast schon
vorprogrammiert. Rück als erstes mal alles vernünftig ein, benutz keine
kilometerlangen Variablennamen sonderen kurze Selbsterklärende und
schmeiss die sinnfreien Kommentare raus, dann findest du den Fehler
bestimmt selber.
So wie du jetzt schreibst ist dein Quelltext schon bei so einem Witz
Programm unlesbar...
Lange Variablennamen können auch ganz gut selbsterklärend sein. Ich
möchte mir aber manchmal Tipparbeit sparen und schreibe dann in den
Kommentar, was ich mit einem kryptischen Kürzel meinte:
unsigned char bdhfb; //BDHighestFailureByte
alternativ könnte man das Kürzel später mit "Suchen und Ersetzen" wieder
"lang machen".
@Gast: Stilfragen sind so eine Sache. Man neigt dazu,den eigenen Stil zu
bevorzugen und findet fremde Programme oft schaurig.
So schlimm finde ich den übrigens nicht, schon garnicht die Variablen.
Den Operatoren würden ein paar Blanks nicht schaden und der eine oder
andere Kommentar wäre als Block statt endloser Wurst am Ende der Zeile
besser, aber was soll's.
Spitzenklasse ist allerdings der Filename.
Hallo,
Die selbsterklärenden langen Variablennamen erleichten dem Anfänger das
Leben.
Um meine Tipparbeit kümmere ich mich selbst, meistens durch Copy und
Paste...
Strukturiert ist das ganze übersichtlich in Funktionen.
Abstände bei Operatoren und Kommentare nicht in lange Zeilen ziehen: das
lege ich mir ans Herz.
Also ausser Rüge habt ihr mich auf ein Gedanke gebracht.
Im gesanten Code gibt es nur eine einzige Zuweisung für diese Variable,
die sie durch die eingebaute Bedingung nur erhöhen könnte:
if (BDStableFailureByte>BDHighestFailureByte)
{BDHighestFailureByte=BDStableFailureByte;}
Ein Reset gibt es ja nur am Anfang von main, bei den
Variablen-Deklarationen:
BDHighestFailureByte=0x00
Das heisst, mein Programm MUSS von neu gestartet gewesen sein.
Aber wie kriege ich das raus? Meine Versorgungsspannung ist perfekt, die
restliche Logik hat - bevor ich anfangen habe den BDHighestFailureByte
zu überwachen - tadellos funktioniert, Interrupts und Watchdogs sind
keine im Spiel.
Mal durchschlafen. Gute Nacht da drüben!
ist einfach nur bescheuert. Du musst 10 Sekunden die Zeile anstarren um
überhaupt erst mal die einzelnen Worte zu finden
1
if((BD_PrevSingleFB==BD_SingleFB)&&
2
(CC_PrevSingleFB==CC_SingleFB))
(was auch immer das BD und CC bedeuten mag.)
Zum Problem: Sind irgendwelche Arrays im Spiel?
Das Programm jetzt genauer zu analysieren tu ich mir nicht an. Nicht
solange das eine wüste Buchstabensuppe ist
> Das heisst, mein Programm MUSS von neu gestartet gewesen sein.>> Aber wie kriege ich das raus?
Schalte am Anfang alle LEDS die du hast für 1 Sekunde ein und danch
wieder aus. Das kriegst du auf jeden Fall mit, wenn zwischendurch alle
LEDs immer wieder mal für 1 Sekunde angehen.
Fällt mir ein: Kann es sich vielleicht um einen Variablen-Überlauf
handeln?
unsigned char geht ja nur bis 255
So kann der Wert ja auch erniedrigt werden.
Ich empfehle Dir, die Fehlerzähler zu kapseln - und zwar in eine
Funktion, die eine obere Grenze sicherstellt, also quasi so:
void increment_limited(unsigned char *counter)
{
if ((*counter) < 255) {
(*counter)++;
}
}
Im Code rufst Du dann statt:
EqualFailuresCounter++;
dieses auf:
increment_limited(&EqualFailuresCounter);
Gruß,
Bernd
Karl heinz Buchegger schrieb:
> ist einfach nur bescheuert. Du musst 10 Sekunden die Zeile anstarren um> überhaupt erst mal die einzelnen Worte zu finden>>
1
>if((BD_PrevSingleFB==BD_SingleFB)&&
2
>(CC_PrevSingleFB==CC_SingleFB))
3
>
>> (was auch immer das BD und CC bedeuten mag.)
Gleiche gilt nun fuer FB - wenn das nicht mal eine bescheuerte
Abkuerzung ist.
Manchmal ist ein volatile für kleine Wunder gut.
Mit volatile wird die Optimierung des Compilers unterbunden und die
Variable behält ihre Gültigkeit. Das es sich nur um lokale Variablen
handelt versucht der Compiler diese registeroptimal zu nutzen.
Da kann es schon mal vorkommen, daß ein Register für mehrere Variablen
genutzt wird.
Noname schrieb:
> Manchmal ist ein volatile für kleine Wunder gut.> Mit volatile wird die Optimierung des Compilers unterbunden und die> Variable behält ihre Gültigkeit. Das es sich nur um lokale Variablen> handelt versucht der Compiler diese registeroptimal zu nutzen.> Da kann es schon mal vorkommen, daß ein Register für mehrere Variablen> genutzt wird.
Du willst also sagen, dass es beim C Compiler normal ist, dass ab und zu
mal lokale Variablen verloren gehen, weil ein Register "schon mal" von
anderen Variablen belegt wird?
Was ist denn das für ein Unsinn ;)
gut, das hat aber nichts damit zu tun, daß ein und dasselbe Register
durch die Optimierung nacheinander für mehrere Variablen genutzt
werden kann. Vielmehr verhindert volatile, daß eine Variable
überhaupt in einem Register gepuffert wird zwecks
Beschleunigung.
Also ich muß auch zugeben, daß diese Monstervariablen das Lesen
erheblich erschweren und erst recht die Monsterzeilen.
Warum machst Du nicht wenigstens noch Leerzeichen, damit man die
Operatoren erkennen kann?
Und Du machst nen Haufen völlig unnötiger Leerzeilen, die höchstens den
Scrollfinger trainieren, aber überhaupt nichts lesbarer machen.
Du hast damit bestimmt hier gute Chancen:
http://www.ioccc.org/main.html
Ich hab mühsam rausgekriegt, daß es ein Leitungstester sein soll.
Ich hatte mal nen Tester für 8-poliges Patchkabel gemacht mit nem 8051.
Vielleicht kannst Du ja damit was anfangen:
1
#include<reg51.h>
2
3
#define uchar unsigned char
4
5
sbitxLED_OK=P0^2;
6
sbitxLED_ERROR=P0^1;
7
sbitxLED_CROSSOVER=P0^0;
8
9
#define LED_ON(x) (~(x)) // low active: 0 = LED on
Klaus Wachtler schrieb:
> gut, das hat aber nichts damit zu tun, daß ein und dasselbe Register> durch die Optimierung nacheinander für mehrere Variablen genutzt> werden kann. Vielmehr verhindert volatile, daß eine Variable> überhaupt in einem Register gepuffert wird zwecks> Beschleunigung.
Das stimmt so nicht. Volatile hat nichts mit Registern zu tun, sondern
bedeutet, dass der Compiler keinerlei Annahmen über die Variable machen
darf. Der Compiler muß also davon ausgehen, dass sich die Variable
jederzeit außerhalb seiner Kontrolle ändern könnte.
Je nach Architektur legt man beispielsweise Speicher von
Memory-Mapped-HW gerne auf volatile Variablen.
Eine Codestückchen wie dieses:
hdlc_controller_txflag = 1; /* start transmission */
delay_us(100); /* after this time flag should be cleared hy HW */
if(hdlc_controller_txflag) {
notify_error(TXFLAG_STUCK); /* controller hangs */
}
Läuft Gefahr, dass der Compiler (Optimzier) ohne volatile für
hdlc_controller_txflag messerscharf schließt:
"Variable wird gesetzt, durch delay_us() mit Sicherheit nicht verändert
- wozu im nächsten Befehl prüfen, ob die Variable immer noch gesetzt
ist. Wer hätte sie auch löschen sollen?"
Nach dem Optimzier (ohne volatile) sieht der Code dann so aus:
hdlc_controller_txflag = 1; /* start transmission */
delay_us(100); /* after this time flag should be cleared */
notify_error(TXFLAG_STUCK);
Aus Compilersicht völlig legitim - woher soll der Compiler wissen, dass
noch jemand anders (out of scope) auf dieser Variablen arbeitet.
Wenn eine volatile-Variable aber beispielsweise als call-by-value in
einer Funktion landet, dann steht es dem Compiler frei, den Wert vor dem
Funktionsaufruf in ein Register zu kopieren und zu übergeben (je nach
ABI).
Gruß,
Bernd
Bernd O. schrieb:
> Klaus Wachtler schrieb:>> gut, das hat aber nichts damit zu tun, daß ein und dasselbe Register>> durch die Optimierung nacheinander für mehrere Variablen genutzt>> werden kann. Vielmehr verhindert volatile, daß eine Variable>> überhaupt in einem Register gepuffert wird zwecks>> Beschleunigung.> Das stimmt so nicht. Volatile hat nichts mit Registern zu tun, sondern> bedeutet, dass der Compiler keinerlei Annahmen über die Variable machen> darf. Der Compiler muß also davon ausgehen, dass sich die Variable> jederzeit außerhalb seiner Kontrolle ändern könnte.
.. und der Compiler kann sie deshalb zwangsläufig nicht in
einem Register halten.
Du hast natürlich Recht, daß volatile erstmal nichts direkt mit
Registern zu tun hat.
Aber daß eine volatile-Variable nicht in einem Register landet,
ist eine zwangsläufige Folge.
Ich hatte ich insofern ungenau ausgedrückt, daß eine
volatile-Variable natürlich in ein Register kopiert werden kann
(für andere Zwecke).
Aber der nächste Zugriff auf die Variable wird wieder auf das
RAM zugreifen, und nicht auf die Kopie im Register.
(Letztlich wollte ich aber auf etwas anderes hinaus, nämlich daß
volatile nichts mit dem Umstand zu tun hat, daß gelegentlich
ein und dasselbe Register nacheinander für mehrere Variablen
verwendet werden kann.)
> ...> Wenn eine volatile-Variable aber beispielsweise als call-by-value in> einer Funktion landet, dann steht es dem Compiler frei, den Wert vor dem> Funktionsaufruf in ein Register zu kopieren und zu übergeben (je nach> ABI).
Natürlich, aber dann steht nicht die Variable im Register, sondern
eine Kopie davon, und die ist ja nicht volatile.
Die Variable selbst liegt wie sonst auch im RAM und wird bei ihrer
nächsten Verwendung von dort geholt und nicht aus der Kopie im
Register oder sonstwo.
>>> Gruß,> Bernd
Hallo,
also da bin ich nochmal. Zurück zum Thema...
Im gesanten Code gibt es nur eine einzige Zuweisung für diese Variable,
die sie durch die eingebaute Bedingung NUR ERHÖHEN könnte
(Maximum-Tracer):
if ( BDStableFailureByte > BDHighestFailureByte )
{ BDHighestFailureByte = BDStableFailureByte; }
Ein Reset gibt es ja nur am Anfang von main, bei den
Variablen-Deklarationen:
unsigned char BDHighestFailureByte = 0x00;
Durch charakterisches Blinken am Anfang von main habe ich jetzt
rausgekriegt, dass mein Programm NICHT immer wieder von neu gestartet
wird. Trotzdem beobachte ich eine Erniedrigung des BDHighestFailureByte,
sie geht mit BDStableFailureByte mit. Und immer weiss ich noch nicht
warum...
Grüße
Michal
Wie voll ist dein Speicher? Kann es sein, das bei Funktionaufrufen der
Stack bis in deinen Variablenbereich wächst, und so Variablen
überschrieben werden?
Gast
Hallo,
mein Speicher ist nur mit 8 % (Programm) und 0,2 % (Data) voll.
Die & und | habe alle auf && und || geändert.
Bin jetzt in der Arbeit, stelle dann das neue Code von zuhause rein.
Grüße
Michal
Das mit Codeformatierung und Variablennamen ist wie so vieles
Geschmackssache, solange du nicht in einer SW Gruppe arbeitest, wo es
extra Codingconventions gibt ist es im Prinzip dir überlassen wie du
deinen Code Formatierst, solange DU damit gut zurecht kommst. Allerdings
haben sich für verschiedene Sprachen unterschiedliche Stile eingebürgert
(C, C++, Java, ...) und es kann nicht schaden, wenn man sich an die
etwas anlehnt.
Etwas anderes ist es mit den Operatoren, ich meine hier die logischen
und bitweisen Operatoren. Hier ist es wichtig, dass dir der unterschied
von Anfang an klar ist, und du sie gleich immer richtig verwendest.
Sonst kommt es schnell zu Fehlern die man gerne tagelang sucht. (Auch
wenn die Vergliche im aktuellen Bsp. auch bitweise funktionieren
würden.)
Aber zurück zum eigentlichen Problem:
Wie testest du eigentlich welcher Wert in BDHighestFailureByte bzw.
CCHighestFailureByte steht? Durch deine blinkenden LEDs an Port B?
Also wenn die nur 1/3 Sekunde lang blinken und dann wieder einen neuen
Wert anzeigen, würd ich mir nicht zutrauen diesen Wert sicher erkennen
zu können. Außerdem schaltest du in Zeile 162
1
PORTB=BDSingleFailureByte;// Red LEDs at the failure bits outputs
einen Fehlerstatus(?) auf's Port B.
Der blinkt dir da auch noch zusätzlich rein.
Erhöh die Anzeigedauer mal auf 1 Sek. damit man die Werte gut erkennt
und von den Statusanzeigen unterscheiden kann.
Ich hab mal versucht dein Programm durch den Simulator zu jagen.
1) Der Compiler optimiert echt gut :-) (mit den std.Einstellungen von
AVR Studio)
Der Disassembler zeigt: Nachdem CCHighestFailureByte nirgends mehr
verwendet (gelesen) wird, wird es einfach weg optimiert. Genau das soll
ein gut optimierender Compiler auch machen! Was mich zurück zu der Frage
von oben bringt, wie debuggst du CCHighestFailureByte und
BDHighestFailureByte?
2) Probier mal das ganze unoptimiert zu testen: Compilerswitch –O0 statt
–Os
(unter AVR Studio: Menu -> Project -> Configuration Options ->
Optimization)
Dann passt das Programm allerdings nicht mehr in den Flash. Also hab ich
die Beepfunktionen auskommentiert, da die IMHO nichts zum eigentlichen
Kabeltest beitragen – nicht, dass sie nicht trotzdem für den Bug
verantwortlich sein könnten, aber das kann man dann in einem weiteren
Schritt abklären.
also die Funktionen: BeepForFail, BeepForPass und BeepForPassOrFail
auskommentieren
und auch die Zeilen:
Jetzt sollte das Programm wieder richtig compilieren und in den Speicher
passen.
Tritt der Fehler jetzt immer noch auf, liegt es an der HW, oder der
Testlogik, oder wir sind alle zu doof einen Alg.Bug in einer
Maximumsfunktion zu finden ;-)
Hast du jetzt keinen Fehler mehr, ist die HW zu 99.9% OK und die
prinzipielle Programmlogik ist damit auch verifiziert (nicht nur die
Maximumsfunktion).
Hoffe, dass hilft dir etwas weiter.
by(e)
Stephan
Hallo Stephan,
danke, ich bin sprachlos dass sich jemand die Zeit genommen hat und mein
elendige Code noch mit dem Simulator getestet hat.
Dadurch hast, nehme ich an, verstanden wie mein Kabeltester genau
gedacht ist, aus welchen Ports (und Teil-Ports) ich die Testpattern
schicke und an welchen ich sie empfange.
Ich werde mich mit Deinen wertwolle Tipps, u.a. zum Kompilator (-0s,
-00) genauer auseinandersetzen.
Was ich nicht verstehe, auch bei -0s sollte der BDHighestFailureByte
nicht wegoptimiert werden, weil er ja hier für die Entscheidung über die
Klang-Signalisierung VERWENDET wird:
if
((BDStableFailureByte<BDHighestFailureByte)|(CCStableFailureByte<CCHighe
stFailureByte))
BeepForPassOrFail ();
Es geht darum, dass **HighestFailureByte einem herausgezogenem Stecker
entspricht und das Ding bei jedem Kabel-Wechsel nicht ärgerlich piepsen
sollte.
Will Benützer z.B. einen 6-Adrigen Kabel testen, soll er die restlichen
4 Testports fix verbinden. Das Programm wird dann nach einem Ein- und
Ausstecken durch diesen Maximum-Tracer "**HighestFailureByte" lernen,
welcher Fehler einem herausrausgezogenen Stecker entspricht und dabei
nicht mehr piepsen (nur rote LEDs zeigen).
Das gefragte Blinken habe ich erst jetzt für Debugging eingeführt weil
mir diese Logik mit dem herausgezogenem Kabel eben nicht funktionieren
wollte.
Ich lege die vorherige Version bei, die TADELLOS FUNKTIONIERT, aber die
herausgezogenen Stecker noch nicht erkennt hat, zum Vergleich bei.
Vielen Dank nocheinmal
Michal
Ich kann natürlich nicht sehen, wie gut das mit dem Blinken
funktioniert, aber du solltest dir wirklich sicher sein, dass du genau
weißt wann was angezeigt wird und wie es dann zu interpretieren ist. Und
gerade wenn du Bitmuster vergleichen willst, würd ich sie mind. 3-5 Sek.
stehen lassen, um sie zur Not auch mal abschreiben zu können.
Naja, also ehrlich gesagt, hab ich die eigentliche Testfunktion nur grob
überflogen.
Ich hab's mir jetzt noch mal angeschaut, dabei sind mir folgende Sachen
aufgefallen, die aber alle nix mit deinem Maximum-Problem zu tun haben.
I/O setzen:
------------
In der Funktion TestPattern() läufst du offensichtlich alle Adern eines
10-poligen Kabels durch. Dabei verwendest du Port C sowohl als Eingang
als auch als Ausgang. Das ist vollkommen in Ordnung, nur wenn du ein
Port gemischt verwendest (sei es auch nur indirekt z.B. über UART, SPI,
etc.) musst du beim setzen der Bits etwas aufpassen.
1
PORTC=0x00&CSentUsedBitsMask;
1. 0 & irgendwas ist immer = 0
Also kannst du gleich schreiben: PORTC = 0x00;
2. Ich glaube aber, was du eigentlich machen wolltest ist: "setze alle
Bits in CSentUsedBitsMask auf 0" das funktioniert etwas anders. Du musst
nämlich aufpassen, dass du nur die Output-Bits setzt, und die Input-Bits
nicht veränderst, sonst löscht du dir event. gesetzte Pull-ups (was du
mit deinem Code gemacht hast).
Da du nicht direkt auf einzelne Bits eines Ports zugreifen kannst, musst
du das zwischenbuffern.
1
tmp=PORTC;
2
tmp&=^CSentUsedBitsMask;// alle Bits in der Maske löschen, die anderen bleiben unberührt
3
tmp|=data&CSentUsedBitsMask;// Datenbits ausmaskieren und entsprechend setzen
4
PORTC=tmp;
Dieses Konstrukt musst du auch weiter unten verwenden, bei:
1
CSentByte=0x01&CSentUsedBitsMask;
2
PORTC=CSentByte;
In LEDsFailureSignalisation() hast du wieder das gesamte Port C gesetzt.
Das mag zwar für dein Programm funktionieren, kann aber die Ursache
einer nie enden wollenden Debug-Orgie werden. Also gewöhn die ab besten
gleich an: nur die Bits angreifen, die du auch wirklich ändern willst.
1
PORTC|=(1<<PC5);// Green LED on
statt
1
PORTC=0x20;// At no failure green LED is lightning from the 00100000 from the port C
In Zeile 161 machst du das richtig:
1
PORTC&=~(1<<PC5);// Green LED off
Aber gleich drauf, setzt du wieder das gesamte PORT.
1
PORTC=CCSingleFailureByte;// Red LEDs at the failure bits
2
outputs
Fällt im konkreten Fall nicht auf, da die grüne LED sowieso auf 0 ist.
Wäre die, grüne LED jetzt aber low-active, würdest du dich wundern,
warum du einen Fehler hast, und trotzdem grün leuchtet.
Debuggen
-------------
Zum Debuggen, gennerell: Wenn es sich mit deiner HW irgendwie machen
lässt, führ die UART Schnittstelle raus und verwende irgendeinen UART
<-> USB Adapter (z.B. FTDI & Co) um Debugmeldungen an den PC zu senden.
Ich wollte mich früher auch immer davor drücken, weil du wieder mehr
Leitungen hast, dann brauchst wieder eine UART Lib (aber die gibt's ja
schon fertig), usw. Aber im Endeffekt ist dann doch bei jedem Projekt
ein UART Stecker drauf gelandet. Es lässt sich damit einfach viel besser
debuggen als mit LED Morsecode, und ab einer gewissen Komplexität bleibt
dir sowieso nix anderes mehr übrig.
Abgestecktes Kabel
------------------------
Ok, jetzt hab ich endlich verstanden, was du mit BDHighestFailureByte
eigentlich bezwecken willst :-)
Ich glaub da ist die Logik etwas suboptimal. Wenn ich dein Programm
richtig durchschaut habe, brauchst du mal 30 Testzyklen ohne Kabel nur
mit den Leerbrücken um den Kabeltyp zu lernen. Und wenn du Kabeln
wechselst, kannst du nur zu mehrpoligen wechseln, und nicht zu weniger
poligen.
Was hältst du von folgendem Vorschlag. (Der spart dir sogar die
Drahtbrücken brauchst allerdings einen Resettaster oder Ein/Ausschalter,
aber der sollte ja eh irgendwo vorhanden sein.)
1. Beim Einschalten ist ein geprüftes Masterkabel des jeweiligen Typs
angeschlossen. Das wird als Sollmuster gelernt.
2. Danach wird der Lernvorgang durch ein Piepsen oder Blinken
quittiert.
3. Jetzt kannst du Kabeln dieses Typs ganz normal testen
4. Soll ein anderer Typ getestet werden: Masterkabel d'ran, Reset bzw.
Ein-Aus; goto 1
Umsetzung:
1. Pullups wieder einschalten
2. Vor der Hauptschleife das aktuelle Muster lernen. Eine Maske
erstellen, die gleich dem invertierten Muster ist.
3. in der Hauptschleife alle Fehler mit der Maske ausmaskieren.
Ups, das mit dem Optimieren hab ich jezt ganz vergessen.
Du hast natürlich recht, ich hab bei mir alle Beep-Funktionen
ausgeklammert, daher war auch dir Abfrage nicht drinnen und somit wurde
BDHighestFailureByte
weg optimiert.
Wenn ich's mit deiner Originalversion durch den Dissassambler schicke,
bleicht BDHighestFailureByte auch als Register erhalten.
by(e)
Stephan