Forum: Mikrocontroller und Digitale Elektronik <rotary.h> mit bool "ein" und Ausschalten.


von oldeurope O. (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe den AD7C-VFO so erweitert, dass ich damit meinen
cquam-Modulator steuern kann.

Der Boolean "ein" Zeile 42, geht nach Tastendruck für eine
einstellbare Zeit HIGH, Zeile 169, schaltet die Displaybeleuchtung
und die Aussteuerungsanzeige ein.

Ich hätte das gerne so, dass auch der Rotary erst durch den
bool "ein" aktiviert wird.

Ich habe keine Ahnung wie diese Rotary.h da ausgewertet wird
und wo ich mit dem bool die Auswertung ein- und ausschalten
kann. Momentan kann ich bei dunklem Display die Frequenz
ändern, was ich nicht so toll finde.

Alternativ könnte ich den bool "ein" HIGH machen, wenn der
Rotary gedreht wird. Auch dazu erkenne ich nichts, was
ich in die if Bedingung Zeile 169 einbringen kann.

Bitte um Hilfe.

LG
old.

von Stefan F. (Gast)


Lesenswert?

Die Formatierung des Code ist eine schlechte Zumutung. Wie oft hat da 
jemand von anderen Kopiert, um das so zu verunstalten?

Lasst uns den folgenden formatierten Quelltext als Diskussionsgrundlage 
verwenden:
1
#include <Wire.h>
2
#include <LiquidCrystal_I2C.h>
3
#include <rotary.h>
4
#include <EEPROM.h>
5
6
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // 27=A4=SDA, Pin28=A5=SCL
7
8
int volt = A1;                          // 24 Atmega Eingang Spannungskontrolle
9
10
int spg;
11
bool start, obi, unterspg, flagspg;
12
unsigned long unterspgstart, unterspgist;
13
unsigned long flagspgstart, flagspgist;
14
unsigned long unterspgverz = 21;
15
16
bool ul, uh, uth, utl, uts, us;
17
unsigned long startul, istul, startuh, istuh;
18
19
int sumeing = A3;                       // 26 Atmega Eingang Summensignal
20
int diffeing = A2;                      // 25 Atmega Eingang Differenzsignal
21
22
int c;
23
int d;
24
int L;
25
int R;
26
27
int rot = 13;                           // 19 Atmega  Anzeige Clippgrenze erreicht
28
int gelb = 12;                          // 18 Atmega  Anzeige Vollaussteuerung
29
int gruen = 7;                          // 13 Atmega  Anzeige Summensignal (Mono)
30
int blau = 4;                           // 6 Atmega  Anzeige Differenzsignal (Stereo)
31
32
bool clip;
33
unsigned long cstart;
34
unsigned long cist;
35
unsigned long causverz = 200;           // MF Clippanzeige
36
37
bool voll;
38
unsigned long vstart;
39
unsigned long vist;
40
unsigned long vausverz = 500;           // MF Vollaussteuerung
41
42
bool sum;
43
unsigned long sumstart;
44
unsigned long sumist;
45
unsigned long sumausverz = 1000;        // MF Summensignal
46
47
bool diff;
48
unsigned long diffstart;
49
unsigned long diffist;
50
unsigned long diffausverz = 1000;       // MF Differenzsignal
51
52
int pwmDuty;
53
long sineINC;
54
55
bool ein;
56
unsigned long einstart;
57
unsigned long einist;
58
unsigned long eindauer = 1200000;       //20min (nach Tastendruck)
59
60
bool button;
61
unsigned long buttonstart;
62
unsigned long buttonist;
63
unsigned long buttoneinverz = 1000;     //Tastverzögerung
64
unsigned long previoushMillis = 0;
65
const long intervalh = 1250;            //Sperrzeit Herztaster
66
67
long n;
68
69
//Setup some items
70
#define W_CLK 8                         // Pin 8 - connect to AD9850 module word load clock pin (CLK) 14 Atmega
71
#define FQ_UD 9                         // Pin 9 - connect to freq update pin (FQ)                    15 Atmega
72
#define DATA 10                         // Pin 10 - connect to serial data load pin (DATA)            16 Atmega
73
#define RESET 11                        // Pin 11 - connect to reset pin (RST)                        17 Atmega
74
#define pulseHigh(pin) {
75
    digitalWrite(pin, HIGH);
76
    digitalWrite(pin, LOW);
77
}
78
79
Rotary r = Rotary(2, 3);                // sets the pins the rotary encoder uses.  Must be interrupt pins.
80
81
int_fast32_t rx = 1233000;              // Starting frequency of VFO (1233KHz)
82
int_fast32_t rx2 = 1;                   // variable to hold the updated frequency
83
int_fast32_t increment = 9000;          // starting VFO update increment in HZ.
84
int buttonstate = 0;
85
86
String hertz = "Raster      9KHz";
87
int hertzPosition = 0;
88
89
byte ones, tens, hundreds, 
90
thousands, tenthousands, 
91
hundredthousands, millions;             //Placeholders
92
93
String freq;                            // string to hold the frequency
94
int_fast32_t timepassed = millis();     // int to hold the arduino miilis since startup
95
96
int memstatus = 1;                      // value to notify if memory is current or old. 0=old, 1=current.
97
int ForceFreq = 1;                      // Change this to 0 after you upload and run a working sketch to activate the EEPROM memory.  
98
                                        // YOU MUST PUT THIS BACK TO 0 AND UPLOAD THE SKETCH AGAIN AFTER STARTING FREQUENCY IS SET!
99
100
101
void setup() {
102
    pinMode(rot, OUTPUT);
103
    pinMode(gelb, OUTPUT);
104
    pinMode(gruen, OUTPUT);
105
    pinMode(blau, OUTPUT);
106
    pinMode(A0, INPUT);                 // Connect to a button that goes to GND on push
107
108
    digitalWrite(A0, HIGH);
109
    lcd.begin(16, 2);
110
    // lcd.backlight();
111
112
    PCICR |= (1 << PCIE2);
113
    PCMSK2 |= (1 << PCINT18) | (1 << PCINT19);
114
    sei();
115
116
    pinMode(FQ_UD, OUTPUT);
117
    pinMode(W_CLK, OUTPUT);
118
    pinMode(DATA, OUTPUT);
119
    pinMode(RESET, OUTPUT);
120
121
    pulseHigh(RESET);
122
    pulseHigh(W_CLK);
123
    pulseHigh(FQ_UD);                   // this pulse enables serial mode on the AD9850 - Datasheet page 12.
124
125
    lcd.setCursor(hertzPosition, 1);
126
    lcd.print(hertz);
127
128
    // Load the stored frequency  
129
    if (ForceFreq == 0) {
130
        freq = String(EEPROM.read(0)) + 
131
               String(EEPROM.read(1)) + 
132
               String(EEPROM.read(2)) + 
133
               String(EEPROM.read(3)) + 
134
               String(EEPROM.read(4)) + 
135
               String(EEPROM.read(5)) + 
136
               String(EEPROM.read(6));
137
        rx = freq.toInt();
138
    }
139
}
140
141
142
143
void loop() {
144
145
    /*    
146
    // Anzeige Unterspannung
147
    
148
    spg = analogRead (volt);
149
150
    if(millis() > 500) {
151
        start = HIGH;
152
    } 
153
    else {
154
        start = LOW;
155
    }
156
    if( spg < 292) {
157
        obi = HIGH;
158
    } 
159
    else {
160
        obi = LOW;
161
    }
162
163
    unterspg = obi && start;
164
    if(unterspg == LOW) {
165
        flagspgist = millis();
166
        if(flagspgist - flagspgstart > unterspgverz){
167
            flagspg = LOW;
168
        }
169
    }
170
    else {
171
        flagspgstart = millis(); 
172
        flagspg = HIGH;
173
    }
174
   
175
    if(flagspg == LOW) {
176
        istul = millis();
177
        if(istul - startul > unterspgverz){
178
            ul = LOW;
179
        }
180
    }
181
    else{
182
        startul = millis(); 
183
        ul = HIGH;
184
    } 
185
    
186
    utl = (ul && !flagspg);
187
 
188
    if(!flagspg == LOW) {
189
        istuh = millis();
190
        if(istuh - startuh > unterspgverz){
191
            uh = LOW;
192
        }
193
    }
194
    else {
195
        startuh = millis(); 
196
        uh = HIGH;
197
    }
198
    
199
    uth = (uh && flagspg);
200
    
201
    if(uth == HIGH) {
202
        lcd.setCursor(0,1); 
203
        lcd.print("Unterspannung   ");
204
    }
205
    
206
    if(utl == HIGH){
207
        lcd.setCursor(0,1); 
208
        lcd.print(hertz);
209
    } 
210
    
211
    // Ende Anzeige Unterspannung 
212
    */
213
    
214
    if (ein == HIGH) {
215
        lcd.backlight();
216
    } else {
217
        lcd.noBacklight();
218
    }
219
    
220
    c = analogRead(sumeing);
221
    c -= 511;                           // Nullinie wird von 511 auf 0 geschoben.
222
    
223
    d = analogRead(diffeing);
224
    d -= 511;                           // Nullinie wird von 511 auf 0 geschoben.
225
    
226
    R = (c + d);
227
    L = (c - d);
228
    
229
    if (R < -481 || R > 481 || 
230
        L < -481 || L > 481 || 
231
        d < -481 || d > 481) {
232
        clip = HIGH;
233
    }                                   // Clipp Abstand 30,
234
    else {
235
        clip = LOW;
236
    }
237
    
238
    if (clip == LOW)                    // MonoFlop für Clippanzeige
239
    {
240
        cist = millis();
241
        if (cist - cstart > causverz) {
242
            digitalWrite(rot, LOW);
243
        }
244
    } else {
245
        cstart = millis();
246
        digitalWrite(rot, HIGH);
247
    }
248
    
249
    if ((R < -356 || R > 356 || 
250
         L < -356 || L > 356 || 
251
         d < -179 || d > 179
252
        ) && ein) {
253
        voll = HIGH;
254
    } //Vollausst. (511*0,7) (255*0,7) >-3dB
255
    else {
256
        voll = LOW;
257
    }
258
    
259
    if (voll == LOW)                    // MonoFlop für Vollaussteuerungsanzeige
260
    {
261
        vist = millis();
262
        if (vist - vstart > vausverz) {
263
            digitalWrite(gelb, LOW);
264
        }
265
    } else {
266
        vstart = millis(); // 
267
        digitalWrite(gelb, HIGH);
268
    }
269
    
270
    if ((c < -50 || c > 50) && ein) {
271
        sum = HIGH;
272
    } else {
273
        sum = LOW;
274
    } //Summenanzeige
275
    
276
    if (sum == LOW)                     // MonoFlop für Summenanzeige
277
    {
278
        sumist = millis();
279
        if (sumist - sumstart > sumausverz) {
280
            digitalWrite(gruen, LOW);
281
        }
282
    } 
283
    else {
284
        sumstart = millis(); 
285
        digitalWrite(gruen, HIGH);
286
    }
287
    
288
    if ((d < -50 || d > 50) && ein) {
289
        diff = HIGH;
290
    } //Differenzsignal
291
    else {
292
        diff = LOW;
293
    }
294
    
295
    if (diff == LOW)                    // MonoFlop für Differenzsignalanzeige
296
    {
297
        diffist = millis();
298
        if (diffist - diffstart > diffausverz) {
299
            digitalWrite(blau, LOW);
300
        }
301
    } else {
302
        diffstart = millis(); 
303
        digitalWrite(blau, HIGH);
304
    }
305
    
306
    n = rx / 7843;
307
    analogWrite(6, n);                  // Spannung als funktion der Frequenz PWM an Pin11 Atmega
308
    pwmDuty = 128 + 126 * 
309
        sin(micros() * 0.000157);
310
    analogWrite(5, pwmDuty);            // 25Hz PWM an Pin12 Atmega
311
    
312
    if (rx != rx2) {
313
        showFreq();
314
        sendFrequency(rx);
315
        rx2 = rx;
316
    }
317
    
318
    buttonstate = digitalRead(A0);
319
    if (buttonstate == LOW) {
320
        buttonist = millis();
321
        if (buttonist - buttonstart > buttoneinverz) {
322
            button = LOW;
323
        }
324
    } else {
325
        buttonstart = millis();
326
        button = HIGH;
327
    }
328
    
329
    if (button == LOW) {
330
        setincrement();
331
    };
332
    
333
    if (buttonstate == HIGH) {
334
        einist = millis();              //Einschalten mit Tastendruck für Einschaltdauer.
335
        if (einist - einstart > eindauer) {
336
            ein = LOW;
337
        }
338
    } else {
339
        einstart = millis();
340
        ein = HIGH;
341
    }
342
    
343
    if (memstatus == 0) {               // Write the frequency to memory if not stored and 2 (10sek) seconds have passed since the last frequency change.
344
        if (timepassed + 10000 < millis()) {
345
            storeMEM();
346
        }
347
    }
348
}
349
350
351
352
ISR(PCINT2_vect) {
353
    unsigned char result = r.process();
354
    if (result) {
355
        if (result == DIR_CW) {
356
            rx = rx + increment;
357
        } else {
358
            rx = rx - increment;
359
        };
360
        if (rx >= 2000000) {
361
            rx = rx2;
362
        };                              // UPPER VFO LIMIT
363
        if (rx <= 100000) {
364
            rx = rx2;
365
        };                              // LOWER VFO LIMIT
366
    }
367
}
368
369
370
371
// frequency calc from datasheet page 8 
372
// = <sys clock> * <frequency tuning word>/2^32
373
374
void sendFrequency(double frequency) {
375
    int32_t freq = frequency * 
376
        4294967295 / 125000000;                     // 4294967295*2=8589934590 note 125 MHz clock on 9850.  
377
                                                    // You can make 'slight' tuning variations here by 
378
                                                    // adjusting the clock frequency.
379
    for (int b = 0; b < 4; b++, freq >>= 8) {
380
        tfr_byte(freq & 0xFF);
381
    }
382
    tfr_byte(0x000);                                // Final control byte, all 0 for 9850 chip
383
    pulseHigh(FQ_UD);                               // Done!  Should see output
384
}
385
386
387
388
// transfers a byte, a bit at a time, 
389
// LSB first to the 9850 via serial DATA line
390
391
void tfr_byte(byte data) {
392
    for (int i = 0; i < 8; i++, data >>= 1) {
393
        digitalWrite(DATA, data & 0x01);
394
        pulseHigh(W_CLK); //after each bit sent, CLK is pulsed high
395
    }
396
}
397
398
399
400
void setincrement() {
401
    unsigned long currenthMillis = millis(); //delay Herzbutton
402
    if (currenthMillis - previoushMillis >= intervalh) {
403
        previoushMillis = currenthMillis;
404
        
405
        if (increment == 9000) {
406
            increment = 1;
407
            hertz = "Raster       1Hz";
408
        } else if (increment == 1) {
409
            increment = 10;
410
            hertz = "Raster      10Hz";
411
        } else if (increment == 10) {
412
            increment = 100;
413
            hertz = "Raster     100Hz";
414
        } else if (increment == 100) {
415
            increment = 1000;
416
            hertz = "Raster      1KHz";
417
        } else if (increment == 1000) {
418
            increment = 10000;
419
            hertz = "Raster     10KHz";
420
        } else if (increment == 10000) {
421
            increment = 99000;
422
            hertz = "Raster     99KHz";
423
        } else if (increment == 99000) {
424
            increment = 100000;
425
            hertz = "Raster    100KHz";
426
        } else {
427
            increment = 9000;
428
            hertz = "Raster      9KHz";
429
        }
430
        
431
        lcd.setCursor(0, 1);
432
        lcd.print(hertz);
433
    }
434
}
435
436
437
void showFreq() {
438
    millions = int(rx / 1000000);
439
    hundredthousands = ((rx / 100000) % 10);
440
    tenthousands = ((rx / 10000) % 10);
441
    thousands = ((rx / 1000) % 10);
442
    hundreds = ((rx / 100) % 10);
443
    tens = ((rx / 10) % 10);
444
    ones = ((rx / 1) % 10);
445
    lcd.setCursor(0, 0);
446
    lcd.print("                ");
447
    
448
    if (millions > 9) {
449
        lcd.setCursor(1, 0);
450
    } else {
451
        lcd.setCursor(2, 0);
452
    }
453
    
454
    lcd.print(millions);
455
    lcd.print(".");
456
    lcd.print(hundredthousands);
457
    lcd.print(tenthousands);
458
    lcd.print(thousands);
459
    lcd.print(".");
460
    lcd.print(hundreds);
461
    lcd.print(tens);
462
    lcd.print(ones);
463
    lcd.print("  Hz  ");
464
    timepassed = millis();
465
    memstatus = 0; // Trigger memory write
466
};
467
468
void storeMEM() {
469
    //Write each frequency section to a EPROM slot. 
470
    // Yes, it's cheating but it works!
471
    EEPROM.write(0, millions);
472
    EEPROM.write(1, hundredthousands);
473
    EEPROM.write(2, tenthousands);
474
    EEPROM.write(3, thousands);
475
    EEPROM.write(4, hundreds);
476
    EEPROM.write(5, tens);
477
    EEPROM.write(6, ones);
478
    memstatus = 1; // Let program know memory has been written
479
};
480
481
482
/*
483
VFO code by Richard Visokey AD7C - www.ad7c.com
484
20190528, delay entfernt, Pilotton Sinus auf pin3Atmega
485
https://radio-bastler.de/forum/showthread.php?tid=8756&pid=154185#pid154185
486
20190614 Frequenzabhängige Steuerspannung auf pin11Atmega
487
20190906 I2C-Display https://www.instructables.com/id/How-to-Connect-I2C-Lcd-Display-to-Arduino-Uno/ 
488
20190920 Herztaster Tastverzögerung gegen versehentliches Antippen des Tasters.
489
20190924 Audiopegelanzeige mit LEDs
490
20190929 Unterspannungsanzeige
491
*/

