Forum: Mikrocontroller und Digitale Elektronik unterbrechbare Ausschaltverzögerung für Peak&Hold


von Thomas (Gast)


Lesenswert?

Guten Morgen zusammen,
ich habe einen funktionierenden C-Code für eine Peak&Hold-Ansteuerung 
(siehe unten). Ziel der Peak&Hold ist es, sobald der Taster gedrückt 
wird, gibt es einen Peak z.B. 500ms und dannach geht er in den 
Haltezustand über. Sobald der Taster aber losgelassen wird, muss das 
Ausgangssignal sofort auf Null gehen (auch in der Peak-Phase).

Bei diesem Code wird ein Inkrement i++; verwendet. Ich habe mit Abbsicht 
kein "delay" verwendet, da wenn der Taster nicht mehr gedrückt wird, die 
gewünschte Unterbrechnung nicht funktioniert. Daher wurde das Inkrement 
verwendet und die Optimierung ausgeschaltet bzw. O0 gewählt.
Will ich nun weitere unabhänige Funktionsstrukturen mit in den C-Code 
einbauen, die ein "delay" verwenden, muss ich den Optimierer ja 
aktivieren. Dann wird das Inkrement aber entfernt.

Durch welche Programmierstruktur oder Abänderung kann das Problem 
angegangen werden? Hab schon überlegt mit Timer, wusster aber nicht so 
recht wie und ob überhaupt möglich.
Wäre froh wenn ihr mir ein paar Tipps geben könnt. Vielen Dank.
Gruß Thomas
1
#include <avr/io.h>          
2
#define F_CPU 3686400
3
#include <util/delay.h>
4
#include <stdint.h>
5
6
7
int main()
8
{
9
  // Konfiguration Timer/Counter 2
10
  TCCR2 = 0b01100001; // Timer Control Register 
11
  DDRB  = 0b00111000; // Data Direction Register B: 0=Eingänge; 1=Ausgänge
12
13
14
  // Konfiguration AD-Wandler
15
  ADMUX = 0xE0;
16
  ADCSRA = 0xE0;
17
    
18
  PORTB= 0b00000011;          // Pull-up Widerstand: 1=aktiv 
19
  char Taster=0b00000001;
20
  char z=0;
21
  char PEAK=180;
22
  char HOLD=20;
23
  char OFF=0;
24
  unsigned int HOLD_TIME=50000;
25
  unsigned int i=0;
26
27
  while(1)
28
  {
29
    switch(z)
30
    {
31
    case 0: OCR2 = OFF;
32
        i=0;
33
34
        if(!(PINB & Taster))
35
        z=1;
36
        else
37
        {
38
        z=0;
39
        }
40
        break;
41
42
    case 1:  OCR2 = PEAK;
43
        i++;
44
        
45
        if(PINB&Taster)
46
        z=0;
47
        else
48
        {
49
          if(!(PINB & Taster)&&(i<HOLD_TIME))
50
          z=1;
51
          else
52
          {
53
          z=2;
54
          }
55
        }
56
        break;
57
    
58
    case 2: OCR2 = HOLD;
59
60
        if(!(PINB & Taster)&&(i=HOLD_TIME))
61
        z=2;
62
        else
63
        {
64
        z=0;
65
        }
66
        break;
67
    }
68
  }
69
}

von Thomas (Gast)


Lesenswert?

Hallo zusammen,
hab ich mich so schlecht ausgedrückt oder weiß das wirklich niemand 
hier?
Habe drei verschiedene Zustände "Peak", "Hold" und "Off". Diese sollen 
mit einem Taster gesteuert werden. Wird der Taster lange genug gedrückt, 
soll er nach der "Peak"-Phase in den "Hold"-Zustand übergehen. Sobald 
der Taster nicht mehr gedrückt wird, egal ob in der "Peak" oder "Hold" 
Phase soll am Ausgang Null bzw. "Off" anliegen.
Wie gesagt wär euch wirklich dankbar, wenn ihr mir Tipps für die 
programmiertechnische Umsetztung geben könnt.
Mit hoffnungsvollen Grüßen
Thomas

von Jobst M. (jobstens-de)


Lesenswert?

Thomas schrieb:
> hab ich mich so schlecht ausgedrückt

Jop. es fehlt mindestens die Hälfte!

Du beschreibst Dinge, die im Code nicht vorkommen und keiner weiß, was 
aussen herum passiert.

Du redest z.B. von einem Ausgang. Wo ist der? Im Program und in der 
Hardware?

Also: Komplette Software (und dann auch bitte als Anhang) und Schaltplan 
schicken.


Gruß

Jobst

von Thomas (Gast)


Lesenswert?

