Hallo, habe jetzt seit ein paar Tagen versucht und versucht. Aber es will nicht funktionieren. Ich möchte eine Blinklichtschaltung über Poti geregelt machen. #define F_CPU 3686400 // Taktfrequenz des myAVR-Boards #include <avr\io.h> // AVR Register und Konstantendefinitionen #include <inttypes.h> #include <avr\interrupt.h> volatile unsigned char timer_value; ISR (TIM0_OVF_vect) { PORTB = PORTB^ ( 1<<PB1 ); // Flankenwechsel für Tonfrequenz TCCR0B = timer_value; } ISR(ADC_vect) { int adc_value; adc_value = ADC; timer_value = char(adc_value/5); ADCSRA |= (1<<ADSC); // restart ADC } void adcInit() { ADMUX = 0b00000011; // Port, Referenzspannung und Auflösung ADCSRB = 0b10011110; // Modus, Interrupt und Start } void initTimer0() { timer_value = 0xFF; TCCR0B=0x05; // 0b00000011,Vorteiler 64 TIMSK0=0b00001010; // 0b00000010, maskiere Timer-INT } void initPorts() { sbi(DDRB,0); //OUT Summer sbi(DDRB,1); //OUT LED } //====================================================================== main() { adcInit(); initPorts(); // PortB als Ausgang initialisieren initTimer0(); // Timer Interrupt initialisieren sei(); // enable interrupts do {} while (true); // Mainloop } Momentan ist es so dass die Led beim einschalten kurz aufleuchtet. Vielleicht habe ich auch einen Fehler in der Schaltung. Auf PB3 habe ich den Poti. Gegen VCC und GND.PB1 die LED. Fehlt da noch was oder habe ich etwas falsch angeschlossen. Bin echt am verzweifeln. Habe schon viel Tipps und Hilfe bekommen, bekomme es aber nicht hin. Ich hoffe auf euer Verständniss einem Neueinsteiger zu helfen. Gruß Andy
bitte keine Zahlen sondern Namen verwenden, keiner wird Lust haben die Bits aufzudröseln Kommentare sollten auch zum Programm passen ansonsten habe ich nicht entdeckt wo die Interrupts freigegeben werden
Du gibst 2 Timer-Interrupts frei (welche, habe ich keine Lust, aufzudröseln - schreibe bitte die Bitnamen hin und kein 0b<irgendwas>, hast jedoch nur eine Timer-Interrupt-Routine. Das gibt einen garantierten Soft-Reset.
OK habs mal umgeschrieben ich hoffe es passt so.
1 | #define F_CPU 3686400 // Taktfrequenz des myAVR-Boards
|
2 | #include <avr\io.h> // AVR Register und Konstantendefinitionen |
3 | #include <inttypes.h> |
4 | #include <avr\interrupt.h> |
5 | |
6 | volatile unsigned char timer_value; |
7 | |
8 | ISR (TIM0_OVF_vect) |
9 | {
|
10 | PORTB = PORTB^ ( 1<<PB1 ); // Flankenwechsel für Tonfrequenz |
11 | TCCR0B = timer_value; |
12 | }
|
13 | |
14 | ISR(ADC_vect) |
15 | {
|
16 | int adc_value; |
17 | |
18 | adc_value = ADC; |
19 | timer_value = char(adc_value/5); |
20 | ADCSRA |= (1<<ADSC); // restart ADC |
21 | |
22 | }
|
23 | void adcInit() |
24 | {
|
25 | ADMUX = (1<<REFS0) | (1<<MUX1) | (1<<MUX0);// Port, Referenzspannung und Auflösung |
26 | |
27 | ADCSRA = (1<<ADEN) | (1<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1); // Modus, Interrupt und Start |
28 | }
|
29 | |
30 | void initTimer0() |
31 | {
|
32 | timer_value = 0xFF; |
33 | TCCR0B=(1<<FOC0B) | (1<<CS02) | (1<<CS00); // Vorteiler 1024 |
34 | TIMSK0=(1<<OCIE0B) | (1<<TOIE0);// maskiere Timer-INT |
35 | }
|
36 | |
37 | void initPorts() |
38 | {
|
39 | // sbi(DDRB,0); //OUT Summer
|
40 | sbi(DDRB,1); //OUT LED |
41 | }
|
42 | |
43 | //======================================================================
|
44 | main() |
45 | {
|
46 | adcInit(); |
47 | initPorts(); // PortB als Ausgang initialisieren |
48 | initTimer0(); // Timer Interrupt initialisieren |
49 | sei(); // enable interrupts |
50 | do {} while (true); // Mainloop |
51 | }
|
Und funktioniert es oder nicht?
Vielleicht solltest du die Wandlung erstmal irgendwo starten. Wie soll
er in die ISR, wenn noch keine Wandlung gelaufen ist.
Welchen Timerinterrupt willst du eigentlich verwenden oder willst du
beide verwenden? Wenn du Compare Interrupt verwenden willst, dann muss
du in den Compare-Register auch ein Wert reinschreiben, damit der
Interrupt bei Übereinstimmung ausgelöst wird.
Und was wird das hier?
> TCCR0B = timer_value;
Also jetzt läst sich die LED dimmen, aber sie blinkt noch nicht.
1 | #define F_CPU 3686400 // Taktfrequenz des myAVR-Boards
|
2 | #include <avr\io.h> // AVR Register und Konstantendefinitionen |
3 | #include <inttypes.h> |
4 | #include <avr\interrupt.h> |
5 | |
6 | volatile unsigned char timer_value; |
7 | |
8 | ISR (TIM0_OVF_vect) |
9 | {
|
10 | PORTB = PORTB^ ( 1<<PB1 ); // Flankenwechsel für Tonfrequenz |
11 | TCCR0B = timer_value; |
12 | }
|
13 | |
14 | ISR(ADC_vect) |
15 | {
|
16 | int adc_value; |
17 | |
18 | adc_value = ADC; |
19 | timer_value = char(adc_value/5); |
20 | ADCSRA |= (1<<ADSC); // restart ADC |
21 | |
22 | }
|
23 | void adcInit() |
24 | {
|
25 | ADMUX = (1<<REFS0) | (1<<MUX1) | (1<<MUX0);// Port, Referenzspannung und Auflösung |
26 | ADCSRA = (1<<ADEN) | (1<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1); // Modus, Interrupt und Start |
27 | }
|
28 | |
29 | void initTimer0() |
30 | {
|
31 | timer_value = 0xFF; |
32 | TCCR0B=(0<<FOC0B) | (0<<WGM02) | (1<<CS02) | (1<<CS00); // Vorteiler 1024 |
33 | TIMSK0=(1<<OCIE0B) | (1<<TOIE0);// maskiere Timer-INT |
34 | }
|
35 | |
36 | void initPorts() |
37 | {
|
38 | // sbi(DDRB,0); //OUT Summer
|
39 | sbi(DDRB,1); //OUT LED |
40 | }
|
41 | |
42 | //======================================================================
|
43 | main() |
44 | {
|
45 | adcInit(); |
46 | initPorts(); // PortB als Ausgang initialisieren |
47 | initTimer0(); // Timer Interrupt initialisieren |
48 | sei(); // enable interrupts |
49 | do {} while (true); // Mainloop |
50 | }
|
jetzt weis ich zumindes das der Poti über ADC gelesen wird und muss jetzt halt noch das blinken hinbekommen.
Andy schrieb: > Also jetzt läst sich die LED dimmen, aber sie blinkt noch nicht. Ehrlich? Bei dem Programm hätte ich alles mögliche erwartet, inklusive Kernschmelze. Nur nicht, dass sich da irgendein Effekt an der LED zeigt. Anscheinend hast du das Glück (Pech?), dass dein µC genau im Verhältnis der Poti Stellung abstürzt und das Programm damit im richtigen Takt restartet. Geh doch erst mal schrittweise vor. * Leeres Programm * Timer initialisieren * Interrupt routine anhängen * erstes Teilziel: LED blinkt korrekt, indem du im Programm einen Zahlenwert veränderst. Willst du eine andere Blinkrate, dann veränderst du diesen Zahlenwert und compilierst neu * ADC Routine aus dem Tutorial übernehmen. Ohne Interrupt! * Einen Aufruf der ADC Routine direkt in die Hauptschleife einbauen. Dort wo vorher dein 'fixer' variabler Zahlenwert war, baust du das ADC Ergebnis ein -> jetzt muss die LED aufs Poti reagieren * und erst dann baust du den ADC auf Interrupt Betrieb um (falls du das dann überhaupt noch willst)
> TCCR0B = timer_value; Dazu hatte ich dir in deinem anderen Thread schon was geschrieben. Diese Stelle ist grottenfalsch! > ADCSRA |= (1<<ADSC); // restart ADC Restart in der ISR sehe ich, aber wo ist der 1. Start ausserhalb der ISR? In die ISR mit Restart geht es erst, wenn der 1. Start ein Ergebnis liefert... > TIMSK0=(1<<OCIE0B) | (1<<TOIE0);// maskiere Timer-INT ^^^^^^a ^^^^^^^^b a/ Die ISR für OCIE0B sehe ich im Restprogramm nicht. b/ Es ist kein "maskieren", sondern die beiden angegebenen Timerinterrupts werden erlaubt. > timer_value = char(adc_value/5); Ein C typischer Cast an dieser Stelle sähe so aus: timer_value = (unsigned char) (adc_value/5);
> TCCR0B = timer_value;
Dazu hatte ich dir in deinem anderen Thread schon was geschrieben. Diese
Stelle ist grottenfalsch!
Wie wäre es denn richtig.
Wo sind jetzt die Fehler oder wie müste das Programm umgeschrieben
werden dass es geht.
Andy schrieb: > Wie wäre es denn richtig. > Wo sind jetzt die Fehler oder wie müste das Programm umgeschrieben > werden dass es geht. Das Problem: Das scheint für dich alles noch viel zu viel zu sein. Zu viele Details, die alle gleichzeitig beachtet werden wollen. Ich empfehle dir dringend dich an den Stufenplan, den ich dir weiter oben gepostet habe, zu halten. Es bringt jetzt nicht viel, dir die 20 Zeilen Code zu geben. Du siehst sie dir an und sagst: "Schön, da wär ich irgendwann alleine auch drauf gekommen" und gehst zur Tagesodnung über. Und beim nächsten Programm stehst du wieder daneben. Du musst schrittweise lernen. Daher auch der Stufenplan.
Naja das bringt mich nicht weiter wollte nur das Programm hinbekommen. Beim ATMega8 hat es ja geklappt nur das portieren auf den ATtiny13 bekomm ich nicht hin und darum dachte ich ihr könnt mir helfen es zum laufen zu bekommen. So lernt man auch wenn man dann seine Fehler sieht.
Andy schrieb: > Naja das bringt mich nicht weiter wollte nur das Programm hinbekommen. > Beim ATMega8 hat es ja geklappt Mit Verlaub. Entweder * hast du das nicht selbst geschrieben * oder es sieht nur so aus als ob es funktioniern würde Denn im Grunde sind deine Fehler lächerlich einfach: * Der ADC Interrupt wird ausgelöst, wenn der ADC fertig ist. Der fängt aber nicht alleine an! Den muss man einmal starten, damit ein erstes Ergebnis vorliegt Als Folge dieses Ergebnisses wird die ISR aufgerufen, die dann die nächste Wandlung startet. Aber irgendwann muss der Prozess einmal starten, so wie eine Dominokette auch nicht von alleine umfällt: Den ersten Stein muss irgendwer einmal umwerfen. Und erst ab dann läuft die Kette von alleine * Du gibst Interrupts frei, für die du keinen Handler hast. * Du weist an Konfigurationsregister, die eigentlich iregndwelche Funktionalitäten ein/aus schalten, Zeitwerte zu. Kein Mensch weiß was dieser Zeitwert überhaupt macht, wenn ihn die Hardware als "diesen und jenen Funktionsblock ein/ausschalten" interpretiert. Das alles sind grundlegende Fehler, die auf einem Mega auch nicht anders sind als auf dem Tiny. All diese Fehler wurden dir schon genannt. Aus der Tatsache, dass dich diese Fehlerbeschreibungen nicht weiter bringen schliesse ich, dass du das Pgm auf dem Mega nicht selbst geschrieben hast.
* Leeres Programm * Timer initialisieren * Interrupt routine anhängen * erstes Teilziel: LED blinkt korrekt, indem du im Programm einen Zahlenwert veränderst. Willst du eine andere Blinkrate, dann veränderst du diesen Zahlenwert und compilierst neu * ADC Routine aus dem Tutorial übernehmen. Ohne Interrupt! * Einen Aufruf der ADC Routine direkt in die Hauptschleife einbauen. Dort wo vorher dein 'fixer' variabler Zahlenwert war, baust du das ADC Ergebnis ein -> jetzt muss die LED aufs Poti reagieren * und erst dann baust du den ADC auf Interrupt Betrieb um (falls du das dann überhaupt noch willst)
Wie Karl heinz Buchegger geschrieben hat, glaube ich auch nicht, dass das Programm funktioniert hat. Denn wenn man es selbst geschrieben hätte und es hätte auch so funktioniert, wie man es wollte, dann wüsste man, was er gemacht hat und dann hätte man das Programm auf den anderen uC ohne Probleme übertragen können.
Einen Punkt habe ich noch vergessen: Dir scheint auch das Verständnis dafür zu fehlen, wie da eigentlich eine variable Blinkrate erzeugt werden soll. Entweder man macht das in Software oder man macht das in Hardware. Beides sind unterschiedliche Techniken. Dein jetztiges Programm macht weder noch und es ist noch nicht einmal im Ansatz erkennbar, wie du dir das vorstellst.
Zeig mal dein Quellcode für den ATmega8, welches (angeblich) funktioniert.
#define F_CPU 3686400 #include <avr\io.h> #include <inttypes.h> #include <avr\interrupt.h> //---------------------------------------------------------------------- ---- unsigned char timer_value; ISR (TIMER0_OVF_vect) { PORTB = ~ PORTB; // Flankenwechsel für Tonfrequenz TCNT0 = timer_value; } ISR(ADC_vect) { int adc_value; adc_value=ADC; timer_value=char(adc_value/4); sbi (ADCSRA,6); // restart ADC } void adcInit() { ADMUX=0; ADCSRA=0xDD; //0b11011101, ADC-Clock, ADC ON, INT ON } void timer0Init() { timer_value=0xFF; TCCR0=0x03; // 0b00000011, Vorteiler 64 TIMSK=0x01; // 0b00000001, maskiere Timer-INT } void portsInit() { sbi(DDRB,0); //OUT Summer sbi(DDRB,1); //OUT LED } main() { //Initialisierung portsInit(); // PortB als Ausgang initialisieren timer0Init(); // Timer Interrupt initialisieren adcInit(); sei(); // enable interrupts do { } while(true); // mainloop }
Das Programm läuft bestimmt auf dem ATmega8. Jetzt muss du nur das Datenblatt von ATmega8 nehmen, dir aufschreiben was alles gesetzt ist und was nicht. Dann nimmst du das Datenblatt von Attiny13 und setzst die gleichen Bits, wie bei ATmega8. Und dann hoffe ich, dass das Programm auf dem Attiny läuft. Das alles ist bestimmt nicht böse gemeint, aber wenn wir dir das Programm schreiben, wirst du dabei nichts lernen und ich glaube es ist nicht das letzte Mal, dass du den uC programmierst. Deswegen erweitere dein Programm Schritt für Schriff, so wie Karl heinz Buchegger es dir vorgeschlagen hat und du wirst bestimmt merken, dass es doch nicht so schwer ist.
WEnn du jetzt bei deinem Mega8 Program die ganzen 'magischen Konstante', wie zb hier ADCSRA=0xDD; //0b11011101, ADC-Clock, ADC ON, INT ON in eine vernünftige Schreibweise bringst, hast du doch schon fast das Tiny Programm. LOL Im Mega8 Programm
1 | ISR (TIMER0_OVF_vect) |
2 | {
|
3 | PORTB = ~ PORTB; // Flankenwechsel für Tonfrequenz |
4 | TCNT0 = timer_value; |
5 | }
|
im Tiny Programm
1 | ISR (TIM0_OVF_vect) |
2 | {
|
3 | PORTB = PORTB^ ( 1<<PB1 ); // Flankenwechsel für Tonfrequenz |
4 | TCCR0B = timer_value; |
5 | }
|
vergleich doch mal die beiden! Und ich meine jetzt nicht die Sache mit dem PORTB. Die ist schon in Ordnung Welche Bedeutung hat das TCNT0 Register beim Timer 0? Welche Bedeutung hat das TCCR0B Register beim Timer 0? Was hast du daher angerichtet, als du das TCNT0 Register vom Mega8 mit dem TCCR0B Register vom Tiny 'übersetzt' hast?
Ok ich entschuldige mich erstmal. Ich werd jetzt mal versuchen die beiden Datenblätter zu vergleichen und alles herausfinden wo die unterschiede sind. Danke nochmal an alle für die Tipps und Antworten.
Andy schrieb: > Ok ich entschuldige mich erstmal. > Ich werd jetzt mal versuchen die beiden Datenblätter zu vergleichen und > alles herausfinden wo die unterschiede sind. +-------------------------------------------------------------------+ | | | Fang damit an, den Mega8 Code erst mal vernünftig zu machen! | | | +-------------------------------------------------------------------+ So was
1 | ADCSRA=0xDD; //0b11011101, ADC-Clock, ADC ON, INT ON |
ist einfach nur Mist! Ein grosser Haufen Mist! Und jetzt weist du auch warum! Weil man beim Übertragen von einem Prozessor auf einen anderen aufpassen muss wie ein Haftlmacher. Man muss auch so aufpassen, aber mit einer vernünftigen Schreibweise reduziert sich der Aufwand gewaltig. Du wirfst dir mit solchen Schreibweisen nur unnötig Prügel zwischen die Beine. Prügel? Ganze Baumstämme! Bereinige das erst mal! Dann portiert sich dein Programm schon fast von alleine! (Ich bin allerdings immer noch nicht überzeugt davon, dass du das selbst geschrieben hast. Nur zur Klarstellung)
Also habs hinbekommen es geht jetzt soweit. Die Blinkfrequenz ist noch nicht so ideal aber ich denke das bekomm ich hin. Danke
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.