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.
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!
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.
Wo wird denn hier der Rotary Encoder überhaupt benutzt? Ich sehe es nicht.
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.
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.
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.
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
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.
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.
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).
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.