Nächstes mal bitte selber aufräumen, bevor du andere um Hilfe bittest!

von Wolfgang (Gast)


Lesenswert?

Aus der W. schrieb:
> Ich habe keine Ahnung wie diese Rotary.h da ausgewertet wird
> und wo ich mit dem bool die Auswertung ein- und ausschalten
> kann.

Woher sollen wir das wissen, was in deiner Rotary-Bibliothek passiert.
Für Details wirst du vermutlich auch nach einer Rotary.ino gucken 
müssen.

von Stefan F. (Gast)


Lesenswert?

Wo wird denn hier der Rotary Encoder überhaupt benutzt? Ich sehe es 
nicht.

von Stefan F. (Gast)


Lesenswert?

Ich glaube ich hab's: Vermutlich ist die ISR das Kernstück der Rotary 
encoder Abfrage. Vorschlag:

Ändere die bool Variable "ein" in den Typ "volatile bool". Und füge in 
die ISR ganz am Anfang eine Zeile ein:

if (!ein) return;

Warum das mit dem volatile sein muss, liest du am besten in der 
Dokumentation der avr-libc nach. Oder benutze die Suchfunktion dieses 
Forums. Das wird hier gefühlt jeden Monat erneut erklärt.

von oldeurope O. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Ich sehe es
> nicht.

