Forum: Mikrocontroller und Digitale Elektronik Atmega32 RS232 Probleme mit Register


von Jakob (Gast)


Lesenswert?

Hallo, nach langen Versuchen möchte ich hierum Hilfe bitten.
Es geht da drum zu erkennen ob der RS485 Bus noch Daten sendet, in 
dieesm Fall ob dieser angeschlossen ist oder nicht.

Der 485 Bus wird für'n Atmega in 232 umgewandelt

Von einen externen Gerät bekomme ich in Sekunden Takt ein Zeichen an 
meinen Atmega32 mit LC-Display gesendet :
71,79,82
Was das alles auf sich hat ist unwichtig. Das System funktioniert. Wenn 
ich den Bus angeschlossen habe gibt der Atmega immer das richtige aus.
Nun möchte ich das dieser erkennt ,dass wenn 2 Sek kein Zeichen kommt 
ein Fehler ausgibt. Die funktioniert bislang nur wenn ich den Atmega 
Resete und den Bus nicht angeschlossen habe. Schließe ich nun den Bus an 
springt er sofort auf die jeweilige Anzeige. Ziehe ich diesen wieder ab, 
erkennt der Atmega aber trotzdem das letzte Zeichen und springt in die 
dazu gehörige Routine.
Durch das Debuggen hab ich raus gefunden ,dass  troz nicht anliegen Bus 
das RXC Bit im UCSRA gesetzt ist und deshalb nicht in meine Routine 
springt die nach 2 Sek anzeigen soll das nichts anliegt. Kann ich dieses 
Bit "clearen" oder etc ? Damit er erkennt das nichts anliegt oder 
übersehe ich etwas offensichtliches ?

Er springt also in :
1
if (UCSRA & (1<<RXC))
2
  {  
3
  Zeichen=uart_getchar();  //Empfängt Zeichen am UART Eingang und überträgt dieses an die Variable Zeichen
4
  }
obwohl der Bus abgezogen wurde.(Immo. mit Steckverbinder)

