Hi Mit Hilfe eines Timers sollte jedes Mal eine Wandlung des ADC gestartet werden (in der ISR vom Timer0). Nach Fertigstellung der Wandlung sollte der ADC in die ISR springen und dort einen Port-Pin auf 1 setzen (LED). Allerdings wird die LED nie gesetzt. Hier noch mein (Test)-Programm: #include <mega128.h> #include <stdlib.h> #include <stdio.h> void init_ADC(void); void init_Timer0(void); unsigned char adc_wert; void init_ADC() { ADMUX=0x60; //AVCC, Left adjust, ADC0 ADCSRA=0x89; //Enable, Single Mode, Interrupt aktivieren, Prescaler 2 SFIOR=SFIOR&0x8F; } void init_Timer0() { ASSR=0x00; TCCR0=0x02; //prescaler 8 ==> Timer Takt 1MHz TCNT0=0x05; //Vorladewert OCR0=0x00; //Kein Compare Mode, nur Überlauf // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x01; //Overflow Interrupt aktiviert ETIMSK=0x00; } interrupt [ADC_INT] void ADC_isr (void) { PORTE.6=1; //LED auf 1 setzen adc_wert=ADCH; //gewandelten WErt auf Variable speichern } interrupt [TIM0_OVF] void timer0_ovf_isr(void) { ADCSRA=0xD9; //Wandlungs-Start ADC TCNT0=0x05; // Vorladewert nachladen } void main (void) { init_ADC(); init_Timer0(); #asm("sei") // Global enable interrupts PORTE=0x00; //PORT E 0-Zustand bei Init DDRE=0xFF; //PORT E alle Pins als Ausgang while(1) { } } mfg Peter M.
achja...M103C Fuse nicht gesetzt (also nicht im ATmega103 Kompatibilitätsmodus) ATmega128 Takt = 8MHz
Und wie ist die LED angeschlossen? Abgesehen davon solltest Du adc_wert mit dem Typqualifizierer volatile versehen, da Du sonst nicht weißt, was der Linker der Variablen antut (also volatile unsigned char adc_wert)
Die LED hängt direkt an PORTE.6 mit einem Widerstand parallel (~470Ohm). Interne PullUps sind deaktiviert und die LED funktioniert auch wenn ich sie einfach so ansteuere. Nur wenn das "zum-leuchten-bringen" in der ISR des ADC steht dann gehts nicht (also Vermutung ADC ISR wird nie aufgerufen, Warum?). Danke für den Tipp mit volatile mfg Peter M.
@Die LED hängt direkt an PORTE.6 mit einem Widerstand parallel @(~470Ohm). Also eine den Vorwiderstand würde ich nicht parallel sonder seriell zum Port anbringen. Setze doch mal den "LED an"-Code mal in Deinen Timerinterrupt und schau ob der funktioniert..... Richtiges Debuggen muss man sich auch gut überlegen...
Hallo Mit 'Wie ist die LED angeschlossen' meinte ich eigentlich, ob sie Low Side oder High Side dranhängt. Aber mit nem Parallelwiderstand kann es eigentlich gar nicht funktionieren (zumindest nicht lange, weil der Portpin nach kurzer Zeit abrauchen dürfte). Im Code kann ich auch nach mehrmaligem Durchsehen keinen Fehler finden, der darauf hindeutet, dass der Interrupt nicht ausgelöst wird. Die Steuerregister sind anscheinend korrekt initialisiert. Du solltest Dir aber vielleicht noch eine andere Schreibweise angewöhnen, damit nicht jeder erst im Datenblatt nachsehen muss, was Du da überhaupt machst (Die Steuerbits haben Namen:-). Also versuchs mal mit dem Hinweis von Sebastian. Das ist sicher nicht verkehrt. Gruß Johnny
Hab jetzt mal umgelötet und den Widerstand in Serie gehängt (PORT "lebt" immer noch). Wenn der "LED-an" code in der Timer ISR steht, dann leuchtet sie, aber in der ADC ISR nicht. Muss ich noch irgendwas mit Interruptvektor oder so was anpassen (so weit ich weiß braucht man das ja in C nicht, aber schön langsam bin ich mit meinem Latein am Ende) @johnny: habs normalerweise nicht so mit den kommentaren :), werds mir aber merken Grüße, Peter M.
Hallo Es ging ja nicht um die Kommentare, die waren so weit i.O. Aber in der Header-Datei sind für jedes Bit Namen definiert, die man auch im Programm benutzen kann und sollte. Die Vektortabelle brauchst Du in C tatsächlich nicht zu initialisieren. Das macht der Compiler selbst. Fehler sehe ich in Deinem Code immer noch nicht. Was mir noch aifgefallen ist (ganz nebenbei) ist, dass Du den ADC mit 4 MHz quälst. Ich glaube kaum, dass Du selbst wenn Du nur 8 Bit Auflösung brauchst, mit dem Takt noch ein brauchbares Ergebnis bekommst. Mit wesentlich mehr als 1 MHz würde ich den nicht betreiben. OK, aber damit ist das Erleuchtungsproblem noch nicht gelöst... Hast Du mal versucht, den ADC mit Auto Trigger zu starten? Ich habe gesehen, dass Du das SFIOR ja bereits korrekt initialisiert hast. Ansonsten könntest Du mal schauen, ob das ADC-Flag überhaupt gesetzt wird (Interrupt deaktivieren und im HP das ADIF abfragen). Gruß Johnny
> @johnny: habs normalerweise nicht so mit den kommentaren :),
Es geht nicht um Kommentare
Es geht darum, dass du anstelle von
void init_ADC() {
ADMUX=0x60; //AVCC, Left adjust, ADC0
ADCSRA=0x89; //Enable, Single Mode, Interrupt
aktivieren, Prescaler 2
SFIOR=SFIOR&0x8F;
besser schreibst:
void init_ADC() {
ADMUX = ( 1 << REFS0 ) | ( 1 << ADLAR );
ADCSRA = ( 1 << ADEN ) | ( 1 << ADIE ) | ( 1 << ADPS0 );
...
Anstatt da jetzt jede der Hex-Zahlen auseinanderzunehmen, um
zu sehen welches Bit du eigentlich setzt, kann man das in
der alternativen Version wunderbar sehen. Das erspart zwar
nicht den Blick ins Datenblatt aber immerhin erspart man
sich die Bit-Pfriemelei.
Zum Beispiel sieht man in der 2. Version ganz deutlich, dass
das ADSC ( AD - Start Conversion ) Bit im ADCSRA nie gesetzt
wird. Bei ADCSRA=0x89 kann man das ohne Kopfrechnen nicht so
deutlich sehen.
@Karl-Heinz: Guck mal in die Timer ISR, da wird es gesetzt. Ich dachte auch, dass dort der Fehler liegt. Makros zu verwenden erhöht wirklich die Lesbarkeit, und vergössert nur den Quelltext, nicht das Assembler-File.
> @Karl-Heinz: Guck mal in die Timer ISR, da wird es gesetzt. Ich > dachte auch, dass dort der Fehler liegt. Asche auf mein Haupt. Alelrdings kann man das auch als Beispiel dafuer nehmen, dass diese Makros die Lesbarkeit deutlich erhoehen. Ansonsten koennte man das nur schwerlich uebersehen. Jetzt bin ich allerdings auch mit meinem Latein am Ende :-)
@Peter: Hast du den ADC schon mal im poll-Modus zum Laufen bekommen? Jonny hat auch Recht, dass 1MHz etwas viel ist. Irgendwas um die 100kHz (500-200kHz?) sollte man laut Datenblatt einstellen. Bin mir jetzt aber nicht ganz sicher, ob das mit der Genauigkeit zusammenhing.
@Rahul: 50-200 kHz sind tatsächlich nur für (volle) 10 Bit Auflösung erforderlich. Bei geringerer Auflösung kann man höher gehen, wobei im Datenblatt glaub ich nicht drinsteht, WIE hoch. Aber ich gehe mal aus Erfahrung davon aus, dass 4 MHz (ADC-Prescaler-Taktteilung durch 2, anscheinend betreibt er den µC mit 8 MHz, geht jedenfalls aus dem Kommentar bei der Timer-Init hervor) auch bei reduzierter Auflösung zu viel sind. 1 MHz geht vielleicht sogar noch... Aber daran lag es eh nicht. Wie gesagt, versuchs mal mit Polling, also so was wie while(!(ADCSRA & (1 << ADIF))); PORTE.6 = 1; Den Interrupt musste natürlich erst deaktivieren. Gruß Johnny
im datenblatt steht nur das man nicht größer als 100kHz gehen soll wenn man 10bit auflösung verwendet. bei geringerer auflösung steht das höhere frequenzen möglich sind (ich verwende 8bit daher hohe frequenz) ja mit dauerwandlung lief der ADC bereits! >>Hast Du mal versucht, den ADC mit Auto Trigger zu starten? kenn leider die funktion nicht. was ist das? >>Ansonsten könntest Du mal schauen, ob das ADC-Flag überhaupt gesetzt wird (Interrupt deaktivieren und im HP das ADIF abfragen). werd ich mal probieren, danke. @all: okay das mit meiner Hex-Code Zuweisung sollte ich wahrscheinlich wirklich mal überdenken (ist halt schon gewohnheitssache)
Auto-Trigger: Steht im Datenblatt. Trotzdem kurz: Das ADSC-Bit (ADC Start Conversion) kann nicht nur per Software sondern auch durch bestimmte Hardware-Ereignisse (z.B. den Timer 0 Overflow) gesetzt werden. Das SFIOR enthält die entsprechenden Bits (ADTS..) zur Auswahl der Triggerquelle. Das Bit ADATE im ADCSRA aktiviert den Auto-Trigger. Ist die elegantere Möglichkeit. Aber das dürfte auch nicht die Ursache für Dein Problem sein. Gruß Johnny
Hallo, ich habe dein Programm mittels AVR-Studio simuliert. Den Timer0 bekomme ich nicht zum Laufen. Ich kenne den ATmega128 nicht, daher kenne ich die zu setzenden Register nicht. Geh' erstmal sicher ob Dein Timer wirklich funktioniert. Lass von mir aus die LED blinken.... Sebastian.
>>SFIOR enthält die entsprechenden Bits (ADTS..) zur Auswahl der Triggerquelle. SFIOR: Bit 7: TSM, timer/counter synchronisation modus Bit 6-4: reserved Bit 3: ACME, analog comparator multiplexer enable Bit 2: PUD, generelles PullUp Disable BIt 1: PSR0, wert für asynchron modus für timer Bit 0: PSR321, prescaler reset timer1, 2, 3 >>Das Bit ADATE im ADCSRA aktiviert den Auto-Trigger. ADCSRA: Bit 7: ADEN, ADC enable Bit 6:ADSC, ADC start conversion Bit 5:ADFR, free running, single conversion Bit 4:ADIF, Interrupt flag Bit 3:ADIE, ADC Interrupt enable Bit 2-0: Prescaler Auswahl Also bei mir gibts die Funktion nicht
Ups, dann ist da beim Mega128 was komplett anders. Die Funktion an sich müsste es allerdings geben. Habe nur das Datenblatt vom Mega16 da. Kann es jetzt nicht überprüfen (Über Modem dauert das downloaden so ewig...). Kann mir aber net vorstellen, dass der 'dicke' Mega128 keine ADC Auto Trigger Möglichkeit hat. Sorry Johnny
Verd****, hab grad nachgesehen, der Mega128 hat tatsächlich KEINEN ADC Auto Trigger... Sorry für die Verwirrnis... Der Mega64 (mit dem ich im Unterschied zum 128 schon gearbeitet hab), der ansonsten dem 128 recht ähnlich ist hat das nämlich. Wundere mich ein wenig, dass der 128 das nicht hat. Ist nämlich eine feine Sache... Gruß Johnny
Also ich hab' Dein Programm nochmals simuliert mit der neuesten Version vom AVRStudio. Alles funktioniert so wie von Dir gewollt. Der ADC-ISR wird auch angesprungen. Entweder ist Dein Atmega128 hin oder mit Deiner Hardware stimmt was nicht. Gibt es beim Atmeg128 AVCC ?! Sebastian
@johnny.m: wenigstens bin ich kein fall von RTFM ;) @sebastian: ja das mit AVCC müsste passen mfg Peter M
Problemstelle gefunden (ich hoffe ihr hängt mich jetzt nicht) Hab im ganz oben angeführten Programm eben nur die relevanten Teile eingefügt. Allerdings hab ich auch gleich die USART mitinitialisiert (für spätere Verwendung) und ich dachte das wäre nicht wichtig für die Lösung des ADC Problems. Allerdings geht der ADC in die ISR wenn ich die USART NICHT initialisiere. Die Frage ist nur warum? Meine USART INIT: UCSR0A=0x00; //Flag register der USART UCSR0B=0xF8; //RX Complete Interrupt Enable (IEN), TX Complete IEN, Data Register Empty IEN, Receiver enable, Transmitter enable UCSR0C=0x06; //synchron, no parity, 1stop-bit, 8bit Datenlänge UBRR0H=0x00; //BAudrate 9600 UBRR0L=0x33; //Baudrate 9600 Daten senden mach ich über den printf Befehl! Sorry für die undurchsichtigen Hex-Werte für die Register, muss das erst ändern!
Ja die USART-BEschaltung ist vollkommen in Ordnung und funktioniert auch einwandfrei. Hab es mit HyperTerminal von Windows probiert! mfg Peter M.
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.