Forum: Mikrocontroller und Digitale Elektronik Wie String im Software-Interrupt zerhacken und characterweise ausgeben?


von Markus B. (ysr)


Angehängte Dateien:

Lesenswert?

Hallo,
ich programmiere derzeit eine Lageerkennung für eine Art Wippe. Die 
interruptgesteuerte Zustandserkennung funktioniert soweit tadellos. Den 
Zustand gebe ich derzeit über "t" für zu tief, "h" für zu hoch und "w" 
für in Waage interruptgesteuert über die serielle Schnittstelle aus, 
sobald das USART Data Register leer ist.
Nun möchte ich den Zustandausgabe gerne mit einen String realisieren. 
Leider funktioniert die Zeichenzerhackung des Strings während des 
Interrupts nicht bzw. kommt gleich die Fehlermeldung "status has an 
incomplete type".
Ich verwende derzeit einen Atmega16 (mit 4Mhz) auf einem STK500 und die 
serielle Übertragung läuft mit 8N2 (8Datenbits, no parity und 2 
stopbits) bei 9600 Baud ab.

Hier ein Auszug aus dem Quellcode der main.c, wobei denke ich nur der 
untere Teile interessant ist im ISR (USART_UDRE_vect):
1
#include <avr/io.h>                  // Namen der IO Register
2
#include <avr/interrupt.h>
3
4
#define F_CPU 4000000UL              // CPU-Takt muss vor der <util/delay.h> stehen!
5
#include <util/delay.h>
6
#include "uart.h"
7
8
// INT0 = zu tief -->LED0, INT2 = zu hoch -->LED2, waage (Standard, bei Abweichung wird IRQ ausgelöst) -->LED1
9
volatile char zustand;
10
volatile char status[];
11
volatile int flag_tief, flag_hoch;
12
//volatile char text[] = "Hallo Welt." CR;
13
14
15
void start_Uebertragung(void)
16
{
17
  UCSRB |= (1<<UDRIE);      // wenn UDRIE = 1 dann Interrupt weil Data Register Empty
18
19
}
20
21
void stop_Uebertragung(void)
22
{
23
  UCSRB &= ~(1<<UDRIE);      // wenn UDRIE = 0 dann Interrupt stoppen, weil Data Register Full
24
  PORTB |= (1<<PB7);      // Status für serielle Übertragung auschalten
25
26
  PORTB |= (1<<PB0)|(1<<PB1)|(1<<PB2);  // LED0, LED1 und LED2 aus
27
}
28
29
int main(void)
30
{
31
     DDRB |= 0b11111111;             //PORTB als Ausgang definieren
32
     PORTB |= 0b11111111;          //PORTB auf Low setzen (Leds aus)
33
  
34
  uart_init();          // UART initialisieren
35
36
  GICR = (1<<INT0) | (1<<INT1);  // IRQ an INT0 und INT1 aktivieren
37
  MCUCR =(1<<ISC00) | (0<<ISC01) | (1<<ISC10) | (0<<ISC11);  // LOGICAL CHANGE an INT0 bzw. INT1 -->IRQ
38
39
  while(1)
40
  {
41
    cli();
42
    
43
    if(/*zustand == 't' && */flag_tief == 1)
44
    {
45
    PORTB |= (1<<PB1)|(1<<PB2);  // LED1 und LED2 aus
46
    PORTB &= ~(1<<PB0);      // LED0 an für zu tief
47
    start_Uebertragung();
48
    }
49
    else if(/*zustand == 'h' && */flag_hoch == 1)
50
    {
51
    PORTB |= (1<<PB1)|(1<<PB2);  // LED1 und LED2 aus
52
    PORTB &= ~(1<<PB2);      // LED2 an für zu hoch
53
    start_Uebertragung();
54
    }
55
    else if(flag_hoch == 0 && flag_tief == 0)
56
    {
57
    zustand = 'w';
58
59
    start_Uebertragung();
60
61
    PORTB |= (1<<PB0)|(1<<PB2);  // LED0 und LED2 aus --> gerade kein Interrupt!
62
    PORTB &= ~(1<<PB1);      // LED1 anschalten --> Wippe in der Waage
63
    }
64
    
65
    GICR = (1<<INT0) | (1<<INT1);  
66
    sei();  
67
  }
68
}
69
70
ISR (INT0_vect)            // Interrupt "zu tief" durch den rechten Taster (Switch 2)
71
  {  
72
    GICR &= (0<<INT0);
73
74
    if(PIND & ~(1 << PD2))      // wenn aktueller Pegel LOW...
75
    {
76
    zustand = 'h';
77
    flag_hoch = 1;
78
    flag_tief = 0;
79
    }
80
    if(PIND & (1 << PD2))      // wenn aktueller Pegel HIGH...
81
    {
82
    zustand = 'w';
83
    flag_tief = 0;
84
    flag_hoch = 0;
85
    }
86
  }
87
88
ISR (INT1_vect)            // Interrupt "zu hoch" durch den linken Taster (Switch 3)
89
  {
90
    GICR &= (0<<INT1);
91
92
    if(PIND & ~(1 << PD3))      // wenn aktueller Pegel LOW...
93
    {
94
    zustand = 't';
95
    flag_tief = 1;
96
    flag_hoch = 0;
97
    }
98
    if(PIND & (1 << PD3))      // wenn aktueller Pegel HIGH...
99
    {
100
    zustand = 'w';
101
    flag_tief = 0;
102
    flag_hoch = 0;
103
    }
104
  }
