www.mikrocontroller.net

Forum: Compiler & IDEs Zu großer Code, obwohl winziges Programm


Autor: Daniel B. (inox5) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#include <avr/io.h>      //Grundfunktionen
#ifndef F_CPU        //Vordefinieren für delay.h
#define F_CPU 1000000UL    //Definition von F_CPU in Herz
#endif      
#include <util/delay.h>    //Warteschleifen
#include <stdint.h>

int main (void)        //Hauptfunktion
{              //Anfang der Hauptfuktion
DDRB=0b11111111;      //Alles Ausgänge
uint16_t a;          //Variable 16Bit
char i;            //Zählvariable für die Schleife
a=1000;            //Der Impuls soll 1ms lang sein
  while(1)      
  {
  i=50;          //Durch diese Definierung ist die While(i) Schleife immer 1s (50*0,02s) lang
    while(i)
    {
    PORTB=0b11111111;
    _delay_us(a);    //Impulslänge
    PORTB=0b00000000;
    _delay_us(20000-a);  //Hierdurch wird erreicht, dass das Gesamtsignal genau 20ms lang ist
    i--;
    }
  a=a+100;        //Ich will aber das die Impulse länger werden
    if(a==2000)      //Da aber ab einer Impulslänge von über 2ms der Servo kaputt gehen kann, wird hier nun die Notbremse gezogen
    {
    a=1000;
    }
}
return 0;
}

Hallo,
Dieser Code hat die Funktion 11 verschiedene Pulslängen an PORTB eines 
Attiny2313 zu bilden. Das Problem ist aber, dass der Code eine Größe 
erreicht die etwa doppelt so groß ist, wie der Speicherplatz eines 
Attiny2313. Die Optimierung 0s ist eingestellt.
Vielleicht könnte mir ja jemand helfen. Danke schonmal im Vorraus.

MfG
Inox

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dein Flashfresser dürfte die float-Arithmetik sein, die von _delay_us 
benötigt wird.

Es wäre besser, wenn du einen Timer programmierst und aus der 
Interruptroutine heraus dem Hauptprogramm signalisierst, daß soundsoviel 
Zeit vergangen ist.

Das geht dann mit reiner int-Arithmetik...

Autor: Ralf W. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

vielleicht wegen diesen Zeilen:
> _delay_us(20000-a);
>a=a+100;

Soweit ich weiss mag die AVR Lib C dies nicht. Dort steht,
das für die _delay_us Funktionen möglichst Konstanten benutzt
werden sollen.
Quote AVR LibC Reference:

In order for these functions to work as intended, compiler optimizations 
must be enabled, and the delay time must be an expression that is a 
known constant at compile-time. If these requirements are not met, the 
resulting delay will be much longer (and basically unpredictable), and 
applications that otherwise do not use floating-point calculations will 
experience severe code bloat by the floating-point library routines 
linked into the application.

Vielleicht solltest du dich mit den Timern der Avr beschäftigen.
Die Tutorials bieten hier einen guten Einstieg.

gruß ralf

Autor: ... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kenne die Optimierungsstufen nicht, aber kännte es sein, dass in der 
gewähten die Schleifen "abgerollt" werden?

Autor: Kachel - Heinz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit Timer sollte das einfacher gehen.

KH

Autor: Ralf W. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

nö da werden Floating Point Routinen hinzugelinkt.

experience severe code bloat by the floating-point library routines
linked into the application.

gruß ralf

Autor: Daniel B. (inox5) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich werde es wohl mit den Timern lösen.
Ich werde wahrscheinlich mit einem Timer eine 100µs Pause schreiben und 
diese einsetzen.

MfG
Inox

Autor: Thomas Weyhrauch (thomas100)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

du kannst dir ja mal das Assemblerlisting oder das map-file angucken. Da 
siehst du, was dein Programm so aufbläst.

_delay_us ist so deklariert:
void _delay_us(double __ms)
und macht auch float-Berechnungen während der Laufzeit, die nicht weg 
optimiert werden können, wenn du keine Konstante übergibst.
Alternativ kannst du mal versuchen, eine eigene for-Schleife zu 
schreiben und _delay_loop_1() oder _delay_loop_2() aufzurufen. Die sind 
in der "delay_basic.h" deklariert.

