Bargraph-Anzeige

OP #3318406
Lesenswert?

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
#3318440
Lesenswert?

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.
OP #3318549
Lesenswert?

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
OP #3318631
Lesenswert?

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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren