Hi,
ich bin grade dabei von Bascom auf C umzusteigen.
Nun hab ich folgenden Code fuer meinen Robo gebastelt.
Intressanterweise funktioniert er nicht auf WinAVR mit gcc 4.3
Unter Linux mit gcc 4.8 geht er astrein.
Er enthaelt hoechstwahrscheinlich einige Fehler.
Anbei noch der Programmablauf, Schaltplan.
1
2
#define F_CPU 3688000UL
3
#include<avr/io.h>
4
#include<util/delay.h>
5
#include<stdlib.h>
6
7
intmain(void){
8
DDRB|=(1<<PB0);// Ausgang setzen
9
DDRB|=(1<<PB1);
10
DDRB|=(1<<PB2);
11
DDRB|=(1<<PB3);
12
13
DDRD|=(1<<PD5);// Ausgang LED
14
DDRD|=(1<<PD4);// Ausgang Piezzo
15
16
voidlong_delay(uint16_tms)
17
{
18
for(;ms>0;ms--)_delay_ms(1);
19
}
20
21
while(1){
22
if(PIND&(1<<3)){
23
unsignedcharmin=1;
24
unsignedcharmax=2;
25
unsignedcharzufall=0;
26
zufall=(rand()%(max-min+1)+min);
27
28
PORTD|=(1<<PD5);// LED an
29
PORTB|=(1<<PB0);// Rueckwaerts (default)
30
PORTB&=~(1<<PB1);
31
PORTB|=(1<<PB2);
32
PORTB&=~(1<<PB3);
33
long_delay(1000);
34
35
if(zufall==1){
36
PORTB|=(1<<PB0);// Drehen (default)
37
PORTB&=~(1<<PB1);
38
PORTB&=~(1<<PB2);
39
PORTB|=(1<<PB3);
40
long_delay(800);
41
}
42
else{
43
PORTB&=~(1<<PB0);// Drehen (default)
44
PORTB|=(1<<PB1);
45
PORTB|=(1<<PB2);
46
PORTB&=~(1<<PB3);
47
long_delay(800);
48
}
49
50
}
51
else{
52
PORTD&=~(1<<PD5);// led AUS
53
54
PORTB&=~(1<<PB0);// Vorwaerts (default)
55
PORTB|=(1<<PB1);
56
PORTB&=~(1<<PB2);
57
PORTB|=(1<<PB3);
58
}
59
}
60
return0;
61
}
Vieleicht kann mir ja der eine oder andere ein paar Tipps geben.
Gruss Matze
Random ... schrieb:> Kommentare und Funktions-/Variablennamen auf Englisch. Liesst sich> leichter.
Wenn man davon absieht, dass wir in einem deutschsprachigen Forum sind.
Was funktioniert denn nicht? Lässt es sich nicht compilieren oder
funktioniert es nicht wie es soll? Was für Fehler treten auf?
Matthias I. schrieb:> Vieleicht kann mir ja der eine oder andere ein paar Tipps geben.
An den Pins 3,4,5,7 und 9 von JP1 fehlen die Knotenpunkte. ;-)
Ebenso verwirren die Referenzkennzeichen IC1 und IC2, in Eagle muss
jedes Bauteil U$1...U$x heißen. ;-)
Matthias I. schrieb:> Intressanterweise funktioniert er nicht auf WinAVR mit gcc 4.3> Unter Linux mit gcc 4.8 geht er astrein.
Ich bin jetzt nicht im Bilde, ob es im 4.3 ein paar bekannte Bugs gab
oder nicht.
>> DDRD |= (1 << PD5); // Ausgang LED> DDRD |= (1 << PD4); // Ausgang Piezzo
Wenn du dir ein paar #define machst
1
#define F_CPU 3688000UL
2
#include<avr/io.h>
3
#include<util/delay.h>
4
#include<stdlib.h>
5
6
#define LED (1<<PD5)
7
#define PIEZO (1<<PD4)
dann kannst du durch die Textersetzung erreichen, dass sich dieser
Original-Abschnitt hier so liest
1
DDRD|=LED;
2
DDRD|=PIEZO;
(es ginge auch
1
#define LED PD5
2
#define PIEZO PD4
3
....
4
5
DDRD|=(1<<LED);
6
DDRD|=(1<<PIEZO);
)
was den Vorteil hat, dass du dir den Kommentar ganz offensichtlich
sparen kannst, was an und für sich eine gute Sache ist. Hast du die Wahl
zwischen einem Kommentar und einer Möglichkeit den Code so
umzuformulieren, dass der Kommentar überflüssig wird, dann bevorzuge
letzteres! Denn der Code ist immer das was compiliert wird - sprich:
Kommentare können auch falsch sein ohne das es jemandem auffällt, der
nicht genau überprüft ob der Kommentar mit dem Code zusammenstimmt.
Wenn ich hier im Forum Codefehler suche, dann ignoriere ich Kommentare
zb vollständig. Eben weil sie immer wieder sich mal als falsch
herausstellen.
>> void long_delay(uint16_t ms)> {> for(; ms>0; ms--) _delay_ms(1);> }
Funktionen in Funktionen zu definieren ist in C eigentlich nicht
zulässig.
Aber eigentlich brauchst du gar keine Funktion long_delay. _delay_ms
kann derartige Zeiten wunderbar ganz für sich alleine abhandlen. einfach
_delay_ms( 1000 ); aufrufen und gut ists.
>> while(1) {> if ( PIND & (1 <<3) ){
Hier dasselbe. An deinem Portbit 3 hängt ein Taster, der vielleicht
sogar eine Beschriftung hat (sagen wir mal "Bumper") bzw. wenn er nicht
beschriftet ist, dann hat er zumindest eine logische Funktion (in deinem
Fall ist das eben der Front-Bumper
1
....
2
#define FRONT_BUMPER PD3
3
4
....
5
6
7
if(PIND&(1<<FRONT_BUMPER))
8
...
liest sich doch gleich viel besser. Und wenn mal mehrere Bumper oder
Tasten im Spiel sind, dann erleichtert dir ein entsprechender
Makro-Ersatz auch das Auseinanderhalten im Code, mit welchem externen
Bumper oder Taster du es hier an dieser Codestelle zu tun hast.
> unsigned char min = 1;> unsigned char max = 2;> unsigned char zufall = 0;> zufall = (rand() % (max-min+1) +min);>> PORTD |= (1 << PD5); // LED an
Das wäre dann (mit der 2.ten Makro Variante)
1
PORTD|=(1<<LED);
... und wieder ist der Kommentar überflüssig geworden
> PORTB |= (1 << PB0); // Rueckwaerts (default)> PORTB &= ~(1 << PB1);> PORTB |= (1 << PB2);> PORTB &= ~(1 << PB3);
selbiges auch hier: "Benenne" deine Ausgänge je nach Funktionalität mit
hilfe eines Makros. Du willst derartige Bezeichnungen wie PB1, PB2, aber
auch PORTB etc. eigentlich nicht direkt im Code stehen haben!
> Wenn ich hier im Forum Codefehler suche, dann ignoriere ich Kommentare> zb vollständig. Eben weil sie immer wieder sich mal als falsch> herausstellen.
Na, immerhin steht im Kommentar, was der Code tun SOLL.
Ich würde mir auch Funktionen für die Beschaltung der MOtoren für
"typische Bewegungsmuster" machen. Eine Funktion frü Vorwärts, eine
Funktion für Rückwärts, eine für Rechts, eine für Links.
1
voidForward()
2
{
3
PORTB&=~(1<<PB0);
4
PORTB|=(1<<PB1);
5
PORTB&=~(1<<PB2);
6
PORTB|=(1<<PB3);
7
}
8
9
voidBackward()
10
{
11
PORTB|=(1<<PB0);
12
PORTB&=~(1<<PB1);
13
PORTB|=(1<<PB2);
14
PORTB&=~(1<<PB3);
15
}
16
17
voidTurnRight()
18
{
19
PORTB|=(1<<PB0);
20
PORTB&=~(1<<PB1);
21
PORTB&=~(1<<PB2);
22
PORTB|=(1<<PB3);
23
}
24
25
voidTurnLeft()
26
{
27
PORTB&=~(1<<PB0);
28
PORTB|=(1<<PB1);
29
PORTB|=(1<<PB2);
30
PORTB&=~(1<<PB3);
31
}
32
33
intrandom(intmin,max)
34
{
35
returnrand()%(max-min+1)+min;
36
}
37
38
intmain()
39
{
40
....
41
42
while(1){
43
if(PIND&(1<<FRONT_BUMPER)){
44
45
PORTD|=(1<<LED);
46
Backward();
47
48
_delay_ms(1000);
49
50
if(random(1,2)==1){
51
TurnLeft();
52
else
53
TurnRight();
54
55
_delay_ms(800);
56
}
57
58
else{
59
PORTD&=~(1<<LED);
60
Forward();
61
}
62
63
return0;
siehst du, um wieviel leichter die Hauptschleife in main() zu verfolgen
und zu verstehen ist? Das liegt daran, dass ich mich als Leser nicht
mehr mit den Details von zb. dem Rückwärtsfahren beschäftigen muss. Im
Code in der Hauptschleife steht einfach Backward() und das genügt mir
beim Lesen des Codes um zu verstehen, das an dieser Stelle im Code das
Fahrzeug zurück setzen soll. Wenn mich die Details interessieren, wie
dieses Rückwärts fahren funktioniert, dann kann ich mir die Funktion
ansehen. WEnn es aber darum geht, die Logik zu verstehen, wie das
Fahrzeug einem Hindernis ausweicht, dann muss ich nur wissen, dass das
Fahreug mit dem Aufruf dieser Funktion rückwärts fährt.
Die in der Hauptschleife kodierte Logik des Ausweichens ist so viel
kürzer formuliert und auch in problembezogeneren Ausdrücken, so dass es
viel leichter fällt sich davon zu überzeugen, dass diese Logik
eigentlich funktionieren müsste, ohne das ich ständig über irgendwelche
technischen Details stolpere.
J. L. schrieb:>> Wenn ich hier im Forum Codefehler suche, dann ignoriere ich Kommentare>> zb vollständig. Eben weil sie immer wieder sich mal als falsch>> herausstellen.>> Na, immerhin steht im Kommentar, was der Code tun SOLL.
Dein Wort in Gottes Ohr.
Alles schon gehabt:
Code richtig, Kommentar falsch
Code falsch, Kommentar von der Idee her richtig
Code falsch, Kommentar falsch
Code falsch, Kommentar passt überhaupt nicht dazu und redet von etwas
ganz anderem
Code richtig, Kommentar richtig. Allerdings: Kommentar überflüssig
und natürlich auch
Code richtig, Kommentar richtig und tatsächlich hilfreich
J. L. schrieb:>> Wenn ich hier im Forum Codefehler suche, dann ignoriere ich> Kommentare>> zb vollständig. Eben weil sie immer wieder sich mal als falsch>> herausstellen.>> Na, immerhin steht im Kommentar, was der Code tun SOLL.
Ein guter Kommentar sollte nicht nur das Was sondern das WARUM
dokumentieren. Das was steht schon da in Form von Code.
Zum Thema verbessern: "Clean code" lesen.
So ich hab mal einiges nach den Vorschlaegen hier geaendert :)
Das ganze ist so etwas uebersichtlicher!
Jetzt muss ich noch den Buzzer zum Piepen bringen.
Mit Bascom ist das ja ganz einfach, so wie es wohl aussieht brauch ich
unter C eine PWM und einen Timer.
Mal sehen ob ich das zum laufen bekomme.
@ Matthias I. (matze5)
>Jetzt muss ich noch den Buzzer zum Piepen bringen.>Mit Bascom ist das ja ganz einfach, so wie es wohl aussieht brauch ich>unter C eine PWM und einen Timer.
Kann man machen. Aber du bist ja anscheinend Mr. Jan Delay ;-)
>Mal sehen ob ich das zum laufen bekomme.
Versuchs mal mit einer gescheiten Einrückung, das kann (WILL!) doch
keiner lesen!
http://www.mikrocontroller.net/articles/Strukturierte_Programmierung_auf_Mikrocontrollern#Formatierung_des_Quelltextes
Btw. hab ich ein Problem pack ich die Funktion in Main() geht alles.
Pack ich sie extra, gehts nicht.
Edit.. ausserdem hab ich ich den Falschen Code oben gepostet.. war die
Falsche Datei :)
@ Matthias I. (matze5)
>So funktionierts uebrigens.. obwohls offensichtlich falsch ist... :
Kannst du oder willst du nicht lesen? Dein Tabulatoren sind SCHROTT!
Random ... schrieb:> ist das compilierbar? Funktion in einer Funktion?
Ja, lokale Fnuktionen sind eine GCC-Erweiterung, die in GNU-C zur
Verfügung steht. Harrig wird's, wenn die lokale Funktion auf Variablen
der enthaltenden Funktion zugreift und diese die Adresse der lokalen
Funktion nimmt. Instruktives Beispiel:
1
extern void dispatch (void(*)(void));
2
3
int fun (int x)
4
{
5
void callback (void)
6
{
7
x++;
8
}
9
10
dispatch (callback);
11
return x;
12
}
callback bekommt von dispatch keine Argumente; es hat das Call-Interface
jeder anderen void-Funktion. Die Adresse von x ist zur Ladezeit nicht
bekannt, und zwischen fun und callback können beliebig viele Callframes
liegen. Trotzdem muß callback irgendwie an x rankommen.
Mit avr-gcc ist das übrigens nicht übersetzbar, da dort kein Code auf
dem Stack ausführbar ist.
Falk: mit deinen Code funktionierts auch nicht.
Das erklaert auch nicht warum das Programm nicht ablaueft wenn die
Funktionen ausserhalb von Main sind, wo sie hingehoeren.
Matthias I. schrieb:> Falk: mit deinen Code funktionierts auch nicht.>> Das erklaert auch nicht warum das Programm nicht ablaueft wenn die> Funktionen ausserhalb von Main sind, wo sie hingehoeren.
1
main.c: In function ‘rueckwaerts’:
2
main.c:20:11: error: expected ‘;’ before ‘~’ token
3
PORTB ~&= MOTOR_B;
4
^
5
main.c:22:11: error: expected ‘;’ before ‘~’ token
Das hab ich schon alles gefunden und behoben, dennoch lauefts nicht :)
Speaker wird eh nicht benutzt im Moment.
Kompilieren tut es astrein, aber die funktionen laufen nur wenn sie in
main() sind...
Das ist das einzige Problem, egal wie ich da was formatiere.. oder
Tabulatoren setze..
Matthias I. schrieb:> So funktioniert alles:#define F_CPU 3688000UL
...
Was ist denn jetzt der Unterschied? Ich gehe ganz sicher nicht jede
Zeile durch.
Steffen Rose schrieb:>> So funktioniert nichts:>> Was heißt das genau? Welches Verhalten zeigt sich?
Hat er doch schon geschrieben: Es funktioniert nicht. Erwartest Du jetzt
noch Fehlermeldung (Screenshot) und dergleichen?
Es gibt keine Screenshots der Code compiliert nur laueft das Programm
nicht ab.
Sobald ich das in den Tiny Flashe tut sich nichts mehr.
Der "Falsche Code" geht astrein.
Nur laueft keine Funktion die ich erstelle.
Ausser sie sind in Main().
Dann gehen sie.
Ich erwarte eine genaue Fehlerbeschreibung.
z.B. Er fährt nur vorwärts. Oder er ändert ständig die Richtung ohne an
den Buzzer zu kommen.
Du gehts ja auch nicht zum Arzt und sagst nur "Mir gehts nicht gut".
Daher nicht wundern, dass bei solch einer nichtssagenden
Fehlerbeschreibung nur die Codequalität diskutiert wird. Was soll man
auch anderes machen, als nach einer falsch gesetzte Klammer zu suchen.
Matthias I. schrieb:> Sobald ich das in den Tiny Flashe tut sich nichts mehr.
Was sagt die LED (an, aus, flackern)?
Du kannst Das Programm auch erstmal nur auf "vorwärts" reduzieren. Und
dann Stück für Stück weiter.
Wenn wirklich garnicht geht, prüfen, ob main überhaupt durchlaufen wird.
Dafür kann man die LED nutzen, wenn man sonst nichts hat.
Wie siehst mit Compilerwarnings aus? Warnungen eingeschaltet? Die
könnten einen Hinweis geben. Oder warnt der Linker?
Ich bezweifle momentan, dass das Problem am geposteten Code liegt.
Steffen Rose schrieb:> Ich bezweifle momentan, dass das Problem am geposteten Code liegt.
Vermutlich hat er ein grundlegendes Problem in seinem Build-Prozess. Bei
der beschriebenen Symptomatik könnte ich mir z.B. vorstellen, dass er
das ELF-File in den Controller brennt (oder sogar nur ein ungelinktes
Object-File).
Also fuer Dumm verkaufen lasse ich mich sicher nicht.
Elf file flashen und so. Muss hier ja oft vorkommen.
Der Roboter macht einfach gar nichts, kein LED blinken nichts.
Wenn ich den Code mit den Funktionen in Main() als Hex brenne passt
alles.
Wenn die Funktionen ausserhalb von Main() sind gehts nicht.
ist das so schwer zu verstehen ?
Geht nicht heisst, es geht nichts.
Da blinkt nichts, Kein Motor dreht, einfach nichts.
Der Controller zuckt kein Bisschen.
avr-gcc -mmcu=attiny2313 -Os -c motorun.c -o motorun.o
avr-gcc motorun.o -o motorun.elf
avr-objcopy -O ihex -j .text -j .data motorun.elf motorun.hex
avrdude -p t2313 -c avrisp2 -P usb -U flash:w:motorun.hex
ich wuesste nicht was da falsch ist.
Mein Geraet funktioniert und tut auch was es soll.
Nur eben mit den unschoenen Funktionen in der Main()
Edit: wenn der Code minimal reduziert ist funktionierts auch nicht.
Also fehlt wohl irgendwas um Funktionen zu unterstuetzen.
Denn es geht auch keine simple Funktion wie:
(Ausgang natuerlich in main definiert..)
void led_an(){
PORTD |= LED;
}
Matthias I. schrieb:> Also fuer Dumm verkaufen lasse ich mich sicher nicht.> ...> ist das so schwer zu verstehen ?
Kein Grund hier pampig zu werden.
Matthias I. schrieb:> ich wuesste nicht was da falsch ist.
Code ist nicht für den richtigen Controller gelinkt.
Besten Dank,
tut mir leid das ich etwas ungehalten war, ich war schlichtweg entnervt.
Nun geht tatsaechlich alles wie es soll..
Gleichzeitig bin ich noch auf einen Bug im Gentoo avr-gcc gestossen
Die Linkerscripte waren nicht verlinkt.
ln -s /usr/lib/binutils/avr/2.24/ldscripts/ /usr/avr/lib/ldscripts
behebt das folgende Problem:
Cannot open linker script file ldscripts/avr25.xn: Datei oder
Verzeichnis nicht gefunden
Und was ich nicht wusste war:
avr-gcc -mmcu=attiny2313 -O2 -c motorun.c -o motorun.o
avr-gcc -g -mmcu=attiny2313 motorun.o -o motorun.elf
avr-objcopy -O ihex -j .text -j .data motorun.elf motorun.hex
So gehts nun.
Ich arbeite dran :)
dafuer das ich mir alles selbstbeigebracht hab und weder Ahnung von C
noch Elektrik hatte ist es ganz gut geworden.
http://www.youtube.com/watch?v=TYfIhrqZPVU
Matthias I. schrieb:> Ahja der Compiler:>> Konfiguriert mit: --disable-fixed-point
Na prima. Da wird mit viel Aufwand Assembler-optimerter Fixed-Point
Support in avr-gcc eingebaut, und dann wird's einfach ausgeknipst...
@Johann L. (gjlayde) Benutzerseite
>> Konfiguriert mit: --disable-fixed-point>Na prima. Da wird mit viel Aufwand Assembler-optimerter Fixed-Point>Support in avr-gcc eingebaut, und dann wird's einfach ausgeknipst...
Gefrickel 3.0
Wenn man schon mti Kommandozeile und selbstgestricktem Makefile arbeiten
will, sollte man es wenigstens können. Da lob ich mir mein AVR-Studio!
F7!