Forum: Mikrocontroller und Digitale Elektronik Alarmanlage mit ATMEGA8L


von Sebastian F. (25sebi05)


Lesenswert?

Hallöchen, ich bin sehr neu in diesem Forum und generell wenn es um C 
Programmierung und Mikrocontroller geht.
Ich bin seit 2014 im ersten Ausbildungsjahr als Ssyteminformatiker, habe 
vorher noch nie Programmiert, und soll eine kleine "Alarmanlage bauen", 
da die Raucher in unserem Gebäude (mehrere Firmen) ständig die Türen 
offen lassen obwohl dies untersagt ist.
Grundaufbau: Ich hab einen Magnetschalter, einen Summer, eine LED, und 
einen ATMEGA8L, Stromzufuhr sind 3* AA Batterien.

Prinzip ist die Tür ist geschlossen, der Magnetkontakt liegt an und der 
Controller soll in den PWR_DOWN Modus versetzt werden.
Wird die Tür geöffnet, beginnt ein Timer(zum überprüfen habe ich immer 
mal die Zeitabstände verändert), und wenn die Tür nicht rechtzeitig 
schließt dann werden der Summer und die LED für eine bestimmte Zeit 
angeschalten.
Damit der Stromverbrauch nicht zu hoch ist sollen diese nach einer Zeit, 
auch wenn die Tür noch offen steht, abgeschaltet werden und der 
Controller in PWR_DOWN versetzt werden.
Das eigentliche Programm steht, aber die Sleep-Modi machen mir zu 
schaffen-.-
Nachdem der Summer und die LED abgeschaltet werden fährt der Controller 
in PWR_DOWN, jedoch nicht wenn die Tür geschlossen wird.
Dass bereitet mir alles Kopfzerbrechen und ich soll eigentlich nächste 
Woche fertig sein...
Mein Ausbilder sagt ständig,obwohl er auch nur grundlegende Kenntnis in 
diese Richtung hat, es muss funktionieren  und wenn es nicht geht, hast 
du einen Fehler eingebaut. Er schaut aber nichtmal drüber...

Könnt ihr mir helfen?

Hier mein Code:
1
#define F_CPU 1000000
2
 
3
#include <avr/io.h>
4
#include <avr/sleep.h>
5
#include <avr/interrupt.h>
6
#include <util/delay.h>
7
 
8
// lange, variable Wartezeit, Einheit in Millisekunden
9
 
10
void long_delay(uint16_t ms) {
11
    for (; ms>0; ms--) _delay_ms(1);
12
}
13
 
14
int main (void) {
15
int i,m;
16
 
17
// IO konfigurieren
18
 
19
    DDRD = 0xFB;        // PD2 = INT0 = Eingang
20
    PORTD = 0x04;       // Pull Up aktivieren
21
 
22
// Analogcomparator ausschalten
23
 
24
    ACSR = 0x80;
25
 
26
// Interrupt konfigurieren
27
 
28
    MCUCR &= ~0x3;              // levelgesteuerter Interrupt an INT0
29
 
30
// Interrupts freigeben
31
 
32
    sei();
33
 
34
// Endlose Hauptschleife
35
 
36
    while(1) {
37
  
38
      if(PIND & (1<<PD2)){
39
    for(m=0;((!(PIND & (1<<PD2)))||m<5);m++){long_delay(1000);}
40
    
41
        i=0;
42
    while((i<5)&&(PIND & (1<<PD2))){
43
    long_delay(1000);
44
    i++;
45
    PORTD |= (1 << PD4);
46
    PORTD |= (1 << PD1);            // LED für eine Sekunde anschalten
47
        
48
             }
49
    i=0;
50
        PORTD &= ~(1 << PD4);  
51
    PORTD &= ~(1<<PD1); 
52
     _delay_ms(10);                               
53
    while((PIND & (1<<PD2))){
54
    GICR |= (1 << INT0);            // externen Interrupt freigeben
55
 
56
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
57
        sleep_mode();                   // in den Schlafmodus wechseln
58
 
59
        // hier wachen wir wieder auf
60
        GICR &= ~(1 << INT0);           // externen Interrupt sperren
61
                                       // WICHTIG! falls der externe LOW Puls an INT0
62
    _delay_ms(10); 
63
    }
64
    }
65
    
66
    else {
67
    GICR |= (1 << INT0);            // externen Interrupt freigeben
68
 
69
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
70
        sleep_mode();                   // in den Schlafmodus wechseln
71
 
72
        // hier wachen wir wieder auf
73
        GICR &= ~(1 << INT0);           // externen Interrupt sperren
74
                                       // WICHTIG! falls der externe LOW Puls an INT0
75
    _delay_ms(10); 
76
    }
77
78
    }
79
}
80
81
 
