Hallo Experten,
ich habe wieder mal eine PIC-Frage! Ist nicht ganz einfach zu erklären, ich versuchs dennoch: ich bastle wieder mal ein neues Produkt, so ähnlich wie mein altes. Das läuft bei mir seit etwa 8 Jahren problemlos. Und weil ich „quick-and-dirty“ programmiere, hab ich das einfach 1:1 übernommen. Nur spinnt das Teil jetzt völlig. Ich habe im Interupt eine Uhr eingebaut. Wenn ich das Teil starte, klappt das mit der ersten Sache, ein 200-mS-Interupt supi. Dann solls in die zweite Stufe gehen, bis 10 zählen und dann wieder auf 0 und weiter.
Aber genau hier fängts an. Obwohl im Programm definitiv drin steht - bei 10 wieder auf 0 - zählt der trotzdem weiter bis 16.
Das geht dann so etwa 10, 15 oder 20 mal so. Dann hat er es entlich begriffen.
Jetzt die zweite Stelle - soll bis 6 Zählen. Aber auch hier wieder das Gleiche.
Habe jetzt schon dreimal das Ding über Nacht laufen lassen. Dann läufts, aber mit der falschen Zeit.
Ich hab noch drei Haare zum rausreisen!
Hat irgend wer von Euch eine Idee?
Schon im Voraus Danke für jeden Tip!
Grüße, jo_enn
Hallo jo_enn
Da müsste ich in den Code schauen können um Dir ev. zu helfen.
Auch müsste ich einen Schema-Auszug haben, wo die PIC-Belegung und der Interruptteil sichtbat ist.
Gruss Walter
Hallo jo_enn,
Du solltest angeben für welchen PIC das Programm war und auf welchem es jetzt laufen soll.
Und das Programm selbst wäre auch wichtig!
MfG Peter(TOO)
Hallo,
Aber genau hier fängts an. Obwohl im Programm definitiv drin
steht - bei 10 wieder auf 0 - zählt der trotzdem weiter bis 16.
eine grundsätzliche Sache, die man beim Programmieren beachten sollte.
Nicht auf Zähler = 10 testen, sondern besser auf Zähler > 9
Das erhöht die Zuverlässigkeit deutlich.
So werden Probleme vermieden, die z.B. durch Rundungsfehler und „unpraktische“ Zahlenformate entstehen.
Eine angezeigte 10 kann evtl. intern eine 10,000000001 sein und schon hast du ein Problem.
Gruß Uwi
Hallo Jo_enn,
programmiere, hab ich das einfach 1:1 übernommen.
gleicher Takt, gleiche leistungklasse der pics?
Ich habe im Interupt eine Uhr eingebaut … ein 200-mS-Interupt
vorher auch 200ms?
und jedes fünfte mal zählst Du 1 Sekunde rauf?
Neben Uwis Hinweis könnte ich mir vorstellen
- Interruptzeit zu klein (z.B. weil jetzt mehr Register gesichert werden, mehr gemacht wird oder sonstwie anderes Timing)
- die Zahl wird in Interrupt und normalprogramm gesetzt (asynchrones Schreiben)
Frage. Was macht denn die zweite Zahl? Da Du „16“ schriebst, nehme ich an Du arbeitest mit Nibbeln, bei 16 springts auf 0. Wann (und durch wen) ändert sich denn die 10er Stelle, wenn die Einer-stelle „Durchläuft“? garnicht, bei 10 oder beim durchlauf?
Und falls nibble, bist Du sicher, dass Du beim Vergleich auch nur das nibble und nicht das Byte auf „10“ vergleichst?
Gruß
achim
Hallo,
es wurde ja bereits alles Wesentliche gesagt. Ergänzend kann ich noch anmerken, dass viele derartige Fehler dadurch entstehen, dass Register und RAM-Variablen nicht richtig initialisiert bzw. gelöscht werden. Der Programmablauf kann dann je nach zufälligem Inhalt eines Registers variieren. Werden die Register nach dem Interrupt richtig wiederhergestellt? Quick & dirty birg natürlich immer die Gefahr, dass man am Ende viel mehr Zeit mit Fehlersuche verbringt, als man beim unsauberen Programmieren gespart hat.
Jörg
Hallo jo_enn,
irgendwie kommt mir das Ganze bekannt vor.
Schreib doch mal auf, was das Programm (oder das neue Gerät) tun soll. Dann wäre der PIC-Typ, die Schaltung mit den Anzeige-Elementen und schließlich Dein Programm wichtig, uns mitgeteilt zu werden. Andernfalls müssten wir versuchen, die Lösung in der Kristallkugel zu finden. Das hat dann allerdings nichts mehr mit Elektronik zu tun!
Viele Grüße von Ph33
Hallo Walter,
danke erst mal für Deine Antwort.
Da müsste ich in den Code schauen können um Dir ev. zu helfen.
Auch müsste ich einen Schema-Auszug haben, wo die PIC-Belegung
und der Interruptteil sichtbat ist.
Ich versuche mal den Code hier rein zu bringen:
;********************************
org 4
isr
movwf w_temp
swapf STATUS,w
clrf STATUS ; ISR - ROUTINE EIN
movwf status_temp
movf PCLATH,w
movwf pclath_temp
clrf PCLATH
;---------------------------------------------
movlw .96 ;Teiler setzen
movwf TMR0
incf _5ms
movf _5ms,w
xorlw .200 ;volle Sekunde erreicht?
btfss STATUS,Z
goto uhr1 ;nein
clrf _5ms ;ja, zurück auf 0 stellen
incf _01s ;Sekunde inkrementieren
decf zahl
movf _01s,w
xorlw .10 ;volle Minute erreicht?
btfss STATUS,Z
goto uhr1 ;nein
clrf _01s ;ja, zurück auf 0 stellen
incf _10s
movf _10s,w
xorlw .6 ;volle Minute erreicht?
btfss STATUS,Z
goto uhr1 ;nein
clrf _10s ;ja, zurück auf 0 stellen
incf min01 ;Minute inkrementieren
movf min01,w
xorlw .10 ;Minuteneiner = 10?
btfss STATUS,Z
goto uhr1 ;nein
clrf min01 ;ja, zurück auf 0 stellen
incf min10 ;Minutenzehner inkrementieren
movf min10,w
xorlw .6 ;=6?
btfss STATUS,Z
goto uhr1 ;nein
clrf min10 ;ja, zurück auf 0 stellen
incf std01 ;Stundeneiner inkrementieren
movf std01,w
xorlw .4 ;=4? (evtl. Mitternacht?)
btfss STATUS,Z
goto uhr2 ;nein!
movf std10,w
xorlw .2 ;=2? (wirklich nicht?)
btfss STATUS,Z
goto uh2 ;nein!
clrf std01 ;DOCH
clrf std10 ;es ist 00:00
; --------------------------------------------------
;hier Gangkorrektur!
incf min01 ;Korrektur Tageszeit
incf min01
incf min01
movlw .36
movwf _01s ;+ 3min 36s pro Tag
uhr2
movf std01,w ;ansonsten
xorlw 0ah ;Stundeneiner=10?
btfss STATUS,Z
goto uhr1 ;nein!
clrf std01 ;ja, dann wieder 0
incf std10
uhr1
; --------------------------------------------------
movf pclath_temp,w
movwf PCLATH
swapf status_temp,w
movwf STATUS ; ISR - ROUTINE AUS
swapf w_temp,f
swapf w_temp,w
bcf INTCON,2
retfie
;***************************************************
So, auch wenn’s nicht so sauber rüberkommt, aber immerhin siehst Du erst mal etwas, die Interruptroutine.
Vielleicht hilft das schon weiter.
Ach so, ich verwende immer noch bzw. wieder den PIC16F877, der Quarz ist ein 4,096 MHz. Also alles so wie es schon bei der ersten Version war. Nur eben die Startschwierigkeiten. Habe das Ganze auch mit verschiedenen PICs versucht, weil ich dachte, es liegt am PIC. Ist aber bei allen das Gleiche.
Erst mal Danke und Grüße, jo_enn
Hallo Peter(TOO),
Du solltest angeben für welchen PIC das Programm war und auf
welchem es jetzt laufen soll.Und das Programm selbst wäre auch wichtig!
Hast Recht: also der PIC ist wieder ein 16F877 und das Programm, jedenfalls die Interruptroutine siehst Du ein paar Zeilen tiefer bei der Antwort von Walter.
Bis später, Grüße, jo_enn
Hi Uwi,
Aber genau hier fängts an. Obwohl im Programm definitiv drin
steht - bei 10 wieder auf 0 - zählt der trotzdem weiter bis 16.eine grundsätzliche Sache, die man beim Programmieren beachten
sollte.
Nicht auf Zähler = 10 testen, sondern besser auf Zähler > 9
Das erhöht die Zuverlässigkeit deutlich.
So werden Probleme vermieden, die z.B. durch Rundungsfehler
und „unpraktische“ Zahlenformate entstehen.
Eine angezeigte 10 kann evtl. intern eine 10,000000001 sein
und schon hast du ein Problem.
Danke für Deinen Tip, aber ich muss sagen, ich programmiere unter Assembler, und da kommt so was nicht vor.
Trotzdem nochmals Danke für Deine Bemühungen. Grüße, jo_enn
Hallo Achim,
programmiere, hab ich das einfach 1:1 übernommen.
gleicher Takt, gleiche leistungklasse der pics?
Ich habe im Interupt eine Uhr eingebaut … ein 200-mS-Interupt
vorher auch 200ms?
und jedes fünfte mal zählst Du 1 Sekunde rauf?
Genau!
Neben Uwis Hinweis könnte ich mir vorstellen
- Interruptzeit zu klein (z.B. weil jetzt mehr Register
gesichert werden, mehr gemacht wird oder sonstwie anderes
Timing)- die Zahl wird in Interrupt und normalprogramm gesetzt
(asynchrones Schreiben)Frage. Was macht denn die zweite Zahl? Da Du „16“ schriebst,
nehme ich an Du arbeitest mit Nibbeln, bei 16 springts auf 0.
Wann (und durch wen) ändert sich denn die 10er Stelle, wenn
die Einer-stelle „Durchläuft“? garnicht, bei 10 oder beim
durchlauf?
Ja, genau da liegt ja mein Problem: ich habe das gleiche Programm schon seit etwa 8 Jahren auf einem gleichen PIC (16F877) und mit gleicher Frequenz: 4,096 MHz.
Und falls nibble, bist Du sicher, dass Du beim Vergleich auch
nur das nibble und nicht das Byte auf „10“ vergleichst?
Ich habe das Programm ja „quick-and-dirty“ übernommen.
Was ich nicht begreife, nach 10 - 15 - 20 Durchläufen bis zur 16 springt „er“ plötzlich auf das richtige. Aber dann geht’s in der nächsten Sache wieder genauso weiter.
Die Interruptsache steht bei Walter, paar Zeilen weiter unten, drin.
Erst mal Danke, jo_enn
Hallo Ph33,
klar kennen wir uns schon!
irgendwie kommt mir das Ganze bekannt vor.
Völlig klar!
Schreib doch mal auf, was das Programm (oder das neue Gerät)
tun soll. Dann wäre der PIC-Typ, die Schaltung mit den
Anzeige-Elementen und schließlich Dein Programm wichtig, uns
mitgeteilt zu werden.
Also die Interruptroutine steht ja schon bei Walter, paar Zeilen weiter unten.
Der PIC ist ein 16F877 und wird mit 4,096 MHz getaktet. Also exakt genau wie das Vorgängermodell. Und da läuft es schon seit etwa 8 Jahren problemlos.
Und da liegt ja das Problem. Ich habe sogar schon die PICs beide neu programmiert und getauscht, aber der „Fehler“ bleibt beim neuen. Ich begreifs einfach nicht.
Andernfalls müssten wir versuchen, die
Lösung in der Kristallkugel zu finden. Das hat dann allerdings
nichts mehr mit Elektronik zu tun!
Die hab ich mittlerweile rüber in den Wald getragen =8o)
Also nochmals Danke, jo_enn
Hallo Jörg,
Ist ja schon alles gesagt, trotzdem Danke für Deine Antwort!
Grüße, jo_enn
hallo.
Ich hab noch drei Haare zum rausreisen!
nichts gegen assembler, benutze ich selbst noch hin und wieder, auch auf größeren maschinen.
aber vielleicht solltest du wenigstens ein haar übrig lassen, um C zu lernen.
das ist zwar etwas initialaufwand, spart unterm strich aber doch enorm viel arbeitszeit. vor allem wenn’s drum geht, sich in jahre alten code reinzufinden.
die compiler sind bezahlbar/kostenlos und mittlerweile auch richtig gut.
gruß
michael
Spoiler: Und der Preis gebührt Uwi!
Hallo jo_enn,
Uwi wies darauf hin, auf >9 statt ==10 zu vergleichen. Das gilt auch für assembler, schreibt sich dort nur anders.
Wenn Du _01s einen Wert von z.B. 36 zuweisst,
UND von dieser Zahl nur die unteren 4 Bit auswertest und anzeigst,
DANN wird die Zahl 14 * bis 16 laufen und dann erst funktionieren.
Gruß
achim
Hallo Achim,
Uwi wies darauf hin, auf >9 statt ==10 zu vergleichen. Das
gilt auch für assembler, schreibt sich dort nur anders.
danke für diesen Tip, werde ich gleich mal ausprobieren.
Nur weiss ich noch nicht wie das in Assembler gehen soll. Und wieso es im anderen Teil seit Jahren problemlos lief. Habe ja schon 16 mal, immer wegen der sch*** Zeitumstellung, gemacht.
Wenn Du _01s einen Wert von z.B. 36 zuweisst,
UND von dieser Zahl nur die unteren 4 Bit auswertest und
anzeigst,
DANN wird die Zahl 14 * bis 16 laufen und dann erst
funktionieren.
Ich melde mich wenns klappt!
Grüße, jo_enn
Hallo jo_enn,
Du machst XOR und vergleichst ob Z gesetzt ist --> beide gleich?
Alternativ SUBLW oder SUBWF, also Subtraktion und C und DC abfragen --> größer bzw. kleiner.
Gruß
achim
Hallo jo_enn,
in Deiner isr fragst Du STATUS,Z ab. Das ist beim ersten Mal o.k., da Du STATUS gelöscht hattest. Bei den weiteren Abfragen solltest Du vorher bcf STATUS,Z ausführen.So mache ich das.
Viele Grüße von Ph33
Hi achim,
Du machst XOR und vergleichst ob Z gesetzt ist --> beide
gleich?
Genau das mache ich ja, trotzdem macht „er“ erst mal 15 volle Durchläufe.
Danach gehts. Aber das macht „er“ bei allen, also einer Sekunden, zehner Sekunden, einer Minuten, … das nervt unheimlich.
Ich weiß einfach nicht weiter.
Dennoch Danke, jo_enn
Hallo jo_enn,
Du machst XOR und vergleichst ob Z gesetzt ist --> beide
gleich?Genau das mache ich ja, trotzdem macht „er“ erst mal 15 volle
Durchläufe.
Ähm, und darum solltest Du doch mal die von Uwi vorgeschlagene, und von mir konkretisierte Alternative, nämlich vergleich auf >9 (durch subtraktion und übewachung des Carry-Flags) ausprobieren.
Zudem ist mir noch immer nicht klar, was beim Durchlaufen passiert.
Wenn die Einer durchlaufen, incrementieren die 10er dann
- garnicht?
- bei jedem Sprung von 9 auf 10?
- bei jedem Sprung von 15 auf 0?
Wenn die Einer durchlaufen korrelliert das mit dem Durchlaufen der Zehner, oder fängt das immer irgendwie an und kommt dann nicht wieder?
Soviel Spaß das Raten auch macht, wenn Du den aus diesem Grunde auch weithin üblichen Vergleich auf > statt == einfügst, ist das Problem verschwunden! Um sich keine Gedanken über Vorzeichen zu machen, ist die robustere Abfrage natürlich, ob der Zähler im Bereich 0…9 liegt, sonst --> 0.
gruß
achim