Hallo allemiteinander,
bei einen Glühkerzenheizer für Modellmotore verwende ich einen
Drehencoder, um den Strom für die Kerze einzustellen. Damit man auch
optisch sehen kann, wie weit die Regelung aufgedreht ist, habe ich eine
LED-Bargraph-Anzeige mit zehn Balken, also zehn LEDs angeschlossen. Die
ersten sieben LEDs sind grün und bei einem Atmega16 an den Ports C0 bis
C6 angeschlossen. Die letzten drei Balken sind rot und an den Ports A0
bis A2 dran.
Die Regelung der Kerze funktioniert einwandfrei, mit der Anzeige habe
ich jedoch große Probleme. Vielleicht könnte mir hier jemand auf die
Sprünge helfen. Erschwerend kommt noch hinzu, dass ich auch nicht der
große C-Profi bin.
Ich poste mal das bis auf die Anzeige abgespeckte Programm:
1 | // target: ATmega16
| 2 | // Bargraph Test
| 3 | // PS20130912
| 4 | //----------------------------------
| 5 |
| 6 | #include <avr/io.h>
| 7 | #include <stdlib.h>
| 8 | #include <avr/pgmspace.h>
| 9 | #define F_CPU 8000000
| 10 | #include <avr/interrupt.h>
| 11 |
| 12 | #define LEDSGN_DDR DDRC
| 13 | #define LEDSGN PORTC // green LEDs against VCC
| 14 | #define LEDSRT_DDR DDRA
| 15 | #define LEDSRT PORTA // red LEDs against VCC
| 16 |
| 17 | const uint16_t const_array[] PROGMEM =
| 18 | {0b1111111110000000,
| 19 | 0b1111111111111110,
| 20 | 0b1111111111111100,
| 21 | 0b1111111111111101,
| 22 | 0b1111111111111101,
| 23 | 0b1111111111111001,
| 24 | 0b1111111111111011,
| 25 | 0b1111111111111011,
| 26 | 0b1111111111110011,
| 27 | 0b1111111111110111,
| 28 | 0b1111111111110111,
| 29 | 0b1111111111100111,
| 30 | 0b1111111111101111,
| 31 | 0b1111111111101111,
| 32 | 0b1111111111001111,
| 33 | 0b1111111111011111,
| 34 | 0b1111111111011111,
| 35 | 0b1111111110011111,
| 36 | 0b1111111110111111,
| 37 | 0b1111111110111111,
| 38 | 0b1111111110111111,
| 39 | 0b1111111010111111,
| 40 | 0b1111111010111111,
| 41 | 0b1111111011111111,
| 42 | 0b1111111011111111,
| 43 | 0b1111110011111111,
| 44 | 0b1111110111111111,
| 45 | 0b1111110111111111,
| 46 | 0b1111100111111111,
| 47 | 0b1111101111111111,
| 48 | 0b1111100011111111};
| 49 |
| 50 |
| 51 | // --------------------------------------------------
| 52 |
| 53 | void init(void)
| 54 | {
| 55 | DDRD = (1<<PD4) | (1<<PD5); // set Port PD4 and PD5 as output
| 56 | LEDSGN_DDR = 0xFF; // PC0..7 alle Ausgang
| 57 | LEDSRT_DDR = (1<<PA0) | (1<<PA1) | (1<<PA2); // PA0 - PA2 Ausgang
| 58 |
| 59 | TCCR1A = (1<<WGM10)|(1<<COM1A1)|(1<<COM1B1);
| 60 | TCCR1B = (1<<WGM12)|(1<<CS12)|(1<<CS10);
| 61 | }
| 62 |
| 63 | // --------------------------------------------------
| 64 | // --------------------------------------------------
| 65 |
| 66 | int main( void )
| 67 | {
| 68 | int16_t value = 0;
| 69 |
| 70 | int16_t last_val = 256;
| 71 | int8_t value8bit = 0;
| 72 | uint8_t tmp_leds_low;
| 73 | uint8_t tmp_leds_high;
| 74 |
| 75 | init(); // Ports und Timer1 init
| 76 |
| 77 | ////encode_init(); // Encoder initialisieren
| 78 |
| 79 | while(1)
| 80 | {
| 81 | ////value += encode_read4(); // hier wird der Drehencoder eingelesen.
| 82 |
| 83 | // Bereich von 20 bis 50
| 84 | if (value <= 20 )
| 85 | value = 20;
| 86 | else if (value >= 50 )
| 87 | value = 50;
| 88 |
| 89 | if ( value != last_val ) // Wert vom Encoder veraendert?
| 90 | {
| 91 | last_val = value;
| 92 |
| 93 | OCR1A = value; // PWM einstellen
| 94 | OCR1B = 0;
| 95 |
| 96 |
| 97 | value8bit = value; // Wert sichern
| 98 | value8bit = value8bit - 19;
| 99 |
| 100 |
| 101 | tmp_leds_high = pgm_read_byte(&const_array[value8bit]);
| 102 | value8bit = value8bit - 1;
| 103 | tmp_leds_low = pgm_read_byte(&const_array[value8bit]);
| 104 |
| 105 | LEDSRT = tmp_leds_high; // Bitmuster ausgeben
| 106 | LEDSGN = tmp_leds_low; // Bitmuster ausgeben
| 107 | }
| 108 |
| 109 | }
| 110 | }
|
Bei jedem Bit, das auf 0 gesetzt wird, leuchtet die dazugehörende LED
(die Anoden sind jeweils über einen Widerstand auf +5V gelegt). Die Bits
7, 11, 12, 13, 14 und 15 sind immer 1, da an diesen Ports nichts
angeschlossen ist.
Der Bereich von value zwischen 20d und 50d ist für die Glühkerze
notwendig.
Die Anzeige mit den grünen LEDs funktioniert so, wie ich mir das
vorgestellt habe - zumindest, seit ich die Zeile
1 | value8bit = value8bit - 1;
|
eingefügt habe. Allerdings gehen die roten LEDs parallel mit, obwohl
diese doch erst im letzten Drittel angesteuert werden sollten. Wenn ich
diese Zeile weglasse, kommt nur noch Chaos zur Anzeige.
Egal was ich versuche, die roten LEDs machen was sie wollen. Könnte mir
jemand einen Tipp geben? Als Werkzeug verwende ich das Atmel Studio 6.1.
Servus
Peter
Peter Spiess schrieb:
> Könnte mir
> jemand einen Tipp geben?
value8bit = value; // Wert sichern
value8bit = value8bit - 19;
Wieso 19?
Wenn value Werte von 20 bis 50 annehmen kann, dann musst du 20 abziehen,
damit bei einem Wert von 20 der Arrayindex 0 rauskommt.
Wir fangen bei 0 zu zählen an!
Hör mit diesem Quatsch auf, dein Array als uint16_t anzulegen und dann
mittels pgm_read_byte (BYTE(!)) zuzugreifen.
Nimm einen pgm_read_word, der liest eine 16-Bit Einheit. Und die
zerlegst du dann im Speicher in den Teil für die grünen LED und den Teil
für die roten LED. Genauso wie du es auch machen würdest, wenn du dein
Array nicht mittels PROGMEM ins Flash geschoben hättest. Dann klappts
auch mit der Byte-Order bzw. der Offsetberechnung durch den Compiler,
ohne dass du dich gross darum kümmern musst.
Karl Heinz Buchegger schrieb:
Hallo Karl Heinz,
erstmal danke für Deine Antwort. Ok, das mit den -19 ist klar. Da habe
ich mich vertan.
> Hör mit diesem Quatsch auf, dein Array als uint16_t anzulegen und dann
> mittels pgm_read_byte (BYTE(!)) zuzugreifen.
>
> Nimm einen pgm_read_word, der liest eine 16-Bit Einheit. Und die
> zerlegst du dann im Speicher in den Teil für die grünen LED und den Teil
> für die roten LED. Genauso wie du es auch machen würdest, wenn du dein
> Array nicht mittels PROGMEM ins Flash geschoben hättest. Dann klappts
> auch mit der Byte-Order bzw. der Offsetberechnung durch den Compiler,
> ohne dass du dich gross darum kümmern musst.
Ok, Du hast Recht, ist schon ein bisschen durcheinander. Kann ich das
gelesene "word" als Bitfeld behandeln? So wie es im AVR-GCC-Tutorial
beschrieben ist? Ich probiere das aus.
Servus
Peter
Hallo Karl Heinz,
jetzt funktioniert die Anzeige! Ich habe das Programm wie folgt
geändert:
1 | uint16_t tmp_leds;
| 2 | uint8_t tmp_leds_low;
| 3 | uint8_t tmp_leds_high;
| 4 |
| 5 | // -19 war der erste Fehler:
| 6 | value8bit = value8bit - 20;
| 7 |
| 8 | tmp_leds = pgm_read_word(&const_array[value8bit]);
| 9 |
| 10 | tmp_leds_high = tmp_leds >> 8;
| 11 | tmp_leds_low = tmp_leds;
|
Bestimmt gibt es auch eine andere (bessere) Lösung. Aber es funktioniert
so :-)
Danke Karl Heinz für Deine Hilfe.
Servus
Peter
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|