Naja ich weiß nicht ob die komplette Software hilfreich ist. Anbei habe 
ich sie hinzugefügt. Es geht um die Ansteuerung auf ein LCD-Display. 
Hier benötige ich eben die "delay"-Befehl.

Wie gesagt mit dem "Inkrement" funktioniert die Peak&Hold-Ansteuerung 
einwandfrei. Wird die Darstellung auf dem LCD-Display mit eingebunden 
und der Optmierer aktiviert, funktioniert die Peak&Hold nicht mehr.

Hoff wirklich auf einen guten Tipp. Danke!
1
/********************************************************************
2
*                                  *
3
*              LCD-Text                *
4
*                                  *
5
*********************************************************************
6
*                                  *
7
*  Funktion:  Textausgabe auf myAVR LCD-Display im 4-BitModus    *
8
*  Schaltung:  myAVR-Display am Stecker angesteckt          *
9
*        PortD Bit 4-7:  Daten                *
10
*        PortD Bit 2:   RS, high=Daten, low=Kommando    *
11
*        PortD Bit 3:   E, high-Impuls für gültige Daten  *
12
*                                  *
13
*********************************************************************
14
*                                  *
15
*  Autor:    Prof. Dr.-Ing. U. Kosiedowski            *
16
*  Version:  1.0                          *
17
*  Datum:    13.04.2010                      *
18
*                                  *
19
********************************************************************/
20
21
22
23
//==================================================================
24
//        Funktion für LCD-Kommandos
25
//==================================================================
26
//  Name:    lcd_cmd(cmd)
27
//  Funktion:  sendet ein Kommando an das LCD-Display
28
//  Argument:  cmd: Kommando, 1 Byte
29
//==================================================================
30
31
#include <avr/io.h>            // Bezeichnungen für Register
32
#define F_CPU 3686400
33
#include <util/delay.h>
34
#include <stdint.h>
35
36
void lcd_cmd(unsigned char cmd)
37
{
38
  unsigned char tmp = cmd;  // Kommando in Arbeitsvariable speichern
39
  tmp &= 0xF0;        // unteres Halbbyte ausblenden, RS=0, E=0
40
  PORTD = tmp;        // Signalausgabe
41
  tmp |= 0x08;        // Bit 3 setzen -> E=1
42
  PORTD = tmp;        // Signalausgabe
43
  tmp &= 0xF7;        // Bit 3 rücksetzen -> E=0
44
  PORTD = tmp;        // Signalausgabe
45
  
46
  tmp = cmd<<4;        // Kommando unteres Halbbyte -> Arbeitsvariable
47
  PORTD = tmp;        // Signalausgabe
48
  tmp |= 0x08;        // Bit 3 setzen -> E=1
49
  PORTD = tmp;        // Signalausgabe
50
  tmp &= 0xF7;        // Bit 3 rücksetzen -> E=0
51
  PORTD = tmp;        // Signalausgabe
52
  _delay_ms(1);        // Verzögerung 1ms -> Ausführung
53
}
54
55
//==================================================================
56
//        Funktion zur Anzeige einer Zeichenkette
57
//==================================================================
58
//  Name:    lcd_text(char* pText)
59
//  Funktion:  sendet eine Zeichenkette an das LCD-Display
60
//        Zeichenkette muss mit 0x00 abgeschlossen sein
61
//  Argument:  cmd: Zeiger auf Anfang der Zeichenkette, 1 Byte
62
//==================================================================
63
void lcd_text(char* pText)
64
{
65
  int j = 0;            // Zählvariable für Zeichen
66
  while(pText[j]!=0)        // Ausgabe bis 0-Zeichen als Ende-Kennung
67
  {
68
    unsigned char tmp = pText[j];  // Text in Arbeitsvariable speichern
69
    tmp &= 0xF0;        // unteres Halbbyte ausblenden, RS=1, E=0
70
    tmp |= 0x04;        // Bit 2 setzen -> RS=1
71
    PORTD = tmp;        // Signalausgabe
72
    tmp |= 0x08;        // Bit 3 setzen -> E=1
73
    PORTD = tmp;        // Signalausgabe
74
    tmp &= 0xF7;        // Bit 3 rücksetzen -> E=0
75
    PORTD = tmp;        // Signalausgabe
76
    
77
    tmp = pText[j]<<4;      // Kommando unteres Halbbyte -> Arbeitsvariable
78
    tmp |= 0x04;        // Bit 2 setzen -> RS=1
79
    PORTD = tmp;        // Signalausgabe
80
    tmp |= 0x08;        // Bit 3 setzen -> E=1
81
    PORTD = tmp;        // Signalausgabe
82
    tmp &= 0xF7;        // Bit 3 rücksetzen -> E=0
83
    PORTD = tmp;        // Signalausgabe
84
    
85
    _delay_ms(1);        // Verzögerung 1ms -> Ausführung
86
    j++;            // Index auf nächstes Zeichen setzen
87
  }
88
}
89
90
//==================================================================
91
//        Funktion zur Initialisierung des LCD-Displays
92
//==================================================================
93
//  Name:    lcd_goto(int row, int col)
94
//  Funktion:  Positionierung des Cursors
95
//  Argumente:  row: Zeile 1..2, integer
96
//        col: Spalte 1..16, integer
97
//==================================================================
98
void lcd_goto(char row, char col)
99
{
100
  row--;        // Null-basierend
101
  row&=0x01;      // sicherheitshalber
102
  row*=0x40;      // Zeile nach Bit 6 bringen
103
  col--;        // Null-basierend
104
  col&=0x0f;      // sicherheitshalber
105
  char tmp=row|col;
106
  tmp|=0x80;      // Cursor setzen
107
  lcd_cmd(tmp);    // senden
108
}
109
110
//==================================================================
111
//        Funktion zur Initialisierung des LCD-Displays
112
//==================================================================
113
//  Name:    lcd_init()
114
//  Funktion:  Initialisierung der Ports
115
//        Initialisierung des LCD-Displays
116
//  Argument:  N/A
117
//==================================================================
118
void lcd_init()
119
{
120
  DDRD=0xff;            // Port D als Ausgang konfigurieren
121
  PORTD=0;            // Port D löschen bis LCD gebootet hat
122
  _delay_ms(50);          // LCD-Bootvorgang -> Verzögerung 50ms
123
    
124
  // Soft-RESET Kommando 3x senden          
125
  PORTD = 0x30;          // Soft-Reset Kommando, E=0, RS=0
126
  PORTD = 0x38;          // Soft-Reset Kommando, E=1, RS=0
127
  PORTD = 0x30;          // Soft-Reset Kommando, E=0, RS=0
128
  _delay_ms(5);          // Befehlsausführung -> Verzögerung 5ms
129
  
130
  PORTD = 0x38;          // Soft-Reset Kommando, E=1, RS=0
131
  PORTD = 0x30;
132
  _delay_ms(1);          // Befehlsausführung -> Verzögerung 1ms
133
  
134
  PORTD = 0x38;          // Soft-Reset Kommando, E=1, RS=0
135
  PORTD = 0x30;
136
  _delay_ms(5);          // Befehlsausführung -> Verzögerung 5ms
137
  
138
  // 4-BitModus einschalten
139
  PORTD=0x20;            // oberes Halbbyte, E=0, RS=0
140
  PORTD=0x28;            // oberes Halbbyte, E=1, RS=0
141
  PORTD=0x20;  
142
  _delay_ms(1);          // Befehlsausführung -> Verzögerung 5ms
143
  
144
  // ab hier läuft das LCD im 4-Bit-Modus
145
  lcd_cmd(0x28);          // Funktions-Set: 2 Zeilen, 5x7 Matrix, 4 Bit
146
  lcd_cmd(0x06);          // Entry Mode
147
  lcd_cmd(0x0E);          // LCD einschalten
148
  lcd_cmd(0x01);
149
  _delay_ms(1);          // Befehlsausführung -> Verzögerung 2ms
150
}
151
152
153
154
155
156
157
//==================================================================
158
//        Funktion zur Umwandlung von Zahlen in Text
159
//==================================================================
160
//  Name:    lcd_zahl()
161
//  Funktion:  Zahl in Text
162
//  Argument:  Zahl, Zahl_T
163
//==================================================================
164
  void lcd_zahl(unsigned int zahl,char *Zahl_T)
