Rigister Kurzname, woher kennt Arduino die?

Hi @all,
hab mir grad mal die FlexiTimer.cpp angeschaut und festgestellt das hier direkt die Namen der Register verwendet werden. Aber woher kennt Arduino die? Irgendwo müssen doch die Adressen zugeordnet werden, aber wo? Kann mir da jemand weiterhelfen?
MfG Jago

Der Code von FlexiTimer.cpp:

/*
  FlexiTimer2.h - Using timer2 with a configurable resolution
  Wim Leers <work@wimleers.com>

  Based on MsTimer2
  Javier Valencia <javiervalencia80@gmail.com>

  History:
    25/April/10 - Based on MsTimer2 V0.5 (from 29/May/09)

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <FlexiTimer2.h>

unsigned long FlexiTimer2::time_units;
void (*FlexiTimer2::func)();
volatile unsigned long FlexiTimer2::count;
volatile char FlexiTimer2::overflowing;
volatile unsigned int FlexiTimer2::tcnt2;

void FlexiTimer2::set(unsigned long ms, void (*f)()) {
    FlexiTimer2::set(ms, 0.001, f);
}


/**
 * @param resolution
 *   0.001 implies a 1 ms (1/1000s = 0.001s = 1ms) resolution. Therefore,
 *   0.0005 implies a 0.5 ms (1/2000s) resolution. And so on.
 */
void FlexiTimer2::set(unsigned long units, double resolution, void (*f)()) {
	float prescaler = 0.0;
	
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || (__AVR_ATmega1280__)
	TIMSK2 &= ~(1<<TOIE2);
	TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
	TCCR2B &= ~(1<<WGM22);
	ASSR &= ~(1<<AS2);
	TIMSK2 &= ~(1<<OCIE2A);
	
	if ((F_CPU >= 1000000UL) && (F_CPU <= 16000000UL)) {	// prescaler set to 64
		TCCR2B |= (1<<CS22);
		TCCR2B &= ~((1<<CS21) | (1<<CS20));
		prescaler = 64.0;
	} else if (F_CPU < 1000000UL) {	// prescaler set to 8
		TCCR2B |= (1<<CS21);
		TCCR2B &= ~((1<<CS22) | (1<<CS20));
		prescaler = 8.0;
	} else { // F_CPU > 16Mhz, prescaler set to 128
		TCCR2B |= ((1<<CS22) | (1<<CS20));
		TCCR2B &= ~(1<<CS21);
		prescaler = 128.0;
	}
#elif defined (__AVR_ATmega8__)
	TIMSK &= ~(1<<TOIE2);
	TCCR2 &= ~((1<<WGM21) | (1<<WGM20));
	TIMSK &= ~(1<<OCIE2);
	ASSR &= ~(1<<AS2);
	
	if ((F_CPU >= 1000000UL) && (F_CPU <= 16000000UL)) {	// prescaler set to 64
		TCCR2 |= (1<<CS22);
		TCCR2 &= ~((1<<CS21) | (1<<CS20));
		prescaler = 64.0;
	} else if (F_CPU < 1000000UL) {	// prescaler set to 8
		TCCR2 |= (1<<CS21);
		TCCR2 &= ~((1<<CS22) | (1<<CS20));
		prescaler = 8.0;
	} else { // F_CPU > 16Mhz, prescaler set to 128
		TCCR2 |= ((1<<CS22) && (1<<CS20));
		TCCR2 &= ~(1<<CS21);
		prescaler = 128.0;
	}
#elif defined (__AVR_ATmega128__)
	TIMSK &= ~(1<<TOIE2);
	TCCR2 &= ~((1<<WGM21) | (1<<WGM20));
	TIMSK &= ~(1<<OCIE2);
	
	if ((F_CPU >= 1000000UL) && (F_CPU <= 16000000UL)) {	// prescaler set to 64
		TCCR2 |= ((1<<CS21) | (1<<CS20));
		TCCR2 &= ~(1<<CS22);
		prescaler = 64.0;
	} else if (F_CPU < 1000000UL) {	// prescaler set to 8
		TCCR2 |= (1<<CS21);
		TCCR2 &= ~((1<<CS22) | (1<<CS20));
		prescaler = 8.0;
	} else { // F_CPU > 16Mhz, prescaler set to 256
		TCCR2 |= (1<<CS22);
		TCCR2 &= ~((1<<CS21) | (1<<CS20));
		prescaler = 256.0;
	}
#endif
	
	tcnt2 = 256 - (int)((float)F_CPU * resolution / prescaler);
	
	if (units == 0)
		time_units = 1;
	else
		time_units = units;
		
	func = f;
}