Hier mal der Code , Code wird noch aufgeräumter (bitte keine Kommentare 
zum printf Befehl =) )
1
//_________________Main____________________
2
ISR(TIMER1_COMPA_vect)  //Timer1 Routine
3
{
4
  PORTA ^= 0x20;  //Dieser Pin wird durch die Exklusiv Oder Verknüpfung getoggelt
5
}
6
7
ISR(TIMER0_COMP_vect)
8
{
9
  mS++;
10
  if (mS==1000)
11
  {
12
    Sek++;
13
    mS=0;
14
  }  
15
}
16
17
int main(void)
18
{
19
  DDRA = 0b00100000; //Deklaration 11110000 1=Ausgang 0=Eingang  // X1-4a bis 7c
20
  DDRB = 0xFF; 
21
  DDRC = 0xFF;
22
  DDRD = 0xFF;  
23
24
  init_uart(207);            //RS232 Initialisierung 4800Baud = 207    
25
  
26
  InitialisierungDisplay();  
27
  DisplayAnD();           // Display An und Course Blinkt nicht
28
  
29
   
30
  start_timer1(23);        // Timer zur Frequenz erzeugung startetn. In den Klammern wird angegeben welche Frequenz man möchte 1Hz-106kHz !
31
  
32
  char Zeichen;              
33
  int Startclock=0;
34
    
35
  while(1){  
36
    
37
    
38
    
39
  if (UCSRA & (1<<RXC))
40
  {  
41
  Zeichen=uart_getchar();  //Empfängt Zeichen am UART Eingang und überträgt dieses an die Variable Zeichen
42
  }  
43
  
44
  else
45
  {
46
    Startclock++;
47
    if (Startclock==1)
48
    {
49
      start_timer0(2);
50
    }
51
    if (Sek==2)
52
    {
53
      LCD_xy(0,1);
54
      printf("---FBE-System---");
55
      LCD_xy(0,2);
56
      printf("EEEEEEEEEEEEE");
57
    }
58
  }
59
  
60
  switch (Zeichen)
61
  {
62
  case 79: //  O in Ascii = 79. Die Zeichen werden in Ascii übermittelt
63
  LCD_xy(0,1);
64
  printf("---FBE-System---");
65
  LCD_xy(0,2);
66
  printf("Signalausfall!!!");  
67
  Startclock=0;
68
  Sek=0;
69
  mS=0;
70
  
71
  
72
  break;
73
  
74
  
75
  case 71: //  G in Ascii = 71. Die Zeichen werden in Ascii übermittelt
76
  LCD_xy(0,1);
77
  printf("---FBE-System---");
78
  LCD_xy(0,2);
79
  printf("Frequenz im Band");  
80
  Startclock=0;
81
  Sek=0;
82
  mS=0;
83
  break;
84
  
85
  
86
  case 82:  //  R in Ascii = 82. Die Zeichen werden in Ascii übermittelt
87
  LCD_xy(0,1);
88
  printf("---FBE-System---");
89
  LCD_xy(0,2);
90
  printf("Freq. ausserhalb");  
91
  Startclock=0;
92
  Sek=0;
93
  mS=0;
94
  break;
95
  } //switch(zeichen)
96
  
97
98
    
99
  }//while(1)
100
}//Main
101
102
//_______________________Routinen________
103
104
unsigned char uart_getchar (void)
105
{    
106
    return UDR;            // Zeichen aus UDR an Aufrufer zurueckgeben
107
}
108
109
void start_timer0(uint8_t prescale0){
110
  
111
  TCCR0 = 0; //8bit Timer
112
  
113
  if (prescale0 == 0)
114
  {
115
    TCCR0 = (1<<CS00) | (1<<WGM01);
116
  }
117
  
118
  if (prescale0 == 1)
119
  {
120
    TCCR0 = (1<<CS01) | (1<<WGM01);
121
  }
122
  
123
  if (prescale0 == 2)
124
  {
125
    TCCR0 = (1<<CS01) |(1<<CS00) | (1<<WGM01);
126
  }
127
  
128
  if (prescale0 == 3)
129
  {
130
    TCCR0 = (1<<CS02) | (1<<WGM01);
131
  }
132
  
133
  if (prescale0 == 4)
134
  {
135
    TCCR0 = (1<<CS02) | (1<<CS00) | (1<<WGM01);
136
  }
137
  
138
  
139
  TIMSK |= (1<<OCIE0);        //Timerinterrupt für Vergleich aktivieren  //Für Overlow Deaktiviert
140
  OCR0 = 256 - 1 ;              //Vergleichswert bis wohin er durchzählt  zählt!(länge des Timers abhängig vom Prescaler)
141
  //TIMSK |= (1<<TOIE0);        // Timer Overflow Interrupt freischalten  //Für Compa Deaktivieren
142
  sei();                //Interrupt enable
143
  
144
}

von Karl H. (kbuchegg)


Lesenswert?

Jakob schrieb:

Deine Programmlogik ist
1
  while( 1 ) {
2
3
    Sieh nach ob ein Zeichen da ist und wenn ja
4
      hole es
5
6
    andernfalls
7
      mach irgendwas mit dem Timeout-Timer
8
9
    werte Zeichen aus
10
  }
11
}

meine Frage:
WIe kannst du ein Zeichen auswerten, wenn gar keines angekommen ist?

Die Logik müsste so sein
1
  while( 1 ) {
2
3
    Sieh nach ob ein Zeichen da ist und wenn ja {
4
      hole es
5
      werte das zeichen aus
6
    }
7
8
    andernfalls
9
      mach irgendwas mit dem Timeout-Timer
10
  }

es liegt ja wohl auf der Hand, dass man nur dann ein Zeichen auswerten 
kann, wenn auch tatsächlich eines eingetroffen ist.

von Karl H. (kbuchegg)


Lesenswert?

Deine Timeout Sache.

Grundsätzlich solltest du von derartigen Timer Start/Stop Dingen Abstand 
nehmen. Das ist meistens viel zu kompliziert.
Einen Timer startet man einmalig beim Programmstart und dann lässt man 
ihn im Normalfall durchlaufen.

Deine ISR sieht so aus
1
volatile uint8_t ms;
2
3
ISR( ... )
4
{
5
  if( ms < 2000 )
6
    ms++;
7
}