165
166
  {
167
    unsigned char Ziffer100=0;
168
    unsigned char Ziffer10=0;
169
    unsigned char Ziffer1=0;
170
171
    while(zahl>=100)        // Hunderterstelle
172
    {
173
    Ziffer100++;
174
    zahl-=100;
175
    }
176
177
    while(zahl>=10)          // Zehnerstelle
178
    {
179
    Ziffer10++;
180
    zahl-=10;
181
    }
182
    
183
    while(zahl>=1)           // Einserstelle
184
    {
185
    Ziffer1++;
186
    zahl-=1;
187
    }
188
189
    Zahl_T[0]=Ziffer100+0x30;
190
    Zahl_T[1]=Ziffer10+0x30;
191
    Zahl_T[2]=Ziffer1+0x30;
192
  }
193
194
195
/*======================================================================================
196
        HAUPTPROGRAMM
197
======================================================================================*/
198
 
199
 int main()
200
{
201
  // Konfiguration Timer/Counter 2
202
  TCCR2 = 0b01100001; // Timer Control Register 
203
  DDRB  = 0b00111000; // Data Direction Register B: 0=Eingänge; 1=Ausgänge
204
205
206
  // Konfiguration AD-Wandler
207
  ADMUX = 0xE0;
208
  ADCSRA = 0xE0;
209
    
210
  PORTB= 0b00000011;          // Pull-up Widerstand: 1=aktiv 
211
  char Zahl_T[1];
212
  char Taster=0b00000001;
213
  char z=0;
214
  char PEAK=180;
215
  char HOLD=20;
216
  char OFF=0;
217
  unsigned int HOLD_TIME=50000;
218
  unsigned int i=0;
219
220
  lcd_init();              // Initialisierung des Displays
221
  lcd_goto(1,1);            // Positionierung des Cursors
222
  lcd_text("AD-Wandler 0-255");    // erste Textzeile
223
  lcd_goto(2,1);            // Positionierung des Cursors
224
  lcd_text("P1:");          // zweite Textzeile
225
226
  while(1)
227
  {
228
    switch(z)
229
    {
230
    case 0: OCR2 = OFF;
231
        i=0;
232
        lcd_zahl(OFF,Zahl_T);
233
        lcd_goto(2,5);          // Positionierung des Cursors
234
        lcd_text(Zahl_T);
235
236
        if(!(PINB & Taster))
237
        z=1;
238
        else
239
        {
240
        z=0;
241
        }
242
        break;
243
244
    case 1:  OCR2 = PEAK;
245
        i++;
246
        lcd_zahl(PEAK,Zahl_T);
247
        lcd_goto(2,5);          // Positionierung des Cursors
248
        lcd_text(Zahl_T);
249
250
        if(PINB&Taster)
251
        z=0;
252
        else
253
        {
254
          if(!(PINB & Taster)&&(i<HOLD_TIME))
255
          z=1;
256
          else
257
          {
258
          z=2;
259
          }
260
        }
261
        break;
262
    
263
    case 2: OCR2 = HOLD;
264
        lcd_zahl(HOLD,Zahl_T);
265
        lcd_goto(2,5);          // Positionierung des Cursors
266
        lcd_text(Zahl_T);
267
268
        if(!(PINB & Taster)&&(i=HOLD_TIME))
269
        z=2;
270
        else
271
        {
272
        z=0;
273
        }
274
        break;
275
    }
276
  }
277
}

