Forum: Mikrocontroller und Digitale Elektronik atmega8 8bit pwm counter1


von Florian (Gast)


Lesenswert?

Hallo.

Ich wuerde gerne ueber eine 8bit pwm leds Ansteuern. Mit der 8bit 
Counter klappt das auch. Nur mit dem 16bit Counter habe ich ein Problem.

Ich schreibe die Werte von 0 - 255 in OCR1AL und schreibe 0x00 nach 
OCR1AH. Die WGM Bits sind folgendermasze gesetzt:

WGM13  WGM12  WGM11 WGM10
   0             1             0          1

Laut Datenblatt ist das der 8Bit FastPwm Mode, und Top ist 0x00FF. Wenn 
ich die Werte nun 'von Hand' schreibe:

for( uint8_t i=0; i < 256; i++ )
{
   OCR1AH = 0x00;
   OCR1AL  = i;
}

klappt das ganze auch gut. Wenn ich die Werte aber aus einer uint8_t 
Tabelle nehme:
table[360][3] = { {0, 4, 0} ..... } };

Wird die Led erst hell, flackert dann einmal kurz und faengt von Vorne 
an.

Hat jemand eine Idee warum die flackert? Die Werte in der Tabelle 
uebersteigen 255 nicht. Die Tabelle ist wirklich als uint8_t angelegt 
und auch die Indizierung ist richtig. Die Tabelle enhaelt RGB-Werte die 
einmal den HSV-Farbraum durchlaufen von 0-360Grad.

Grusz Florian

von Florian (Gast)


Lesenswert?

Ich vergasz zu sagen:
Ich deaktiviere alle Interrupts bevor ich in das High/Low register 
schreibe.

von Juergen G. (jup)


Lesenswert?

Du must nicht das OCR1AH und OCR1AL register getrennt schreiben,

OCR1A = DeinWert;

tut es auch.

und wenn Du das in der ISR machst musst Du auch keine Interrups 
deaktivieren.

for( uint8_t i=0; i < 256; i++ )

ist alte coding style

deklariere i vorher

und dann nur

for( i=0; i < 256; i++ )

bei einem i als uint8_t wird Deine Bedingung (i < 256) immer war sein

Ju

von Karl H. (kbuchegg)


Lesenswert?

> for( uint8_t i=0; i < 256; i++ )
>
> ist alte coding style

eigentlich nicht.
Das ist eigentlich neuer Stil und ist eine Empfehlung es so zu machen.


> Hat jemand eine Idee warum die flackert? Die Werte in der
> Tabelle uebersteigen 255 nicht. Die Tabelle ist wirklich als
> uint8_t angelegt und auch die Indizierung ist richtig.

Na denn. Wenn ohnehin alles richtig ist, dann gibt es auch kein Problem. 
Da es aber ein Problem gibt, wird eben nicht alles richtig sein.

Moral von der Geschichte: Anstatt deinen Code zu beschreiben poste ihn 
lieber! Denn irgendwo hast du einen Fehler, den du selber nicht siehst. 
Du du ihn selber aber nicht siehst, taucht er logischerweise auch in 
deiner Prosabeschreibung des Codes nicht auf.

Aber abgesehen davon

uint8_t table[360][3] = ....

das sind 360*3 Bytes. Also 1080 Bytes. Wieviel SRAM hat ein Mega8 noch 
mal?

von Juergen G. (jup)


Lesenswert?

Karl Heinz Buchegger schrieb:
>> for( uint8_t i=0; i < 256; i++ )
>>
>> ist alte coding style
>
> eigentlich nicht.
> Das ist eigentlich neuer Stil und ist eine Empfehlung es so zu machen.
>

uups,

ich hab C vor vielen Jahren mit

for( int i=0; i < 256; i++ )

gelernt. Dann musste ich es irgenwann verwerfen weil die Compiler es 
immer angemeckert haben.

Jetzt hab ich mich daran gewoehnt und schon geht es "back to the roots" 
?

Nach der Aussage von kbuchegg musste ich das natuerlich gleich testen, 
und er hat recht, mein compiler benutzt -std=gnu99 und er mecker es 
nicht mehr an.

Also dann, Kommando zurueck. Es koente ja langweilig werden.

Ju

von Karl H. (kbuchegg)


Lesenswert?

Juergen G. schrieb:

> ich hab C vor vielen Jahren mit
>
> for( int i=0; i < 256; i++ )
>
> gelernt.

Da hattest du einen neueren Compiler

> Dann musste ich es irgenwann verwerfen weil die Compiler es
> immer angemeckert haben.

Ältere Compiler.

> Jetzt hab ich mich daran gewoehnt und schon geht es "back to the roots"
> ?


