Archiv verlassen und diese Seite im Standarddesign anzeigen : Verstehe Programmcode vom Prof nicht
Hallo,
ich bin neu auf dem Gebiet Mikrocontroller und deren Programmierung.
Jetzt habe ich Code von meinem Professor bekommen, welchen ich hinten und vorne nicht verstehe. Jetzt wollte ich diesen Code mittels AVR Studio begreifen aber ich scheitere schon daran, dass der Code nicht einmal im AVR Studio lauffähig ist. Ich bin mir sicher, dass noch Bibliotheken like #include <avr/io.h> und weitere Befehle fehlen.
Jetzt meine Frage, kann mir von Euch jemand behilflich sein diese Code (es sind drei Bsp.) lauffähig zu bekommen? Damit ich endlich mal die Befehle etc. verstehen kann.
Bsp. 1:
void main()
{
uint8_t step; //Schrittweite
uint16_t value;
uint16 count;
initPort();
value = 1;
while (1)
{
step = (PINA & 0x06) | ((PIND>>2)&0x01);
value <<= step;
value = (value & 0xFF) | (value >> 8);
PORTC = (uint8_t) value;
for (count = 0; count < 5000; count++)
asm volatile („nop“);
}
}
Bsp. 2:
volatile uint32_t sec;
void initTimer0()
{
sec = 0;
TCNT0 = 256-16;
TCCR0 = (1 << CS02) | (1 << CS00);
TIMSK = (1 << TOIE0);
sei();
}
volatile uint8_t tick = 0;
SIGNAL (SIG_OVERFLOW0)
{
TCNT0 = 256-16;
tick ++;
if (tick==16)
{
sec++;
tick = 0;
}
}
Bsp. 3:
void initKey()
{
PORTD &= ~(1 << PD2);
DDRD &= ~(1 << PD2);
MCUCR |= (1 << ISC00);
GICR |= (1 << INT0);
sei();
}
Über Hilfe bin ich sehr dankbar, da ich leider im Moment noch auf keinen grünen Zweig komme. :-(
Besserwessi
15.09.2009, 18:06
Um die Befehle zu verstehen sollte man einfach ein Buch oder Tutorial über C lesen. Eventeull auch nur STückweise nach den Befehlen die man gerade nicht versteht.
Das sind 3 Code Fragmente. Man könnte die alle 3 zusammen tun, und dann noch das oben schon erwähnte include dazu. Das sollte dann schon reichen um es wenigstens mit AVRStudio + Winavr zu compilieren, wenn man den Projekttyp auf GCC setzt.
Beim ersten Bsp fehlt noch dieDefinition von initPort() .
Hubert.G
15.09.2009, 18:26
Wichtig wäre welcher Kontroller da verwendet wird.
Im ersten Beispiel fehlt bei uint16 count das _t also uint16_t
Die Funktion initPort() fehlt.
Beim nop gehört je ein " davor und danach.
Das zweite und dritte Beispiel besteht nur aus Fragmente.
Hallo ihr zwei!
Im Grunde verstehe ich den C Code. Schwierig wird es da eher bei den Controller typischen Sachen wie (PINA & 0x06) | ((PIND>>2)&0x01); oder asm volatile etc.
Mir fehlt auch so irgendwie das allgemeine Nachschlagewerk für diese Befehle. Das Datasheet erschlägt mich förmlich. Da stehen Dinge drin die ich gar nicht zuordnen und verwenden kann.
Und zu initport(); Was mache ich damit? Was muss da rein? Ich hab absolut keinen Plan und mein Prof verweist immer nur auf das Datasheet. Da könnt ich durch drehen! ](*,)
Wir simulieren mit einem Atmel ATMega16 Controller.
Grüße
Besserwessi
15.09.2009, 22:17
Bei initport sollte wohl festgelegt werden, welche Bits Ein- oder Aus-gänge sind.
Zu den Controller spezifischen dingen hilft eventuell so etwas die das c tutorial aus dem Wissensbereich. Z.B. :
http://www.rn-wissen.de/index.php/Avr-gcc
oberallgeier
15.09.2009, 23:43
Hi xAmp,
... Schwierig .. bei den Controller typischen Sachen wie (PINA & 0x06) | ((PIND>>2)&0x01); oder asm volatile etc. ...Stimmt - ich raff das heute, nach vielen Monaten C(äh)-Programmiererei, noch nicht wirklich. Das RN-Tutorial zum AvR-Gcc zeigt leider etwas wenig zu Bitmanipulationen, die sind hier besser erklärt:
http://www.mikrocontroller.net/articles/Bitmanipulation
Volatile könnte hier einigermassen verständlich werden:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#IO-Register_als_Parameter_und_Variablen
Na ja und zu PORTD oder PINC: die IO-Pinne bei den Controllern sind gruppenweise zu 8 Stück zusammengefasst - es gibt (aber) nicht immer alle 8 Pinne - manche controller haben nur eine Untermenge (wenn halt zu wenig Beine da sind *ggg*). Die Ports sind mit Großbuchstaben bezeichnet: PORTA, PORTB, die Pinne heißen (bei den meisten Controllern) dann PC2 - das ist der DRITTE Pin - weil in der IT fast immer von 0 weg gezählt wird.
DDRB ist das DatenRichtungsByte - oder -bit. Jeder Portpin hat ein separates Datenrichtungsbit - ist das 0, so funktioniert der Pin als Eingang, ist das pin-eigene DDRB aber 1, so funktioniert der Pin als Ausgang. Portpinns können also als Ausgang oder Eingang konfiguriert werden (hier ein Beispiel aus einem aktuellen Code von mir:
// Pins/Ports als Ein- (0) oder Ausgänge (1) konfigurieren, Pull Ups (1) aktivieren
// A = Ausgang, E = Eingang ohne , EU = Eingang MIT PullUp
DDRB = 0b00011111; // siehe aktuell oben oder Fortschritt/R2D2
PORTB = 0b00100000; // und Port/Pull Ups (1) aktivieren
DDRC = 0b01110000; // PC3 ist ADC3, PC0 .. 6 , kein PC7-Pin bei m168
PORTC = 0b00000111; // Beachte für ADC: PC3 ist ADC-Eingang ##>> OHNE Pullup !!
Nun kann man aber eben auch die Bits nicht nur "im Paket" setzen wie oben in meinem Codebeispiel, sondern man kann sie auch einzeln manipulieren:
PORTB |= (1<<PB5) macht etwa dasselbe wie die einzelne "1" im obigen Beispiel - wenn der Rest des Ports Null ist. Vorteil der Geschichte: es wird nur der eine Portpin verändert, der Rest der Portpinne bleibt wie er vorher war !
Einzulesende Pinne werden aber nicht als PORTB = (PB4) gelesen, sondern etwa so: if (PINB &(1<<PB4)) {}
Sieht anfangs chaotisch aus - leider. Später aber (manchmal) auch noch.
Viel Erfolg. Hoffentlich hilft Dir dies
Hallo!
Ja ich hab mich heute noch einmal an die ganze Sache ran getraut. Ich hab mich jetzt mal entschlossen die Aufgabe meines Profs hier zu stellen, inklusive meines Lösungsansatzes.
Also die Aufgabe lautet wie folgt:
Eine Lichtpunkt soll die LEDs von LED1 bis LED8 durchlaufen. Dabei sollen die LEDs gedacht kreisförmig angeordnet sein. Nach LED8 leuchtet also LED1. Mit den Schaltern S1 bis S3 geben Sie die Schrittweite binär an. Programmieren Sie das Lauflicht als Endlosschleife. Der Prozessor soll zwischen zwei Zuständen bis 5000 zählen.
Mein Ansatz zur Lösung:
#include <avr/io.h>
void main()
{
uint8_t step; //Schrittweite
uint16_t value;
uint16_t count;
DDRA = 0x00;
PORTA = 0x00; //oder müsste das 0xFF sein?
DDRC = 0xFF;
PORTC = 0x00;
DDRD = 0x00;
PORTD = 0x00; //oder müsste das 0xFF sein?
value = 1;
while (1)
{
step = (PINA & 0x06) | ((PIND>>2)&0x01);
value <<= step;
value = (value & 0xFF) | (value >> 8);
PORTC = (uint8_t) value;
}
}
Um den Code besser zu verstehen hab ich hier noch ein Schaltbild, was auch die Schikane dabei verdeutlicht. Und zwar liegt ein Schalter auf einem anderen Port. Den Zähler der nach jedem Durchlauf der while-Schleife auf 5000 zählen soll, habe ich aus Simulationszwecken mal weg gelassen.
Meine zwei Fragen:
- Sind die Ports richtig initialisiert?
- Wieso "läuft" mein Licht nicht?
Leider kann ich in meiner Simulation mittels AVR Studio kein Lauflicht erkennen. Was mache ich falsch?
Danke für Hilfe!
Hi,
du musst an allen genutzten Tastern die Pullups aktivieren ("//oder müsste das 0xFF sein?" - Ja)
Die 5000 Schleifendurchläufe sind auf realer Hardware vermutlich als Schutz gegen prellende Kontakte gedacht.
Sonst kann ich auf die schnelle keinen Fehler entdecken, ich bin aber auch lausig im Fehlersuchen ohne Debugger/Hardware ;)
mfG
Markus
Edit: Ich habs mal schnell durchsimuliert, der Code funktioniert so wie du ihn eingestellt hast wunderbar (abgesehen von den fehlenden 0xFF, die aber nur auf echter Hardware auffallen weil die Taster nichts tun) - im übrigen finde ich die Lösung mit der 16-Bit Value richtig pfiffig, ich hätte da vermutlich versucht etwas über den ASM-Befehl ROL (Linksrotation durch das Carry-Bit) gedreht
Hi Markus,
danke für dein Antwort. Okay ich hab jetzt PORTD = 0xFF; und PORTA = 0xFF; gesetzt.
Aber die Simulation kann ich irgendwie nicht ganz nachvollziehen. ^^ Ich glaub ich hab noch ein paar Schwierigkeiten mit dem AVR Studio. :-b
Ich müsste doch jetzt auf Port C im I/O View meine Ports "laufen" sehen oder etwa nicht? Bei mir tut sich da irgendwie gar nichts. Zum verdeutlichen hab ich mal einen Screenshot mit angehängt.
Wäre super wenn mir da noch jemand dabei behilflich sein könnte. 8-[
021aet04
20.09.2009, 13:13
Bei AVR Studio kann man in der Simulation schrittweiße debuggen. Zuerst musst du es compilieren und die Simulation starten. Die Icons sind dort, wo am Anfang ein grüner Pfeil ist.
Hey xAmp,
schau dir nochmal die Aufgabenstellung an und stell dir die Frage, WANN das Bit durch Port C wandert?
*Trommelwirbel*
Richtig, wenn du einen der Taster S1-3 "drückst", was man auch dadurch lösen kann, dass man das entsprechende Bit in PINx setzt.
Dazu ist es aber sinnvoll, den Debugger im Einzelschrittmodus zu fahren und das Bit nach der Zeile "step = (PINA & 0x06) | ((PIND>>2)&0x01);" wieder zu löschen, sonst rauscht dir deine LED davon.
ACHTUNG: Es gibt noch einen kleinen Fehler - durch die Pullups sind die ganzen Pins erst einmal High, also 1 und werden als Low (0) gelesen, wenn der Taster gedrückt wird. Du musst also den eingelesenen Wert von PINA/PIND noch invertieren!
mfG
Markus
Vielen Dank ihr zwei für eure Antworten!
Ohje das raubt mir noch den letzten Nerv. :-s
Um die Pull-Up zu invertieren, könnte ich doch die beiden Befehle
PINA &=~(1<<0x06);
PIND &=~(1<<0x04);
vor der while-Schleife verwenden. Ist das soweit korrekt?
Kann ich die Taster nicht irgendwie Simulieren? Muss ich da jetzt jedes mal nach einem Schleifendurchlauf händisch die davor gesetzten Pins wieder invertieren?
So ganz ist der Groschen bei mir noch nicht gefallen. Vor allem finde ich es sehr schwer so etwas auch aus einem Tutorial zu "erkennen".
Gruß und Dank!
oberallgeier
20.09.2009, 15:29
... Kann ich die Taster nicht irgendwie Simulieren ...Doch, kannst Du. Dazu musst Du nur
... jedes mal nach einem Schleifendurchlauf händisch die davor gesetzten Pins wieder invertieren ...Denn die Taster werden ja auch händisch betätigt. Du kannst allenfalls den Simulator in solchen oder ähnlichen Fällen betrügen, indem Du den Zähler für den Schleifendurchlauf händisch hochsetzt. Beides gehört zu den Problemen, durch die ich auch sehr zähhhh gekommen bin.
Um die Pull-Up zu invertieren, könnte ich doch die beiden Befehle
PINA &=~(1<<0x06);
PIND &=~(1<<0x04);
Nein, damit würdest du entweder die Pullups der gedrückten Taster toggeln (also ein/aus), oder aber gar nichts bewirken - wie sich schreibende Zugriffe auf das PINx-Register auswirken findest du im Datasheet deines AVR.
Du musst den eingelesenen Wert invertieren, nicht den Wert des Eingangsregisters manipulieren.
Wenn du damit die Pullups aktivieren wolltest (und ich dich falsch verstanden habe), musst du die entsprechenden Bits von PORTA und PORTD setzen. Genaueres verrät dir auch hier das Datasheet.
AVR-Studio bietet übrigens sogenannte Stimuli mit denen man sich theoretisch das manuelle Toggeln sparen kann, ich habe damit aber noch nicht gearbeitet und mir hat bisher das manuelle rumgeklicke gereicht.
mfG
Markus
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.