Hallo,
ich verzewifel hier langsam an dem unten stehenden programmabschnitt
...das ganze soll mal über rs232 nen AD-Wandler-Kanal auswählen und dann
dauerhaft die werte aus dem gewählten kanal über RS232 an den pc
senden...
wenn ich mir mit meinem terminalprogramm (HTerm) anschaue was rauskommt
so sehe ich dass zwar dass daten ankommen, aber ich kann nicht den kanal
wechseln...
das steuern des PORTB funktioniert, was meiner meineung nach nahe legt
dass das problem mit folgender warnung zusammenhängt (:-D) :
../ATMega8-UART.c:86: warning: 'adchannel' may be used uninitialized in
this function
hier der programmabschnitt:
1
intmain(void)
2
{
3
4
DDRB|=(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(1<<PB5);//ausgänge für ventilsteuerung angesprochen mit !1...!5 sind pb1...5
5
charLine[3];
6
chars[20];
7
uint8_tadchannel;
8
InitUART(9600);
9
sei();
10
11
while(1){
12
13
14
uint16_tresult=ADC_Read(adchannel);//senden und wandeln des wertes an channel "adchannel"
> das steuern des PORTB funktioniert, was meiner meineung nach nahe legt> dass das problem mit folgender warnung zusammenhängt (:-D) :> ../ATMega8-UART.c:86: warning: 'adchannel' may be used uninitialized in> this function
Eigentlich nicht.
Wenn du wissen willst, was in der Maschine abgeht, dann bau dir
zusätzliche Ausgaben ein.
zb so
1
case'?'://? meint abfrage des channels 0...7
2
3
usart_puts("Schalte nach #");
4
usart_putc(Line[1]);
5
uasrt_puts("#\r");
6
7
switch(Line[1]){
dann erzählt dir der µC, was er empfangen hat und du kannst rausfinden
warum die Umschaltung nicht klappt.
Bakunin schrieb:> case '!': //! meint steuerbefehl 1...5>> switch(Line[1]){>> case '1':PORTB=0b00000010; break;>> case '2':PORTB=0b00000100; break;>> case '3':PORTB=0b00001000; break;>> case '4':PORTB=0b00010000; break;>> case '5':PORTB=0b00100000; break;>> }>> break;>>>> case '?': //? meint abfrage des channels 0...7>> switch(Line[1]){>> case '0':adchannel=0; break;>> case '1':adchannel=1; break;>> case '2':adchannel=2; break;>> case '3':adchannel=3; break;>> case '4':adchannel=4; break;>> case '5':adchannel=5; break;>> case '6':adchannel=6; break;>> case '7':adchannel=7; break;>> }
LOOOOLLLL!!!
Wieso nicht so?
Immer noch falsch Fabian. SChau dir genau an, was er mit dem PORTB
macht.
Lass uns bitte erst am Problem arbeiten, ehe wir Vereinfachungen
vorschlagen. ok?
Karl heinz Buchegger schrieb:> Lass uns bitte erst am Problem arbeiten, ehe wir Vereinfachungen>> vorschlagen. ok?
Jawohl!
Funktioniert denn überhaupt: ADC_Read(adchannel); richtig? Bzw. woher
weißt Du, dass der Kanal nicht gewechselt wird?!
Ein häufiges Problem ist, wenn der A/D Kanal gewechselt, aber nicht
lange genug bis zur Messung gewartet wird. Das S&H Glied muss sich ja
erstmal umladen.
>Immer noch falsch Fabian.>Lass uns bitte erst am Problem arbeiten, ehe wir Vereinfachungen>vorschlagen. ok?
Naja, eine halben Stern im Heft hat er sich verdient ;)
Wie lang sind eigentlich die empfangenen Kommandos?
Zwei Zeichen plus \r?
Dann ist die 3 als Feldlänge zu knapp, wenn noch eine
abschließende 0 dazukommt; ggf. noch eines mehr für \n etc..
@Fabian: wesendlich eleganter, soviel steht fest (mach das noch nicht
lange) ;)
@kbuchegg: stimmt, ausgabe ist jezt in HTerm 'Schal?LL???1023<\r>' um
diese meldung herum steht der zu erwartende input von ADC0, nämlich jede
menge '1023'
Bakunin schrieb:> @kbuchegg: stimmt, ausgabe ist jezt in HTerm 'Schal?LL???1023<\r>' um> diese meldung herum steht der zu erwartende input von ADC0, nämlich jede> menge '1023'
Wie Klaus schon sagte: Geh erst mal mit dem Line Array höher. Solche
Felder dimensioniert man nie auf Knirsch, sondern immer mit Reserve.
Mach da mal 80 draus.
Und dann fügst du nach jedem \r noch ein \n in die Ausgabe ein, damit
neuer Output den alten nicht überschreibt, sondern eine neue Zeile im
Terminal angefangen wird, damit man auch was sieht.
Und dann zeigst du deine Empfangsroutine.
ok, line mit 80 feldern, noch ein \n hinters \r :
ausgabe ist:
<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023
<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023
<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023
<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023
<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023
<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023
<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>1023<\r><\n>
...also wie vorher
Schalte doch bitte dein HTerm in den Modus, dass es Steuerzeichen
interpretiert anstelle das es sie hinschreibt. Das die Zahlen stimmen
glaub ich dir ja. Ich bin am Zusatztext interessiert!
Ich brauch den Text der bei der eingefügten Ausgabe rauskommt.
Hast du eh gesehen, dass die 2te Ausgabe kein uart_puts sondern ein
uart_putc (ein einzelnes Zeichen) ist?
Hmm
Das lässt sich verifizieren, ob man in der ADC_Read weiter suchen muss
1
while(1){
2
uint16_tresult;
3
4
uart_puts("Sample Kanal ");
5
utoa(adchannel,s,10);
6
uart_puts(s);
7
uart_puts(" -> ");
8
9
result=ADC_Read(adchannel);//senden und wandeln des wertes an channel "adchannel"
10
11
utoa(result,s,10);
12
uart_puts(s);
13
uart_puts("\r\n");
14
15
....
Ich bin bisher eigentlich von einem Problem in der gets ausgegangen (ein
\r der irgendwo übrig geblieben ist, oder so was in der Art). Aber auch
das könnte man verifizieren (was bei Benutzer-Eingaben sowieso immer
eine gute Idee ist)
ich hab das ganze so aufgebaut dass bei interner Uref am ADC0 5V
anliegen, an ADC1 per spannungsteiler ca 2,5V an den anderen rauschen
ausgabe ist
<\n>1023<\r>
<\n>1023<\r>
<\n>1023<\r>
uswusw
wobei sich bei übertragen von !1 oder anderen nichts ändert
Bakunin schrieb:> ich hab das ganze so aufgebaut dass bei interner Uref am ADC0 5V
und welchen Wet hat die Referenzspannung?
> anliegen, an ADC1 per spannungsteiler ca 2,5V an den anderen rauschen
Wo kommt das Rauschen her? Sind die Pins offen?
Bakunin schrieb:> ich hab das ganze so aufgebaut dass bei interner Uref am ADC0 5V> anliegen, an ADC1 per spannungsteiler ca 2,5V an den anderen rauschen>> ausgabe ist>>> <\n>1023<\r>> <\n>1023<\r>> <\n>1023<\r>> uswusw>
nochmal.
Die Zahlen dazwischen sind uninteressant.
INteressant ist, wenn du im HTerm das Kommando absetzt
?3
was kommt dann am µC an.
Nur das ist momentan interessant.
> wobei sich bei übertragen von !1 oder anderen nichts ändert
wieso ! ?
Ich denke die ADC Kanalumschaltnug geht nicht. Die hast du aber mit ?
und nicht mit ! programmiert. ! schaltet den Port B um
du kannst auch in die Hauptschleife erst mal einen
_delay_ms( 500 );
(und natürlich oben das Header File) einfügen, damit dir der µC nicht so
den Schirm zumüllt.
Bakunin schrieb:> meine (naja, nicht MEINE) ADC_Read sieht volgendermassen aus
Und.
Hast du sie getestet?
Was passiert, wenn du einfach mal ADC_Read mit 1 aufrufst?
Kriegst du dann den erwarteten Wert?
Hi
>Vieleicht sollte er den ADC mal initialisieren>und eine Vref Quelle auswählen;)>ich hab das ganze so aufgebaut dass bei interner Uref am ADC0 5V>anliegen, an ADC1 per spannungsteiler ca 2,5V an den anderen rauschen
Und was ist mit dem Prescaler?
MfG Spess
TCCR0|=(1<<CS02);//Select the clock source to be used by the timer/counter --> CPU Takt --> 8MHz/1024
9
TIFR|=(1<<TOV0);//interrupt starts with each overflow
Die Funktion heißt ADC_Init. Die hat nichts mit dem Timer zu tun. Das
gehört da nicht heinein.
(ISt jetzt aber nur ein Nebenschauplatz. Du hast doch hoffentlich eine
ISR für den Timer geschrieben)
Bakunin schrieb:> äh sorry, "?1" war gemeint, das resultat ist das selbe wie oben> gepostet, keine änderung... (auch bei ?3 nicht)
Nochmal:
Wenn du ?2 im HTerm eingibst .....
.... dann müsste der µC in den Programmteil
1
case'?'://? meint abfrage des channels 0...7
2
3
usart_puts("Schalte nach #");
4
usart_putc(Line[1]);
5
uasrt_puts("#\r");
6
7
switch(Line[1]){
8
....
kommen und dir ausgeben welches 2.te Zeichen er nach dem '?' empfangen
hat.
Kommt die Ausgabe und wenn ja, welches Zeichen taucht zwischen den #
auf? Das kann nur ein einzelnes Zeichen sein. Da kann kein #+34z78
stehen, es sei denn du hast irrtümlich anstelle von
usart_putc( Line[1] );
ein
usart_puts( Line[1] );
geschrieben.
Mach dir ein _delay_ms( 1000 ) in die Hauptschleife rein, wenn die
Zahlen zu schnell durchrauschen und du nichts mehr sehen kannst. Aber
ehe wir weiter suchen, sollten wir sicherstellen, dass aus deiner
uart_gets Funktion auch das rauskommt, was du denkst das rauskommen
sollte.
>Wie groß ist interne Referenzspannung?
Zu klein;)
Ich empfehle die Spannungen an den ADC Eingängen mal
unter 2,56V zu bringen. Oder AVCC als VREF zu nehmen.
laut datenblatt ist Vref intern 2,56 V. getestet ist die funktion
ADC_Read - ich habe passende werte erhalten, nur leider nicht mit von
mir über rs232 steuerbar sondern nur mit einer konstanten statt
adchannel sprich mit
1
uint16_tresult=ADC_Read(1);//hier ist die variable "adchannel" mit 1 ersezt
2
itoa(result,s,10);
3
uart_puts(s);
4
uart_putc('\r');
das mit dem delay macht das ganze weniger stressig, danke :)
oder einfach mal einen Pin auf GND legen, dann wird auch was anderes als
1023 rauskommen :-)
holger schrieb:> Ich empfehle die Spannungen an den ADC Eingängen mal> unter 2,56V zu bringen. Oder AVCC als VREF zu nehmen.
>Ich empfehle die Spannungen an den ADC Eingängen mal>unter 2,56V zu bringen. Oder AVCC als VREF zu nehmen.
Upps, oder je nach CPU Typ (welcher ist das) sogar unter 1V.
Bakunin schrieb:> @kbuchegg: wie gesagt, es tut sich nichts
Gar nichts?
Dann funktioniert deine uart_gets nicht richtig.
Ändere die mal (Vermutung ins Blaue)
1
voiduart_gets(char*Buffer,uint8_tMaxLen)
2
{
3
uint8_tNextChar;
4
uint8_tStringLen=0;
5
NextChar=uart_getc();// Warte auf und empfange das nächste Zeichen
6
// Sammle solange Zeichen, bis:
7
// * entweder das String Ende Zeichen kam
8
// * oder das aufnehmende Array voll ist
9
while(NextChar!='\n'&&StringLen<MaxLen-1){
10
if(NextChar!='\r'){
11
*Buffer++=NextChar;
12
StringLen++;
13
}
14
NextChar=uart_getc();
15
}
16
// Noch ein '\0' anhängen um einen Standard
17
// C-String daraus zu machen
18
*Buffer='\0';
19
}
Moment.
Das ist ein wartendes gets.
Da dürfen überhaupt keine Zahlen in der Hauptschleife durchrauschen,
weil jedesmal nach dem ADC auslesen darauf gewartet wird, dass du eine
Zeile vom PC rüberschickst.
<Nachdenk>
>nochmal der code mit den gemachten variationen, diesmal in der gesamten>"pracht":
Nö.
> TIMSK |= (1<<TOIE0); //Enable Timer/counter0 overflow interrupt
Wo ist die Interrupt Routine für Timer0?
>#define _AVR_ATmega8_ 1>#define OSCSPEED 8000000 /* in Hz */
Auaaaaa...
OSCSPEED interessiert
#include <util/delay.h>
nicht die Bohne.
Die Baustelle ist größer als bisher angenommen;)
also ich empfange <\n>1023<\r> ...oft
-bzw eine 1 wenn ichs auf gnd lege bzw rauschen wenn ich den pin offen
halte , die ADC an sich ist hier denke ich nicht das problem...
was die übertragung von strings angeht,
1
while(1){
2
uart_puts("Hallo");
gibt aus: ????! oder binär: 10000101 10110001 10110001 10111101 00100001
Poste alles.
Da kommen ein paar Dinge zusammen. Einzeln aussortieren ist nicht.
Aber der wichtigste Punkt ist:
WENN DU KEINE INTERRUPT SERVICE ROUTINE HAST, DANN DARFST DU AUCH FÜR
DEN TIMER KEINEN INTERRUPT FREIGEBEN!
Und das nächste mal versteckst du keinen Timer in den ADC Funktionen.
Schon gar nicht, wenn da ein Interrupt dafür freigegeben wird. Da sucht
man sich nämlich dumm und dämlich danach.
die Interrupt Routine für Timer0 such ich auch grade :D nee aber es ging
wie gesagt problemlos ohne, dass ich rauschen emfange belegt das meiner
meinung
util/delay.h musste ich erst durch die while reinnehmen, änderung:
eingebut wurde #define F_CPU 8000000L
nun bekomm ich nach resetten lauter Hallos wie gewollt also uart_puts
läuft
Bakunin schrieb:> die Interrupt Routine für Timer0 such ich auch grade :D nee aber es ging> wie gesagt problemlos ohne,
Nein.
Es geht eben nicht problemlos.
Das hat nur so ausgesehen.
Der gcc Standard ISR Handler hat das Programm alle paar ms neu
gestartet. Und da du PORTB nicht initialisiert, hat der Wert am PortB
dieses überlebt.
oh äh ok hab mal
TIMSK |= (1<<TOIE0); //Enable Timer/counter0 overflow interrupt
testweise auf 0 gesezt- resultat war dass nichts mehr gesendet wird...
Bakunin schrieb:> oh äh ok hab mal> TIMSK |= (1<<TOIE0); //Enable Timer/counter0 overflow interrupt> testweise auf 0 gesezt-
Schmeiss es ganz raus.
Timerinitialisierung hat in einer Funktion die den ADC initialisiert
nichts verloren.
> resultat war dass nichts mehr gesendet wird...
Du meinst ausser dem ersten Messergebnis.
Das ist auch nicht anders zu erwarten.
deine uart_gets wartet darauf, dass sie eine Zeile bekommt. Der
Programmlauf geht erst dann weiter, wenn die Zeile da ist.
Jetzt nähern wir uns langsam.
Vorschläge was du dagegen tun willst?
>oh äh ok hab mal>TIMSK |= (1<<TOIE0); //Enable Timer/counter0 overflow interrupt>testweise auf 0 gesezt- resultat war dass nichts mehr gesendet wird...>Das ist ein wartendes gets.
Passt doch gut zusammen;)
Der fehlende Timer Interrupt hat dein Programm durch
ständige Resets am Leben gehalten.
Bakunin schrieb:> ...morgen sicherlich :) danke schonmal bis hier hin, iss ja schon> ganzschön was zusammengekommen in dem thread ...
Na komm.
Jetzt sind wir auf der Zielgeraden.
Deine uart_gets muss zuerst prüfen, ob überhaupt etwas an der UART
eingetroffen ist und wenn nicht liefert sie einfach einen leeren String
zurück.
Ist was da, dann wartet sie bis die Zeile komplett ist und gibt erst
dann zurück.
Ist zwar nicht optimal, aber schnell umgesetzt.
if(UCSRA&(1<<RXC)){// wartet ein Zeichen in der UART?
7
NextChar=uart_getc();// Warte auf und empfange das nächste Zeichen
8
// Sammle solange Zeichen, bis:
9
// * entweder das String Ende Zeichen kam
10
// * oder das aufnehmende Array voll ist
11
while(NextChar!='\n'&&StringLen<MaxLen-1){
12
if(NextChar!='\r'){
13
*Buffer++=NextChar;
14
StringLen++;
15
}
16
NextChar=uart_getc();
17
}
18
}
19
// Noch ein '\0' anhängen um einen Standard
20
// C-String daraus zu machen
21
*Buffer='\0';
22
}
Dein ADC misst jetzt solange du am Terminal nichts tust.
Fängst du zu tippen an, dann geht die uart_gets in den Wartemodus. Sie
wartet bis du fertig getippt hast (Return) und gibt die Zeile zurück.
Die Zeile wird in der Hauptschleife ausgewetret und weiter gehts in der
Hauptschleife und da dann die UART wieder leer ist, geht auch uart_gets
nicht mehr in den Wartemodus und wartet danach nicht mehr. Bis du wieder
zu tippen anfängst.
ok, änderungen die ich gemacht habe sind: löschen der kompletten
timerinizialisierung sowie erneuern der uart_gets() nach kbucheggs
vorschlag(danke!)
...schön ist dass jezt die warteschleife so läuft wie sie soll :)
allerdings resultiert das senden einer abfrage zb ?2 oder auch !2 im
abbruch der hauptschleife (jedenfalls werden keine werte mehr
ausgegeben, auchnicht das testweise implementierte "Schalte nach #
'Line[1]' #")
aber auf jedenfall ist jezt so wie ich das sehe mit der initialisierung
und den verwendeten funktionen alles im reinen... ...vorschläge?
Sicher, dass du zu dem ?3 auch ein \n schickst? Ansonsten wartet deine
getchar-Routine darauf, dass das Array voll ist. Und das bedeutet, dass
du 80 Zeichen schicken musst.
ok es liegt anscheinend auf jeden fall an der uart_gets() genauer gesagt
an der bedingung
1
while(NextChar!='\n'&&StringLen<MaxLen-1){
sobald ich das array Line[] auf 3 felder länge setze läuft alles wies
soll... - beötigt man für StringLen zufällig ne bibliothek die ich nich
implementiert hab oder sowas?
nachtrag zu oben: dass ich standardmässig \0 am ende sende muss nicht
sein-schöner währ ja ohne :)
aber wir (oder besser ihr) seit schon nah dran denk ich..
Bakunin schrieb:> nachtrag zu oben: dass ich standardmässig \0 am ende sende muss nicht> sein-schöner währ ja ohne :)
Was, oder besser gesagt, wer sendet eigentlich.
Du (an einem Terminal) oder ein anderes Programm.
Ehe du an anderes Programm das Senden übernehmen lässt, solltest du erst
mal selbst per Hand von einem Terminal aus deinen µC 'füttern'
(die 80 Zeichen können dir nur dann einen Strich durch die Rechnung
machen, wenn dadurch das SRAM voll ist. Deine 'Lösung' mit Array auf 3
Zeichen zurückschrauben ist, abgesehen von diesem Sonderfall, keine
Lösung.
So wie Lasse das vorschlägt, kann man das natürlich auch machen.
Allerdings ist es zum einen Flucht vor dem Feind, zum anderen wirst du
deine Debug-Fähigkeiten nie entwickeln wenn du Schwierigkeiten immer nur
aus dem Weg gehst und zu guter letzt ist eine uart_gets keineswegs eine
esoterische Funktion, die man nie wieder braucht.
Du kennst mitlerweile die Techniken, wie man solchen Problemen auf den
Grund geht:
Bau dir Ausgaben ein!
In deiner uart_gets kommen die Zeichen herein. Also kannst du dir dort
Ausgaben einbauen, an Hand derer du verfolgen kannst, was deine UART
eigentlich empfängt.
Haha ok wie bekloppt- mein terminal-programm war so eingestellt dass \0
on enter gesendet wird- mit der einstelölung \r on enter läufts
logischer weise :D
später will ich labview zur steuerung nutzen (da ist es auch nicht
sonderlich wild eben noch nen carriage return als konstante an den
befehlsstring anzuhängen)
vielen dank fürs aufräumen meines codes und die verbessenungen!!!