Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit Timer0
Hallo
Ich habe leider noch ein Problem mit dem Timer0 meines AtMega8. Ich bekomme den Timer zum laufen. In die ISR geht er auch. Dort möchte ich eine Variable hochzählen... Also soetwas wie einen verschachtelten Timer. Das benötige ich um ein großes Zeitfenster zu bekommen. Mir schwebt da soetwas vor wie while(t<50)... in der Zeit wird im Hauptprogramm etwas ausgeführt. Und "Zwischendurch" wird in der ISR immer wieder die Variable t hochgezählt. Das scheint aber nicht zu funktionieren.... :-( Dass ich die Variable auch irgendwann wieder zurücksetzten muss weiß ich auch... mir geht`s im Moment ersteinmal überhaupt einen Durchlauf hin zu bekommen... Hier mal mein Code:
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <util/delay.h>
#define F_CPU = 12000000L
int t=0; //Variable t für Timer anlegen
int main(void)
{
DDRD &= ~(1<<DDD2); //Pin D2 (INT0) als Eingang deklarieren
PORTD |= (1<<PD2); //Pull Up für D2 einschalten
DDRB = (1<<DDB0); //Port B0 als Ausgang definieren (LED)
PORTB |= (1<<PB0); //LED aussschalten
TCCR0 |= (1<<CS00)|(1<<CS02); //Timer initialisieren und einschalten
TIMSK |= (1<<TOIE0); //TimerOverflow Interrupt freigeben??
sei(); //Interrupts freigeben
while(t<10)
{
PORTB &= ~(1<<PB0); //Einschalten der LED
}
while(1);
}
Und hier die ISR:
ISR(TIMER0_OVF_vect)
{
t++;
}
Vielleicht könnt ihr mir ja auch sagen dass das so gar nicht möglich ist und ich das anders versuchen muss... :-( Vielen Dank schonmal...
Grüße!!
Bean
Klasischer Fehler:
Deklariere mal t als volatile
Gruß Sebastian
Mhh Danke... muss zugeben das mit dem volatile hab ich noch nicht so ganz verstanden :-( hab das jetz mal in "volatile int t=0;" geändert. Hab aber leider nichts gebracht... :-( Brauch ich einen Return aus der ISR?
Grüße!!
Bean
Nein return brauchst Du nicht, woran erkennst Du daß Dein Programm nicht klappt ?
geht die LED nicht an ?
Gruß Sebastian
Doch, bei while(t<10) geht die LED an. Aber ich bin Meinung dass Sie nur so lange an sein sollte wie t<10... sobald t>10 sollte Sie aus gehen.. aber kann auch sein dass da mein Denkfehler liegt... :-) Jetzt wo ich näher drüber nachdenk...
Grüße
Bean
Aber ich bin Meinung dass Sie nur so lange an sein sollte wie t<10... sobald t>10 sollte Sie aus gehen.
warum soll sie dann ausgehen ?
Nachdem die while Schleife verlassen wird ist das Programm auch zu Ende,
kommt nur noch eine Endlosschleife...
irgendwo mußt Du sie ja noch ausschalten...
Gruß Sebastian
](*,) ](*,) ](*,) ](*,)
Ja Ich hab es jetzt grad mal mit einem Blinklicht innerhalb der Schleife versucht... Das scheint zu funktionieren...
Grüße!!
Bean
oberallgeier
16.01.2008, 22:37
... das mit dem volatile hab ich noch nicht so ganz verstanden ...Schau mal hier (klicken) im C-Tutorial (https://www.roboternetz.de/wissen/index.php/C-Tutorial) nach und suche dort nach volatile.
Oder in anderen Tutorials.
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
http://www.schellong.de/c.htm
http://www.galileocomputing.de/openbook/c_von_a_bis_z/ in einem Unerpunkt ist hier volatile
recht gut erklärt http://www.galileocomputing.de/openbook/c_von_a_bis_z/c_011_009.htm#RxxobKap011009040027701F02618E
Ja Ich hab es jetzt grad mal mit einem Blinklicht innerhalb der Schleife versucht... Das scheint zu funktionieren...
Ja siehst Du, alles wird gut ;-)
@Joe, wie ich sehe hast Du Dir eine gute Samlung an Links angelegt...
Gruß Sebastian
oberallgeier
16.01.2008, 22:54
Hallo Sebastian,
wenn ich das wüsste, was ich nicht weiß, und das nicht wüsste was ich weiß - dann wäre ich (in C) VIEL besser :)
@Joe jetzt übertreibst Du aber ;-)
Gruß Sebastian
oberallgeier
17.01.2008, 00:13
Danke, sehr lieb - aber meine letzte, dreitägige Fehlersuche am mega168 hatte den Grund (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=343051#343051):
... TIMSK1 |= (1<<TOIE1); // heisst eben nicht: Tmr/Cntr1 Overflow interrupt disabled. Jetzt steht dort TIMSK1 &= ~(1<<TOIE1); und "alles" läuft prächtig ...
und so etwas ist ja nun wirklich total doof.
Sorry, ich gerate immer wieder OT ;-)
Guten morgen!
vielen Dank für eure Hilfe! Ich hab jetzt mal noch etwas rum gerechnet. Und zwar will ich die LED für eine Sekunde aufleuchten lassen. Ich hab einen Versorgungstakt von 12MHz. Wenn ich den Prescaler auf 1024 stelle bedeutet das einen Takt von 11,71875kHz für den Timer.
Das würde heißen dass die ISR in einer Sekunde 45,77mal durchlaufen wird. Also muss ich ja schreiben:
while(t<46)
{
.
.//LED an
.
}
Sehe ich das richtig oder habe ich eine Denk/Rechenfehler?
Grüße!!
Bean
Sieht gut aus, sofern Du mit der Genauigkeit auskommst.
Gruß
oberallgeier
17.01.2008, 10:56
Vielleicht ist Dir das
http://oberallgeier.ob.funpic.de/50Hz.jpg
eine Hilfe. Du kannst Dir also eine ISR machen, die ungefähr 50 Hz läuft - das ist annähernd das Langsamste, was mit Deiner Konfiguration geht.
In dieser Routine zählst Du eine Zahl runter. Wenn Du Null erreichst, dann setzt Du diese Zahl wieder auf den Anfangswert und toggelst einen Port - oder machst sonst was.
Aufpassen: Bei 12 MHz und beim Prescaler 1024 kannst Du keine (na ja, gaaanz wenige) ganzzahligen Werte fahren. Es sind eben auch nur UNGEFÄHR 50 Hz, siehe Tabelle.
Ok?
Guten Morgen!!
Vielen Dank für euer Hilfe!! Bin viel weiter gekommen. Habe gestern Abend noch etwas mit den Zeiten herum experimentiert. Das passt ja schon recht gut. Soll heißen dass die Genauigkeit für das was ich es brauche vollkommen ausreicht... :-)
Jetzt hab ich nur noch ein Problem mit der while Schleife. Und zwar will ich nun in dieser Schleife einen Analogwert einlesen und in Abhängigkeit von diesem einen Port schalten... Das will aber noch nicht so richtig... :-( Ich hab jetzt mal so angefangen:
while(t<2746)
{
AD_einlesen();
if(result<350)
{
PORTB |= (1<<PB0);
}
}
So scheint es aber nicht zu funktionieren. Ich hab leider gerade nicht den kompletten Code zur Hand. Hab auch schon probiert mit itoa den "resultwert" vor der if Schleife umzurechnen... Aber hat nicht das gewollte Ergebniss gebracht... :-( Habt ihr eine Idee?
Grüße!!
Bean
oberallgeier
18.01.2008, 09:21
Brrrrr - ist diese Schleife in der ISR? Das hiesse dann mit dem Formel1 nach dem Start bei Vollgas voll auf die Bremse :( .... (ok, schlechter Vergleich, viele fahren so gokartmässig).
Vielleicht warten wir mal den kompletten/erweiterten Code ab
Nein Nein, in der ISR wird nach wie vor nur t hochgezählt (t=t+1; ). Mehr steht da nicht drin. Der Rest steht alles in main...
Grüße!!
Bean
oberallgeier
18.01.2008, 14:21
... wird ... nur ... t=t+1; ...
Ok, gut so. Nun will ich nicht päpstlicher sein als ... Ausserdem bin ich eher ein C-Anfänger. Aber die C-Freaks sehen es ja pfiffig, dass man dann schreibt:
t++;
Ich mach das mittlerweile auch - es spart sogar Schreibarbeit :) :)
ja die Schreibweise kenne ich... :-) Danke... :-) bin halt eher altmodisch... :-)
oberallgeier
18.01.2008, 14:47
hihihi - besser als ich - ich bin nur alt, nicht mehr modisch
sechsrad
18.01.2008, 18:14
...t=t+1....
dies ist eine gute schreibweise die man von dem anderen c-gewusel gut lokalisieren kann. der compilercode sieht bei beiden varianten gleich aus. also warum solche (t++) unübersichtlichen kürzel schreiben, das das auge weh tut.
sechsrad
18.01.2008, 18:21
....while(1); ......
schau mal in der lss-datei nach ob die schleife oben wegoptimiert wurde.
Hallo
Ich muss zugeben dass ich zu Anfang auch t++; da stehen hatte. Hab aber gedacht versuchst es mal auf die alte Variante als mein Programm nicht funktioniert hat... 8-[ Wollte eben alles ausschließen... :-)
Nun hab ich mal noch den kompletten Code:
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <lcd.h>
#include <util/delay.h>
#define F_CPU = 12000000L
void long_delay(uint16_t ms); //Prototyp der Warteschleifen long_delay
void ADC_init(void); //Prototyp von ADC_init
uint16_t ADC_einlesen(void); //Prototyp der Einlesefunktion
uint16_t result = 0; //Variable result deklarieren
char buffer[8]; //buffer_Array für Umrechnung deklarieren
volatile int t=0; //Variable t für Timer anlegen
int a=0;
int main(void)
{
ADC_init(); //AD Wandler initialisieren
ADC_einlesen();
DDRD &= ~(1<<DDD2); //Pin D2 (INT0) als Eingang deklarieren
PORTD |= (1<<PD2); //Pull Up für D2 einschalten
DDRB = (1<<DDB0)|(1<<DDB1); //Port B0 als Ausgang definieren (LED)
PORTB |= (1<<PB0); //LED aussschalten
PORTB |= (1<<PB1); //LED aussschalten
TCCR0 |= (1<<CS00)|(1<<CS02); //Timer initialisieren und einschalten
TIMSK |= (1<<TOIE0); //TimerOverflow Interrupt freigeben
sei(); //Interrupts freigeben
while(t<2760)
{
ADC_einlesen();
PORTB &= ~(1<<PB0); //Einschalten der LED an B0
if(result<350)
{
PORTB &= ~(1<<PB1); //Einschalten der LED an B1
}
else
{
PORTB |= (1<<PB1); //wenn result größer, LED ausschalten
}
}
t=0;
while(1);
}
void ADC_init(void)
{
ADCSRA = (1<<ADEN) | (1<<ADPS0) | (1<<ADPS2); //ADC amtivieren und Teilungsfaktor auf 32 stellen
ADMUX = (!(1<<MUX0)) | (!(1<<MUX1)) | (!(1<<MUX2)); //Kanal des Multiplexers wählen (ADC 0)
ADMUX |= (1<<REFS1) | (1<<REFS0); //interne Referenzspannung verwenden (2,56V)
ADCSRA |= (1<<ADSC); //Dummyreadout starten
while(ADCSRA & (1<<ADSC));
}
uint16_t ADC_einlesen(void)
{
uint8_t i; //Variable i deklarieren
for (i=0; i<3; i++) //for-Schleife für dreimalige Wandlung
{
ADCSRA |= (1<<ADSC); //Wandlung starten
while(ADCSRA & (1<<ADSC)); //auf Ergebnis warten
result += ADC; //Ergebnis in Variable result schreiben
}
ADCSRA &= ~(1<<ADEN); //ADC deaktivieren
result /=3; //result durch 3 teilen
return result;
}
ISR(TIMER0_OVF_vect)
{
t=t+1;
}
Was ich eigentlich wie gesagt will, ist dass die while Schleife 1min läuft, und in dieser Zeit immer wieder der Analogwert eingelesen wird und in Abhängigkeit von diesem (größer oder kleiner eines Referenzwertes) ein Port geschalten wird. Das will aber noch nicht so richtig. Die andere LED benutze ich auch um mir anzuzeigen bis "wohin" das Programm bereits funktioniert. Also nicht irritieren lassen... ;-)
Grüße!!
Bean
Ja also,
warum wird result und der andere Krempel global deklariert ?
Das tut weh und nicht
also warum solche (t++) unübersichtlichen kürzel schreiben, das das auge weh tut. was ein ganz normaler Schreibstill ist.
Und überlege welche Werte Dein result hat nachdem ADC_einlesen paar mal durchgelaufen ist...
2. In ADC_einlesen machst Du zum Schluß den Wandler aus, wo wird es wieder eingeschaltet ?
3. Vermeide so Sachen wie /3 nimm 2-er Potenzen /4 /8 usw.
Gruß Sebastian
Hallo
Danke für die Antwort, ich war der Meinung dass ich die Variable result global anlegen muss, da Sie ja auch in mehreren Methoden verwendet wird... :-(
Im Moment stehe ich etwas auf dem Schlauch, wenn ich in der While Schleife den ADWandler das erstemal aufgerufen hab, dann steht der AD Wert in Result das hab ich mit auch schon auf einem LCD ausgeben lassen. Dann geht es weiter bis zum Ende der whileschleife. Da ist die Bedingung (t<<...) noch nicht erfüllt, also beginnt die Schleife von vorne. AD Wandler wird erneut aufgerufen etc...
Wo hab ich da meinen Denkfehler? Tut mir Leid dass ich so frag... 8-[ Aber nur dadurch lerne ich etwas... ;-)
Grüße!!
PS.: Noch eine Frage, warum soll ich Zweierpotenzen verwenden? Ist das für den Controller besser? Oder aus welchem Grund? :-k
Bean
Tut mir Leid dass ich so frag... Anxious Aber nur dadurch lerne ich etwas...
Das ist wohl wahr...
ich war der Meinung dass ich die Variable result global anlegen muss, da Sie ja auch in mehreren Methoden verwendet wird...
Hab ich mich verguckt ?
result wird in main gebraucht und von ADC_einlesen geliefert :-k
deklariere dann in der main result mit uint16_t result;
In ADC_einlesen wird auch eine lokale Variable deklariert und eine 0 zugewiesen
uint16_t result = 0;
Blöd wenn sie den gleichen Namen haben, das stört aber nicht weiter, wenn Du magst kanst Du sie anders benennen.
So die Sache mit ADC ausschalten, in der ADC_init wird ADC eingeschaltet, gut
In ADC_einlesen zum Schluß abgeschaltet, und wo wird ADC neu eingeschaltet in der 2. 3. ...n. Wandlung ?
ja die 2-er Potenzen.
Wie Teilt man durch 2-er Potenzen...
Indem man die Zahl binärgesehen um eine Stelle nach rechts schiebt, Beispiel:
11001100 -> dezimal 204
01100110 -> dezimal 102
Das wäre da /2 /4 muß man es noch eine Stelle nach rechts schieben usw.
und weißt Du wie lange der AVR für dies da ^ braucht ?
1. Takt bei Deiner 16 Bit Variable dann 2 Takte bei Teilen durch 4 4 Takte
burch 8 6 Takte usw.
Wieviel er bei Teilen /3 braucht entzieht sich meiner Kenntnis, aber glaub mal länger und verbraucht auch entsprechend viel Flash.
So klar soweit ?
Gruß Sebastian
Naja also wenn ich result in main deklariere, dann bekomme ich folgende Fehlermeldung beim Compilieren:
../Regelung_Reflow_Ofen.c:134: error: 'result' undeclared (first use in this function)
Das sieht mir schon sehr danach aus als wenn die Deklaration gar nicht sooooo schlecht war.... :-s
Ok, ich muss noch die Variable in einlesen deklarieren. Aber warum ist es besser das auf diese Weise zu machen anstatt 1 Variable global anzulegen? Naja die anderen Sachen hab ich noch nicht versucht, aber das mit /4 ist ja schnell geändert... ;-)
Grüße!
Bean
Das sieht mir schon sehr danach aus als wenn die Deklaration gar nicht sooooo schlecht war....
Soll das jetzt heissen, mein Gelabber war hier um sonst ? :-s
Was steht denn bitte schön in der Zeile 134 und um welche Funktion handelt es sich ?
Hast Du alles gelesen, was ich Dir geschrieben habe ?
Hast Du in ADC_lesen auch eine lokale Variable deklariert ?
Hallo Nein Dein "Gelaber" war natürlich nicht umsonst!!!!
Versteh nur noch nicht warum es besser ist zwei Variablen zu deklarieren anstatt eine global zu deklarieren... :-(
hab in ADC_einlesen auch noch eine result_i deklariert. Und result in main...
Glaube ich hab grad nicht den kopf dafür... geh jetzt erstmal ins Training... morgen ist ein neuer Tag mit viel Zeit... :-)
Grüße und Danke!!
BEan
Versteh nur noch nicht warum es besser ist zwei Variablen zu deklarieren anstatt eine global zu deklarieren...
Da hab ich mir was angetan ;-)
Aber wenn man a sagt muß man auch b sagen, ich versuchs mal.
Es ist allgemein besser, wenn sich Funktionen Ihre Daten gegenseitig zuschieben, anstatt die Daten über globale Variablen auszutauschen, du hast auch gut angefangen schau:
uint16_t ADC_einlesen(void)
{
uint8_t i; //Variable i deklarieren
for (i=0; i<3; i++) //for-Schleife für dreimalige Wandlung
{
ADCSRA |= (1<<ADSC); //Wandlung starten
while(ADCSRA & (1<<ADSC)); //auf Ergebnis warten
result += ADC; //Ergebnis in Variable result schreiben
}
ADCSRA &= ~(1<<ADEN); //ADC deaktivieren
result /=3; //result durch 3 teilen
return result;
}
Bei dieser Variante ist return result nicht nötig, weil result bei Dir global ist, die Funktion hätte ohne Rückgabewert funktioniert.
Du kannst von überall auf result zugreifen, verändern usw.
Das ist schon der Erste knackpunkt.
Du könntest es auch verändern ohne es zu wollen.
Zugegeben bei diesem kleinem Programm wohl nicht so einfach, du willst aber irgendwann was größeres schreiben, vielleicht über mehrere *.c Dateien verteilt, da sieht es schon anders aus mit der Übersichtlichkeit.
Sowas hat mit Datenkapselung zu tun und Gültigkeitsbereichen, ich denke da an OOP mit Klassen und private Atributen.
Nehmen wir jetzt eine Variante mit lokalen Variablen
uint16_t ADC_einlesen(void)
{
uint8_t i; //Variable i deklarieren
uint16_t result = 0;
for (i=0; i<4; i++) //for-Schleife für dreimalige Wandlung
{
ADCSRA |= (1<<ADSC)|(1<<ADEN); //Wandlung starten
while(ADCSRA & (1<<ADSC)); //auf Ergebnis warten
result += ADC; //Ergebnis in Variable result schreiben
}
ADCSRA &= ~(1<<ADEN); //ADC deaktivieren
result /=4; //result durch 3 teilen
return result;
}
Hier wird Dein ADC Ergebnis zurückgeliefert, ich habe mir erlaubt noch 2 Änderungen vorzunehmen, OK ?
Diese Funktion wird in main so aufgerufen und zwar ohne lokale Variable zu nehmen
if(ADC_einlesen() <350)
{
PORTB &= ~(1<<PB1); //Einschalten der LED an B1
}
else
{
PORTB |= (1<<PB1); //wenn result größer, LED ausschalten
}
}
Ich hoffe, du stimmst mir zu, das die Sache übersichtlicher ist 8-[
Denke man daran daß Du eventuell in einem Jahr an Deinem Programm was ändern willst.
Andere Sache ist, Globale Variablen 'leben' im Ram, lokale fast immer in Registern, auch der Rückgabewert wird in Registern übergeben was die Sache natürlich schneller macht.
Zum Schluß Zitiere ich paar Zeilen aus Kerninghan&Ritchie
" Übrigens besteht eine Tendenz alle nur denkbaren Variablen extern zu vereinbaren, denn das vereinfacht anscheinend die Zusammenarbeit
zwischen Funktionen - Parameterlisten sind kurz und Variablen sind immer verfügbar, wenn wir sie benötigen.
Aber externe Variablen sind immer verfügbar, sogar dann, wenn wir sie nicht benutzen wollen.
Sich zu sehr auf externe Variablen zu verlassen ist höchst gefählich,
denn es führt zu Programmen, deren Dattenverbindungen absolut nicht offensichtlich sind - Variablen können an unerwarteten Stellen sogar unbeabsichtlich verändert werden, und das Programm ist sehr schwer zu ändern..."
Seite 32
So jetzt habe ich keine Lust mehr ;-)
P.S. Wenn Du mit global besser klar kommst werde ich es Dir nicht mehr ausreden, wir sprechen uns irgendwann mal wieder O:)
oberallgeier
18.01.2008, 21:54
.. Da hab ich mir was angetan ;-) .. Aber wenn man a sagt muß man auch b sagen, ich versuchs mal...Herrlich, Sebastian. Auf die Art fange sogar ich an, C zu verstehen.
Aber nun (m)ein Sonderfall ! ? Die ISR. Die kann doch keinen aufrufenden Parameter haben. Und nun will ich den Wert (beispielsweise eine Zeitmarke)
ISR(TIMER0_COMPA_vect) // Vektor 14
{
{
if (Izeit_1 < 60000) //Zeitstand Interrupt-Timer läuft von 1 .. 60 000
Izeit_1 ++; // d.h. alle drei Sekunden wird 60000 erreicht
// und Izeit_1 bleibt in der uint16-Grenze
else
{
Izeit_1 = 0; // ansonsten: Rückstellen auf Null
// d.h. alle drei Sekunden wird 60000 erreicht
PORTC ^= (1<<PC0); // Zur Kontrolle im Test PC1 toggeln - 50 µs.
}
}
{
if (Iregmo < 200) //Zeitstand Regelungs-Timer läuft von 1 .. 200
Iregmo ++; // d.h. alle Sekunden wird 100 mal geregelt
else
{ Iregmo = 0; // ansonsten: Rückstellen auf Null und
// 100 mal pro Sec Regelungsaktion durchführen
PORTC ^= (1<<PC2); // Statt Regelung im Test PC1 toggeln,
// 200 * 0,050 ms => 10 ms.
}
}
}
auch im main auswerten - ohne ihn zu beschädigen oder beim Auslesen von der ISR beschädigt zu bekommen. Klar - Übernahme im main erst nach cli. Aber anders als global geht es doch hier garnicht. Oder?
Hallo Joe,
ja Du hast recht wenn Du mit Interrupts Daten tauschen willst, kommst Du um Globale Variablen nicht herum, leider.
Bei kleinen Programmen geht das noch, kein Problem, aber sobald es größer wird...
Vor allem wenn Du über mehrere *.c Dateien gehst.
z.B. Der avr-gcc Port von Butterfly http://www.siwawi.arubi.uni-kl.de/avr_projects/#bf_app
Den habe ich seinerzeit auseinandergenommen um den Butterfly in einen Dattenlogger zu verwandeln, das war eine Fleißarbeit glaube mir.
Gruß Sebastian
oberallgeier
18.01.2008, 22:59
Danke Sebastian, dann bin ich erstmal beruhigt. Und Deinen Rat - na ja, mit dem von K&R natürlich - werde ich hoffentlich IMMER beherzigen.
Schliesslich - ISR sind doch meist recht projektbezogen, oder? Zumindest meine soll Zeitgeber und Antriebsregelung werden. Das kann ja nicht so leicht allgemein verwendet werden.
Ja Joe,
keine Panik, vielleicht habe ich mich etwas zu weit aus den Fenster gelehnt, so schlimm ist es ja nicht wenn man was global macht, nur Anfänger neigen dazu die nur noch zu nehmen (sehe Zitat aus K&R)
Es gab hier sogar schon einen 'Helfer' der gesagt hat man sollte alle Variablen volatile machen um Problemen wie im Anfangspost aus dem Weg zu gehen...
Wie weit bist Du mit Deinem K&R ? Da sind wirklich sehr gute Beispiele wie Funktionen untereinander Daten austauschen, findest Du das Buch gut, oder haben wir Dir doch was falsches empfohlen ?
Gruß Sebastian
oberallgeier
18.01.2008, 23:38
Ja - ich finde das Buch gut (schon allein deswegen, weil ich es seit Jahrzehnten vom Hörensagen kenne). Also hier mal meinen Dank. Ohne euren (drängenden) Rat hätte ich den weder gekauft noch gelesen. Aber ich bin nicht durch. Ich mache so ein Gemisch aus Buch lesen, programmieren (fehlerbehaftet, siehe unten) und "löten".
Andererseits: Nein, ich finde die Tutorials besser. Wo sonst kann ich mit [Strg] [F] nach - beispielsweise so etwas wie &= ~ "auf die Schnelle" finden - weil ich da einen dämlichen Fehler (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=343051#343051) gemacht hatte, der drei Tage böse Worte gegen des mega168 ergab.
Sinn ergibt also das Gemisch aus allen vieren: K&R, tutorials, selber machen UND in den Threads schmökern.
Immerhin ist mein jüngstes Problem (mega168 - SRAM zu 76 % voll und ich will noch was reinbringen) nur auf die dritte Art lösbar - wenn man dann alle sendusart´s streicht, bleiben knapp 4% genutztes SRAM übrig.
Nee, es ist sogar ein Gemisch aus fünfen: einer der wirklich wichtigen Punkte sind die hilfreichen Geister, die sich durch meine elllenlangen Codes durcharbeiten und Tips geben oder aufmuntern - einfach wirklich helfen!
Immerhin ist mein jüngstes Problem (mega168 - SRAM zu 76 % voll und ich will noch was reinbringen) nur auf die dritte Art lösbar - wenn man dann alle sendusart´s streicht, bleiben knapp 4% genutztes SRAM übrig.
BITTE ?
Was hast Du alles an Variablen drin ?
Geht sicher zu lösen? sendusarts ? lass mich raten, Du gibst viele Texte aus ?
Hmm wir werden Offtopic hier (wie immer) schreib mir bitte ein PN mit Deinem Problem, vielleicht kann ich helfen
Gruß Sebastian
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.