Forum: Mikrocontroller und Digitale Elektronik Alarmanlage mit ATMEGA8L


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Sebastian F. (25sebi05)


Bewertung
0 lesenswert
nicht 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:
#define F_CPU 1000000
 
#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <util/delay.h>
 
// lange, variable Wartezeit, Einheit in Millisekunden
 
void long_delay(uint16_t ms) {
    for (; ms>0; ms--) _delay_ms(1);
}
 
int main (void) {
int i,m;
 
// IO konfigurieren
 
    DDRD = 0xFB;        // PD2 = INT0 = Eingang
    PORTD = 0x04;       // Pull Up aktivieren
 
// Analogcomparator ausschalten
 
    ACSR = 0x80;
 
// Interrupt konfigurieren
 
    MCUCR &= ~0x3;              // levelgesteuerter Interrupt an INT0
 
// Interrupts freigeben
 
    sei();
 
// Endlose Hauptschleife
 
    while(1) {
  
      if(PIND & (1<<PD2)){
    for(m=0;((!(PIND & (1<<PD2)))||m<5);m++){long_delay(1000);}
    
        i=0;
    while((i<5)&&(PIND & (1<<PD2))){
    long_delay(1000);
    i++;
    PORTD |= (1 << PD4);
    PORTD |= (1 << PD1);            // LED für eine Sekunde anschalten
        
             }
    i=0;
        PORTD &= ~(1 << PD4);  
    PORTD &= ~(1<<PD1); 
     _delay_ms(10);                               
    while((PIND & (1<<PD2))){
    GICR |= (1 << INT0);            // externen Interrupt freigeben
 
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
        sleep_mode();                   // in den Schlafmodus wechseln
 
        // hier wachen wir wieder auf
        GICR &= ~(1 << INT0);           // externen Interrupt sperren
                                       // WICHTIG! falls der externe LOW Puls an INT0
    _delay_ms(10); 
    }
    }
    
    else {
    GICR |= (1 << INT0);            // externen Interrupt freigeben
 
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
        sleep_mode();                   // in den Schlafmodus wechseln
 
        // hier wachen wir wieder auf
        GICR &= ~(1 << INT0);           // externen Interrupt sperren
                                       // WICHTIG! falls der externe LOW Puls an INT0
    _delay_ms(10); 
    }

    }
}

 
// externer Interrupt INT0 
 
// Die Interruptroutine kann leer sein, ABER sie muss existieren!
// Sonst springt der AVR nach dem Aufwachen zum Reset, weil kein sinnvoller
// Interruptvektor eingetragen ist!
 
ISR(INT0_vect) {
}

Bitte echt um eure Hilfe,
mfG. Sebi

: Bearbeitet durch Moderator
von Karl H. (kbuchegg) (Moderator)


Bewertung
0 lesenswert
nicht 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 Moderator
von MaWin (Gast)


Bewertung
0 lesenswert
nicht 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
while(1)
{
    GICR |= (1 << INT0);            // externen Interrupt freigeben
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    sleep_mode();                   // in den Schlafmodus wechseln
    // hier wachen wir wieder auf
    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:
    long_delay(5000); // oder wie lange die Tür offen sein darf
    if(PIND & (1<<PD2)) // immer noch Tür offen ?
    {
        PORTD |= (1 << PD4) | (1 << PD1); // LED und Summmer 
        long_delay(1000); // für eine Sekunde anschalten
        PORTD &= ~((1 << PD4) | (1 << PD1)); // ausschalten
    }
    // Schleife läuft rum und uC schläft wieder bis Tür aufgeht
}

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) (Moderator)


Bewertung
0 lesenswert
nicht 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 ...
...
    while(1) {
  
      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
....
    else {
    GICR |= (1 << INT0);            // externen Interrupt freigeben
 
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
        sleep_mode();                   // in den Schlafmodus wechseln
 
        // hier wachen wir wieder auf
        GICR &= ~(1 << INT0);           // externen Interrupt sperren
                                       // WICHTIG! falls der externe LOW Puls an INT0
    _delay_ms(10); 
    }
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 Moderator
von Karl H. (kbuchegg) (Moderator)


Bewertung
0 lesenswert
nicht 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 Moderator
von VEB Kraftverkehr Acapulco (Gast)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


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

Das ist ein verlockender Gedanke...

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.