d.h. der Timer versucht ständig ms zu erhöhen, bis er bei 2000 
angekommen ist.

Was ihn daran hindert, die 2000 zu erreichen, das ist das Eintreffen 
eines Zeichens, welches die Variable ms wieder auf 0 zurück setzt.
1
  while( 1 ) {
2
3
    Sieh nach ob ein Zeichen da ist und wenn ja {
4
      hole es
5
      werte das zeichen aus
6
      cli();
7
      ms = 0;
8
      sei();
9
    }
10
11
    andernfalls
12
      mach irgendwas mit dem Timeout-Timer
13
  }

und natürlich wird dann im Falle, das kein Zeichen eingetroffen ist, 
diese Variable untersucht, ob sie die 2000 erreicht hat. Wenn ja, dann 
sind 2 Sekunden seit dem letzten Zeichen vergangen. Wenn nein, dann ist 
die Wartezeit noch nicht abgelaufen
1
  while( 1 ) {
2
3
    Sieh nach ob ein Zeichen da ist und wenn ja {
4
      hole es
5
      werte das zeichen aus
6
      cli();
7
      ms = 0;
8
      sei();
9
    }
10
11
    andernfalls {
12
      cli();
13
      if( ms == 2000 )
14
        Timeout ist aufgelaufen!
15
      sei();
16
    }
17
  }


(da ms eine uint16_t Variable ist, müssen Zugriffe aus main mit cli() 
bzw. sei() gekapselt werden.)

: Bearbeitet durch User
von Jakob (Gast)


Lesenswert?

Hallo, tue ich dies nicht im nachfolgen Code ?
Das Zeichen was ankommt wird auf die Variable Zeichen geschrieben und 
dann dementsprechend reagiert.
Der ATmega erkennt aber ein Zeichen obwohl Keins kommt und aber er 
springt in diese Routine.

von Karl H. (kbuchegg)


Lesenswert?

Jakob schrieb:
> Hallo, tue ich dies nicht im nachfolgen Code ?

Nein.

Ich hab dir extra eine Codezusammenfassung geschrieben.

Du versuchst Zeichen IMMER auszuwerten. Egal ob was reingekommen ist 
oder nicht.

> Das Zeichen was ankommt wird auf die Variable Zeichen geschrieben und
> dann dementsprechend reagiert.

nicht dementsprechend.
Du reagierst immer, egal ob was reingekommen ist oder nicht.
Deine Zeichenauswertung hängt in keinster Weise davon ab, OB ein Zeichen 
eingetrudelt ist oder nicht.

> Der ATmega erkennt aber ein Zeichen obwohl Keins kommt und aber er
> springt in diese Routine.

In welche Routine?

Der Teil hier
1
...
2
  switch (Zeichen)
