Forum: Mikrocontroller und Digitale Elektronik Bargraph-Anzeige


von Peter S. (petersp)


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

von Karl H. (kbuchegg)


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.

von Peter S. (petersp)


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

von Peter S. (petersp)


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

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.