void FlexiTimer2::start() {
	count = 0;
	overflowing = 0;
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || (__AVR_ATmega1280__)
	TCNT2 = tcnt2;
	TIMSK2 |= (1<<TOIE2);
#elif defined (__AVR_ATmega128__)
	TCNT2 = tcnt2;
	TIMSK |= (1<<TOIE2);
#elif defined (__AVR_ATmega8__)
	TCNT2 = tcnt2;
	TIMSK |= (1<<TOIE2);
#endif
}

void FlexiTimer2::stop() {
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || (__AVR_ATmega1280__)
	TIMSK2 &= ~(1<<TOIE2);
#elif defined (__AVR_ATmega128__)
	TIMSK &= ~(1<<TOIE2);
#elif defined (__AVR_ATmega8__)
	TIMSK &= ~(1<<TOIE2);
#endif
}

void FlexiTimer2::_overflow() {
	count += 1;
	
	if (count >= time_units && !overflowing) {
		overflowing = 1;
		count = 0;
		(*func)();
		overflowing = 0;
	}
}

ISR(TIMER2_OVF_vect) {
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || (__AVR_ATmega1280__)
	TCNT2 = FlexiTimer2::tcnt2;
#elif defined (__AVR_ATmega128__)
	TCNT2 = FlexiTimer2::tcnt2;
#elif defined (__AVR_ATmega8__)
	TCNT2 = FlexiTimer2::tcnt2;
#endif
	FlexiTimer2::_overflow();
}

Und die FlexiTimer2.h:

#ifndef FlexiTimer2_h
#define FlexiTimer2_h

#include <avr/interrupt.h>

namespace FlexiTimer2 {
	extern unsigned long time_units;
	extern void (*func)();
	extern volatile unsigned long count;
	extern volatile char overflowing;
	extern volatile unsigned int tcnt2;
	
	void set(unsigned long ms, void (*f)());
	void set(unsigned long units, double resolution, void (*f)());
	void start();
	void stop();
	void _overflow();
}

#endif

Teil des AVR-GCC Compilers. Der Compiler versteht auch Assemblercode wenn er in den richtigen Tags eingebettet ist und übersetzt diesen.
Grüße Uwe

Cool, da gibt´s ja wieder Welten zu entdecken! Und ich hab keine Zeit... An Assembler musste ich denken als du meintest das das Blinkbeispiel schon ein 1kByte Code hat, das lässt sich sicher sehr stark reduzieren. Eigentlich hat ich mir geschworen um die Sprache einen großen Bogen zu machen, aber irgendwie hat sie stellenweise schon ihren Charme...

PS.: Hab grad mal einen Sketch compiliert der nur aus void setup() {} und void loop() {} besteht, da gehen ja schon 450 bytes weg. Würd mich echt mal interessieren was da alles gemacht wird (schau ich mir aber bei gelegenheit selbst an)

Das Blink Beispiel ist nicht so groß, weil der Compiler schlecht arbeitet, sondern weil verschiedene Setups der internen Periferie des ATmega vorgenommen werden müssen. Den Sketch in Assembler zu schreiben bringt nicht so viel wie man erwarten würde (wen man den Zeitaufwand zur Programmierung mal außer acht läßt. Assemblerteile rechnen sich in den seltesten Fällen. Grüße Uwe

Wenn der Mikrocontroller zu langsam ist, kann man teilweise mit Assembler noch etwas mehr an Geschwindigkeit rausholen da es der Maschinensprache sehr ähnlich ist und dadurch besonders schnell abläuft.

Platz mäßig macht es nicht so viel aus.

Assembler ist eine für Menschen verständliche Darstellung der Maschinensprache mit einigen Hilfen ( zb Label für Sprungadressen). Maschinencode sind per Definition Zahlen. Ein Assembler(Programm) wandelt die menschenlesbaren Befehlsnamen in die zahlen des Maschinencode um. Ein Disassembler macht es umgekehrt. Dasrum ist unter Assembler und Maschinencode das gleiche gemeint. Grüße Uwe

Das Blink Beispiel ist nicht so groß, weil der Compiler schlecht arbeitet, sondern weil verschiedene Setups der internen Periferie des ATmega vorgenommen werden müssen. Den Sketch in Assembler zu schreiben bringt nicht so viel wie man erwarten würde (wen man den Zeitaufwand zur Programmierung mal außer acht läßt. Assemblerteile rechnen sich in den seltesten Fällen. Grüße Uwe

Das der Compiler schlecht arbeitet wollt nicht behaupten. Ich meint nur das ich mir das mal anschauen mag was da gemacht wird. Reinweg aus interesse. Davon mal abgesehen, 450 byte gehen für setup und loop weg, bleiben 550 byte für Led an/aus und verzögerung. Ich find das viel, wenn ich mich recht erinner dann muss in assembler nur ein paar Zeilen schreiben. Geschätzt liegen die garantiert unter 100 byte. Hintergrund ist der, das ich im zuge meines USB-Oszilloskop Projekts überlegt hatte einen parallelen A/D-Wandler einzusetzen. Da würde ich, denk ich, einiges an Leistung gewinnen wenn ich Assembler zum einlesen verwende. Um abzuschätzen wieviel Assembler bringt, muss ich wohl erstmal ein wenig von der Sprache lernen. Ohne grund wird es wohl kaum die Möglichkeit geben diese Sprache einzusetzen. Die Leute die Assembler historisch bedingt noch sprechen dürften ja langsam aussterben.

@Jomelo: Das man mit Assembler ein wenig Speed rausholen kann hatte ich im Studium auch gehört. Langsam wird´s mal zeit das auch nachzuprüfen. Hatte übrigens früher Mikrocontrollertechnik gehasst, was zum einen an den Dozenten lag, zum anderen das wir das besch.... System auf der Welt verwendet hatten (68HC12 + dazugehöriger Entwicklungsumgebung). Das umgehen der BUG´s hat immer länger gedauert als das Programmieren....

MfG Jago

Hab nicht vor so schnell auszusterben ;) ;) ;)