105
106
ISR (USART_UDRE_vect)        // USART Data Register Empty
107
  {
108
    /*  UDR = zustand;        // Sende "zustand"  --> funktioniert!
109
110
      PORTB &= ~(1<<PB7);      // Status-LED für serielle Übertragung ein
111
112
      stop_Uebertragung();*/
113
    int i = 0;
114
115
    if(zustand == 'w')
116
    {
117
    status = "in Waage";
118
/*    status[0] = 'i';
119
    status[1] = 'n';
120
    status[2] = ' ';
121
    status[3] = 'W';
122
    status[4] = 'a';
123
    status[5] = 'a';
124
    status[6] = 'g';
125
    status[7] = 'e';
126
*/    }
127
    if(zustand == 't')
128
    {
129
    status = "zu tief";
130
/*    status[0] = 'z';
131
    status[1] = 'u';
132
    status[2] = ' ';
133
    status[3] = 't';
134
    status[4] = 'i';
135
    status[5] = 'e';
136
    status[6] = 'f';
137
    status[7] = ' ';
138
*/    }
139
    if(zustand == 'h')
140
    {
141
    status = "zu hoch";
142
/*    status[0] = 'z';
143
    status[1] = 'u';
144
    status[2] = ' ';
145
    status[3] = 'h';
146
    status[4] = 'o';
147
    status[5] = 'c';
148
    status[6] = 'h';
149
    status[7] = ' ';
150
*/    }
151
152
    while(status[i] != '\0')
153
      {                             
154
        UDR = status[i]; 
155
          i++;
156
      }
157
      PORTB &= ~(1<<PB7);            // Status-LED für serielle Übertragung ein
158
    stop_Uebertragung();
159
  }

Kenne mich mit der seriellen Übertragung im Speziellen noch nicht so gut 
aus, hoffe ihr könnt mir da ein wenig helfen bzw. kleine Hinweise 
gebenwie man es mit dem incomplete type und der Zeichenzerhackung 
hinbekommt. Sitze nun schon den ganzen Sonntag an der Aufgabe, 
durchforste das Forum, stehe aber so langsam aufm Schlauch...

Vielen Dank im Voraus für eure Hilfe!

Viele Grüße
Markus

von Achim M. (minifloat)


Lesenswert?

Du kannst Strings nicht zuweisen. Die müssen Zeichenweise reinkopiert 
werden.
Auf dem PC nimmt man dazu strcpy() aus der string.h

Ich würde das anders machen:

static char meldungen[3][9] =
{
   {"zu hoch"},
   {"zu tief"},
   {"in waage"}
}

char *zgr;

und nachher einfach
zgr = &meldungen[0][0]; //Zeiger zeigt auf das z von "zu hoch"
zgr = &meldungen[1][0]; //Zeiger zeigt auf das z von "zu tief"
zgr = &meldungen[2][0]; //Zeiger zeigt auf das i von "in waage"

oder
zgr = meldungen[0]; //Zeiger zeigt auf das z von "zu hoch"
zgr = meldungen[1]; //Zeiger zeigt auf das z von "zu tief"
zgr = meldungen[2]; //Zeiger zeigt auf das i von "in waage"

mfg mf
ps: nachher dann

while(*zgr)//'\0' ist gleich 0x00, Schleife läuft bis Nullzeichen da 
ist.
{
   UDR = *zgr;
   zgr++;
}

von Matthias N. (nippey)


Lesenswert?

Hi, was mir gerade als erstes auffällt:
1
volatile char status[];
ohne Größenangabe für das Array wird Status nur als Pointer 
initialisiert, du würdest bei folgenden Operationen wild in anderen 
Daten rum schreiben.
Wenn du folgendes machst:
1
status = "zu hoch";
Müsste der Compiler was dagegen haben, du hast leider nicht geschrieben 
auf welche Programmzeile sich die Fehlermeldung bezieht.

Am besten initialisierst du das Array status ausreichend groß:
1
volatile char status[15];

und nutzt zum Speichern von Strings entweder die von dir auskommentierte 
Methode oder
[code]strcpy(status, "zu hoch");[/copy]

von Achim M. (minifloat)


Lesenswert?

Und eine Bremse beim UART-Beschreiben wäre super.
sowas hier z.B.
1
while(! (UCSRA & (1 << UDRE)) )
2
      ;
 mfg mf

von Matthias N. (nippey)


Lesenswert?

@ Mini Float:
Die Methode gefällt mir noch besser! ;)
Ist gerade bei Interrupt Anwendungen viel besser, da schneller.

@ Markus
Du solltest nur Sicherstellen das eine Manipulation des Text-Zeigers 
verhindert wird, wenn gerade eine Übertragung läuft.
Bei deiner aktuellen Programmstruktur ist das aber unbedenklich.

von Markus B. (ysr)


Lesenswert?

Hey,
vielen vielen Dank für eure Hilfe. Habe es nun zum Laufen bekommen, 
klappt super! ;)

Viele Grüße
Markus

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.