PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : bräuchte hilfe zu sporadischen fehlern



Lazareth
20.11.2009, 11:29
Morgen leute!!!!

also, ich fang am besten mal von vorne an. Ich habe für meinen vater und dessen Hühner eine automatische klappe gebastelt, die auf Helligkeit reagiert und die Klappe entsprechend bewegt. hat seit rund 2 monaten alles wunderbar funktioniert, kein huhn war bisher unter der klappe o.ä.
nun seit geraumer zeit, macht die klappe allerdings komische gestalten. Immer (nicht immer, geht mal 2-5 tage gut, aber immer in der herabbewegung) beim herabfahren, reagiert der ATmega8 nichtmehr. der motor dreht munter weiter und nur ein ausschalten der schaltung bringt diesen zum stoppen. Ich hab mittlerweile den µC, den LDR und die komplette Schaltung getauscht, ohne erfolg.

zum aufbau am besten mal ein Schaltplan:
http://img44.imageshack.us/img44/4396/huehnerklappe.png
ich denke, die anschlussbelegung sollte klar sein, Motor, LDR und Endschalter als abschaltende begrenzung.

zum Programm:
ich erkläre mal kurz, was ich mir dabei gedacht habe :)
also, ich setze den C für rund 4 min schlafen, und überprüfe dann den Spannungswert am ADC. sollte eine änderung eingetreten sein, wird entsprechend reagiert.
haupt:
in "haupt" wird die Spannung abgefragt und bei einer änderung entsprechend verzweigt.
slep:
legt den C für 4 min schlafen.
auf/ab:
setzt die ausgänge entsprechend fürs hinauf/abfahren und wartet bis ein schalter auslöst oder die zeit für die bewegung beendet ist (sicherheit).
entprellen:
entprellt die mechanischen Endschalter. hierfür wird auch die software-warteschleife ms10 benötigt.
zeitaktiv_auf/ab:
hier wird der Timer gesetzt, solange die bewegung maximal dauern darf (für hoch und runter unterschiedliche zeiten, weil der auffahren länger dauert)
timer0:
ist die reaktion auf die abgelaufene zeit ( ausgänge abschalten, und timer rücksetzen)

daher kommt auch meine annahme das der µC abschmiert, weil er weder auf die zeit, noch auf die endschalter reagiert. und die ausgäng bleiben tatsächlich bis zum abschalten gesetzt, ich habe entsprechend LED´s dran gelötet.
habe das programm nun schon nach nem überlaufenden stack hin untersucht, leider nichts gefunden. vielleicht schaut mal schnell ein profi drüber ob er einen fehler findet, bzw. ob er eine andere vermutung hat.
ich danke deshalb schonmal im voraus für eure hilfe, bin gerade leicht am verzweifeln =P



.equ zeit = 1700 ;für die MS10 routine, 10ms warteschleife
.equ schleife_durch = 10 ;10 ;für entprellroutine durchläufe
.equ schleife_sleep = 4 ;4 ;schleifendurchläufe für timer. 1 durchlauf = 67 sekunden.
.equ slep_tcnt_vorladen = 1 ;zum vorladen des register tcnt des timers 1, um feiner abstufungen zu erreichen. Normal=0
.equ adc_wert = 130 ;100 ;vergleichswert für adc und lichtsensor
.equ Zeit_hochfahren = 33 ;33 ;Wert zur einstellung der Zeit, die für das hochfahren der klappe verantwortlich ist.
.equ Zeit_runterfahren = 24 ;24 ;wert zur einstellung der Zeit für das Herunterfahren
;4 => 1 sec. (1zyklus = 261,1 ms)

; = 4.22V am LDR = 21.14Uhr am 24.07.09
; 4.66V am LDR = 21.23Uhr
; differenz rund 0.44 V

;***definitionsdatei***

.include "m8def.inc"

;***interrupt adressen***

.org 0x000 rjmp reset ;Programm start
;.org 0x001 rjmp stop ;Näherungsschalter
;.org 0x002 rjmp aus ;Interrupt schalter
.org 0x008 rjmp timer ;Timer für sicherheit, wird aktiviert nach dem schalten der ausgänge
.org 0x009 rjmp timer0 ;Timer0 für das hoch/runterfahren der tür

; Stack initialisieren
reset:
ldi r16, LOW(RAMEND)
out SPL, r16
ldi r16, HIGH(RAMEND)
out SPH, r16

;Ein/Ausgänge konfigurieren

ser r16 ;ausgang
out DDRB, r16
clr r16 ;Eingang
out DDRC, r16
out DDRD, r16

;sleep mode aktivieren

ldi r16, 0b10000000; 0b10001111
out MCUCR, r16
;ldi r16, 0b00000001
;out GICR, r16

;variable für ersten durchlauf ins register kopieren
ldi r16, 1
mov r2, r16

sei ;interrupts frei

Haupt:

;ADC konfig, ADC0