Na wenn Du das nicht siehst, wie soll ich das dann schaffen?

Übrigens finde ich es total doof, dass Du den Code in Deinen
Beitrag kopiert hast. Dazu gibt es doch die Codeansicht.
(Leider ohne Zeilennummerierung, aber die hast Du ja auch nicht
drin.

LG
old.

von Wolfgang (Gast)


Lesenswert?

Stefanus F. schrieb:
> Ändere die bool Variable "ein" in den Typ "volatile bool". Und füge in
> die ISR ganz am Anfang eine Zeile ein:
>
> if (!ein) return;

Da ist es wohl deutlich stilvoller, den Interrupt gar nicht erst 
freizugeben, i.e. das zugehörigen IE-Bit nur zu setzen, wenn der Encoder 
aktiv sein soll.

von Stefan F. (Gast)


Lesenswert?

Aus der W. schrieb:
> Na wenn Du das nicht siehst, wie soll ich das dann schaffen?

Ich dachte du bist der Autor des Programms, dann musst du doch wissen, 
wie es funktioniert.

> Übrigens finde ich es total doof, dass Du den Code in Deinen
> Beitrag kopiert hast (statt anzuhängen)

Kritik angenommen

von oldeurope O. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Ich glaube ich hab's: Vermutlich ist die ISR das Kernstück der
> Rotary
> encoder Abfrage. Vorschlag:
>
> Ändere die bool Variable "ein" in den Typ "volatile bool". Und füge in
> die ISR ganz am Anfang eine Zeile ein:
>
> if (!ein) return;

Das hört sich gut an. Werde ich nachher probieren und berichten.

LG
old.

von oldeurope O. (Gast)


Angehängte Dateien:

Lesenswert?

Stefanus F. schrieb:
> if (!ein) return;

Wunderbar, klasse Lösung. Zeile 178

volatile ist nicht erforderlich.
Danke für "return"
https://www.arduino.cc/reference/de/language/structure/control-structure/return/
Warum muss return nicht in geschweifte Klammern?

LG
old.

von Stefan F. (Gast)


Lesenswert?

Aus der W. schrieb:
> volatile ist nicht erforderlich.

Doch ist es. Ansonsten ist das Gelingen reine Glückssache.

Eine andere Compiler Version, oder ein paar Zeilen neuer Code an ganz 
anderer Stelle können sonst schon zum Versagen führen.

> Warum muss return nicht in geschweifte Klammern?

Klammern fassen Blöcke von Befehlen zusammen. Hier soll nach der 
Bedingung nur ein einziger Befehl ausgeführt werden, daher sind die 
Klammern optional. Wenn du den Code mit Klammern besser lesbar findest, 
dann füge sie hinzu. Auf der Arbeit muss ich das tun (gemeinsam 
abgestimmte Code-Style Regel).

von oldeurope O. (Gast)


Lesenswert?

Also, ich habe jetzt die Klammern und das volatile hinzugefügt.
Keine Ahnung warum gerade dieser boolean das brauchen könnte und
die anderen booleans nicht. Jedenfalls funktioniert das so.

LG
old.

von Stefan F. (Gast)


Lesenswert?

Aus der W. schrieb:
> Keine Ahnung warum gerade dieser boolean das brauchen könnte

Ich dachte ich hätte dich dazu animiert, es zu googeln.

Der Compiler berücksichtigt nicht, dass dein Programm durch Interrupts 
unterbrochen werden kann.

Wenn der Interrupt eine Variable liest, die das Hauptprogramm ändert 
(oder anders herum), kann zu eifriges Cachen in CPU Registern dazu 
führen, das die eine Seite (ISR) nicht sieht, was die andere Seite 
(Hauptprogramm) gemacht hat.

Volatile verhindert diesen Konflikt. Mehr Details bitte googeln, ich 
habe keine Lust das immer wieder durchzukauen.

von oldeurope O. (Gast)


Lesenswert?

Also weil der <rotary.h> über Interrupts arbeitet, muss der
boolean da volatile sein. OK, merke ich mir.

Als nächstes versuche ich mal mit dem Rotary eine
Spannung über einen PWM-Pin zur Pegeleinstellung zu gewinnen.
Ich muss ein großes Tandempoti los werden.

LG
old.

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.