Forum: Mikrocontroller und Digitale Elektronik Fenster/Türkontakte auswerten


von RN (Gast)


Lesenswert?

Hallo Forum,

ich möchte mit einem Mega8 Fenster und Türkontakte überwachen. Die Daten 
werden alle ca. 1 Sek. übertragen und in einem Programm ausgewertet.
Jetzt soll aber, wenn eine Tür/Fenster geöffnet wird die Meldung sofort 
kommen und nicht erst nach Durchlauf der Schleife.

Da ich in Sachen Microcontroller nicht allzu fit bin, bräuchte ich mal 
einen Denkanstoss. Ich denke, hier wäre ein Interrupt wohl angebracht, 
der bei Kontakt Betätigung die Schleife unterbricht und entsprechend 
sendet.
Tutorial Interrupt habe ich mir schon angesehen, doch sehe ich vor 
lauter Bäumen den Wald nicht.

Hier mal der bis jetzt funktionierende Code.

Schon mal Vielen Dank im voraus.

Gruß
RN
1
//--------------------------------------------------------------------
2
#define F_CPU 3686400
3
#include <avr\io.h>
4
#include <util/delay.h>
5
#define UART_BAUD_RATE 9600
6
#define UART_BAUD_CALC(UART_BAUD_RATE,F_OSC) ((F_CPU)/((UART_BAUD_RATE)*16L)-1)
7
//--------------------------------------------------------------------
8
9
// Zeichen zu Uart senden
10
void uartPutChar(char data)
11
{
12
    //warte bis Senden möglich
13
    while (!(UCSRA & (1<<UDRE)));
14
    //sende
15
    UDR = data;
16
}
17
//----------------------------------------------------------------------
18
// Zeichen sammeln
19
void print(char buffer[])
20
{
21
  for (int i=0;buffer[i]!=0;i++)
22
    uartPutChar(buffer[i]);
23
}
24
//------------------------------------------------------------------------
25
// Initialisierungen
26
//------------------------------------------------------------------------
27
void init()
28
{
29
   // Ports initialisieren
30
   //DDRC = 0x00; //alle Pins von Port C als Eingang 
31
  //PORTC = 0xff: // interne Pull-Ups an allen Port-Pins aktivieren 
32
  DDRC &= ~(1<<DDC0); // Pin PC0 als Eingang 
33
  PORTC |= (1<<PC0);  // internen Pull-Up an PC0 aktivieren 
34
  DDRC &= ~(1<<DDC1); // Pin PC1 als Eingang 
35
  PORTC |= (1<<PC1);  // internen Pull-Up an PC1 aktivieren 
36
  DDRC &= ~(1<<DDC2); // Pin PC2 als Eingang 
37
  PORTC |= (1<<PC2);  // internen Pull-Up an PC2 aktivieren 
38
  DDRC &= ~(1<<DDC3); // Pin PC3 als Eingang 
39
  PORTC |= (1<<PC3);  // internen Pull-Up an PC3 aktivieren 
40
  DDRC &= ~(1<<DDC4); // Pin PC4 als Eingang 
41
  PORTC |= (1<<PC4);  // internen Pull-Up an PC4 aktivieren 
42
  DDRC &= ~(1<<DDC5); // Pin PC5 als Eingang 
43
  PORTC |= (1<<PC5);  // internen Pull-Up an PC5 aktivieren 
44
   
45
   // UART initialisieren
46
   UCSRB |= (1<<TXEN);  // TX aktiveren
47
  UCSRC |= (1<<URSEL)|(3<<UCSZ0); //Asynchron 8N1
48
  // Baudrate setzen
49
   UBRRH=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8);
50
  UBRRL=(uint8_t)UART_BAUD_CALC(UART_BAUD_RATE,F_CPU);
51
   
52
}
53
54
/////////////////////////////////////////////////////////////////////////////
55
// Main-Funktion
56
/////////////////////////////////////////////////////////////////////////////
57
int main(void)
58
{
59
   init();   // Initialisierungen
60
  while (1)    // Mainloop-Begin  
61
   {
62
     if (!(PINC &(1 << DDC0))) // Eingang 1 
63
    {
64
      print ("A1:1;");
65
    }
66
    else
67
    {
68
      print("A1:0;");
69
    }
70
    _delay_ms(1000);
71
    if (!(PINC &(1 << DDC1))) // Eingang 2
72
    {
73
      print ("A2:1;");
74
    }
75
    else
76
    {
77
      print("A2:0;");
78
    }
79
    _delay_ms(1000);
80
    if (!(PINC &(1 << DDC2))) // Eingang 3
81
    {
82
      print ("A3:1;");
83
    }
84
    else
85
    {
86
      print("A3:0;");
87
    }
88
    _delay_ms(1000);
89
    if (!(PINC &(1 << DDC3))) // Eingang 4
90
    {
91
      print ("A4:1;");
92
    }
93
    else
94
    {
95
      print("A4:0;");
96
    }
97
    _delay_ms(1000);
98
    if (!(PINC &(1 << DDC4))) // Eingang 5
99
    {
100
      print ("A5:1;");
101
    }
102
    else
103
    {
104
      print("A5:0;");
105
    }
106
    _delay_ms(1000);
107
     
108
  }
109
  
110
}

von Gast (Gast)


Lesenswert?