ldi r16, 0b01100000
out admux, r16
ldi r16, 0b11000011
out adcsra, r16
adcrun:
in r10, adcsra
sbrc r10, 6
rjmp adcrun

;adc werte in reg. schreiben

in r17, ADCL
in r18, ADCH

;ACHTUNG, unteren WERT ebenfalls ändern
cpi r18, adc_wert ;hier einstellwert für sreg
in r16, SREG ;SREG speichern
andi r16, 0b00000001
mov r1, r16
eor r1, r0
mov r0, r16
sbrc r2, 0
rjmp erstedurchgang
breq slep
;ACHTUNG, oberen Wert ebenfalls ändern
cpi r18, adc_wert ;hier einstellwert
brlo ab1 ;hier tor zu
brsh auf1 ;hier tor auf
rjmp slep
;unterprogramme

slep: ;schlafen legen, und alle 10 min wieder wecken
ldi r16, 0b00000101 ;teiler
out TCCR1B, r16
ldi r16, 0b00000100
out TIMSK, r16
ldi r30, schleife_sleep ;schleifendurchläufe für wartezeit
clr r31
slep1:
;wdr ;watchdog reset
ldi r16, low(slep_tcnt_vorladen) ;63535 ins register laden = 2 sekunden
ldi r17, high(slep_tcnt_vorladen)
out TCNT1H, r17
out TCNT1L, r16
sleep
nop
tst r30
brne slep1
rjmp haupt

erstedurchgang:

clr r2
rjmp haupt

auf1:
ldi r16, 0b00000101
out PORTB, r16
rcall zeitaktiv_auf ;Timer1 für Sicherheitszeit aktivieren
;warten bis schalter betätigt
warten1:
sbrc r31, 0 ;wenn timer1 interrupt fahrt beendet
rjmp slep ;dann springt wieder nach slep zurück
in r16, PIND
sbrc r16, 3
rjmp entprellen
rjmp warten1

ab1:
ldi r16, 0b00000110
out PORTB, r16
rcall zeitaktiv_ab ;Timer1 für Sicherheitszeit aktivieren
;warten bis schalter betätigt
warten2:
sbrc r31, 0 ;wenn timer1 interrupt fahrt beendet
rjmp slep ;dann springt wieder nach slep zurück
in r16, PIND
sbrc r16, 2
rjmp entprellen
rjmp warten2

;entprell routine
entprellen:
push r16
ldi r17, schleife_durch ;schleifendurchläufe
in r16, PIND
mov r3, r16
aus1:
in r16, PIND
mov r2, r16
eor r2, r3
mov r3, r16
push r16
rcall ms10
pop r16
dec r17
tst r17
brne aus1
sbrc r16, 3
rjmp aus2
sbrc r16, 2
rjmp aus2
rcall ms10
clr r17
pop r16
rjmp slep
aus2:
clr r16
clr r17
clr r19
out PORTB, r16
out TCCR0, r16 ;timer deaktivieren
out TCNT0, r16 ;timer0 zählregister nullen
pop r16
rjmp slep

;timer0 fürs bewegen der Tür aktivieren
zeitaktiv_auf:
;r29 zum herunterzählen beladen.
ldi r29, zeit_hochfahren
ldi r16, 0b00000101 ;teiler
out TCCR0, r16
ldi r16, 0b00000001 ;interrupt starten
out TIMSK, r16
ret
zeitaktiv_ab:
;r29 zum herunterzählen beladen.
ldi r29, zeit_runterfahren
ldi r16, 0b00000101 ;teiler
out TCCR0, r16
ldi r16, 0b00000001 ;interrupt starten
out TIMSK, r16
ret


;***********Warteschleife*********

ms10: ;taster entprellen
;wdr
push r17
push r18
ldi r16, low(zeit)
ldi r17, byte2(zeit)
ldi r18, byte3(zeit)
ms101:
subi r16, low(1) ;1 Takt
sbci r17, byte2(1) ;1 Takt
sbci r18, byte3(1) ;1 Takt
sbrs r18, 0 ;1 takt
breq ms102 ;
rjmp ms101 ;2 takte
ms102:
pop r18
pop r17
ret


;*************************interrupt handler***************************
;sleep-timer, 16 bit
timer:
dec r30
reti

;nach abgelaufener zeit motor aus, timer0, 8bit
timer0:
dec r29
tst r29
breq timer0_stop
reti
timer0_stop:
push r16
clr r16
out PORTB, r16
out TCCR0, r16
out TCNT0, r16
sbr r31,1
pop r16
reti

Rofo88
20.11.2009, 11:42
Ohne das Programm zu sehr angeschaut zu haben : Wenn das nur passiert wenn der Motor lauft : brown out dedector und Watchdog aktivieren....kann nen Programmfehler nicht verhindern aber verhindert das sich der µC aufhängt

Was hat das Ding für ne Spannungsversorgung? Batterien?

Besserwessi
20.11.2009, 11:44
Bei der Schaltung ist die Versorgung von AVCC (Pin20) falsch:

