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.
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;
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.
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)