Erstmal meine Hardware
STK500 mit Atmega16
LEDs sind an PORTB angeschlossen und SWITCHES an PORTD
Irgendwie bekomme ich es nicht gebacken.
Im Grunde möchte ich verschiedenen Tastenkombinationen einen bestimmten
Ascii Code hinterlegen. Wenn man z.B. Taste 1 + 2 + 5 drückt soll der
Ascci Code für den Buchstaben "G" an den PC übersendet werden.
Bin totaler Anfänger in dem Gebiet von uC. Habe aber bereits kleine
Übungen gemacht und einiges an Literatur über dieses Thema gelesen.
Programmierkenntnisse sind in JAVA bei mir vorhanden.
Würde mir jemand dabei über einen Instant Messenger helfen, den
schliesslich lernt man wenn man es selber macht und nicht fertiges
überniehmt.
Das Tut hier auf der Seite habe ich zwar mir angeguckt, finde aber
einiges schwer für einen Anfänger.
Willst du mit C programmieren? Hast du bereits einen C
Entwicklungssystem für die AVRs installiert? Welches? WINAVR wenn du
mit Windows PC arbeitest?
Du schreibtst was vom Tutorial - meinst du das AVR-GCC-Tutorial?
Hast du schon die ersten kleinen Programme geschrieben?
LED blinken lassen? Taster abgefragt? LED auf Taste reagieren lassen?
Text vom PC über UART empfangen und LED damit gesteuert? Taste abgefragt
und Reaktion über UART zum PC gesendet?
Lass mal sehen, wie weit du schon bist.
JA habe WinAVR und Halt AVR-Studio.
Ich komme mit dem Tut-GCC nicht ganz klar. Habe mir einige Beispiele aus
nem Buch angeuckt und auch bsichen was hinbekommen. Also verstehen tue
ich es schnell. Brauche nur eine Starthilfe und dann läuft das von
alleine. Programmieren möchte ich in C.
""LED blinken lassen? Taster abgefragt? LED auf Taste reagieren lassen?
Text vom PC über UART empfangen und LED damit gesteuert? Taste abgefragt
und Reaktion über UART zum PC gesendet?
""
Genau dazu brauche ich paar Beispiele. So wurde mir Java bei gebracht.
Warum ds Rad neu erfinden, wenn man vom fertigen abgucken kann.
Danke für deine Antwort.
Jürgen Dell wrote:
> Genau dazu brauche ich paar Beispiele. So wurde mir Java bei gebracht.
> Warum ds Rad neu erfinden, wenn man vom fertigen abgucken kann.
Weil man beim Rad-neu-erfinden die Problemstellung erfassen kann und
sich selber einen Weg ausdenkt um somit was zu lernen?
Abgucken wäre also Copy&Paste, oder wie?
Jürgen du schreibst
> habe mir einige Beispiele aus 'nem Buch angeuckt und auch bischen was
> hinbekommen.
aber dann auch
> Genau dazu brauche ich paar Beispiele.
Das widerspricht sich ein wenig.
Die aufgeführten Beispiele
""LED blinken lassen? Taster abgefragt? LED auf Taste reagieren lassen?
Text vom PC über UART empfangen und LED damit gesteuert? Taste abgefragt
und Reaktion über UART zum PC gesendet?
""
beginnen mit dem einfachsten Beispiel und steigern sich im
Schwierigkeitsgrad.
Bis wohin bist du schon gekommen?
Klappt das grundsätzliche Programmieren mit WinAVR/Brennen mit
AVR-Studio/Ablaufenlassen auf dem STK500 nicht?
Oder hapert es an der zündenden Idee die Aufgabe als Rechenvorschrift
abzubilden? In Java könntest du es lösen, bloss die Umsetzung nach C ist
nicht dein Ding?
Oder ist letzteres kein Problem, aber du weisst nicht wie du konkret an
die die Tasteneingabe bekommst und die Daten per UART verschickst? Dann
schick ein Rumpfprogramm und markiere die Stellen, wo du Fragen hast.
ADD:
Für das einfachste Beispiel (Blinkende LED) gibt es eine Einführung bei
http://www.geocities.com/thetonegod/micro/intro.html
Wenn es dann mit Tasten weiter geht, kommt
http://www.geocities.com/thetonegod/micro/io_digital.html ins Spiel.
In Java könnte ich das ohne weiteres hinbekommen. Es happert wie du
schon sagtest die Transparation nach C. Programme auf den yC zu
schreiben und in AVR Studio ablaufen zu lassen dass kann ich.
Copy & Paste meine ich damit nicht. Im Grunde brauche ich eine Person
die mir bei den Grundlagen eniges erläutert.
Tastenabfrage
Datenübertragen
Das Programmieren muss ich selber fertig machen, schliesslich muss ich
es später vorführen und auch erklären das ganze.
Bei den Links bitte beachten: die dortigen delay() Funktionen sind
problematisch. Orientiere dich da besser am Abschnitt Warteschleifen im
AVR-GCC-Tutorial
Die Person hast du in Form von den Usern dieses Forums und in Form der
Schreiber der Tutorials.
Es ist zu mühsam oder es fällt schwer, die Welt komplett umd von Anfang
an zu erklären. Konkrete, bewältigbare Anfragen sind vielleicht
schneller gelöst... Sage halt, um welche Grundlage es konkret geht.
Wenn du ausschliessen willst, stur aufs Tutorial verwiesen zu werden,
lies das vorher durch und konkretisiere die Frage unter Berücksichtigung
des "Lernstoffs". Vielleicht hilft deine Frage, das Tutorial noch
verständlicher zu machen.
Auch für C Neulinge emfehle ich einen Blick ins Assembler
Tutorial.
http://www.mikrocontroller.net/articles/AVR-Tutorial
Der Grund: Manchmal sind gerade die Hardwaredinge im
anderen Tutorial anders erklärt (nicht notwendigerweise
besser, einfach nur anders). Und aus einer zweiten Sichtweise
kann man oft den fehlen Zündfunken holen.
Zum zweiten ist gerade bei diesen Hardwaredingen der Schritt
von Assembler zu C nicht so der grosse Schritt. Ob man da
jetzt in Assembler in spezifisches Hardwareregister mit
einem bestimmten Wert laden muss, oder ob man das in C mit
einer Zuweisung macht, ist letzendlich ziemlich egal, zumal ja
auch in beiden Sprachen die Registerbezeichnung identisch
ist. Der entscheidende Punktist ja nicht, wie das Register
heist, oder wie man es konkret lädt, sonder welches Bit in
diesem Register wöfür zuständig ist. Und das ist völlig
sprachunabhängig (BASCOM mal ausgenommen), da von der Hardware
vorgegeben.
#include <avr/io.h>
int main (void) {
DDRB = 0xff;
DDRD = 0x01;
#define WARTEPIN PIND
#define WARTEBIT PD0
// mit der avr-libc Funktion:
loop_until_bit_is_set(WARTEPIN, WARTEBIT);
while ( !(WARTEPIN & (1 << WARTEBIT)) ) ;
PORTB = 0x03; //LEDs an ausser PB0 und PB1
}
In der Simulation wartet AVR Studio bis ich PD0 gesetzt habe. Aber auf
dem STK500 sieht es so aus, als ob die Abfrage übersprungen wird. Jemand
eine Erklärung für mich ?
Ist klar, der Eingabepin ist falsch konfiguriert und die Abfrage benutzt
die falsche Logik für die STK500-Beschaltung.
Achtung: fehlerhaft! 1 | #include <avr/io.h>
| 2 |
| 3 | // Defines üblicherweise am Programmanfang
| 4 | #define WARTEPIN PIND
| 5 | #define WARTEBIT PD0
| 6 |
| 7 | int main (void)
| 8 | {
| 9 | // http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#I.2FO-Register
| 10 | DDRB = 0xff; // PORTB alle AUSGANG
| 11 | DDRD = 0x01; // PD0 AUSGANG, alle anderen EINGANG ====> #1
| 12 |
| 13 | // Bis zum nächsten RESET...
| 14 | while (1)
| 15 | {
| 16 | #if 1
| 17 | // ENTWEDER
| 18 | // mit dem avr-libc Makro aus avr/sfr_defs.h
| 19 | // (wird von avr/io.h included:
| 20 | loop_until_bit_is_set(WARTEPIN, WARTEBIT); // ====> #1
| 21 | #else
| 22 | // ODER
| 23 | while ( !(WARTEPIN & (1 << WARTEBIT)) )
| 24 | ;
| 25 | #endif
| 26 |
| 27 | PORTB = 0x03; //LEDs an ausser PB0 und PB1
| 28 | }
| 29 |
| 30 | // Soll auf µCs nie erreicht werden!
| 31 | return 0;
| 32 | }
|
#1:
Das passt nicht zu
DDRD = 0x01; // PORTD0 AUSGANG, alle anderen EINGANG
in Verbindung mit
#define WARTEPIN PIND
#define WARTEBIT PD0
Du musst PD0 als Eingang konfigurieren, d.h. dieses Bit darf gerade
nicht gesetzt sein.
#2:
Die Switches sind im STK User Guide im Abschnitt 3-2 beschrieben. Es
handelt sich um eine Active-LOW Schaltung, d.h. bei offenem Switch liegt
eine 1 an und es ist zu warten bis das Bit von 1 auf 0 wechselt
(Tastendruck).
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Tasten_und_Schalter
1 | DDRD = 0xFE; // PD0 EINGANG, alle anderen AUSGANG
| 2 | ...
| 3 | loop_until_bit_is_clear(WARTEPIN, WARTEBIT);
| 4 | ...
| 5 | while ( (WARTEPIN & (1 << WARTEBIT)) )
|
Nächster Lernstoff:
1/ Programmlogik: Zurücksetzen der LEDs beim Löslassen des Tasters
2/ Entprellung:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#.28Tasten-.29Entprellung
Mit deiner Hilfe habe ich endlich einen kleines Programm geschafft.
#include <avr/io.h>
#define WARTEPIN PIND
#define WARTEBIT PD0
int main (void)
{
DDRB = 0xff; // PORTB alle AUSGANG
PORTB = 0xFF; //Alle LEDS aus auf LOW gesetzt
DDRD = 0xFE; // PD0 EINGANG, alle anderen AUSGANG
// Bis zum nächsten RESET...
loop_until_bit_is_clear(WARTEPIN, WARTEBIT);
PORTB = 0xFE; //PB0 auf high
}
Die LED geht erst an wenn ich die Taste von high auf low setze (also die
Taste drücke).
Nun mache ich mit dem nächsten Lernstoff weiter und vertiefe das grad
erlernte
Wie stelle ich es jetzt an, dass wenn ich beliebigen Taster drücke auch
die dazugehörige LED angeht. Nach meinem Verständnis muss ja gelauscht
werden welcher Taster gedrückt wurde, sprich also wo ein
Potentialunterschied ensteht.
Könnte ich da weitere Hilfestellung bekommen?
1 | #include <avr/io.h>
| 2 | #define WARTEPIN PIND
| 3 | #define WARTEBIT PD0
| 4 |
| 5 | int main (void)
| 6 | {
| 7 | DDRB = 0xff; // PORTB alle AUSGANG
| 8 | PORTB = 0xFF; //Alle LEDS ausschalten
| 9 | DDRD = 0x00; // PORTD alle AUSGANG
| 10 | PORTD = 0xFF; // Pullups einschalten
| 11 |
| 12 |
| 13 | while (!(PIND & PD0); // auf Tastendruck an PD0 warten
| 14 |
| 15 | PORTB = 0xFE; //PB0 auf high
| 16 |
| 17 | // Bis zum nächsten RESET...
| 18 | while(1) // Endlosschleife
| 19 | {
| 20 | PORTB = PIND;
| 21 | }
| 22 | }
|
Übrigens ist das Ende deines Programms ungewiss. Man setzt grundsätzlich
eine Endlosschleife ein, damit der Controller in einem stabilen Zustand
bleibt.
Selbst, wenn man nur eine Anweisung machen will und der Controller
danach zum Nichtstun verdammt wird.
Okay wieder was neues gelernt.
Ich als Anfänger erlaube es mir mal deinen Source-Code zu verbessern
""""
#include <avr/io.h>
int main (void)
{
DDRB = 0xff; // PORTB alle AUSGANG
PORTB = 0xFF; //Alle LEDS ausschalten
DDRD = 0x00; // PORTD alle AUSGANG
PORTD = 0xFF; // Pullups einschalten
while ((PIND & PD0)); // auf Tastendruck an PD0 warten
PORTB = 0xFE; //PB0 auf high
// Bis zum nächsten RESET...
while(1) // Endlosschleife
{
PORTB = PIND;
}
}
""""""
Nur wenn die Taste gedrückt ist, ist auch die dazu gehörige LED an.
Wie sehe es aus, wenn die LED so lange anbleiben soll, bis ich
irgendwann wieder auf die Taste gedrückt habe?
1 | #include <avr/io.h>
| 2 | #define WARTEPIN PIND
| 3 | #define WARTEBIT PD0
| 4 |
| 5 | int main (void)
| 6 | {
| 7 | DDRB = 0xff; // PORTB alle AUSGANG
| 8 | PORTB = 0xFF; //Alle LEDS aus auf LOW gesetzt
| 9 | DDRD = 0xFE; // PD0 EINGANG, alle anderen AUSGANG
| 10 |
| 11 | // Bis zum nächsten RESET... =====> #1
| 12 |
| 13 | loop_until_bit_is_clear(WARTEPIN, WARTEBIT);
| 14 | PORTB = 0xFE; //PB0 auf high
| 15 | }
|
#1
Der Kommentar alleine bewirkt garnix. So wie in meiner Antwort oben und
im Kommentar von Rahul zu sehen, brauchst du Schleifenanweisungen, damit
das auch so ist. Z.B.
1 | #include <avr/io.h>
| 2 | #define WARTEPIN PIND
| 3 | #define WARTEBIT PD0
| 4 |
| 5 | int main (void)
| 6 | {
| 7 | DDRB = 0xff; // PORTB alle AUSGANG
| 8 | PORTB = 0xFF; //Alle LEDS aus auf LOW gesetzt
| 9 | DDRD = 0xFE; // PD0 EINGANG, alle anderen AUSGANG
| 10 |
| 11 | // Bis zum nächsten RESET...
| 12 | while(1)
| 13 | {
| 14 | loop_until_bit_is_clear(WARTEPIN, WARTEBIT);
| 15 | PORTB = 0xFE; //PB0 auf high
| 16 | ]
| 17 | }
|
So sieht die Schleife formal aus. Eine Reaktion auf die Taste hast du
aber noch nicht.
Wenn du auf mehrere Tasten testen willst, kannst du die loop_until...
Schleife natürlich nicht mehr benutzen. Die blockiert dir den
Programmablauf.
Du musst PIND direkt abfragen, die betreffenden Bits rausholen und dann
mit bedingten Anweisungen (if, switch, ?:) darauf reagieren, d.h.
Bitmanipulation an PORTB bzw. wie Rahul es macht PIND 1:1 auf PORTB
durchgeben. Aber du willst ja später mehr im Programm machen als nur die
Eingänge auf die Ausgänge zu spiegeln...
1 | #include <avr/io.h>
| 2 | #define WARTEPIN PIND
| 3 | #define WARTEBIT PD0
| 4 |
| 5 | int main (void)
| 6 | {
| 7 | DDRB = 0xff; // PORTB alle AUSGANG
| 8 | PORTB = 0xFF; // Alle LEDS aus (STK500 HIGH)
| 9 | DDRD = 0xF0; // PD0, PD1, PD2, PD3 EINGANG, alle anderen AUSGANG
| 10 |
| 11 | // Bis zum nächsten RESET...
| 12 | while(1)
| 13 | {
| 14 | if ( (WARTEPIN & (1<<PD0)) )
| 15 | {
| 16 | // Schalter PD0 offen => PORTB.0 HIGH (STK500) => LED0 aus
| 17 | PORTB |= (1<<PD0);
| 18 | }
| 19 | else
| 20 | {
| 21 | // Schalter PD0 geschlossen => PORTB.0 LOW (STK500) => LED0 an
| 22 | PORTB &= ~(1<<PD0);
| 23 | }
| 24 |
| 25 | if ( (WARTEPIN & (1<<PD1)) )
| 26 | {
| 27 | // Schalter PD1 offen => PORTB.1 HIGH (STK500) => LED1 aus
| 28 | PORTB |= (1<<PD1);
| 29 | }
| 30 | else
| 31 | {
| 32 | // Schalter PD1 geschlossen => PORTB.1 LOW (STK500) => LED1 an
| 33 | PORTB &= ~(1<<PD1);
| 34 | }
| 35 |
| 36 | // ...
| 37 | }
| 38 | }
|
Danke Stefan für deine Hilfe. Ich nehme deine Kommentare und Co gerne an
und befasse mich weiter damit. Spätestens heute Abend habe ich wieder
Fragen.""
Je mehr man sich damit beschäftigt desto logischer kommt es mir auch
rüber.
Eine 1:1 Spiegelung bringt mir im späteren Verlauf sicherlich recht
wenig. Frage mich grad selber warum ich nicht aus meinen
Java-Kenntnissen nach verschachtelte-Anweisungen gesucht habe.
Vielen Dank bis später
> Nur wenn die Taste gedrückt ist, ist auch die dazu gehörige LED an.
> Wie sehe es aus, wenn die LED so lange anbleiben soll, bis ich
> irgendwann wieder auf die Taste gedrückt habe?
D.h. Zustand merken und in der Abfrage berücksichtigen
1 | #include <avr/io.h>
| 2 | #define WARTEPIN PIND
| 3 | #define WARTEBIT PD0
| 4 |
| 5 | int main (void)
| 6 | {
| 7 | unsigned char taste0_vorher = 0;
| 8 |
| 9 | DDRB = 0xff; // PORTB alle AUSGANG
| 10 | PORTB = 0xFF; // Alle LEDS aus (STK500 HIGH)
| 11 | DDRD = 0xF0; // PD0, PD1, PD2, PD3 EINGANG, alle anderen AUSGANG
| 12 |
| 13 | // Bis zum nächsten RESET...
| 14 | while(1)
| 15 | {
| 16 | if ( (WARTEPIN & (1<<PD0)) )
| 17 | {
| 18 | // Schalter PD0 jetzt offen
| 19 | if (taste0_vorher == 1)
| 20 | {
| 21 | // Schalter PD0 vorher geschlossen => LED umschalten (toggeln)
| 22 | PORTB ^= (1<<PB0);
| 23 |
| 24 | // neuen jetzt Zustand merken
| 25 | taste0_vorher = 0;
| 26 | }
| 27 | }
| 28 | else
| 29 | {
| 30 | // Schalter PD0 geschlossen
| 31 | if (taste0_vorher == 0)
| 32 | {
| 33 | // Schalter PD0 vorher offen => LED umschalten (toggeln)
| 34 | PORTB ^= (1<<PB0);
| 35 |
| 36 | // neuen jetzt Zustand merken
| 37 | taste0_vorher = 1;
| 38 | }
| 39 | }
| 40 |
| 41 | // ...
| 42 | }
| 43 | }
|
Kleine Korrektur
Entweder in der If oder in der Else Anweisung muss
aus PORTB ^= (1<<PB0); ---> PORTB ^= (0<<PB0);
gemacht werden.
Danke für die Hilfe. Ich vervollständige das auch für die restlichen
Tasten. Könnten man das nicht wie in Java in einer Schleife machen ?
>Entweder in der If oder in der Else Anweisung muss
>aus PORTB ^= (1<<PB0); ---> PORTB ^= (0<<PB0);
>gemacht werden.
Nö. Guck dir mal die Verknüpfung und den Sinn der Aussage (0<<PB0).
Es handelt sich dabei um ein XOR...
>Ich als Anfänger erlaube es mir mal deinen Source-Code zu verbessern
Vielleicht habe ich den Fehler absichtlich reingemacht?!
> Vielleicht habe ich den Fehler absichtlich reingemacht?!
Das bringt keinen Lerneffekt, sondern verunsichert nur den Gegenüber.
Ich baue bestimmt keine Fehler absichtlich ein. Aber Fehler kommen vor,
that's life.
Stefan B. wrote:
>> Vielleicht habe ich den Fehler absichtlich reingemacht?!
>
> Das bringt keinen Lerneffekt, sondern verunsichert nur den Gegenüber.
> Ich baue bestimmt keine Fehler absichtlich ein. Aber Fehler kommen vor,
> that's life.
Nein, ich habe ihn nicht extra eingebaut. Das war nur eine Trotzreaktion
auf
>Ich als Anfänger erlaube es mir mal deinen Source-Code zu verbessern
Jeder macht mal Fehler. Ich setze mich wenigstens hin und gucke mir eure
Hilfestellung an und teste es auch, viele würden ainfach Copy&Paste
benutzen und nicht mal Danke sagen.
Ist doch gut, wenn ich selbständig Fehler berichtigen kann. Wollte dich
(rahul) in keiner Weise angreifen.
Jürgen Dell wrote:
> Ist doch gut, wenn ich selbständig Fehler berichtigen kann.
Hast Du aber nicht.
Du hast nur ein sehr verqueres NOP geschrieben.
Ob Stefans Code überhaupt falsch ist, hängt von der Betrachtungsweise
ab.
Er macht an beiden Flanken eine Aktion und das muß ja nicht falsch sein.
Will man sie nur an einer Flanke, dann muß man eine davon wegnehmen,
aber nicht durch einen unsinnigen Code ersetzen.
Und dann wird man auch das Problem des Prellens sehen.
Peter
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|