Oder du nimmst einen Timer und wartest, bis das Overflow-Bit gesetzt 
wird.

Gruß
Thomas

Autor: Andreas K. (ergoproxy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nimm ne For Schleife und schreib in den Schleifenkörper delay_us(1); und 
lass dann die schleife sooft ablaufen, wie du es brauchst, dann hat das 
delay eine Konstante als Parameter und alle sind happy oder nimm gleich 
den Timer.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mehr oder weniger sinnvoll. Die for() muss erst bei jedem Durchlauf 
geprüft werden, was auch wieder Zeit braucht. Somit wird das ganze in 
längeren Wartezeiten doch ziemlich ungenau.

Autor: Daniel B. (inox5) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hm aber die idee mit dem "loopen" der delay_us(1) ist gar nicht 
schlecht.
Werde es jetzt vorerst auch mal so machen, mal schaun wie genau das 
wird...

Danke für diesen Tipp!

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du mit delay_us(1) einen Aufruf von _delay_us mit Parameter int 1 
meinst, wirst du wenig Glück haben. _delay_us braucht selbst 
Fließkommaarithmetik.

Aber du könntest die Routinen aus delay_basic.h verwenden...

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> hm aber die idee mit dem "loopen" der delay_us(1) ist gar nicht
> schlecht.
> Werde es jetzt vorerst auch mal so machen, mal schaun wie genau das
> wird...

Da die Delay-Zeiten immer Vielfache von 100µs sind, würde ich eine
Schleife um einen _delay_us(100) machen. Das macht die Sache genauer.
Reicht die Genauigkeit immer noch nicht, machst du die 100 um so viel
kleiner, wie es dem Schleifen-Overhead entspricht. Das Argument von
_delay_us darf dabei durchaus auch eine gebrochene Zahl, also z.B.
97.4 sein, wichtig ist nur, dass es konstant ist.

Aber früher oder später solltest du es auch mit Timern versuchen, den
dafür sind diese da, und du hast ja schließlich auch Geld dafür bezahlt.
Der Hauptvorteil ist, dass damit der komplette Zeitbedarf des restlichen
Codes der in den Schleifen deines obigen Programms steht, weitgehend
kompensiert wird. Und solltest du irgendwann noch irgendwelche
Interrupts verwenden, stimmen die Zeiten der _delay_xx-Funktionen
überhaupt nicht mehr, da jede Unterbrechung durch einen Interrupts ihre
Ausführungszeit um den Rechenzeitbedarf des Interrupthandlers
verlängert.

Uhu Uhuhu schrieb:
> Wenn du mit delay_us(1) einen Aufruf von _delay_us mit Parameter int 1
> meinst, wirst du wenig Glück haben. _delay_us braucht selbst
> Fließkommaarithmetik.

Aber nur zur Compilezeit, nicht zur Laufzeit, deswegen stört es nicht.

Autor: Frank Schlaefendorf (Firma: HSCS) (linuxerr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nimm assembler!
so kleine controller sind effektiv nur in assembler zu programmieren. 
nutze den timer wenn er noch zur verfügung steht, das ist sinnvoller als 
zeitschleifen. der code wird dann nicht mehr als 10% des flashs 
beanspruchen.

Autor: Daniel der Drüsendieb (druesendieb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Halte ich für ein Gerücht. Man kann auch den Maschinencode, den der 
Compiler erzeugt hat, untersuchen und den Code so modifizieren, daß 
möglichst wenig unnötiger Code entsteht.

Das ist weniger Gefummel, als wenn man alles in ASM schreibt und man 
lernt dabei, sehr effizienten C-Code zu schreiben und nebenbei noch den 
Assembler.

Autor: Daniel B. (inox5) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein Problem mit dem Timer ist aber im Moment folgendes und zwar bekommt 
mein Timer0 (8Bit) 1000000 Impulse in der Sekunde (kein Vorteiler), das 
heißt wiederum das mein Timer 3906,25 pro Sekunde überläuft und das ist 
schon zu langsam, weil der Timer folglich dann nur alle 0,256ms 
überläuft. Der Timer müsste aber alle 0,1ms überläufen.

Mach ich nur en Denkfehler oder besteht die Lösung darin dem µC einen 
höheren Takt zu geben? Oder ließe sich das noch ganz anders lösen?

MfG
Inox

PS: Frohe Weihnachten! :-)

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kenne zwar die Tinys nicht,
aber Du kannst doch das Maximum von TCNT bestimmen bei dem die ISR 
ausgelöst und TCNT zurückgesetzt wird... ?!

Frohe Weihnachten

Autor: Daniel B. (inox5) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein ich kann lediglich auswerten, dass der Timer übergelaufen ist mehr 
nicht. Und das passiert nach 256 Impulsen

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann kannst du TCNT aber mit einem Wert Vorladen !

So das der Timer von z.B. 128 bis 255(überlauf) Zählt, oder ?

Ich glaube das was ich meinte war der CTC Modus...

Autor: Frank Schlaefendorf (Firma: HSCS) (linuxerr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das was du da machen willst, kann der timer ganz allein! benutze den 
pwm-modus und stelle den vorteiler so ein, dass der timer nach 20ms 
überläuft und einen interrupt auslöst. mit dem compare-register stellst 
du dann die breite der impule ein, die du haben willst. wenn der 
interrupt 50mal durchgelaufen ist, änderst du den wert der in das 
compare-register geladen wird. trenne dich von deinen zeitschleifen, das 
ist nonsens, die hardware kann das viel besser und effizienter und der 
code wird viel kürzer.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im Datenblatt auf Seite 68 im Absatz "Clear Timer on Compare Match Mode"

Im CTC Modus Zählt der Counter (TCNT++) hoch bis zu einem Vergleichswert 
der in OCR0A (TCNT==OCR0A) gespeichert ist.

Der hat den Modus also doch.

Das Vorladen des TCNT im Normalen Modus sollte aber auch gehen.

Autor: Frank Schlaefendorf (Firma: HSCS) (linuxerr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast wrote:
> Im Datenblatt auf Seite 68 im Absatz "Clear Timer on Compare Match Mode"
>
wenn er sich nun mit dem timer ein delay zaubern will, dann macht das 
sinn. so wie sein programm aussieht will er eine pwm und das kann der 
timer auch, dass einzige was sein programm tun muss ist die 
compare-werte für das tastverhältnis nachzuladen, den rest macht der 
timer selbst.

Autor: Daniel B. (inox5) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
das is natürlich gut, werd ich sofort ausprobieren. Weil wenn ich mit 
dem Timer alleine meine PWM bekommen kann, ist das natürlich wesentlich 
präziser und einfacher.

Autor: pumpkin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zu groß? Kein Wunder. _delay wird nicht mit einer Konstanten aufgerufen.

Ralf W. wrote:
In order for these functions to work as intended, compiler 
optimizations must be enabled, and the delay time must be an expression 
that is a known constant at compile-time. If these requirements are not 
met, the resulting delay will be much longer (and basically unpredictable),
and applications that otherwise do not use floating-point calculations will 
experience severe code bloat by the floating-point library routines linked 
into the application.

Autor: Daniel B. (inox5) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Abend,
Ich hab mir gedacht ich berichte euch mal was ich nun gemacht habe:
#include <avr/io.h>      //Grundfunktionen
#ifndef F_CPU        //Vordefinieren für delay.h
#define F_CPU 1000000UL            //Definition von F_CPU in Herz
#endif      
#include <util/delay.h>            //Warteschleifen
#include <stdint.h>
#include <avr/interrupt.h> 

ISR(TIMER1_COMPA_vect)
{
OCR1A=2500-OCR1A;   //Im ISR wird das Steuersignal für den Servo, aus der Differenz der Periodenlänge und des vorherigen Vergleichswert gebildet
}


int main (void)        //Hauptfunktion
{        
DDRB=0b11111100;      //Alles Ausgänge bis auf PB0 und PB1
PORTB=0b00000011;      //Pullup für PB0 und PB1
TCCR1A=0b01010000;      //Tooglen von PB3
TCCR1B=0b00001010;      //CTC-Mode und Prescaler 8; Prozessortakt
TIMSK=0b01000000;      //Interrupt bei Timer1 Comp.Match A
OCR1A=2375;    //das bringt den Servo in Neutrallage (1,5ms)
sei();         //Interrupts an
while(1)      //Programmschleife
{
  if ( !(PINB & (1<<PINB0)) )     //Abfrage eines Schalters
  {
  OCR1A=OCR1A+3;
  _delay_ms(50);                  //Verlangsamung der Veränderung
  }
  if ( !(PINB & (1<<PINB1)) )     //Abfrage eines Schalters
  {
  OCR1A=OCR1A-3;
  _delay_ms(50);                  //Verlangsamung der Veränderung
  }
}
return 0;  //C-Standard
}

Letzendlich bin ich am CTC-Modus hängengeblieben ;), nie gedacht, dass 
es so simpel ist, auch mit den Interrupts...
Dieses Programm erzeugt mit Erfolg meine gewünschte PWM, die ich für den 
Servo brauche. Zusätzlich kann man das PWM Signal in 0,024ms Stufen 
verändern, d.h. den Servo aus der Neutralposition links oder rechts 
drehen lassen. Dies geschieht durch die 2 angeschlossenen Schalter.
Mehr dazu bald unter Modellbauservo Ansteuerung im wiki.

Danke nochmal für eure Hilfe,

MfG
Inox

Autor: B e r n d W. (smiley46)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Daniel

Die Timer-Version ist natürlich die sauberere Lösung.

Aber wie Kürbis schon sagte, so wärs auch gegangen:
AVR Memory Usage
Device:  attiny2313
Program: 198 bytes (9.7% Full)
#include <avr/io.h>
#include <util/delay.h>

void 
my_delay_us(unsigned int ms)                          // delay ms
{
   while(ms) {
      _delay_us(0.96);
      ms--;
   }
}

int 
main(void)
{
   DDRB=0b11111111;     //Alles Ausgänge
   uint16_t a;          //Variable 16Bit
   char i;              //Zählvariable für die Schleife

   a=1000;                 //Der Impuls soll 1ms lang sein
   while(1)      
   {
      i=50;                //Durch diese Definierung ist die While(i)
                           //Schleife immer 1s (50*0,02s) lang
      while(i)
      {
         PORTB=0b11111111;
         my_delay_us(a);   //Impulslänge
         PORTB=0b00000000;
         my_delay_us(20000-a);  //Hierdurch wird erreicht, dass das
                           //Gesamtsignal genau 20ms lang ist
         i--;
      }
      a=a+100;             //Ich will aber das die Impulse länger werden
      if(a==2000)          //Da aber ab einer Impulslänge von über 2ms 
                           //der Servo kaputt gehen kann, 
                           //wird hier nun die Notbremse gezogen
      {
         a=1000;
      }
   }
   return 0;
}

Autor: Daniel B. (inox5) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stimmt so wärs auch gegangen, aber auf die zahlreichen Anregungen hier 
Richtung Timer + ISR hab ich beschlossen, dann doch mal Neuland zu 
betreten. Will ja schließlich was lernen.^^

Letzendlich erfüllen beide Programme den gleichen Zweck und welche nun 
die bessere ist, finde ich, muss jeder selbst wissen.

MfG
Inox

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dashier:
void 
my_delay_us(unsigned int ms)                          // delay ms
{
   while(ms) {
      _delay_us(0.96);
      ms--;
   }
}

ist unbestreitbar ein krasser Widerspruch zu demhier:
my_delay_us(20000-a);  //Hierdurch wird erreicht, dass das
                       //Gesamtsignal genau 20ms lang ist

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel B. wrote:
>   OCR1A=OCR1A+3;

Auch wenn dein Programm funktioniert, so hat es noch ein paar Fußangeln.

Sehr versteckt im Tutorial findest du dazu das hier:

http://www.mikrocontroller.net/articles/Interrupt#...

OCR1A ist ein 16-Bit Register, das nicht atomav verändert werden kenn. 
Wenn während des Inkrementierens um 3 eine IRQ auftritt, kann das 
zuProblemen führen (reca condition) und das Servo macht nen Sprung.

Autor: Daniel B. (inox5) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stimmt, das stellt ein Problem dar. Nur wenn gerade just ein Interrupt 
während des in-das-Register-Schreibens passiert fehlt eine Periode 
einfach und noch viel schlimmer: Die Perioden würden ihre Polarität 
ändern! Fragt sich was das geringere Übel ist...

Autor: T. H. (pumpkin) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Daniel B. (inox5) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
int main (void)        //Hauptfunktion
{              //Anfang der Hauptfuktion
DDRB=0b11111100;      //Alles Ausgänge bis auf PB0
PORTB=0b00000011;      //Pullup für PB2
TCCR1A=0b01010000;      //Tooglen von PB3
TCCR1B=0b00001010;      //CTC-Mode und; Prescaler 8; Prozessortakt
TIMSK=0b01000000;      //Interrupt
OCR1A=2375;          //Neutralposition (2375*0,008=1,5ms)
sei();            //Interrupt an
while(1)
{
  if ( !(PINB & (1<<PINB0)) )  //Abfrage eines Schalters
  {
        cli();
  OCR1A=OCR1A+3;
        sei();
  _delay_ms(50);        //Verlangsamung der Veränderung
  }
  if ( !(PINB & (1<<PINB1)) )  //Abfrage eines Schalters
  {
        cli();
  OCR1A=OCR1A-3;
        sei();
  _delay_ms(50);        //Verlangsamung der Veränderung
  }
}
return 0;
}

Ich hab das jetzt so gemacht. Geht auch oder?

MfG
Inox

Autor: Stefan Kleinwort (_sk_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Daniel,

die Idee mit dem atomaren Zugriff ist zwar im Prinzip richtig, beim 
Zugriff auf die Timerregister (ausnahmsweise) überflüssig: den atomaren 
Zugriff regelt die Timer-Hardware selber (siehe ATtiny Manual S. 88: 
accessing 16 Bit registers).

Ein anderes, noch wichtigeres Problem regelt die Timerhardware im 
PWM-Modus aus selbstständig:

angenommen, Dein OCR1A steht auf 15 und Dein Counter zählt hoch:
10, 11, 12, 13, 14, 15, 16, 17, 18, ....
Zum Zeitpunkt, an dem der Counter auf 13 steht, liest Du OCR1A aus 
(=15), ziehst 3 ab und schreibst das Ergebnis (=12) zurück nach OCR1A.

Das Ergebnis ist:
Dein Counter hat den Match mit OCR1A verpasst!

Um das zu vermeiden, ist OCRnA doppelt-gepuffert (siehe auch Man. S. 
95):
Wenn Du OCRnA änderst, änderst Du nur ein Schattenregister. Dessen Wert 
wird immmer dann in das "richtige" OCRnA übernommen, wenn der Timer 
überläuft bzw. NULL erreicht (genaueres steht im Man. bei den 
verschiedenen PWM-Modi beschrieben).

Fazit:
Dein erstes Hardware-PWM Programm war korrekt.

Viel Spass noch, Stefan

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Stefan Kleinwort (sk)

>die Idee mit dem atomaren Zugriff ist zwar im Prinzip richtig, beim
>Zugriff auf die Timerregister (ausnahmsweise) überflüssig: den atomaren
>Zugriff regelt die Timer-Hardware selber (siehe ATtiny Manual S. 88:
>accessing 16 Bit registers).

Das reicht nicht!

MFG
Falk

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
WAS reicht nicht?

Gruß, Stefan

Autor: Frank Schlaefendorf (Firma: HSCS) (linuxerr)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also ich verstehe das alles nicht. warum werden hier komische 
zeitschleifen programmiert, wenn der timer einen pwm-modus hat und es 
ganau das ist worum es hier geht. ich habe das ganz zum anfang schon 
gesagt. der threadersteller hat dann ja den ctc-modus genutzt und sich 
wieder ein delay gebastelt. warum macht man sowas?? nur weil das auch 
gehen muss??? ich kapiers nicht, gibt es da einen wichtigen grund für??
das ist doch so, als wenn ich mir sage: "mensch eine tür müsste man in 
autos einbauen und dann könnte man sogar einsteigen und mitfahren." und 
danach wird tagelang darüber diskutiert, wie man fenster so verändern 
könnte, dass man dadurch bequem einsteigen kann, dabei gibt es die tür 
längst!

ich versteh es nicht!

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Frank,

der TS benutzt doch mittlerweile den PWM, und das ist immerhin Dein 
Verdienst!
Die Delays, die noch in dem Programm sind, sin ja für die 
"Bedienoberfläche", das ist ne andere Baustelle und ich denke, so nur 
zum Testen gedacht.

Viele Grüße, Stefan

Autor: Daniel B. (inox5) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Frank
In der Programmschleife ist nur en delay drin, weil ich dafür net auch 
noch extra nen Timer verwenden will und es somit auch einfacher bleibt. 
Meine PWM (auch der eigentliche Threadgegenstand) hab ich nun ja (dank 
dir) mit dem CTC-Modus gelöst.

@Stefan
Genau so hab ich es gemeint.

MfG
Inox

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Stefan (Gast)

>WAS reicht nicht?

Den atomaren Zugriff auf die 16 Bit Timerregister per Hardware zu 
sichern.
cli() und sei() bzw. bei neueren AVR GCC Versionen ein atomic block sind 
notwendig.

MFG
Falk

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Falk:

Manual ATmega32, S.89:
"When the low byte of a 16-bit register is written by the CPU, the high 
byte stored in the temporary register, and the low byte written are both 
copied into the 16-bit register in the same clock cycle. When the low 
byte of a 16-bit register is read by the CPU, the high byte of the 
16-bit register is copied into the temporary register in the same clock 
cycle as the low byte is read".

Solange ein IR nicht das temporary register ändert, ist ein atomarer 
Zugriff nicht notwendig - diesen erledigt in diesem Fall die 
Timer-Hardware (beide 8-Bit-Register werden von der HW gleichzeitig [in 
the same clock cycle] in die 16-Bit Timer-Register geschrieben).

Gruß, Stefan

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@  Stefan (Gast)

>Solange ein IR nicht das temporary register ändert, ist ein atomarer
>Zugriff nicht notwendig

Das tut sie in diesem Beispiel aber.

OCR1A=2500-OCR1A;

> - diesen erledigt in diesem Fall die
>Timer-Hardware (beide 8-Bit-Register werden von der HW gleichzeitig [in
>the same clock cycle] in die 16-Bit Timer-Register geschrieben).

Du verwechselt den atomaren Zugriff auf Hardwareregister mit dem 
atomaren Zugriff auf normale Variabeln im RAM. Bei BEIDEN muss man 
aufpassen und mit cli/sei arbeiten, wenn auf die selbe Variable/Register 
im Hauptprogramm UND einer ISR zugegriffen wird. Der Mechanismus mit dem 
temp-Register ermöglicht "nur" den atomren zugriff auf 16 Bit 
Hardwareregister mit einer 8 Bit CPU. cli/sei würden dort gar nicht 
nützen, das beeinflusst die 16 Bit Register keine Nanosekunde.

MFG
Falk

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Falk Brunner wrote:
> @  Stefan (Gast)
>
>>Solange ein IR nicht das temporary register ändert, ist ein atomarer
>>Zugriff nicht notwendig
>
> Das tut sie in diesem Beispiel aber.

Zudem handelt es sich im Hauptprogramm bei ... OCR1A = OCR1A+3 nicht nur 
um einen Zugriff, sondern um zwei, nämlich ein Lese- und ein 
Schreibzugriff.

Autor: Stefan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Falk, @Johann:
Ok, ich bin vom Source des TS von 12:50 ausgegangen, dort ist kein 
Interrupt vorhanden. (wahrscheinlich ist er aber einfach nicht 
mitgepostet worden).
Mit IR, jedenfalls so, wie er um 00:54 gepostet wurde, habt Ihr 
natürlich Recht.

@Daniel:
Warum benutzt Du den CTC-Mode? Der Timer hat so viele schöne PWM-Modi, 
die komplett in der Timer-Hardware, ohne einen Software-Eingriff laufen.

Gruß, Stefan

Autor: Daniel B. (inox5) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Stefan
Tut mir leid, hab da nur die Hauptfunktion gepostet. Wollte aus 
Platzgründen nicht den Rest noch dazu posten.

Ja zudem war das mein erstes Programm, das den Timer nutzt. Warum hab 
ich nicht einen anderen Modus genutzt? Gute Frage, mir wurde der 
CTC-Modus schonmal vorgeschlagen und naja da hab ich mir gedacht, der 
wird wohl mehr Ahnung ham als ich, also machst du es mit dem CTC-Modus^^
Nunja fürs nächstemal werd ich genauer schaun, welcher Modus für mein 
Problem passend ist.

MfG
Inox

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.