Salve Aus irgend einem Grund bekomme ich den Free-running-Mode des ADC's nicht zum Laufen. Ich schreibe die Asembler Programme mit AVR-Studio. Ich hab sogar alle nicht benötigten Programmteile aus dem Testprogamm rausgenommen und es wird trotzdem kein Interrupt gesendet. Wenn ich aber den Interrupt der anzeigt dass die ADC-Wandlung fertig ist manuell setze, wird die Interuptroutine abgearbeitet. Kann mir bitte jemand sagen wo ich beim Setzen der Flags für die ADC-Wandlung oder sonst irgendwo einen Fehler gemacht habe? mfg Sepp
Hi Sepp, ich kann Dein Programm nur schwerlich lesen Bsp: ldi R30,0xE0 out ADMUX,R30 besser wäre: ldi temp, 0<<REFS1 | 0<<REFS0 out ADMUX, temp denn so sieht man sofort welches Bit wie gesetzt ist, ansonsten müssen wir erst mühesam hex umrechnen und uns die Datenblätter heraussuchen und das kostet kostbare Zeit. Schreib Dein Code einfach mal um, vielleicht findest Du den Fehler sogar selber, ansonsten nochmal fragen. Bernhard
Hm, komisch. Freilaufend habe ich's auch noch nie versucht, allerdings initialisiere ich meinen ADC und setze erst dann in einem eigenen letzten Schritt das ADSC-Bit im ADCSR-Register.
> ldi R30,0xCF > ; ldi R30,0xFF > out ADCSR,R30 Erkläre uns mal bitte, wie du mit $CF in ADCSR den Free-Run-Mode aktivierst? (ADATE???) Was die Lesbarkeit des Programms angeht, hat Bernhard gar nicht so unrecht. Schmunzeln muss ich immer über '0x00', eine einfache '0' tuts da auch, sieht aber vermutlich zu einfach aus... Schau mal hier: http://www.hanneslux.de/avr/mobau/7ksend/7ksend02.html Das ist zwar auch nicht das Nonplusultra, aber doch immerhin etwas lesbarer. Free-Run und Interrupt hatte ich noch nicht gebraucht. Wenn ich Interrupt nutze, dann brauche ich doch kein Free-Run. Oder checke ich jetzt was nicht? Beispiel: http://www.hanneslux.de/avr/divers/melody/melody04.html ...
@HanneS
> Schmunzeln muss ich immer über '0x00', eine einfache '0' tuts da
auch, sieht aber vermutlich zu einfach aus...
He! Mit dieser Aussage triffst Du nicht nur einen Programmierer! Die
Strukturierung eines Quelltextes ist ja häufig das Geheimnis seines
Programmierers. Daher mag eine '0x00' statt der '0' Informationen
verbergen, die Du nicht siehst. Krasses Extrembeispiel ist ja auch eine
Version von Bernhard:
ldi temp, 0<<REFS1 | 0<<REFS0
Braucht mehr Platz, hat aber auch mehr Informationsgehalt. Aber so hat
jeder seine Gewohnheiten:
sub volt0,volt ;1/256 vom Mittelwert
sbc volt,null ;incl. Übertrag subtrahieren
add volt0,wl ;1/256 des eingelesenen Wertes
adc volt,null ;mit Übertrag addieren
Ich kann keine '0' entdecken.
schmunzel
Hallo, Habe mir deinen Code mal näher angesehen. Damit der free running mode funktioniert muss im SFIOR Register die ADTS2, ADTS1 ADTS0 Bits cleared sein, was du ja auch getan hast. Aber laut datenblatt hat diese Einstellung keinen Effekt wenn im ADCSRA Register das ADATE Bit nicht gesetzt ist. Und dies ist in deinem Fall nicht gesetzt. Teste es mal, vielleicht geht es. Gruß, Andy
@Christian: > Krasses Extrembeispiel ist ja auch eine > Version von Bernhard: > > ldi temp, 0<<REFS1 | 0<<REFS0 Nunja, das ist sehr unglücklich, da extrem wirkungslos. Mit 'ldi' lädt man normalerweise die geshifteten Einsen, die Nullen bleiben von alleine übrig. Ich habe das aber nicht kommentiert, da ich das für einen Schreibfehler hielt. Ich schreibe die Konstanten eigentlich immer so, dass ich (und auch Andere) verstehen kann, was gemeint ist. Handelt es sich um I/O-Register für Spezialhardware, dann schreibe ich die Bits mit den Bitnamen laut Datenblatt. Bei Zählschleifen setze ich Dezimalzahlen ein, ebenso bei Zahlen unter 10, da wirkt das '0x0..' lächerlich. Hexzahlen gebe ich meist mit $ als Präfix ein, ist Gewohnheitssache vom 6502-Assembler. Gelegentlich schreibe ich Konstanten auch als ASCII (add wl,'0'), wenn ich damit zeigen will, dass ich den ASCII-Wert meine. mit "add wl,48" oder "add wl,0x30" sieht man das erst auf dem zweiten Blick. Binärschreibweise nehme ich für Bitmuster, z.B. bei 7-Segment-Anzeigen. > Aber so hat > jeder seine Gewohnheiten: > > sub volt0,volt ;1/256 vom Mittelwert > sbc volt,null ;incl. Übertrag subtrahieren > add volt0,wl ;1/256 des eingelesenen Wertes > adc volt,null ;mit Übertrag addieren > > Ich kann keine '0' entdecken. Dann hast du nicht das ganze Programm gesehen. Bei mir (und etlichen anderen ASM-Programmirern) gibt es inzwischen immer ein unteres Register mit dem Namen 'null' und dem Inhalt 0. Das braucht man nämlich immer wieder, zum Beispiel zum Addieren/Subtrahieren mit Carry bei 16(32)-Bit-Arithmetik oder zum Löschen von I/O-Registern. Ohne dieses Register wäre z.B. die von dir zitierte Mittelwertbildung nicht so effizient (in der ISR im Vorbeigehen) realisierbar. - Oder??? Aber das ist alles relativ. In der Codesammlung gibt es genug ASM-Code von hochkarätigen Programmierern, den auch ich nicht so ohne Weiteres verstehe. ...
Na?? Stolpert keiner über "add wl,'0'"??? - Datt gibbet nämlich nitt... Muss dann "subi wl,-'0'" heißen... ;-) ...
Ich glaub im Freerunning wird nur einmal (nach der ersten Wandlung) ein Interrupt ausgeführt. Danach muß man dann immer wieder den Interrupt aktivieren, oder periodisch abfragen. (Zumindest hab ichs bisher so gemacht)
Bei vielen AVRs braucht man den ADC garnicht starten (ADSC), es genügt, ihn einzuschalten (ADEN, ADIE). Der ADC startet dann selbsttätig, wenn er in den Sleep geschickt wird. Bei einigen AVRs funktioniert das nur im Sleep-Mode ADC-Noisereduction, bei anderen sogar im Idle-Mode. Einfach mal im Datenblatt unter Sleep nachschaun und ausprobieren. ...
@Läubi: Natürlich wird der Interrupt nach jeder Wandlung ausgelöst (auch im Free Running Mode), wenn das Interrupt Flag vorher gelöscht war (was beim Einspringen in die ISR automatisch geschieht). Alles Andere wäre ziemlicher Unfug. Im Free Running Mode muss man afaik das ADSC zum Start der ersten Wandlung einmal setzen. Den Rest macht der µC selber. Gruß Johnny
@HanneS >>Erkläre uns mal bitte, wie du mit $CF in ADCSR den Free-Run-Mode >>aktivierst? (ADATE???) Du hast recht, ich habe vergessen den Wert zurückzustellen. Es hat aber auch nicht mit 0xEF funktioniert. Mit 0xFF wurde die Wandlung einmal durchgeführt, weil dadurch der Interrupt-Flag manuell gesetzt wurde. Das 0x00 habe ich vom Programieren mit höheren Programiersprachen (C/C++,...) übernommen. Wenn ich Konstanten verwende, verwende ich immer nur Hexzahlen. Klar könnte man auch 0 anstatt 0x00 verwenden, aber mann sieht dadurch sofort dass es sich um eine 1-Byte große Konstante für die Verwendung bei (unsigned) char-Variablen handelt. So kommt man nicht mit den Variablentypen bzw. der Bitbreite durcheinander. Ach übrigens >>"subi wl,-'0'" funktioniert nur wenn man wie du ein Workregister low deffiniert hat. Die Initialiesierung der ADC-Register habe ich übrigens dierekt von einem C-Programm übernommen dass ich mit CodeVision AVR geschrieben habe. Da hat der free-running Modus einwandfrei funktioniert. Auch beim ATmega8 hat der free-running Modus nie Probleme gemacht. Ich habe bis jetzt den free-running Modus und den Interrupt verwendet, weil man da den ADC nur einmal einschalten muß und sich dann nicht mehr um die Wandlung kümmern muß. Man schreibt einfach den neuen ADC-Wert in der Interruptroutine in ein eigenes Register und hat somit jederzeit einen gültigen ADC-Wert. Man verschwendet auch keine Prozessor-Zeit durch warten auf das Ende der ADC-Wandlung. Außerdem hat man beim free-running Modus mit Interrupt anstatt einen Timer zu benötigen einen weiteren gewonnen. Laut Datenblatt wird die ADC-Wandlunng gestartet sobald der IDLE-Modus gestartet wird. (Das Gleiche steht beim ADC-Noisereduction.) Desswegen habe ich die ADC-Initialisierung gleich unter die Stack-Initialisierung gepackt. Das hat aber auch nicht funktioniert. Den ADC-Noisereduction Modus möchte ich eigentlich vermeiden, dann im free-running Modus nichts anderes gemacht wird als Analogwerte zu digitalisieren. Und außerdem muß der ADC-Wert in den Anwendungen die ich gerade vor habe nicht sehr genau sein. (Überwachung der Versorgungsspannung.) @Bernhard Schulz Da ich eigentlich grundsätzlich mit PDF-Datenblättern und dem Windows-Rechner im wissenschaftlichem Modus arbeite, erspare ich mir durch deine Methode eigentlich keine Zeit. Ich arbeite bei der Resetroutine lieber mit den Zahlen dierekt, da diese im Quellcode herausleuchten und dadurch schneller zu finden sind. Normalerweise schreibe ich die Hexzahlen in den Komentar binär aufgeschlüsselt mit deren Bedeutung. Beim Zusammenkürzen des Codes dürfte ich versehentlich ein paar Kometarzeilen gelöscht haben. @Alle Was habe ich in diesem Test-Programm falsch gemacht? Mit: ldi R30,0xEF out ADCSR,R30 bzw: ldi R30,0xFF out ADCSR,R30 klappt's auch nicht. mfg Sepp
Mir schwant da grade Fürchterliches, nachdem ich das erste Posting noch mal gelesen habe: Hast Du das ganze bisher nur im Simulator ausprobiert? Darauf deutet jedenfalls der Hinweis hin, Du hättest den Interrupt manuell gesetzt, was m.W. nur in der Simulation geht. Ich hatte mal ein ähnliches Problem mit nem Mega16, das mich zu der Annahme geführt hat, dass der AVR-Simulator mit ADC Auto Trigger (und dazu gehört auch der Free Running Mode) generell nix anfangen kann. Auf meine Anfrage http://www.mikrocontroller.net/forum/read-2-312911.html hat damals leider niemand was zum Besten gegeben. Aber es passt zusammen, vorausgesetzt meine Vermutung stimmt, dass Du das bisher nur im Simulator getestet hast. In meinem Fall hat es in der Hardware tadellos funktioniert, nur eben im Simulator nicht. Wenn die Möglichkeit besteht, dann teste es doch mal in der Hardware. Es würde mich nicht wundern, wenns klappt. In der Init finde ich jedenfalls auf den ersten Blick keine Fehler. Gruß und frohe Ostern Johnny
Hast Du den JTAG in den Fuse-Bits deaktiviert ? Ich hab deswegen schon ein paar Nächte um die Ohren gaschlagen. Gruß Sebastian
@johnny.m Es funktioniert weder Simulieren noch die Hardware. Im Register ADCSR gibt's doch ein ADC Interrupt Flag(Bit 4) dass anzeigt ob ein ADC-Interrupt aufgetreten ist. Wenn man dieses Bit aktiviert wird die Interruptroutine genau einmal ausgeführt. (Beim Simulieren und beim µC) Ich verwende übrigens eine ältere Version von AVR-Studio. (Version 3.irgendwas. Ich weis die Versionsnummer gerade nicht weil ich den Programierrechner gerade heruntergefahren habe.) Da habe ich bis jetzt eigentlich keine Probleme mit dem Simulieren gehabt. Ich vermute dass das Problem mit dem ATmega32 zusammenhängt. Beim ATmega 8 hatte ich nämlich mit fast dem selben Code keine Probleme. @Sebastian Mazur An den Fusebit's habe ich eigentlich nichts gemacht außer den Internen Resonator für einen kleinen Test auf 8MHz zu stellen und danach wieder auf 1MZ zurückzustellen. Vom Rest der Fusebit's habe ich die Finger gelassen. mfg Sepp
Dann würde ich mal den JTAG deaktivieren, er ist standardmäßig aktiviert, Du wärst nicht der erste, der darauf reingefallen wär. Probieren kostet ja nichts, wenn's hilft gut, wenn nicht liegt es wohl an was anderem... Gruß Sebastian
Normalerweise kann man die Interrupt Flags nicht manuell setzen, sondern nur löschen (indem man eine 1 hineinschreibt). Oder ist das beim Mega32 anders? In den meisten mir bekannten Da6tenblättern steht da immer 'Writing a logical 0 to the Bit has no effect' oder so ähnlich. Ich würd mir aber schnellstens die neueste Version von AVRStudio runterladen, v.a. dann wenn man mit einem der neueren AVRs arbeitet. Die vom JTAG-Interface genutzten Pins benutzt Du anscheinend nicht, so dass von da her kein Fehler zu erwarten ist.
Salve Ich hab jetzt das Testprogramm in C mit Code Vision AVR geschrieben und habe keine Probleme gehabt. Also muß es am Programm liegen. @johnny.m Kann sein dass man die Flags so nicht setzen kann. Aber aus irgend einem Grund verhält sich der µC so als ob es funktioniert. mfg Sepp
Hallo Sepp, ich habe Dir mal ein Assenbler-Beispiel für den ATmega8 beigefügt. (Free-Running & Interrupt) Einfach die inc-Datei und die Interrupt-Vektoren auf Deinen µC anpassen. Anschließend testen ==> sich daran erfreuen und uns anschließend erklären, warum es bei Deiner Variante nicht funktionierte. >Da ich eigentlich grundsätzlich mit PDF-Datenblättern und dem >Windows-Rechner im wissenschaftlichem Modus arbeite, erspare ich mir >durch deine Methode eigentlich keine Zeit. Aber uns hättest Du viel Zeit erspart ;) Bernhard
ldi temp, 0<<REFS1 | 0<<REFS0 ich mache das genauso, und gerade auch wenn man 0 als Konstente reinschiebt und temp dann 0 wäre. Denn exakt das enthält die meisten Informationen für den Programmierer. Kurzer Source ist kein Indiz für einen guten Source und sollte niemals als Optimierung herhalten. Die zusätzliche Information ist nämlich Welche Bitkonstanten könnte der Programmierer benutzen ? Welche Bitkonstanten wurden tatsächlich benutzt ? Man sieht also erstmal die lesbaren Konstantennamen, und zweitens braucht man nicht ständig im Datenblatt nachschlagen welche Bitkonstanten nun für das entsprechende Register möglich sind. Ich halte das für einen sehr guten Programmierstil eines vorrauschauendend, planmäßig und diszipliniertem Programmierer. Auch das Weglassen der Klammersetzung sagt mir das der Programmierer die Operatorenprioritäten der Boolschen Algebra kappiert hat und nicht mit unnötig vielen Klamerungen alles unleserlich macht. Gruß Hagen
@Hagen Re (Hagen) und Bernhard Schulz Ihr habt ja recht. Aber als einer der sich das Programieren mit diversen Programiersprachen durch Beispielquellcode und herumprobieren beigebracht hat, kann ich solche Programiertricks nicht wissen. @ Bernhard Ich habe deinen Quellcode etwas verändert (siehe Anhang) damit er auf dem ATmega32 läuft. Aber es will weder beim Simulieren noch auf dem µC funktionieren. Merkwürdigerweise springt das Programm durch den Aufruf von 'rjmp loop' in die Mitte der Reset-Funktion. Genauergesagt in die Einstellung des Startwertes von PortD mit: 'out PORTD, temp'. Was ist da los? Solche Probleme hatte ich beim ATmerga8 nie. mfg Sepp
Deine Interrupt-Vektoren stimmen nicht. AVRs ab 16KB Flash haben aufgrund des größeren Adressraums zwei Adressen (4 Bytes) pro Vektor reserviert, damit der Befehl 'JMP' verwendet werden kann. Ich mach es so:
1 | ;----------------------- Interrupt-Sprungtabelle -------------------- |
2 | .cseg ;Code-Segment (Flash, Programmspeicher) |
3 | .org 0 ;Interrupt-Sprungtabelle ATmega32 |
4 | jmp RESET ;Reset Handler |
5 | jmp nix;EXT_INT0 ;IRQ0 Handler |
6 | jmp nix;EXT_INT1 ;IRQ1 Handler |
7 | jmp nix;EXT_INT2 ;IRQ2 Handler |
8 | jmp nix;TIM2_COMP ;Timer2 Compare Handler |
9 | jmp nix;TIM2_OVF ;Timer2 Overflow Handler |
10 | jmp nix;TIM1_CAPT ;Timer1 Capture Handler |
11 | jmp TIM1_COMPA ;Timer1 CompareA Handler |
12 | jmp TIM1_COMPB ;Timer1 CompareB Handler |
13 | jmp nix;TIM1_OVF ;Timer1 Overflow Handler |
14 | jmp nix;TIM0_COMP ;Timer0 Compare Handler |
15 | jmp nix;TIM0_OVF ;Timer0 Overflow Handler |
16 | jmp nix;SPI_STC ;SPI Transfer Complete Handler |
17 | jmp nix;USART_RXC ;USART RX Complete Handler |
18 | jmp nix;USART_UDRE ;UDR Empty Handler |
19 | jmp nix;USART_TXC ;USART TX Complete Handler |
20 | jmp nix;ADCC ;ADC Conversion Complete Handler |
21 | jmp nix;EE_RDY ;EEPROM Ready Handler |
22 | jmp nix;ANA_COMP ;Analog Comparator Handler |
23 | jmp nix;TWI ;Two-wire Serial Interface Handler |
24 | jmp nix;SPM_RDY ;Store Program Memory Ready Handler |
25 | nix: reti |
Wobei während der Programmierphase die Routine 'nix' Code zum Debuggen enthält. ...
Genau dass war's! Vielen vielen Dank für eure Hilfe. Ganz besonders dir HanneS. @johnny.m Jepp, auch beim Simulieren mit dem älteren AVR-Studio(Version 3.56) wird der ADC-Interrupt nicht ausgelöst. Auf dem Mikrokontroller läuft's aber hervorragend. Frohe Ostern euch allen. mfg Sepp
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.