Hier sollte AVCC direkt mit VCC verbunden sein, also auch +5 V vom Regler kriegen. Dazu noch ein 2 ter Enkoppelkondensator.

Der Widerstand R2 ist ganz fasch, der zieht noch extra Strom aus dem Pin. Der Kondensator C5 ist so auch eher Schädlich, denn Störungen vor dem Regler werden so nach AVCC eingekoppelt. Der Kondensator gehört da hin wo R2 ist.

Gerade beim Mega8 kann das so gut gehen, muß es aber nicht.

An die Versorgung vor den Regler gehört noch ein Elko. Je nach Motor wären so etwa 1000-2200 µF angebracht.
Wenn der Motor stark stört, wäre ein extra RC Glied (z.B. 100 Ohm, 100 µF) vor dem Spannungsregler angebracht, ggf. statt dem Widerstand auch eine Diode.

EDIT:
Bei der Software ist auch noch ein Fehler drin:
Bei den Interrupts muß man noch das Status-register (SREG) retten. Wenn man das nicht mancht, kann man leicht selten Auftretende Fehler bekommen, weil gelegentlich das Hauptprogramm nicht so läuft wie es soll, weil sich unerwarte das Statusregister ändert. Auch mit den anderen Registern muß man ggf. aufpassen, daß man nicht Registser verändert, die auch im Hauptprgramm benutzt werden für etwas anderes als ein "globale Variable".

Lazareth
20.11.2009, 11:47
hmm, ich habe versuche mit dem wdr durchgeführt, allerdings bei 4 min wartezeit wieder vorworfen, weil ich es nicht hinbekommen habe.
aber wenn ich den wdr nur bei einer bewegung starte, könnte es funktionieren. danke, ich werds mal ausprobieren.
@ besserwessi:
meinst du so?
http://img9.imageshack.us/img9/2203/huehnerklappe2.png

und was ich noch vergessen habe zu sagen.
ich habe vor 4 tagen einen 50kohm widerstand parallel zum LDR gesetzt, da der ldr bei dunkelheit im bereich von 1 Mohm war und mein poti (mit aktuell 50kohm) gnadenlos zu klein war und die einstelllung sehr darunter litt.
seitdem ging es dann auch wieder etwas besser, 3 tage, dann war wieder alles shice.

gruß

Besserwessi
20.11.2009, 13:39
Schon besser die Schaltung.
Noch C6 duch einen Widerstand unter 100 Ohm oder eine Induktivität ersetzen, dann ist es gut.

Ich sehe gerade: der LDR geht am 12 V , das ist auch nicht so gut. Besser wäre es den LDR an die stabilen 5 V zu klemmen. Der Widerstand am LDR sollte nichts mit dem eigentlichen Problem zu tun haben. Wenn der Poti zu klein ist, dann halt ein Widerstand in Reihe zum Poti.

Sollen unten die 12 V wirklich an den ISP Anschluß ? Das ist ganz und gar nicht gut !

Lazareth
20.11.2009, 13:46
nein, natürlich nicht. das mit den 12 V hab ich auf dem plan total vermurkst. effektiv hängt nur der motor und der regler an den 12V, der rest (alles was mit dem C zu tun hat) an den 5V.
aber kann die falsche beschaltung des ADC den C durcheinander bringen?
ich werde am wochenende mal den tipp von Rofo umsetzen und nocheinmal probieren.

Besserwessi
20.11.2009, 14:08
Der Anschluß AVCC ist nicht nur für den ADC. Ein falsche Spannung da kann den ganzen µC blockieren und im schlimmsten fall sogar zerstören.


Was man auf alle Fälle ändern sollte, ist die Interruptsroutine im Programm. Ein nicht gesichertes SREG führt gerade zu eher seltenen und schwer zu findenden Fehlern

Lazareth
20.11.2009, 20:01
du meinst also, ich soll das SREG in den Interruptdingern speichern und wieder laden?

Besserwessi
20.11.2009, 20:28
Das sichern des SREG in einer ISR ist absolut standart und fast ein muß, vor allem für Anfänger. Es gibt nur ganz wenige Ausnahmen wo es auch mal ohne geht.
Hier werden je nur wenige Register benutzt und es reicht das SREG in einem dafür reservierten Register zu speicher.

Lazareth
22.11.2009, 17:31
so, kleine zwischenmeldung:
habe die änderungen nun so vorgenommen, bis auf den Watchdog, der hatte irgendwie nicht funktioniert. auf jeden fall speichere ich aber das SREG in den ISR. heute hats funktioniert, mal sehen obs das morgen auch noch so tut, ich werde berichten.
danke nochmal für deine/eure hilfe.

Lazareth
21.12.2009, 21:22
hat nach 5 tagen rumspielerei nicht funktioniert. da ich nun wichtigeres zu tun habe, hab ich auf gekaufte hardware zurückgegriffen :)