von Yalu X. (yalu) (Moderator)


Lesenswert?

Bitte längeren Quellcode nicht in den Beitragstext übernehmen, sondern
als Datei anhängen. Kürzeren Quellcode, der im Beitragstext steht,
kannst du mit
1
[c]
2
C-Quelltext...
3
[/c]
farbig darstellen lassen.

Thomas schrieb:
> Will ich nun weitere unabhänige Funktionsstrukturen mit in den C-Code
> einbauen, die ein "delay" verwenden, muss ich den Optimierer ja
> aktivieren. Dann wird das Inkrement aber entfernt.

Wieso sollte der Compiler Inkrement wegoptimieren? Das Ergebnis des
Inkrementierens wird in der Abfrage i<HOLD_TIME genutzt, und diese
Abfrage hat einen Einfluss auf den weiteren Programmablauf, also darf
das Inkrement nicht wegoptimiert werden.

Wenn du allerding zusätzlichen Code in die Schleife mit aufnimmst,
stimmt die Wartezeit nicht mehr und ist evtl. nicht einmal mehr
konstant.

> Hab schon überlegt mit Timer, wusster aber nicht so recht wie und ob
> überhaupt möglich.

Das ist die richtige Überlegung. Hast du das hier schon gelesen?

  AVR-GCC-Tutorial/Die Timer und Zähler des AVR

Im Wesentlichen brauchst du nur zu Beginn einen Timer zu initialiseren,
die Variable i durch das Timer-Register zu ersetzen und HOLD-TIME
entsprechend anzupassen, damit die Wartezeit wieder 500ms sind.
Alternativ kannst du alles, was jetzt in der While-Schleife steht, in
einem vom Timer generierten zyklischen Interrupt ausführen und
nichtzyklisch ausgeführter Code ins Hauptoriogramm schreiben.


Dein jetziger Code hat aber noch Fehler:

Zahl_T ist als Array mit nur 1 Zeichen definiert. In lcd_zahl() werden
aber 3 Zeichen hineingeschrieben. Außerdem fehlt die String-Ende-Null,
die noch ein viertes Element belegen würde.

In
1
              if(!(PINB & Taster)&&(i=HOLD_TIME))

möchtest du i auf Gleichheit mit HOLD_TIME prüfen. '=' macht aber eine
Zuweisung, der Vergleichsoperator heißt '=='. Der Vergleich ist hier
aber unnötig, da i im Zustand z=2 immer gleich HOLD_TIME ist.

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.