MoinMoin
ich hab mal wieder ein kleines Problem, ich bin dabei mir C ein wenig
nahezubringen und habe dazu eine kleine Routine geschrieben(für nen
Mega32, in CodeBlocks, im AVR-Studio meckert er immer über Fehler?!),
die einen Servo von einem bis zum anderen Anschlag fahren lässt. Soweit
so gut, nach einigen kleinen Fehlschlägen hats dann auch geklappt. Der
Servo fuhr fröhlich von der einen zur anderen Seite.
Dann fiel mir aber ein, das es auf Dauer recht langweilig ist, wenn der
das ganze immer nur in einer Geschwindigkeit machen kann, bzw ich immer
neu flashen muss, wenn ich ne andere Geschwindigkeit haben möchte. Also
hab ich flugs versucht, meine UART-Routine aus Assembler nach C zu
übersetzen. Register entsprechend gesetzt, und ich konnte schonmal
senden. Für den Empfang habe ich dann nach Rätselraten rausgefunden,
welcher Interruptvektor der UART-Empfangsvektor ist, da im Datenblatt
steht es ist 14, aber in iom32.h oder wie sie heißt, ist es 13(Dem Forum
sei dank, auch hier gefunden). Nun konnte ich endlich auch empfangen,
als ich in der ISR folgendes stehen hatte:
1
ISR(Recieve_Int)
2
{
3
UARTrecieve=UDR;
4
UDR=0;
5
}
hat es auch geklappt, wenn ich in HTERM ne Zahl (als Dezimal sowohl
eingeben als gesendet in den Einstellungen, sprich nicht als ASCII)
eingegeben habe, hat sich die Geschwindigkeit geändert.
Nun sieht die ISR so aus:
1
ISR(Recieve_Int)
2
{
3
if(BefehlEmpfangen==0)
4
{
5
BefehlEmpfangen=UDR;
6
}
7
else
8
{
9
if(BefehlEmpfangen==1)
10
{
11
faktor=UDR;
12
BefehlEmpfangen=0;
13
}
14
else
15
{
16
if(BefehlEmpfangen==2)
17
{
18
Verzoegern=UDR;
19
BefehlEmpfangen=0;
20
}
21
else
22
{
23
if(BefehlEmpfangen==3)
24
{
25
minAnschlag=UDR;
26
BefehlEmpfangen=0;
27
}
28
else
29
{
30
if(BefehlEmpfangen==4)
31
{
32
maxAnschlag=UDR;
33
BefehlEmpfangen=0;
34
}
35
else
36
{
37
BefehlEmpfangen=0;
38
}
39
}
40
}
41
}
42
}
43
}
Ich wollte erst eine Zahl senden, die für einen Befehl steht, diese wird
im ersten Durchlauf der ISR gesetzt, und beim nächsten Mal senden soll
dann der Wert für den Befehl kommen.
Aber sobald ich das erste Zeichen gesendet habe kommt nur noch Murks an.
hier noch der ganze Code:
1
/*
2
Servoansteuerung, lässt Servo an PB0 von Links- bis Rechtsanschlag fahren
3
ATMega 32
4
*/
5
#define F_CPU 18432000UL
6
#include<avr/io.h>
7
#include<util/delay.h>
8
#include<avr/interrupt.h>
9
#include<inttypes.h>
10
#define Recieve_Int _VECTOR(13)
11
12
intUARTrecieve;
13
intfaktor=1;
14
intmaxAnschlag=1900;
15
intminAnschlag=100;
16
intVerzoegern=10;
17
intBefehlEmpfangen=0;
18
19
intmain(void)
20
{
21
intk=0;
22
intkAlt=0;
23
24
sei();
25
26
27
DDRB|=(1<<PB0);
28
UBRRH=0x86;
29
UBRRL=0x1D;
30
UCSRB|=(1<<RXCIE)|(1<<RXEN)|(1<<TXEN);
31
UCSRC|=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
32
33
while(1)
34
{
35
if(k>kAlt&&k<maxAnschlag)
36
{
37
PORTB|=(1<<PB0);
38
_delay_us(k);
39
PORTB&=~(1<<PB0);
40
_delay_ms(Verzoegern);
41
kAlt=k;
42
k=k+faktor;
43
UDR=k;
44
}
45
46
else
47
{
48
if(k>kAlt&&k>=maxAnschlag)
49
{
50
PORTB|=(1<<PB0);
51
_delay_us(k);
52
PORTB&=~(1<<PB0);
53
_delay_ms(Verzoegern);
54
kAlt=k;
55
k=k-faktor;
56
UDR=k;
57
}
58
59
else
60
{
61
if(k<kAlt&&k>minAnschlag)
62
{
63
PORTB|=(1<<PB0);
64
_delay_us(k);
65
PORTB&=~(1<<PB0);
66
_delay_ms(Verzoegern);
67
kAlt=k;
68
k=k-faktor;
69
UDR=k;
70
}
71
72
else
73
{
74
if(k<kAlt&&k<=minAnschlag)
75
{
76
PORTB|=(1<<PB0);
77
_delay_us(k);
78
PORTB&=~(1<<PB0);
79
_delay_ms(Verzoegern);
80
kAlt=k;
81
k=k+faktor;
82
UDR=k;
83
}
84
85
else
86
{
87
PORTB|=(1<<PB0);
88
_delay_us(k);
89
PORTB&=~(1<<PB0);
90
_delay_ms(Verzoegern);
91
kAlt=k;
92
k=k+faktor;
93
UDR=k;
94
}
95
}
96
}
97
}
98
}
99
return0;
100
}
101
102
ISR(Recieve_Int)
103
{
104
if(BefehlEmpfangen==0)
105
{
106
BefehlEmpfangen=UDR;
107
}
108
else
109
{
110
if(BefehlEmpfangen==1)
111
{
112
faktor=UDR;
113
BefehlEmpfangen=0;
114
}
115
else
116
{
117
if(BefehlEmpfangen==2)
118
{
119
Verzoegern=UDR;
120
BefehlEmpfangen=0;
121
}
122
else
123
{
124
if(BefehlEmpfangen==3)
125
{
126
minAnschlag=UDR;
127
BefehlEmpfangen=0;
128
}
129
else
130
{
131
if(BefehlEmpfangen==4)
132
{
133
maxAnschlag=UDR;
134
BefehlEmpfangen=0;
135
}
136
else
137
{
138
BefehlEmpfangen=0;
139
}
140
}
141
}
142
}
143
}
144
}
Vielen Dank schonmal im Vorraus, und habt Nachsicht, das sind meine
ersten Schritte in C
MfG Chaos
Du sendest wirklich Hex-bytes mit den Werten 0, 1, 2, 3, ...?
> wenn ich in HTERM ne Zahl (als Dezimal sowohl eingeben als gesendet> in den Einstellungen, sprich nicht als ASCII)
Mit ASCII wärs einfacher. Denn dann könntest du das einfach
zurückschicken und im HTERM sehen, was der µC empfangen hat. So ist das
immer Rätselraten
Und schreib deine if so rum
1
ISR(Recieve_Int)
2
{
3
if(BefehlEmpfangen==0)
4
{
5
BefehlEmpfangen=UDR;
6
}
7
8
elseif(BefehlEmpfangen==1)
9
{
10
faktor=UDR;
11
BefehlEmpfangen=0;
12
}
13
14
elseif(BefehlEmpfangen==2)
15
{
16
Verzoegern=UDR;
17
BefehlEmpfangen=0;
18
}
19
20
elseif(BefehlEmpfangen==3)
21
{
22
minAnschlag=UDR;
23
BefehlEmpfangen=0;
24
}
25
26
elseif(BefehlEmpfangen==4)
27
{
28
maxAnschlag=UDR;
29
BefehlEmpfangen=0;
30
}
31
32
else
33
BefehlEmpfangen=0;
34
}
ist genau die gleiche Logik. Aber 8 mal so übersichtlich.
* dir ist klar, dass du dir den Inhalt von UDR abholen musst? Wenn
nicht, dann wird die ISR wieder und wieder aufgerufen. Solange bis du
irgendwann mal UDR ausliest.
Bei UART Problemen ist es zu Debug-Zwecken eine extrem gute Idee, wenn
man sich eine Rückmeldung über die UART vorsieht. Denn dann sieht man
auch, was der µC verstanden hat, bzw. wie sich die Werte verändern. und
ob sie sich korrekt verändern.
@ j. t. (chaoskind)
Nomen est omen ;-)
>senden. Für den Empfang habe ich dann nach Rätselraten rausgefunden,>welcher Interruptvektor der UART-Empfangsvektor ist, da im Datenblatt>steht es ist 14, aber in iom32.h oder wie sie heißt, ist es 13(Dem Forum
Hättest du einfach den passenden NAmen hingeschrieben, wäre alles OK.
>ISR(Recieve_Int)>{> UARTrecieve = UDR;> UDR = 0;>}
Du musst UDR nicht beschreiben, denn das sendet Daten. LEsen reicht, um
a) an die Daten zu kommen und b) den Interrupt zu löschen.
>Nun sieht die ISR so aus:>Aber sobald ich das erste Zeichen gesendet habe kommt nur noch Murks an.>hier noch der ganze Code:
Zuerst sollte man statt der enlos verschachtelten if einen switch
nutzen.
2. hast du das Problem entdeckt, dass dein Empfänger synhronisiert
werden muss, sprich er muss wissen, wo ein Befehl anfängt und aufhört.
Für den Anfang nutzt man deshalb eine einfaches Protokoll auf ASCII
Ebene. Dort kann man sehr leicht das Ende eines Befehls markieren, z.B.
mit Enter bzw. \n.
Wie man das praktisch anpackt, sieht man u.a. hier
Beitrag "Re: USART Empfangsbuffer"http://www.mikrocontroller.net/articles/Terminal_mit_Kommandointerpreter
Hallo,
zuerst würde ich diese ganzen verschachtelten IFs in der ISR als Switch
case machen, dann wird es wesentlich übersichtlicher. Dann könntest du
mal versuchen die variable BefehlEmfangen als volatile zu machen.
> _delay_us( k );
sowas darfst du nicht machen.
Bei _delasy_us bzw. _delay_ms kann man keine Variablen angeben. D.h.
können tut man schon, nur die Zeiten stimmen nicht.
> für nen Mega32, in CodeBlocks, im AVR-Studio meckert er immer> über Fehler?!
Ok. Jetzt ist es schon egal. Aber in Zukunft:
Geh den Fehlern nach. Insbesondere wenn dein C schwach ist. Der Compiler
'meckert' nicht ohne Grund und aus dem Lesen der Fehlermeldungen und dem
Erkennen was die Ursache dafür ist, wird sich dein C zu einem nicht zu
unterschätzenden Anteil verbessern.
du kannst doch nicht so einfach mir nichts, dir nichts ans UDR was
zuweisen! Du musst schon warten, bis dir die UART signalisiert, dass sie
jetzt was verschicken könnte!
Und tu dir selbst einen Gefallen und verschick die Dinge so, dass du sie
im Klartext lesen kannst. Das hat doch keinen Sinn, wenn da im hTerm ein
Bytestrom reinkommt und du nicht weißt, welches Byte jetzt was ist.
Wenn schon Debugging, dann richtig.
Ein enormes Problem ist in deinem Code natürlich, dass deine
Servoansteuerung im Grund, na-ja, freundlich gast, suboptimal ist
(andere würden sagen: Müll ist). Das geht so nicht. Mit den diversen
_delay_Funktionen wirst du da nicht glücklich werden. Wiederkehrende
Pulse, wie eigentlich fast alles, was mit Zeitsteuerungen zu tun hat,
läuft praktisch immer über einen Timer. Alles andere ist sinnlos.
Modellbauservo Ansteuerung
Danke erstmal für die Antworten =)
@Karl-Heinz
Das mit den Timern wäre dann der nächste Schritt gewesen, ich hab in
Assembler schon ne Routine geschrieben, die den Servo per Timer steuert.
In meiner Assembler UART warte ich auch auf das Sendenbereit_Flag, aber
hier dachte ich, das ist nicht nötig, weil ich ja mit den delays schon
so viel Zeit verbrate, das der mit nem einzelnen Byte fertig ist, bevor
das nächste zu senden ist.
Den Fehlern nachgehen, generell ein guter Tip *gg, dann schmeiß ich das
Studio nochmal an, und schau nach dem Fehler, den er da ausgibt, das war
glaub ich irgendwas von wegen der delay-Geschichten. Noch ne Frage dazu,
wie kann ich denn ein variables delay ausgeben? Wenn _delay_us(k) nicht
geht, kann ich doch nur noch _delay_us(200) bspw sagen?
Das Umschreiben der if else werd ich gleich mal machen, und das auslesen
des UDR hatte ich im letzten else nicht im Kopf,*g danke dafür, werd ich
direkt versuchen.
@Falk
den Beitrag mit dem Empfangsbuffer werd ich mir auch direkt mal ansehen!
@Daniel
Kann man in kurzen Worten erklären was n Switch-Case ist? Und was ist
volatile? Wie gesagt, ich in C blutigster Anfänger
P.S.
Ja ich sende die Befehle als direkt als Dezimal, was von HTERM aber
binär übertragen wird. Sprich ich sag ihm sende 3 dann sendet der
0b00000011
j. t. schrieb:> Noch ne Frage dazu,> wie kann ich denn ein variables delay ausgeben? Wenn _delay_us(k) nicht> geht, kann ich doch nur noch _delay_us(200) bspw sagen?
Vergiss die ganze delay Sache. Machs gleich mit Timern.
Zumindest die Erzeugung der Servopulse.
_delay_xx ist selten die Lösung, aber oft das Problem.
Die Legitimation der _delay_xx Funktionen leitet sich daher, dass man
als Neueinsteiger mit irgendwas anfangen muss. Man kann nicht gleich
alles auf einmal machen und irgendwie will man ja seine LED auch zum
Blinken bzw. das Lauflicht zum Weiterschalten bringen. Aber in dem
Moment, in dem das Programm (scheinbar) mehrere Dinge gleichzeitig
machen soll (bei dir Servopulse erzeugen, die zeitlich zu variieren und
dann auch noch die UART überwachen), ist _delay_xx ein Klotz am Bein,
der dich auf die falsche Fährte führt.
> Kann man in kurzen Worten erklären was n Switch-Case ist? Und was ist> volatile? Wie gesagt, ich in C blutigster Anfänger
Du #brauchst# ein C-Buch!
Das (ok, volatile nicht) ist noch nicht mal die Spitze des Eisbergs, der
noch auf dich wartet.
> Ja ich sende die Befehle als direkt als Dezimal, was von HTERM aber> binär übertragen wird. Sprich ich sag ihm sende 3 dann sendet der> 0b00000011
Sowas geht super, wenn man nur 1 Byte immer und immer wieder zu
übertragen hat. Sobald da aber sowas wie ein 'Command-Interface' ins
Spiel kommt, wirds genauso aufwändig, wie eine ASCII Lösung (nur das bei
ASCII die Prioritäten ganz anders liegen und das ganze leichter zu
bedienen, zu lesen und zu debuggen ist)
Gibt es da auch gute Literatur als PDF zu finden? Ich hab da bisher
nicht viel gefunden. Das meiste was ich an Tutorials gefunden hab, ist
entweder nach dem Motto "Es gibt verschiedene Variablen, int zb hat
keine Nachkommastellen" und dann wird stundenlang drauf rumgeritten, das
ne ganze Zahl ist, statt darauf einzugehen, wozu das ganze gut ist.
j. t. schrieb:> Gibt es da auch gute Literatur als PDF zu finden?
Ein wirklich gut gemeinter Rat.
Kauf dir ein C-Buch als Papierform. Du wirst es laaange benutzen und du
wirst es immer wieder brauchen. Die 30 Euro sind gut angelegtes Geld.
> ist entweder nach dem Motto "Es gibt verschiedene Variablen, int> zb hat keine Nachkommastellen" und dann wird stundenlang drauf> rumgeritten, das ne ganze Zahl ist
ich weiß nicht worauf du dich hier beziehst, aber ... ja, da gibt es so
manche Falle und so manches was man dazu wissen muss.
>, statt darauf einzugehen, wozu das ganze gut ist.
na, wofür wirds gut sein. Um darin Werte abzulegen, die sich mit ganzen
Zahlen repräsentieren lassen. Die Anzahl der Kinder eines Ehepaares ist
nun mal eine ganze Zahl. 2,5 Kinder gibt es nicht. Aber im
bundesdeutschen Durchschnitt gibt es sie. Und
int SummeAllerKinder = ...;
int AnzahlPaare = ....;
double Durchschnitt = SummeAllerKinder / AnzahlPaare;
wäre nun mal grundfalsch um diesen Durchschnitt auszurechnen. Und nach
der Lektüre bzw. dem Studium bzw. dem Durcharbeiten der Übungen deines
C-Buchs zum Thema "Datentypen und wie sie in Ausdrücken verwendet
werden" wäre dir sogar klar, warum das falsch ist und die Ergebnisse
nicht stimmen.
Schönes Beispiel,
genau sowas mein ich, was fehlt. Ich mein ich weiß noch aus der Schule
was ein int ist, aber genau so eine prägnante Erklärung fehlt dann, da
wird nur "Seitenweise" darüber rumlamentiert, "es ist ne ganze Zahl, es
ist ne Zahl ohne Nachkommastellen, es ist ne ganze Zahl".
Ein konkretes Beispiel hab ich grad leider nicht zur Hand...