82
// externer Interrupt INT0 
83
 
84
// Die Interruptroutine kann leer sein, ABER sie muss existieren!
85
// Sonst springt der AVR nach dem Aufwachen zum Reset, weil kein sinnvoller
86
// Interruptvektor eingetragen ist!
87
 
88
ISR(INT0_vect) {
89
}

Bitte echt um eure Hilfe,
mfG. Sebi

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

So chaotisch, wie dein Code eingerückt und formatiert ist, wundert es 
mich nicht, dass du die implementierte Logik nicht mehr im Blick hast.

Wenn du Informatik als Lehrberuf hast, dann solltest du das schleunigst 
abstellen. Codeformatierung ist kein Selbstzweck. Wenn 
Hobbyprogrammierer das lernen, dann wirst du das als hauptberuflicher 
Programmierer auch lernen müssen.

Ich weiss nicht, wei lang du schon in der Ausbildung bist. Wenn du bei 
mir länger als ein halbes Jahr in der Ausbildung gewesen wärst und du 
präsentierst mir so ein Machwerk, dann drucke ich das aus und hau es dir 
so lange um die Ohren, bis nur noch Konfetti übrig ist! (Bildlich 
gesprochen, Gewalt ist ja keine Lösung und auch zu recht verboten)

: Bearbeitet durch User
von MaWin (Gast)


Lesenswert?

Sebastian Fiedler schrieb:
> es muss funktionieren  und wenn es nicht geht, hast
> du einen Fehler eingebaut.

Tja, was hast du überhaupt programmiert ?

Soll die Schaltung nur 1 Tür überwachen oder mehrere ?
(derzeit ja wohl nur 1, aber vielleicht sind die Kontakte in Reihe 
geschaltet).

Geht der PIN auf HIGH oder LOW wenn die Tür geöffnet wird ?

Sicherlich ist
1
while(1)
2
{
3
    GICR |= (1 << INT0);            // externen Interrupt freigeben
4
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
5
    sleep_mode();                   // in den Schlafmodus wechseln
6
    // hier wachen wir wieder auf
7
    GICR &= ~(1 << INT0);           // externen Interrupt sperren
der Kern deines Programms, allerdings würde ich auf
1 01 The rising edge of INTx generates an interrupt request
reagiaren (wenn der Eingang auf HIGH geht wenn die Tür geöffnet wird)

Dann ist das weitere Vorgehen einfach:
1
    long_delay(5000); // oder wie lange die Tür offen sein darf
2
    if(PIND & (1<<PD2)) // immer noch Tür offen ?
3
    {
4
        PORTD |= (1 << PD4) | (1 << PD1); // LED und Summmer 
5
        long_delay(1000); // für eine Sekunde anschalten
6
        PORTD &= ~((1 << PD4) | (1 << PD1)); // ausschalten
7
    }
8
    // Schleife läuft rum und uC schläft wieder bis Tür aufgeht
9
}

Die Logikprobleem mit quasi-gleichzeitigen Abläufen in der Realität 
(warten und währenddessen schliesst sich die Tür) haben viele Leute.

Es gäbe einen EEffekt, wenn die Tür 2 Sekunden aufgeht, 2 Sekunde zu 
geht, wieder 2 Sekunden auf geht, dann glaubt die Schaltung, sie wäre 
über 5 Sekunden offen gewesen. Das kann man auch noch verbessern.

von Karl H. (kbuchegg)


Lesenswert?

Irgendwas stimmt da nicht.

Hier
>     MCUCR &= ~0x3;              // levelgesteuerter Interrupt an INT0
setzt du den Interrupt so, dass du bei Low Level am PD2 Interrupts 
bekommst.