Anders rum.
Am Anfang der Zeit galt die Regel:
Variablendefinitionen werden an den Funktionsanfang zusammengezogen.
Diese Regel wurde irgendwann gelockert zu: Variablendefinitionen können 
auch innerhalb von Blöcken passieren und werden an den Blockanfang 
zusammengezogen
Danach konnte man die Variablendefinitionen an die Stelle verschieben, 
an die die Variable das erste mal tatsächlich benutzt wird.

Der Weg geht also hin zu: Variablendefinitionen sollen so eng wie 
möglich und so kurz wie möglich vor der verwendenden Stelle passieren.

Das Ziel ist es, den Scope von Variablen möglichst einzuschränken und 
die Scopegrenzen möglichst eng um die verwendende Stelle legen zu 
können.

Mit etwas Phantasie könnte man sagen: Die logische Fortsetzung der 
Doktrin globale Variablen sind böse. Und so wie funktionslokale 
Variablen einen Ausweg aus globalen Variablen darstellen, so sind 
blocklokale Variablen der Ausweg aus funkions-'globalen' Variablen. Wenn 
man jetzt noch definiert, dass ein for sich in dieser Beziehung wie ein 
Block verhält, dann sind wir genau bei der jetzigen Situation.

   for( int i = 0; i < 10; i++ ) {
     ...
   }

   .... (A)

   for( int i = 0; i < 10; i++ ) {
     ...
   }

das sind 2 verschiedene Variablen i. Im Code dazwischen (A) existiert 
keine Variable i, ein Zugriff darauf ist an dieser Stelle daher illegal.


C++ hatte da einen großen Einfluss auf diesen Weg, weil dort die 
Objektkonstruktion mittels Konstruktor unter Umständen eine teure 
Operation ist.

void foo()
{
  MeineKlasse xyz;

  if( Operation_gültig )
    xyz.Machwas();
}

hat das 'Problem', dass xyz auf jeden Fall konstruiert werden muss, 
selbst wenn es danach überhaupt nicht benutzt wird. Zieh ich das aber in 
einen Block rein


void foo()
{
  if( Operation_gültig ) {
    MeineKlasse xyz;
    xyz.Machwas();
  }
}

dann spare ich diese Konstruktionskosten im Fall, dass überhaupt nichts 
mit dem Objekt gemacht wird.

In weiterer Folge hat sich dann herausgestellt, dass diese 
Vorgehensweise softwaretechnisch nicht schlecht ist und zu einer 
positiven Codequalität beiträgt. C hat das dann von C++ abgekupfert 
(genauso wie const).

von Florian (Gast)


Lesenswert?

Okay ich habe den Fehler noch nicht finden koennen und poste hier mal 
den code. Vielleicht sieht ja jemand was schief laeuft oder woraum ich 
nicht gedacht habe. Vielen Dank schonmal fuer die bisherigen Antworten.
1
uint8_t color[360][3] = { *snip* };
2
3
int main( void )
4
{
5
   DDRB = 0xff;
6
   // Init pwm:
7
   // FastPwmMode -> ATMEGA8. pwm 8bit -> only 2 16 bit 
8
   //                                        channels avail and we want to drive 3 leds...
9
   // TCCR1A   COM1A1   COM1A0  COM1B1  COM1B0  FOC1A   FOC1B   WGM11   WGM10
10
   //           |       |     |     |      |        |      |     +--> Waveform Generation Mode
11
   //           |       |     |     |      |        |      +--------> Waveform Generation Mode
12
   //           |       |     |     |      |        +---------------> Force Output Compare
13
   //           +-------+-----+-----+------+------------------------> CompareMatchModes ASO.
14
   // COM sets output compare mode depending on WGM (WaveformGenerationMode)
15
   // FastPwm: COM1A1/COM1B1    COM1A0/COM1B0
16
   //                1                0         Clear OC1A/OC1B on compare match - set at BOTTOM
17
18
   // WaveformGenerationMode 
19
   // WGM13  WGM12   WGM11   WGM10
20
   //    0     1       0       1    Fast PWM 8bit -> TOP(0x00ff) UpdateOCR1x(Bottom) TOV(TOP)
21
22
   TCCR1A = 0x00;
23
   TCCR1A |= ( 1 << COM1A1 ) | ( 1 << COM1B1 ) | ( 0 << COM1A0 ) | ( 0 << COM1B0 ) | ( 0 << FOC1A ) | ( 0 << FOC1B ) | ( 0 << WGM11 ) | ( 1 << WGM10 );
24
25
   //TCCR1B:  ICNC1 ICES1  xxx  WGM13   WGM12   CS12   CS11   CS10
26
   //           |       |     |     |      |        |      |     +--> ClockSelect 1 -+{
27
   //           |       |     |     |      |        |      +--------> ClockSelect 0  +   -> clk/1
28
   //           |       |     |     |      |        +---------------> ClockSelect 0 -+{
29
   //           |       |     |     |      +------------------------> WaveformGeneration
30
   //           |       |     |     +-------------------------------> WaveformGeneration
31
   //           |       +-------------------------------------------> InputCaptureEdgeSelect
32
   //           +---------------------------------------------------> InputCaptureNoiseCanceler
33
34
   TCCR1B = 0x00;
35
   TCCR1B |= ( 0 << ICNC1 ) | ( 0 << ICES1 ) | ( 0 << 5 ) | ( 0 << WGM13 ) | ( 1 << WGM12 ) | ( 0 << CS12 ) | ( 0 << CS11 ) | ( 1 << CS10 );
36
37
   TCCR2 = 0x00;
38
   TCCR2 |= ( 0 << FOC2 ) | ( 1 << WGM20 ) | ( 1 << COM21 ) | ( 0 << COM20 ) | ( 1 << WGM21 ) | ( 0 << CS22 ) | ( 0 << CS21 ) | ( 1 << CS20 );
39
40
   uint16_t k=1;
41
42
   uint8_t r=0;
43
   uint8_t g=0;
44
   uint8_t b=0;
45
   sei();
46
   for( ;; )
47
   {
48
      if(k == 359 )
49
         k=0;
50
      OCR1A = color[k][0]; // b
51
      OCR1B = color[k][1]; // g
52
      OCR2  = color[k][2]; // r
53
      _delay_ms(50);
54
      k+=1;
55
   }
56
   return 0;
57
}