Das umgehen der BUG´s hat immer länger gedauert als das Programmieren....

Das ist immer noch so. Fehlersuche ist zeitaufwändiger als programmieren.

Grüße Uwe

Jago: hab mir grad mal die FlexiTimer.cpp angeschaut und festgestellt das hier direkt die Namen der Register verwendet werden. Aber woher kennt Arduino die? Irgendwo müssen doch die Adressen zugeordnet werden, aber wo? Kann mir da jemand weiterhelfen?

Für den ATMega328P z.B. in dieser Include-Datei hier:

C:\arduino-0022\hardware\tools\avr\avr\include\avr\iom328p.h

Die wird wohl irgendwo "included" werden.

Anderer Controller-Typ (1280, 2560) natürlich andere Datei (Verzeichnis wie oben, aber Datei iomxx0_1.h. Ja, das Ding heißt wirklich so und nicht iom1280.h oder iom2560.h, wie man vermuten könnte).

Wolfgang

@uwefed: Du musstest wirklich mit Assembler anfangen weil es nix anderes gab? Das ist doch schon gute 30-40 Jahre her, oder? Dachte immer Arduino ist von Jungspunten für Jungspunte. :D XD :P Das man für die Fehlersuche länger braucht als für´s Programmieren ist ja okay. Aber ich hab keinen Bock ständig irgendwelche Fehler und Besonderheiten in der Entwicklungsumgebung zu beachten. Die soll Funktionieren und fertig. Man muss sich das mal vorstellen, wir hatten immer ein leeres Projekt bereitliegen weil das erstellen eines neuen Projekts ohne weiteres nicht möglich war!

@voithian: Vielen dank für den hinweis. Das einbinden erfolgt wohl über mehrere Ecken. In FlexiTimer2.h steckt eine interrupt.h drin und in der sind auch wieder mehrere Bibliotheken drin. Schon Wahnsinn was man sich alles mit einer Bibliothek ins Boot holt.

Bitte übertreib mal nicht so. So ewig ist das auch wieder nicht her. Nur 30 Jahre. Die ersten Computer die ich hatte ( oder bei Freunden spielte) waren ZX81 von Sinclaire, VC20 und C64 von Commodore. Die Hatten einen Microsoft (ja richtig Microsoft) Basic interpreter mit einer rechenleistung weniger als Arduino in einem Chip. Der ZX81 hatte in der Grundausstattung 1kByte RAm und das war für programm, systemvariablen und Bildschirmspeicher. Der VC20 war da mit 3,5KByte Programmspeicher schon großzügiger. der C64 hatte 64 kByte. Da mußtest Du mit Assembler anfangen um weiterzukommen da Basic sehr langsam war.

Um Assembler zu programmieren mußt Du Dich sehr gut mit der Architektur, Peripherie und dem Microcontroller auskennen ansonsten kommst Du zu nichts. Da ist Arduino mit dem IDE eine Wohltat.

Grüße Uwe

Alles eine Frage des standpunktes, für mich sind 30 Jahre schon Stück. Damals hat auf jedenfall noch keiner an mich gedacht.
Aber irgendwie auch cool wenn man die Entwicklung der Computertechnik von Anfang an miterleben konnte. Grade das Innenleben ist für mich oft schwer zu verstehen.
Bei Mikrocontrollern geht´s glücklicherweise. Nur die arbeit der CPU ist für mich ein wenig Hexerei (noch).

@voithian: Ich hab Quatsch erzählt! Zum einen hab ich uwefed´s ersten Post nicht beachtet “Teil des AVR-GCC Compilers”, zum anderen hab ich´s auch probiert. Die IDE versteht auf anhieb was ich von ihr will.