Morgen allerseits,
also, ich möchte per Terminalprogramm (hterm) am PC über die USART den
aktuellen Wert des ADC auslesen, um zu überprüfen, ob dieser
ordnungsgemäß agiert.
Am analogen Eingang des ADC werden verschiedene Festspannungswerte
angelegt, AVCC dient als Referenzspannung. Das Bit ADIE ist aktiv
(Interrupt) & es findet eine permanente Wandlung statt, da der ADC im
Free-Running Modus betrieben wird. Durch den Interrupt wird der aktuelle
Wert des ADC in eine int-Variable geschrieben & eine Interrupt-Variable
gesetzt, die ich im Mainloop mit einer if-Schleife abfrage. Ich denke,
dass innerhalb dieser if-Schleife, während der ADC-Wert in das UDR
(Sendedatenregister) geschrieben wird, der Fehler liegt.
Mir will aber die Erleuchtung nicht kommen.
Wäre super, wenn mir jemand die Augenbinde entfernen würde. ;)
Hier mein Quelltext in C:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#define F_CPU 16000000UL // definiere Prozessortakt auf 16MHz
4
5
#define Baud 9600UL // Baudrate definieren
6
#define R_UBRR ((F_CPU / (16L * Baud))-1) // Baudrate umrechnen für das Baudraten-Register
7
8
volatileunsignedintADC0=0;// der Variable ADC0 wird der Wert 0 zugeordnet
9
10
volatileunsignedcharADC0_interrupt=0;// Variable für den Interrupt reservieren
11
12
13
// ### Initialisierung der USART
14
15
voidusart_init(void){
16
17
UBRRH=R_UBRR>>8;/* R_UBRR in UBRRH schreiben &
18
um 8 Stellen nach rechts verschieben
19
in UBRRH steht: 0000 0000 */
20
UBRRL=R_UBRR;// R_UBRR in UBRRL schreiben
21
22
UCSRC|=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);/* Zuweisung an UCSRC richten;
Erekosё schrieb:> während der ADC-Wert in das UDR> (Sendedatenregister) geschrieben wird, der Fehler liegt.
welcher Fehler denn? Was geht denn nicht? Du sendest im binary format,
damit wird es keine Klartext zahl gehen, das ist dir hoffentlich
bewusst.
Hi,
ja, ich möchte den Wert auch binär ausgeben.
Der Controller sendet momentan garnichts, ich denke, dass dies daran
liegt, dass die Bedingung der if-Schleife (Interrupt) nie erfüllt wird.
Wenn ich nun aber das Programm ohne die if-Schleife schreibe, also
einfach:
1
while(1){
2
3
//if (ADC0_interrupt == 1) { // wenn Variable in ISR gesetzt wurde
4
ADC0=ADC;
5
6
while(!(UCSRA&(1<<UDRE)));// Warten bis Sendepuffer leer / bereit zum Senden?
7
UDR=ADC0>>8;/* High-Byte senden, ADC0 um 8 Stellen nach rechts verschieben
8
& in UDR (Sendedatenregister) schreiben */
9
while(!(UCSRA&(1<<UDRE)));// Warten bis Sendepuffer leer / bereit zum Senden?
10
UDR=ADC0&0xFF;/* Low-Byte senden, ADC0 mit '0000000011111111' &-verknüpfen
besteht meine Ausgabe letzendlich nur aus einem 'BCD-Format'
Bekomme zum Beispiel nur 00, 01, 10 oder 11 ausgegeben. Dabei ändert
sich der Wert nicht bei jedem Umschalten des analogen Eingangs.
Falls ich das Programm mit der if-Schleife auf den Controller spiele,
wird mir garnichts ausgegeben. Wobei ich in der if-Schleife den ersten
Befehl
ADC0 = ADC;
ebenfalls herausnehme.
spess53 schrieb:> Dir ist aber klar, das dein ADC etwa 20mal so schnell misst, wie deine> UART die ADC-Werte (2Byte) überträgt.
Interrupts in der if-Schleife deaktivieren und am Ende dieser wieder
aktivieren?
Folgendermaßen:
1
while(1){
2
if(ADC0_interrupt==1){// wenn Variable in ISR gesetzt wurde
Mach doch einzelne Wandlungen, wenn deine USART wieder so weit ist.
Richte die Geschwindigkeit der Wandlung nach der USART. Wenn der Wert
übertragen wurde, machst du eine neue Wandlung. Wenn die Wandlung fertig
ist, überträgst du den Wert wieder.
Du solltest dich immer nach dem langsamsten Glied in der Kette richten,
sonst gibts Überläufe.
Hi
>Interrupts in der if-Schleife deaktivieren und am Ende dieser wieder>aktivieren?
Warum Free-Running? Starte den ADC einfach nach der UART-Ausgabe manuell
(UDR abwarten). Oder, bei neueren AVRs möglich, trigger den ADC mit
einem Timer.
MfG Spess
ADC0 = ADC;
herausnehmen
Den Befehl brauchst Du gar nicht bzw. ist bereits in der ISR und einmal
müsste doch eigentlich reichen.
Geh' das Problem doch einfach stur nach Schema-F an.
Alles aus der While-Schleife raus
und die drei Befehlssequenzen:
while(!(UCSRA & (1<<UDRE)));
UDR = 'T';
while(!(UCSRA & (1<<UDRE)));
UDR = 0x0D;
while(!(UCSRA & (1<<UDRE)));
UDR = 0x0A;
einfügen.
Wird nix ausgegeben, ist die serielle Schnittstelle daneben.
Wird brav T<cr> ausgegeben, kannst Du dich mit der A/D-Geschichte
beschäftigen.
amateur schrieb:> Geh' das Problem doch einfach stur nach Schema-F an.>> Alles aus der While-Schleife raus>> und die drei Befehlssequenzen:>> while(!(UCSRA & (1<<UDRE)));> UDR = 'T';> while(!(UCSRA & (1<<UDRE)));> UDR = 0x0D;> while(!(UCSRA & (1<<UDRE)));> UDR = 0x0A;>> einfügen.
Das funktioniert schonmal gut.
ich schrieb:> Mach doch einzelne Wandlungen, wenn deine USART wieder so weit ist.> Richte die Geschwindigkeit der Wandlung nach der USART. Wenn der Wert> übertragen wurde, machst du eine neue Wandlung. Wenn die Wandlung fertig> ist, überträgst du den Wert wieder.> Du solltest dich immer nach dem langsamsten Glied in der Kette richten,> sonst gibts Überläufe.
Diesen Lösungsweg versuche ich mal zu realisieren, falls es Probleme
geben sollte, werde ich mich nochmals melden.
Danke Euch.
Was ist denn das für ein Controller?
Ein Atmega8 kann es nicht sein. Der hat kein ADATE. Ein neuerer auch
nicht, der hat kein URSEL.
Also hast du einen alten mit ADATE. Mit ADATE schaltet man den Auto
Trigger Mode ein. Nicht den Free Running Mode. Der ist allerdings per
default eingestellt.
Also wenn du ADATE hast, kannst du auch die Triggerquellen einstellen
und mit Timer triggern.
Das ist das, was meine Glaskugel jetzt so hergibt.
Ach ja: http://www.if-schleife.de/
mfg.
Mahlzeit,
Thomas Eckmann schrieb:> Ein Atmega8 kann es nicht sein. Der hat kein ADATE. Ein neuerer auch> nicht, der hat kein URSEL.
Ich verwende den ATmega32. Dort ist das URSEL-Bit sowie das ADATE
vorhanden.
Den externen Trigger stelle ich mit dem SFIOR-Register ein.
Thomas Eckmann schrieb:> Also wenn du ADATE hast, kannst du auch die Triggerquellen einstellen> und mit Timer triggern.
Wie man allerdings mit einem Timer den ADC triggert, ist mir noch
unbekannt.
Mir stehen noch Timer0 & Timer2 zur Verfügung.
Erekosё schrieb:> Wie man allerdings mit einem Timer den ADC triggert, ist mir noch> unbekannt.> Mir stehen noch Timer0 & Timer2 zur Verfügung.
Dafür musst du keinen extra Timer "opfern". Du nimmst einen, Timer0 oder
Timer1, der sowieso läuft und vom Timing her passt. Das ADC-Triggern
wird dem einfach untergejubelt, da kriegt der gar nichts von mit. Die
Quelle stellst du im SFIOR ein.
Der ADC wird aber nur beim Aufruf des Interrupts getriggert! Nicht beim
Setzen des zugehörigen Interrupt-Flags.
Den ADC-Wert von der vorherigen Wandlung kannst du in der Timer-ISR am
Anfang auslesen. Die ADC-ISR brauchst du dann nicht mehr. Ist aber auch
nicht verboten, es weiter damit zu machen.
mfg.
René Z. schrieb:> VERDAMMT NOCHMAL, WENN ICH NOCH EINMAL "IF-SCHLEIFE" LESE; LAUFE> ICH> AMOK; DAS HEISST WENN ÜBERHAUPT "IF-ABFRAGE" !!!
Du mußt hier nicht so rumschreien. Der Hinweis wurde zwei Posts davor
schonmal gegeben. Bleib cool :-)