3
  {
4
  case 79: //  O in Ascii = 79. Die Zeichen werden in Ascii übermittelt
5
  LCD_xy(0,1);
6
  printf("---FBE-System---");
7
  LCD_xy(0,2);
8
  printf("Signalausfall!!!");  
9
  Startclock=0;
10
  Sek=0;

hängt bei dir nicht davon ab, ob ein Zeichen angekommen ist oder nicht.

von Karl H. (kbuchegg)


Lesenswert?

Was jetzt natürlich noch sein kann, dass ist das du ja einen offenen 
Eingang hast, wenn du das Kabel abziehst. Und dann fängt sich der offene 
Eingang jedes elektromagnetische Feld aus der Umgebung ein, das er 
kriegen kann.

von Jakob (Gast)


Lesenswert?

Karl Heinz schrieb:
> Was jetzt natürlich noch sein kann, dass ist das du ja einen offenen
> Eingang hast, wenn du das Kabel abziehst. Und dann fängt sich der offene
> Eingang jedes elektromagnetische Feld aus der Umgebung ein, das er
> kriegen kann.

Würde dann doch auch beim Start tun, wenn der Stecker gezogen ist.

Ich werde mich später noch mal damit beschaffen und den Kopf frei 
kriegen.
1
  if (UCSRA & (1<<RXC))
2
  {  
3
  Zeichen=uart_getchar();  //Empfängt Zeichen am UART Eingang und überträgt dieses an die Variable Zeichen
4
  }

Hier erkennt er doch ob ein Zeichen ankommt oder nicht ? Andernfalls 
springt er in die else Routine. Dies macht er aber nicht da er noch 
etwas im UCSRA gesetzt hat.

Naja ich hoffe ich bekomme es nachher hin.

mfg.

von Karl H. (kbuchegg)


Lesenswert?

Jakob schrieb:

>
1
  if (UCSRA & (1<<RXC))
2
>   {
3
>   Zeichen=uart_getchar();  //Empfängt Zeichen am UART Eingang und 
4
> überträgt dieses an die Variable Zeichen
5
>   }
>
> Hier erkennt er doch ob ein Zeichen ankommt oder nicht ? Andernfalls
> springt er in die else Routine. Dies macht er aber nicht da er noch
> etwas im UCSRA gesetzt hat.

Woher weisst du, das er das nicht macht?

In deinem Else Zweig machst du nur dann irgendwas sinnvolles, wenn die 
zeit abgelaufen ist. Und genau die setzt du aber in den nachfolgenden 
switch-case immer wieder auf 0 zurück. Hat der µC einmal ein gültiges 
zeichen dann hat er das auch weiterhin und setzt dann auch weiterhin die 
Zeit immer wieder zurück.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

> Naja ich hoffe ich bekomme es nachher hin.

Bau erst mal deinen Code vernünftig auf. Ich denke, du hast dich da 
jetzt ganz einfach nur planlos verrannt. Und dein geschwätziger Code tut 
sein übriges, dir den Überblick schwer zu machen.

1
volatile uint16_t ms;
2
3
#define TIMEOUT_TIME 2000   // in Millisekunden
4
5
ISR( ... )
6
{
7
  if( ms < TIMEOUT_TIME )
8
    ms++;
9
}
10
11
void ProcessCharacter()
12
{
13
  char c = getchar();
14
15
  cli();
16
  ms = 0;
17
  sei();
18
19
  LCD_xy( 0, 2 );
20
21
    // kein Grund da jetzt 79 hinzuschreiben.
22
    // Wenn du 'O' meinst, dann schreib auch 'O'
23
    // Schreib nicht im Kommentar hin, dass 79 der ASCII Code von 'O'
24
    // ist, sondern schreib direkt im Code hin, dass hier ein 'O' gefragt
25
    // ist. Selbiges für die anderen Buchstaben.
26
  if( c == 'O' )
27
    printf("Signalausfall!!!");  
28
29
  else if( c == 'G' )
30
    printf("Frequenz im Band");  
31
32
  else if( c == 'R' )
33
    printf("Freq. ausserhalb");  
34
}
35
36
int main(void)
37
{
38
...
39
40
  LCD_xy(0,1);
41
  printf("---FBE-System---");
42
43
  start_timer0( 2 );    // Watchdog starten
44
45
  while( 1 ) {
46
    if (UCSRA & (1<<RXC))
47
      ProcessCharacter();
48
49
    else {
50
      cli();
51
      if( ms == TIMEOUT_TIME ) {
52
        LCD_xy( 0, 2 );
53
        printf("EEEEEEEEEEEEE");
54
      }
55
      sei();
56
    }
57
  }
58
} //Main

: Bearbeitet durch User
von Jakob (Gast)


Lesenswert?

Danke, ich werde jetzt den Code aufräumen. Er war/ist wirklich 
"vermüllt". Ich werde mich jetzt nach deinen Beispiel orientieren.

So jetzt funktioniert es erst mal :
1
if (UCSRA & (1<<RXC))
2
  {  
3
  Zeichen=uart_getchar();  //Empfängt Zeichen am UART Eingang und überträgt dieses an die Variable Zeichen
4
  mS=0;
5
  Sek=0;  
6
  }  
7
  
8
  else
9
  {
10
    if (Sek>1)    
11
      Zeichen=2;    
12
  }

von Bülent C. (mirki)


Lesenswert?

Wäre es nicht sinnvoller UDR aus einem interrupt heraus zu lesen, wenn 
eh schon mit interrupts gearbeitet wird?

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.