Interrupt brauchst du dafür noch nicht.
Nimm einfach die Delays raus, die wenigen Abfragen laufen so schnell 
durch, dass die Daten fast in Echtzeit im Controller sind.
Da die Datenübertragung dann viel zu schnell läuft, hast du zwei 
Möglichkeiten: Entweder muss dein Programm die Übertragung erst 
anstoßen, d.h. es muss z.B. "START" senden und der Controller schiebt 
dann die Daten der Reihe nach raus. Oder du arbeitest mit einem Timer 
oder einfachem Zähler, der jede Sekunde die Schleife unterbricht und die 
Daten rausgibt.

Die Abfrage der Startbedingung kannst du auch in der Hauptschleife 
ständig laufen lassen, so verlierst du auch keine Abfrage.

von Karl H. (kbuchegg)


Lesenswert?

Gast schrieb:

> dann die Daten der Reihe nach raus. Oder du arbeitest mit einem Timer
> oder einfachem Zähler, der jede Sekunde die Schleife unterbricht und die
> Daten rausgibt.

Oder aber Mega8 meldet sich beim PC nur dann, wenn sich an einem Sensor 
eine Veränderung ergibt.

Fährt das Programm hoch, wird einmal der komplette aktuelle 
Sensorzustand übertragen und danach wird nur noch bei Änderungen 
reagiert. Ab und zu kann der PC wieder einen kompletten Zustand oder den 
Zustand einzelner Sensoren abfragen. Damit wird zum einen kontrolliert, 
ob die Verbindung noch da ist und zum anderen hat man die Sicherheit, 
dass der PC auch wirklich den aktuellen Stand hat.
Aber auf jeden Fall bleibt die Leitung dadurch soweit frei, dass der 
Mega bei einer Sensoränderung sofort losplärren kann.

> Da ich in Sachen Microcontroller nicht allzu fit bin, bräuchte
> ich mal einen Denkanstoss.

Der Denkanstoss sollte sein: Wenn du schnellstmögliche Reaktion willst, 
dann eleminiere erst einmal alle delay...

von Martin V. (oldmax)


Lesenswert?

Hi
So ganz versteh ich dein Problem nicht. Wieso alle Sekunden etwas 
übertragen, wenn sich sowieso nichts ändert ? Warum nicht nur bei einer 
Änderung etwas senden und den PC einen Zeitstempel dazu setzen ?
etwas so...
LOOP: In R16, Portx
      LDS R17, InByte ; Ablage gelesene Eigänge
      STS InByte, R16 ; neue Werte ablegen
      CP R16, R17     ; Vergleich
      BREQ LOOP       ; is nix ?
      RCALL Send_Action
      RJMP  LOOP

Send_Action: ....  ; was auch immer
             RET

So rotiert dein µC zwar fleißig, aber eine Info an den PC erfolgt nur 
bei einer Änderung. Dieses Ereignis kannst du im PC mit der Zeit 
versehen, wenn du bspw. dazu ein Empfangsprogramm geschrieben hast. Es 
geht auch, das du im Controler eine Zeit laufen läßt, diese stellst und 
dann zum Ereignis ein Telegramm baust, wo du einen Zeitstempel 
mitsendest.  Solange wie sich nix tut, brauchst du auch nix senden. Was 
soll auch die Info im Sekundentakt:" die Tür ist zu, die Tür ist zu, die 
Tür ist zu ...."
Gruß oldmax

von Martin V. (oldmax)


Lesenswert?

zu spät...

von RN (Gast)


Lesenswert?

Hallo,

"Der Denkanstoss sollte sein: Wenn du schnellstmögliche Reaktion willst,
dann eleminiere erst einmal alle delay..."

Das ist mir schon klar, nur müllt er mir dann die Schnittstelle zu.

"Wieso alle Sekunden etwas
übertragen, wenn sich sowieso nichts ändert ?"

Da ich dann weiß, dass noch alles funktioniert. Muss ja nicht alle Sek 
sein.

von Karl H. (kbuchegg)


Lesenswert?

RN schrieb:
> Hallo,
>
> "Der Denkanstoss sollte sein: Wenn du schnellstmögliche Reaktion willst,
> dann eleminiere erst einmal alle delay..."
>
> Das ist mir schon klar, nur müllt er mir dann die Schnittstelle zu.

Dann musst du das abstellen.
Daher dann sofort die nächste Frage: Warum müllt er mir die 
Schnittstelle zu. Antwort: Weil ständig Daten übertragen werden, die 
eigentlich eh keinen interessieren, weil sie sich nicht verändert haben.

> Da ich dann weiß, dass noch alles funktioniert. Muss ja nicht alle Sek
> sein.

Siehst du. Jetzt hast du den Dreh gefunden.
Und noch ein Tip. Um zu wissen, dass die Schnittstelle noch da ist und 
das Kabel nicht gerissen ist, muss man nicht alle Sensorzustände 
übertragen. Ein simples regelmässiges 'x' erfüllt den gleichen Zweck. 
Und das ist schnell übertragen.

von icha (Gast)


Lesenswert?

Hole Dir doch den kompletten Port auf einmal in ein Byte, vergleiche mit 
dem letzten (gespeicherten) Zustand und gibt dann eine Meldung aus, wenn 
sich was ändert. Das einen Timer, der die Abfrage alle x Zeitabstände 
macht und bei jeder y-ten ein "Alles OK" ausgibt, wenn keine Änderungen 
da sind.

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.