von Florian (Gast)


Lesenswert?

Nachtrag:

Variablendeklaration ist in C89 immernoch nicht erlaubt. Der C99 
Standart machts aber moeglich, duerfte somit kein Ansi-C mehr sein.

von Florian (Gast)


Lesenswert?

Ich meinte Variablendeklaration innerhalb der for schleife also for( INT 
i..) anstelle von int i; for( i=0...)

Gab es hier nicht mal ein Edit-button fuer die beitraege?

von Karl H. (kbuchegg)


Lesenswert?

Florian schrieb:

> Vielen Dank schonmal fuer die bisherigen Antworten.

Hast du alle gelesen?

> uint8_t color[360][3] = { snip };

360 * 3 Bytes mach 1080 Bytes. Du wirst dir schwer tun diese Datenmenge 
in 1024 Bytes SRAM, mehr hat der Mega8 nicht, unterzubringen.

von Florian (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Florian schrieb:
>
>> Vielen Dank schonmal fuer die bisherigen Antworten.
>
> Hast du alle gelesen?
>
>> uint8_t color[360][3] = { snip };
>
> 360 * 3 Bytes mach 1080 Bytes. Du wirst dir schwer tun diese Datenmenge
> in 1024 Bytes SRAM, mehr hat der Mega8 nicht, unterzubringen.

Mein Fehler. Mit einer kuerzeren Tabelle laeuft es reibunslos.

Vielen Dank

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

@Florian: Wenn sich deine Werte nicht ändern, schau dir mal PROGMEM in 
der avrlib an. Damit kannst du die Werte im Flash statt im RAM 
speichern.
Zugriff ist dann z.B. mit read_pgm_byte(Adresse) möglich.

Jetzt muss ich aber mal nachhaken. Wenn i eine uint_8t Variable ist, 
kann die doch nie grösser als 255 werden, oder? Damit würde doch die 
Abbruchbedingung niemals erfüllt sein:

Juergen G. schrieb :
> for( uint8_t i=0; i < 256; i++ )

von Karl H. (kbuchegg)


Lesenswert?

Matthias Sch. schrieb:

> Jetzt muss ich aber mal nachhaken. Wenn i eine uint_8t Variable ist,
> kann die doch nie grösser als 255 werden, oder? Damit würde doch die
> Abbruchbedingung niemals erfüllt sein:


Das übliche:
Code extra fürs Forum zurecht gemacht und dabei 5 Fehler eingebaut :-)

>
> Juergen G. schrieb :
>> for( uint8_t i=0; i < 256; i++ )

von Juergen G. (jup)


Lesenswert?

Karl Heinz Buchegger schrieb:

>
> Das übliche:
> Code extra fürs Forum zurecht gemacht und dabei 5 Fehler eingebaut :-)
>
>>
>> Juergen G. schrieb :
>>> for( uint8_t i=0; i < 256; i++ )


Ich hoffe das bezieht sich nicht auf meinen Post.

ich hab das

for( uint8_t i=0; i < 256; i++ )

vom TO aus dem ersten Post kopiert und auch in meinem ersten Post zum 
Thema darauf hingewiesen.

>bei einem i als uint8_t wird Deine Bedingung (i < 256) immer war sein

Ju

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.