Low-Level an diesem Pin bedeutet was?
Offenbar ist der Schalter an der Tür so verschaltet ...
1
...
2
    while(1) {
3
  
4
      if(PIND & (1<<PD2)){

... das
* 1 eine geöffnete Tür darstellt
* 0 eine geschlossene Tür darstellt

Wenn aber 0 eine geschlossene Tür darstellt, dann ist klar, dass dir die 
geschlossene Tür den µC (wegen der Level Einstellung) ständig aus dem 
Sleep herausholen wird. D.h. der Teil hier
1
....
2
    else {
3
    GICR |= (1 << INT0);            // externen Interrupt freigeben
4
 
5
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
6
        sleep_mode();                   // in den Schlafmodus wechseln
7
 
8
        // hier wachen wir wieder auf
9
        GICR &= ~(1 << INT0);           // externen Interrupt sperren
10
                                       // WICHTIG! falls der externe LOW Puls an INT0
11
    _delay_ms(10); 
12
    }
ist völlig sinnlos, denn der µC wird da nicht im Sleep bleiben, sondern 
sofort wieder rauskommen. Dies deshalb, weil die Tür ja geschlossen ist, 
damit hast du einen Input-Pegel von 0, der aber einen Interrupt auslöst 
und den µC sofort wieder aus dem sleep erweckt.

Da du Power-Down nur mit einem externen Level-Interrupt beenden kannst, 
wirst du den so legen müssen, dass der Normalfall (und der wird wohl Tür 
geschlossen sein) eben KEINEN Interrupt auslöst, sondern nur der 
Abnormfall (nämlich wenn die Tür geöffnet ist).

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> Da du Power-Down nur mit einem externen Level-Interrupt beenden kannst,
> wirst du den so legen müssen, dass der Normalfall (und der wird wohl Tür
> geschlossen sein) eben KEINEN Interrupt auslöst, sondern nur der
> Abnormfall (nämlich wenn die Tür geöffnet ist).

D.h. aber auch, wenn eine dauergeöffnete Tür nach der Meldung den µC 
nicht länger blockieren soll, dann wird man den Interrupt 
umkonfigurieren müssen.

Im Normalfall, Tür geschlossen, löst ein High-Pegel Interrupts aus.
Ist die Tür aber zu lange geöffnet, dann muss sich alles umdrehen. Damit 
der µC die Wartezeit bis zum Schliessen der Tür schlafen kann, dürfen 
dann nur noch Low-Pegel einen Interrupt auslösen, so lange bis jemand 
die Tür schliesst. Das ganze so lange, bis dann tatsächlich die Tür 
geschlossen wird, woraufhin die Interrupts umkonfiguriert werden, so 
dass wieder der Normalfall gilt: High Pegel (also geöffnete Tür) löst 
einen Interrupt aus.


Erst mal als Ablaufdiagramm (ohne Beachtung der Details welches Bit wo 
zu setzen ist) formulieren!

: Bearbeitet durch User
von VEB Kraftverkehr Acapulco (Gast)


Lesenswert?

Sebastian Fiedler schrieb:
> Mein Ausbilder sagt ständig,obwohl er auch nur grundlegende Kenntnis in
> diese Richtung hat, es muss funktionieren  und wenn es nicht geht, hast
> du einen Fehler eingebaut. Er schaut aber nichtmal drüber...

O.T.
Wenn das Programm dann funktioniert, gib den Quelltext NUR mit dem 
Fehler raus, sonst gibt es der Ausbilder eventuell noch als sein Werk 
aus. Flashe die funktionierende .hex-Datei und gib ihm einen alten 
Quelltext.

Ich habe solche Schweinereien selbst erlebt und konnte auf diese Weise 
ein Großmaul und Alleskönner vor versammelter Mannschaft vorführen. 
DER macht so Etwas nie wieder...

von Gerald B. (gerald_b)


Lesenswert?

VEB Kraftverkehr Acapulco schrieb:
> Sebastian Fiedler schrieb:
>> Mein Ausbilder sagt ständig,obwohl er auch nur grundlegende Kenntnis in
>> diese Richtung hat, es muss funktionieren  und wenn es nicht geht, hast
>> du einen Fehler eingebaut. Er schaut aber nichtmal drüber...
>
> O.T.
> Wenn das Programm dann funktioniert, gib den Quelltext NUR mit dem
> Fehler raus, sonst gibt es der Ausbilder eventuell noch als sein Werk
> aus. Flashe die funktionierende .hex-Datei und gib ihm einen alten
> Quelltext.
>
> Ich habe solche Schweinereien selbst erlebt und konnte auf diese Weise
> ein Großmaul und Alleskönner vor versammelter Mannschaft vorführen.
> DER macht so Etwas nie wieder...

Dann empfiehlt es sich aber auch die Lock-Fuse setzen :-)

von VEB Kraftverkehr Acapulco (Gast)


Lesenswert?

Gerald B. schrieb:
> Dann empfiehlt es sich aber auch die Lock-Fuse setzen :-)

Das ist ein verlockender Gedanke...

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.