Ah
Also ich habe jetzt WinAVR und das neuste AVRStudio.
Wenn das Paket dann ankommt werde ich mal etwas programmieren.
Mfg
bnitram
Hallo
Ich werde folgendes verwenden:
WinAVR: http://sourceforge.net/projects/winavr/files/WinAVR/
KamAVR: http://www.avrfreaks.net/index.php?m...em&item_id=632
BurnOMat: http://avr8-burn-o-mat.aaabbb.de/
mySmartUSB: http://shop.myavr.de/Programmer/mySm...p.php&artID=42
myAVR ProgTool: http://shop.myavr.de/index.php?ws=do...2107_en_de.zip
(für die Fuses, aber das werden wir wohl nicht benötigen)
Gruß
mic
[Edit]
Am Samstag um 15 Uhr wurde das Päckchen schon geliefert :)
Sonntag 16 Uhr:
ISP mache ich ja eher selten, deshalb ist das für mich auch schon ein kleiner Erfolg ;)Code:C:\WinAVR\bin\avrdude.exe -C C:\WinAVR\bin\avrdude.conf -p m8 -P com2 -c AVR910 -U flash:r:C:\Users\mic\Documents\pingpong.hex:a Found programmer: Id = "AVR ISP"; type = S Software Version = 2.3; Hardware Version = 2.0 Programmer supports auto addr increment. Programmer supports buffered memory access with buffersize = 8 bytes. Programmer supports the following devices: [gekürzt] Reading | ################################################## | 100% 0.06s avrdude.exe: Device signature = 0x1e9307 avrdude.exe: reading flash memory: Reading | ################################################## | 100% 9.22s avrdude.exe: writing output file "C:\Users\mic\Documents\pingpong.hex" avrdude.exe: output file C:\Users\mic\Documents\pingpong.hex auto detected as Intel Hex avrdude.exe done. Thank you.
Ah
Also ich habe jetzt WinAVR und das neuste AVRStudio.
Wenn das Paket dann ankommt werde ich mal etwas programmieren.
Mfg
bnitram
Hallo
Inzwischen kann ich das Teil erfolgreich flashen:
Bild hier
http://www.youtube.com/watch?v=MRRoa1hpnMQ
http://www.youtube.com/watch?v=JpfsYIkHjlw
Da wird sich meine Angetraute sicher sehr freuen, wenn ich ihr fünf so Dinger an den Christbaum hänge ;)
Dieses Beispielprogramm von der elo-Webseite habe ich ausgewählt, weil es zeigt, wie einfach die Daten an die LCD-Matrix ausgegeben werden. Und weil es einen brauchbaren Font mitbringt:
(Code von http://www.elo-web.de/elo/mikrocontr...ng/laufschrift)Code:/* * laufschrift.c * * Ein einfache "Laufschrift" auf dem Ping-Pong Board. * * Kompilierbar mittels AVR Studio 4 oder WinAVR * * Der Sourcecode und das Hexfile dürfen frei verwendet werden. * Nutzung erfolgt auf eigene Gefahr. * * Ver. Date Author Comments * ------- ---------- -------------- ------------------------------ * 1.00 07.11.2009 Sascha Bader initial */ /* ----------------------------------------- * Defines (Präprozessor Makros) * -----------------------------------------*/ #define F_CPU 8000000UL /* CPU Takt (für delay-Routine) */ #define WIDTH 12 /* Breite des Displays */ #define HEIGHT 10 /* Höhe des Displays */ #define FONTWIDTH 8 /* Breite des Zeichensatzes */ #define FONTHEIGHT 10 /* Höhe des Zeichensatzes */ #define GetPixel(x,y) leds[y]&(1<<x) /* Makro: Ein "Pixel" auslesen */ #define SetPixel(x,y) leds[y]|=1<<x /* Makro: Ein "Pixel" setzen */ #define ClearPixel(x,y) leds[y]&=~(1<<x) /* Makro: Ein "Pixel" löschen */ /* ----------------------------------------- * Includes * -----------------------------------------*/ #include <inttypes.h> /* Definition der Datentypen uint8_t usw. */ #include <avr/interrupt.h> /* Interruptbehandlungsroutinen (für Timerinterrupt) */ #include <util/delay.h> /* Definition der Verzögerungsfunktionen (_delay_ms) */ #include <avr/pgmspace.h> /* Hilfsfunktionen um Daten aus dem Flash zu lesen */ #include "font.h" /* Definition des Zeichensatzes */ /* ----------------------------------------- * Globale Variablen * -----------------------------------------*/ uint16_t leds[WIDTH]; /* Inhalt der LED-Matrix */ prog_uint8_t * fnt = (prog_uint8_t *) font; /* Zeiger auf den Zeichensatz im Flash */ volatile uint8_t col = 0; /* Aktuelle Spalte (für Interruptroutine) "volatile", da durch Interrupt verändert */ /* ----------------------------------------- * Text der Laufschrift (Globele Variable) * -----------------------------------------*/ prog_uint8_t text[] = " Frohes Fest und guten Rutsch :)\ ~"; /* Ende-Kennzeichen (nicht vergessen) */ /* ----------------------------------------- * Prototypen der Funktionen * -----------------------------------------*/ void PrintScrollColumn(uint8_t c, int pixelx, int y); void ScrollLeft(void); /* ------------------------------------------------------------------------- * Main Funktion * * Initialisiert den Timer Interrupt und * behandelt die Laufschrift * -------------------------------------------------------------------------*/ int main(void) { uint8_t * tpos; uint8_t softx; cli(); // Interrupts sperren (damit keiner dazwischenfunkt) /*--------------------------------------------------- * Ports konfigurieren (Ein-/Ausgänge) *---------------------------------------------------*/ DDRC = 0x0f; // ( 0x0f PORTC als AD-Eingang) DDRB = 0xff; // Portb = Output DDRD = 0xff; // Portd = Output /*--------------------------------------------------------------------------- * 8-Bit Timer TCCR0 für das Multiplexing der LEDs initialisieren * Es wird ca. alle 2 Mikrosekunden ein Overflow0 Interrupt ausgelöst * Berechnung: T = Vorteiler * Wertebereich Zähler / Taktfreuenz * = 64 * 256 / ( 8000000 Hz ) = 2,048 ms *---------------------------------------------------------------------------*/ TCCR0 |= (1<<CS01) | (1<<CS00); // 8-bit Timer mit 1/64 Vorteiler TIFR |= (1<<TOV0); // Clear overflow flag (TOV0) TIMSK |= (1<<TOIE0); // timer0 will create overflow interrupt sei(); // Interrupts erlauben /*--------------------------------------------------- * Hauptschleife (Laufschrift erzeugen) *---------------------------------------------------*/ while(1) // Endlosschleife { for (tpos=text;pgm_read_byte(tpos)!='~';tpos++) // Aktuelles Zeichen lesen { for (softx=0;softx<FONTWIDTH;softx++) // Pixel des Zeichens abarbeiten { ScrollLeft(); // Platz schaffen und Zeilen nach links schieben PrintScrollColumn(pgm_read_byte(tpos),softx,0); // Ganz rechts eine Spalte des Zeichens ausgeben _delay_ms(35); // Ein bischen warten damit es nicht zu schnell wird } } } return 0; } /* ------------------------------------------------------------------------- * Funktion PrintScrollColumn * * Aktualisiert die Spalte ganz rechts mit * einem 1 "Pixel" breitem Ausschnitt des * Lauftextes. * * \param c Auszugebendes Zeichen * \param pixelx Auszugebende Spalte des Zeichens * \param y Vertikale Vverschiebnung * -------------------------------------------------------------------------*/ void PrintScrollColumn(uint8_t c, int pixelx, int y) { unsigned char fontbyte = 0; uint8_t pixelpos; uint8_t fonty; uint8_t mask; pixelpos = pixelx & 0x07; /* Auf 8 Pixel pro Zeichen limitieren */ for (fonty=0;fonty<FONTHEIGHT;fonty++) { fontbyte = pgm_read_byte_near(fnt+c*FONTHEIGHT+fonty); /* Ein Byte (Zeile) des aktuellen Zeichens lesen */ mask = 1<<pixelpos; /* Maske auf die gewünschte Spalte zurechtschieben */ if ((fontbyte & mask) != 0) /* Prüfen ob das Bit in der Spalte des Zeichens gesetzt ist */ { leds[WIDTH-1]|=1<<fonty; /* Setzen eines Pixels im Display ganz rechts */ } else { leds[WIDTH-1]&=~(1<<fonty); /* Löschen eines Pixels im Display ganz rechts */ } } } /* ------------------------------------------------------------------------- * Funktion ScrollLeft * * Verschiebt den Inhalt LED-Matrix um eine Spalte nach links. * Die erste Spalte tritt dabei an die Position der letzten Spalte. * -------------------------------------------------------------------------*/ void ScrollLeft(void) { uint8_t xcol; /* Spaltenzähler */ uint16_t first; /* Zwischenspeicher der ersten Spalte */ first = leds[0]; /* Erste Spalte sichern */ for (xcol=0;xcol<WIDTH-1;xcol++) { leds[xcol]=leds[xcol+1]; /* Spalten nach links verschieben */ } leds[WIDTH-1] = first; /* Erste Spalte an letzte Spalte kopieren */ } /* ------------------------------------------------------------------------- * Interrupt Routine * * Gibt nacheinander alle Spalten mit LED-Daten aus. * Dazu wird mittels der Schieberegister die aktuelle Spalte * ausgewählt und dann das Bitmuster derselben auf die Ports * gegeben. * Beim nächsten Interrupt ist dann die nächste Spalte dran. * -------------------------------------------------------------------------*/ // interrupt routine SIGNAL (SIG_OVERFLOW0) { uint16_t ledval; uint8_t portcout; uint8_t portdout; cli(); /* Interrupts verbieten */ /*-------------------------------------------------- * Aktuelle Spalte ermitteln *--------------------------------------------------*/ col++; if (col == 12) { col = 0; } /*-------------------------------------------------- * Ports initialisieren *--------------------------------------------------*/ PORTD = 0; PORTB = 0; PORTC = 0; /*--------------------------------------------------- * Eine einzelne 0 durch die Schiebergister schieben *---------------------------------------------------*/ if ( col == 0 ) { PORTB &= ~(1 << 4); /* Bei der ersten Spalte eine 0 ausgeben (PB4 = 0) */ /* Diese 0 geht auf die Reise durch die Schieberegister */ } else { PORTB |= (1 << 4); /* Danach Einsen hinterherschicken (PB4 = 1) */ } /*--------------------------------------------------- * Impulse für die Schieberegister generieren *---------------------------------------------------*/ PORTB |= (1 << 3); /* PB3 = 1 (cl) */ PORTB &= ~(1 << 3); /* PB3 = 0 (!cl) */ PORTB |= (1 << 2); /* PB2 = 1 (str) */ PORTB &= ~(1 << 2); /* PB2 = 0 (!str) */ /*--------------------------------------------------- * Daten der Spalte holen und auf die Ports verteilen *---------------------------------------------------*/ ledval = leds[col]; portdout = ledval & 0xff; /* low byte */ portcout = portdout & 0x0f; /* low nibble */ portdout = portdout & 0xf0; /* high nibble */ PORTD = portdout & 0xff; PORTC = portcout & 0xff; PORTB = (ledval >> 8) & 0x03; /* high byte */ sei(); /* Interrupts wieder erlauben */ }
Gruß
mic
[Edit]
Bild hier
http://www.youtube.com/watch?v=tsTk4Un89uA
Neuer Bildspeicher mit nur 15 Bytes und set()/unset()-Funktionen. Echt ein nettes Spielzeug:
Code:#define F_CPU 8000000UL #include <inttypes.h> #include <avr/interrupt.h> #include <util/delay.h> uint8_t bildspeicher[15]; volatile uint8_t col = 0; uint8_t x, y; void set(uint8_t zeile, uint8_t spalte) { uint8_t temp; if(zeile < 8) bildspeicher[spalte] |= (1 << zeile); else { if(spalte<4) temp = 12; else if(spalte<8) temp = 13; else temp = 14; if(zeile & 1) bildspeicher[temp] |= (1<<((spalte%4)*2+1)); // Zeile 10 else bildspeicher[temp] |= (1<<(spalte%4)*2); // Zeile 9 } } void unset(uint8_t zeile, uint8_t spalte) { uint8_t temp; if(zeile < 8) bildspeicher[spalte] &= ~(1 << zeile); else { if(spalte<4) temp = 12; else if(spalte<8) temp = 13; else temp = 14; if(zeile & 1) bildspeicher[temp] &= ~(1<<((spalte%4)*2+1)); // Zeile 10 else bildspeicher[temp] &= ~(1<<(spalte%4)*2); // Zeile 9 } } int main(void) { cli(); DDRC = 0x0f; DDRB = 0xff; DDRD = 0xff; /*--------------------------------------------------------------------------- * 8-Bit Timer TCCR0 für das Multiplexing der LEDs initialisieren * Es wird ca. alle 2 Mikrosekunden ein Overflow0 Interrupt ausgelöst * Berechnung: T = Vorteiler * Wertebereich Zähler / Taktfreuenz * = 64 * 256 / ( 8000000 Hz ) = 2,048 ms *---------------------------------------------------------------------------*/ TCCR0 |= (1<<CS01) | (1<<CS00); // 8-bit Timer mit 1/64 Vorteiler TIFR |= (1<<TOV0); // Clear overflow flag (TOV0) TIMSK |= (1<<TOIE0); // timer0 will create overflow interrupt sei(); // Interrupts erlauben while(1) { for(x=0; x<15; x++) bildspeicher[x] = 0b10101010; _delay_ms(500); for(x=0; x<15; x++) bildspeicher[x] = 255; // alle LEDs an _delay_ms(1000); for(x=0; x<15; x++) bildspeicher[x] = 0; // alle LEDs aus _delay_ms(500); for(x=0; x<12; x++) for(y=0; y<10; y++) { set(y, x); _delay_ms(25); } _delay_ms(1000); for(y=10; y; y--) for(x=12; x; x--) { unset(y-1, x-1); _delay_ms(25); } _delay_ms(1000); } return (0); } /* ------------------------------------------------------------------------- * Interrupt Routine * * Gibt nacheinander alle Spalten mit LED-Daten aus. * Dazu wird mittels der Schieberegister die aktuelle Spalte * ausgewählt und dann das Bitmuster derselben auf die Ports * gegeben. * Beim nächsten Interrupt ist dann die nächste Spalte dran. * -------------------------------------------------------------------------*/ // interrupt routine SIGNAL (SIG_OVERFLOW0) { uint16_t ledval; uint8_t portcout; uint8_t portdout; cli(); /* Interrupts verbieten */ /*-------------------------------------------------- * Aktuelle Spalte ermitteln *--------------------------------------------------*/ col++; if (col == 12) { col = 0; } /*-------------------------------------------------- * Ports initialisieren *--------------------------------------------------*/ PORTD = 0; PORTB = 0; PORTC = 0; /*--------------------------------------------------- * Eine einzelne 0 durch die Schiebergister schieben *---------------------------------------------------*/ if ( col == 0 ) { PORTB &= ~(1 << 4); /* Bei der ersten Spalte eine 0 ausgeben (PB4 = 0) */ /* Diese 0 geht auf die Reise durch die Schieberegister */ } else { PORTB |= (1 << 4); /* Danach Einsen hinterherschicken (PB4 = 1) */ } /*--------------------------------------------------- * Impulse für die Schieberegister generieren *---------------------------------------------------*/ PORTB |= (1 << 3); /* PB3 = 1 (cl) */ PORTB &= ~(1 << 3); /* PB3 = 0 (!cl) */ PORTB |= (1 << 2); /* PB2 = 1 (str) */ PORTB &= ~(1 << 2); /* PB2 = 0 (!str) */ /*--------------------------------------------------- * Daten der Spalte holen und auf die Ports verteilen *---------------------------------------------------*/ ledval = bildspeicher[col]; portdout = ledval & 0xff; /* low byte */ portcout = portdout & 0x0f; /* low nibble */ portdout = portdout & 0xf0; /* high nibble */ PORTD = portdout & 0xff; PORTC = portcout & 0xff; if(col<4) ledval=bildspeicher[12]; else if(col<8) ledval=bildspeicher[13]; else ledval=bildspeicher[14]; PORTB = (ledval >> (col%4)*2) & 0x03; /* high byte */ sei(); /* Interrupts wieder erlauben */ }
Bild hier
Atmel’s products are not intended, authorized, or warranted for use
as components in applications intended to support or sustain life!
Hallo,
Sieht sehr gut aus was du da gemacht hasst!
Aber eine Frage habe ich noch:
Ich habe das Ping Pong jetzt zuammen gebaut und warte nur noch auf den Programmer.
Ich habe festgestellt das überwiegent KamAVR bei Elo-web benutzt wird.(radbruch benutzt es auch)
Was mus ich in der IDE einstellen damit ich das PingPong programmieren kann??
Muss ich irrgentetwas beachten??
Mfg
bnitram
Hallo
Um das Spiel zu testen kann man auch mit den Fingern auf P1 bis P4 oder C4 (Selbsttest) rumfummeln. Das Programm erkennt den Hautwiderstand dann als Poti ;)
Meine Einstellungen beim KAMAvr, zusätzlich muss man dem Programm noch einmalig (klappt bei mir allerdings grad noch nicht) mitteilen, wo die WINAvr-Installation ist:
Bild hier
Um die Makefiles braucht man sich dann nicht mehr kümmern, denn die werden automatisch erzeugt. Um ein neues Projekt anzulegen (oder um das aktuelle Projekt zu Clonen) speichere ich zuerst das Projekt mit [File->Save Project as..] und anschliessend die Datei mit [File->Save File as...] jeweils mit dem neuen Namen ab. Nach dem Speichern der Datei lasse ich dann noch die Projektdatei in den neuen Namen ändern (PopUp mit [Ja] beantworten) und fertig. Zusätzliche C-Dateien (wie z.B. asuro.c) werden über einen Rechtsklick auf "Files" (über dem test.c) und "Add File..." eingebunden. Die erzeugte Hex-Datei trägt immer den Projektnamen.
Mit dem aktuellen Treiber wurde mein mySmartUSB als serieller Programmer eingebunden. Deshalb sollte meine Einstellung (über [Settings->AVRDUDE]) auch mit dem einfachen seriellen Programmer funktionieren:
Bild hier
COM muss man an die eigenen Verhältnisse anpassen. (btw. hat auch mein HighTech-Board noch eine echte serielle Schnittstelle :)
Gruß
mic
[Edit]
Bild hier
http://www.youtube.com/watch?v=ofswO2OCq-U
Leider ist das Video schlecht, aber mit etwas gutem Willen kann man die vier Helligkeitsstufen erkennen. Interessanterweise zeigen die blauen Phantomleds bei Sekunde drei und vier genau den gewollten Effekt;)
Der ungeputzte Quellcode:
Geputzte Version:Code:#define F_CPU 8000000UL #include <inttypes.h> #include <avr/interrupt.h> #include <util/delay.h> #include <avr/pgmspace.h> #define colors 4 // Anzahl der Farbebenen uint8_t bildspeicher[colors][15]; volatile uint8_t col = 0; uint8_t x, y; void set(uint8_t x, uint8_t y, uint8_t c); int main(void) { cli(); DDRC = 0x0f; DDRB = 0xff; DDRD = 0xff; /*--------------------------------------------------------------------------- * 8-Bit Timer TCCR0 für das Multiplexing der LEDs initialisieren * Es wird ca. alle 2 Mikrosekunden ein Overflow0 Interrupt ausgelöst * Berechnung: T = Vorteiler * Wertebereich Zähler / Taktfreuenz * = 64 * 256 / ( 8000000 Hz ) = 2,048 ms *---------------------------------------------------------------------------*/ TCCR0 |= (1<<CS01) | (0<<CS00); // 8-bit Timer mit 1/8 Vorteiler !!!!!!!!!! TIFR |= (1<<TOV0); // Clear overflow flag (TOV0) TIMSK |= (1<<TOIE0); // timer0 will create overflow interrupt sei(); // Interrupts erlauben for(x=0; x<15; x++) for(y=0; y<colors; y++)bildspeicher[y][x] = 0b10101010; // voll hell _delay_ms(300); for(x=0; x<12; x++) for(y=0; y<10; y++) set(x, y, (x/3)%colors+1); // Helligkeitsstufen anzeigen _delay_ms(2000); for(x=0; x<15; x++) for(y=0; y<colors; y++)bildspeicher[y][x] = 0; // alle LEDs in allen Ebenen aus while(1) { for(x=0; x<12; x++) for(y=0; y<10; y++) set(x, y, ((x+1)^(y+3)^(col+5))%colors+1); // Zufallsfarbe ;) _delay_ms(100); } return (0); } SIGNAL (SIG_OVERFLOW0) { static uint8_t ebene=0; uint16_t ledval; uint8_t portcout; uint8_t portdout; cli(); /* Interrupts verbieten */ // aha ;) PORTD = 0; PORTB = 0; PORTC = 0; if ( col == 0 ) PORTB &= ~(1 << 4);/* Bei der ersten Spalte eine 0 ausgeben (PB4 = 0) */ else PORTB |= (1 << 4); /* Danach Einsen hinterherschicken (PB4 = 1) */ PORTB |= (1 << 3); /* PB3 = 1 (cl) */ PORTB &= ~(1 << 3); /* PB3 = 0 (!cl) */ PORTB |= (1 << 2); /* PB2 = 1 (str) */ PORTB &= ~(1 << 2); /* PB2 = 0 (!str) */ /*--------------------------------------------------- * Daten der Spalte holen und auf die Ports verteilen *---------------------------------------------------*/ ledval = bildspeicher[ebene][col]; portdout = ledval & 0xff; /* low byte */ portcout = portdout & 0x0f; /* low nibble */ portdout = portdout & 0xf0; /* high nibble */ PORTD = portdout & 0xff; PORTC = portcout & 0xff; if(col<4) ledval=bildspeicher[ebene][12]; else if(col<8) ledval=bildspeicher[ebene][13]; else ledval=bildspeicher[ebene][14]; PORTB = (ledval >> (col%4)*2) & 0x03; /* high byte */ col++; if(col>11) { col=0; ebene++; if(ebene == colors) ebene=0; } sei(); /* Interrupts wieder erlauben */ } void set(uint8_t x, uint8_t y, uint8_t c) { uint8_t ebene, temp; y = 9-y; // Koordinatennullpunkt unten links if(y < 8) for(ebene=0; ebene<colors; ebene++) if(c>ebene) bildspeicher[ebene][x] |= (1 << y); else bildspeicher[ebene][x] &= ~(1 << y); else { if(x<4) temp = 12; else if(x<8) temp = 13; else temp = 14; if(y & 1) for(ebene=0; ebene<colors; ebene++) if(c>ebene) bildspeicher[ebene][temp] |= (1<<((x%4)*2+1)); // y 10 else bildspeicher[ebene][temp] &= ~(1<<((x%4)*2+1)); else for(ebene=0; ebene<colors; ebene++) if(c>ebene) bildspeicher[ebene][temp] |= (1<<((x%4)*2)); // y 9 else bildspeicher[ebene][temp] &= ~(1<<((x%4)*2)); } }
Code:// https://www.roboternetz.de/phpBB2/vi...=529702#529702 mic 15.12.2010 #include <avr/interrupt.h> #include <util/delay.h> #include <inttypes.h> //#define F_CPU 8000000UL // macht KAMAvr automatisch #define colors 4 // Anzahl der Farbebenen // Einen Bildpunkt an x, y setzen. Werte für c: 0 ist aus, 1 ist dunkel, 4 ist hell void set(uint8_t x, uint8_t y, uint8_t c); volatile uint8_t col = 0; uint8_t x, y, bildspeicher[colors][15]; int main(void) { cli(); DDRB = 0xff; DDRC = 0x0f; DDRD = 0xff; TCCR0 |= (1<<CS01) | (0<<CS00); // 8-bit Timer mit 1/8 Vorteiler !!!!!!!!!! TIFR |= (1<<TOV0); // Clear overflow flag (TOV0) TIMSK |= (1<<TOIE0); // timer0 will create overflow interrupt sei(); // Interrupts erlauben for(x=0; x<15; x++) for(y=0; y<colors; y++)bildspeicher[y][x] = 0b10101010; // LEDs voll hell _delay_ms(300); for(x=0; x<12; x++) for(y=0; y<10; y++) set(x, y, (x/3)%colors+1); // Helligkeitsstufen anzeigen _delay_ms(2000); for(x=0; x<15; x++) for(y=0; y<colors; y++)bildspeicher[y][x] = 0; // alle LEDs in allen Ebenen aus while(1) { for(x=0; x<12; x++) for(y=0; y<10; y++) set(x, y, (x^y^TCNT0)%colors+1); // Zufallsfarbe ;) _delay_ms(100); } return (0); } SIGNAL (SIG_OVERFLOW0) { static uint8_t ebene=0; uint16_t ledval; PORTB &= ~0x03; // Nur die Pins der Displaymatrix werden auf Low gesetzt PORTC &= ~0x0f; PORTD &= ~0xf0; // Spalten if(col) PORTB |= (1<<4); /* Danach Einsen hinterherschicken (PB4 = 1) */ else PORTB &= ~(1<<4); /* Bei der ersten Spalte eine 0 ausgeben (PB4 = 0) */ PORTB |= (1 << 3); /* PB3 = 1 (cl) */ PORTB &= ~(1 << 3); /* PB3 = 0 (!cl) */ PORTB |= (1 << 2); /* PB2 = 1 (str) */ PORTB &= ~(1 << 2); /* PB2 = 0 (!str) */ // Zeilen ledval = bildspeicher[ebene][col]; // y 9 bis 2 PORTC = ledval & 0x0f; PORTD = ledval & 0xf0; ledval = bildspeicher[ebene][12+(col>>2)]; // y 1 und 0 PORTB = (ledval >> (col%4)*2) & 0x03; col++; if(col>11) { col=0; ebene++; if(ebene == colors) ebene=0; } } void set(uint8_t x, uint8_t y, uint8_t c) { uint8_t ebene; y = 9-y; // Koordinatennullpunkt unten links if(y < 8) // y 9 bis 2 for(ebene=0; ebene<colors; ebene++) if(c>ebene) bildspeicher[ebene][x] |= (1 << y); else bildspeicher[ebene][x] &= ~(1 << y); else // y 1 und 0 for(ebene=0; ebene<colors; ebene++) if(c>ebene) bildspeicher[ebene][12+(x>>2)] |= (1<<((x%4)*2+(y&1))); else bildspeicher[ebene][12+(x>>2)] &= ~(1<<((x%4)*2+(y&1))); }Code:Aufbau der 15 Bytes des Bildspeichers: 0000 0000 0011 | Bytenummer 0123 4567 8901 | 0000 0000 0000 | Bit \ 1111 1111 1111 | | Port C 2222 2222 2222 | | Pin 0-3 3333 3333 3333 | / 4444 4444 4444 | \ 5555 5555 5555 | | Port D 6666 6666 6666 | | Pin 4-7 7777 7777 7777 | / 0246 0246 0246 | Bit \ Port B 1357 1357 1357 | / Pin 0 und 1 |12| |13| |14| | Bytenummer Koordinatennullpunkt von set(0,0, Helligkeit) ist links unten.Code:// Einfache Ansteuerung des PingPong-Spiels mic 20.12.2010 // Das Programm sollte mit der orginalen Hardware des Spiels funktionieren. // Es werden drei Funktionen zur Verfügung gestellt: // cls() löscht das Display // set(x, y, c) setzt an x, y eine LED. Werte für c: 0 ist aus, 1 bis 4 die Helligkeit // readADC(Kanal) liest den ADC, P2 ist Kanal 6, P3 ist Kanal 7 // Neben den vier Helligkeitsstufen sind die LEDs nun auch dimmbar, allerdings // nur alle zusammen. Möglich wird das durch den Timer2, den ich hier im // FastPWM-Mode betreibe und eine zusätzliche ISR. Wie gehabt, werden die LEDs beim // Bildaufbau über die Überlauf-ISR gesetzt. Gelöscht werden sie nun aber in der // Compare-ISR. Diese wird immer dann aufgerufen, wenn das Zählregister des Timers // den selben Inhalt wie das OCR2-Register hat. // Beim Nulldurchgang des Zählregisters werden die LEDs eingeschaltet, bei OCR2 // wieder ausgeschaltet. Somit ist die Leuchtdauer umso größer, je höher der Wert // im OCR2-Register ist. 0 ist dunkel, 255 ist hell. #include <avr/interrupt.h> #include <util/delay.h> #include <inttypes.h> //#define F_CPU 8000000UL // macht KAMAvr automatisch #define colors 4 // Anzahl der Farbebenen void cls(void); // alle LEDs in allen Ebenen aus // Einen Bildpunkt an x, y setzen. Werte für c: 0 ist aus, 1 ist dunkel, 4 ist hell void set(uint8_t x, uint8_t y, uint8_t c); // Potiwerte einlesen, P2 ist Kanal 6, P3 ist Kanal 7 uint16_t readADC(uint8_t channel); volatile uint8_t col = 0; uint8_t x, y, z, bildspeicher[colors][15]; int main(void) { cli(); DDRB = 0xff; DDRC = 0x0f; DDRD = 0xf0; TCCR2 = (1<<CS21) | (0<<CS20); // 8-bit Timer mit 1/8 Vorteiler TCCR2 |= (1<<WGM21) | (1<<WGM20); // Fast PWM TCCR2 |= (0<<COM21) | (0<<COM20); // no OC2-Pin OCR2 = 20; // 0=dunkel, 255=hell TIFR = (1<<OCF2) | (1<<TOV2); // Clear old flags TIMSK |= (1<<TOIE2) | (1<<OCIE2); // overflow and compare interrupt // A/D Conversion (aus der asuro-Lib) ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); // clk/64 sei(); // Interrupts erlauben for(x=0; x<12; x++) for(y=0; y<10; y++) set(x, y, (x/3)%colors+1); // Helligkeitsstufen anzeigen _delay_ms(2000); DDRD |= (1<<PD2); //GND für Potis PORTD |= (1<<PD2); while(1) { z=readADC(6)/110+1; OCR2=readADC(7)/4; for(x=0; x<12; x++) { if(z==x) set(x, 0, 0); else set(x, 0, 2); for(y=1; y<9; y++) if(z==x-1) set(x, y, 3); else if(z==x) set(x, y, 4); else if(z==x+1) set(x, y, 3); else set(x, y, 1); if(z==x) set(x, 9, 0); else set(x, 9, 2); } _delay_ms(50); } return (0); } void cls(void) { uint8_t x, y; for(x=0; x<15; x++) for(y=0; y<colors; y++)bildspeicher[y][x] = 0; } void set(uint8_t x, uint8_t y, uint8_t c) { uint8_t ebene; y = 9-y; // Koordinatennullpunkt unten links if(y < 8) // y 9 bis 2 for(ebene=0; ebene<colors; ebene++) if(c>ebene) bildspeicher[ebene][x] |= (1 << y); else bildspeicher[ebene][x] &= ~(1 << y); else // y 1 und 0 for(ebene=0; ebene<colors; ebene++) if(c>ebene) bildspeicher[ebene][12+(x>>2)] |= (1<<((x%4)*2+(y&1))); else bildspeicher[ebene][12+(x>>2)] &= ~(1<<((x%4)*2+(y&1))); } uint16_t readADC(uint8_t channel) { ADMUX = (1 << REFS0) | (channel & 7);// AVCC reference with external capacitor ADCSRA |= (1 << ADSC); // Start conversion while (!(ADCSRA & (1 << ADIF))); // wait for conversion complete ADCSRA |= (1 << ADIF); // clear ADCIF return(ADC); } SIGNAL (SIG_OUTPUT_COMPARE2) { PORTB &= ~0x03; // Die Pins der Displaymatrix werden auf Low gesetzt PORTC &= ~0x0f; PORTD &= ~0xf4; // PD2 ist GND für Potis! } SIGNAL (SIG_OVERFLOW2) { static uint8_t ebene=0; uint16_t ledval, portb; // Spalten if(col) PORTB |= (1<<4); /* Danach Einsen hinterherschicken (PB4 = 1) */ else PORTB &= ~(1<<4); /* Bei der ersten Spalte eine 0 ausgeben (PB4 = 0) */ PORTB |= (1 << 3); /* PB3 = 1 (cl) */ PORTB &= ~(1 << 3); /* PB3 = 0 (!cl) */ PORTB |= (1 << 2); /* PB2 = 1 (str) */ PORTB &= ~(1 << 2); /* PB2 = 0 (!str) */ // Zeilen ledval = bildspeicher[ebene][12+(col>>2)]; // y 1 und 0 portb = (ledval >> (col%4)*2) & 0x03; ledval = bildspeicher[ebene][col]; // y 9 bis 2 PORTC |= ledval & 0x0f; PORTD |= ledval & 0xf0; PORTB |= portb; col++; if(col>11) { col=0; ebene++; if(ebene == colors) ebene=0; } }
Bild hier
Atmel’s products are not intended, authorized, or warranted for use
as components in applications intended to support or sustain life!
Hallo
Nachdem ich nun noch etwas an der Software rumgeschnitzt habe, kann sich das Ergebniss wirklich sehen lassen:
Bild hier
http://www.youtube.com/watch?v=EpW4n09WuZA
Das sind jetzt vier deutlich unterscheidbare Helligkeitsstufen. Der Trick: Jetzt wird Timer2 im FastPWM-Mode verwendet. Das ermöglicht zwei getrennte ISR, die Overflow-ISR setzt die LEDs, die OutputCompare-ISR löscht sie wieder:
GrußCode:// Scrollen mit vier Helligkeitsstufen mic 27.12.2010 #include <avr/wdt.h> #include <avr/interrupt.h> #include <util/delay.h> #include <inttypes.h> #define colors 4 // Anzahl der Farbebenen volatile uint8_t ebene=0, col = 0; uint8_t x, y, z, bildspeicher[colors][15]; // alle LEDs in allen Ebenen aus void cls(void); // Einen Bildpunkt an x, y setzen. Werte für c: 0 ist aus, 1 ist dunkel, 4 ist hell void set(uint8_t x, uint8_t y, uint8_t c); // Potiwerte einlesen, P2 ist Kanal 6, P3 ist Kanal 7 uint16_t readADC(uint8_t channel); // WatchDog beim Initialisieren ausschalten // https://www.roboternetz.de/phpBB2/vi...=531597#531597 void kill_WD(void) __attribute__((naked)) __attribute__((section(".init3"))); void kill_WD(void) { MCUSR = 0; wdt_disable(); } int main(void) { cli(); DDRB = 0xff; DDRC = 0x0f; DDRD = 0xf0; TCCR2 = (1<<CS21) | (0<<CS20); // 8-bit Timer mit 1/8 Vorteiler TCCR2 |= (1<<WGM21) | (1<<WGM20); // Fast PWM TCCR2 |= (0<<COM21) | (0<<COM20); // no OC2-Pin OCR2 = 100; // 0=dunkel, 255=hell TIFR = (1<<OCF2) | (1<<TOV2); // Clear old flags TIMSK |= (1<<TOIE2) | (1<<OCIE2); // overflow and compare interrupt // A/D Conversion (aus der asuro-Lib) ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1); // clk/64 sei(); // Interrupts erlauben for(x=0; x<12; x++) for(y=0; y<10; y++) set(x, y, (x/3)%colors+1); // Helligkeitsstufen anzeigen _delay_ms(1000); cls(); z=0; while(1) { for(x=0; x<12; x++) for(y=0; y<10; y++) set(x, y, ((x+y+(z%12))/3)%colors+1); _delay_ms(50); z++; } return (0); } void cls(void) { uint8_t x, y; for(x=0; x<15; x++) for(y=0; y<colors; y++)bildspeicher[y][x] = 0; } void set(uint8_t x, uint8_t y, uint8_t c) { uint8_t ebene; y = 9-y; // Koordinatennullpunkt unten links if(y < 8) // y 9 bis 2 for(ebene=0; ebene<colors; ebene++) if(c>ebene) bildspeicher[ebene][x] |= (1 << y); else bildspeicher[ebene][x] &= ~(1 << y); else // y 1 und 0 for(ebene=0; ebene<colors; ebene++) if(c>ebene) bildspeicher[ebene][12+(x>>2)] |= (1<<((x%4)*2+(y&1))); else bildspeicher[ebene][12+(x>>2)] &= ~(1<<((x%4)*2+(y&1))); } uint16_t readADC(uint8_t channel) { ADMUX = (1 << REFS0) | (channel & 7);// AVCC reference with external capacitor ADCSRA |= (1 << ADSC); // Start conversion while (!(ADCSRA & (1 << ADIF))); // wait for conversion complete ADCSRA |= (1 << ADIF); // clear ADCIF return(ADC); } SIGNAL (SIG_OUTPUT_COMPARE2) { OCR2 = (24<<ebene); // hihi PORTB &= ~0x03; // Die Pins der Displaymatrix werden auf Low gesetzt PORTC &= ~0x0f; PORTD &= ~0xf0; } SIGNAL (SIG_OVERFLOW2) { uint8_t ledval, portb; // Spalten if(col) PORTB |= (1<<4); /* Danach Einsen hinterherschicken (PB4 = 1) */ else PORTB &= ~(1<<4); /* Bei der ersten Spalte eine 0 ausgeben (PB4 = 0) */ PORTB |= (1 << 3); /* PB3 = 1 (cl) */ PORTB &= ~(1 << 3); /* PB3 = 0 (!cl) */ PORTB |= (1 << 2); /* PB2 = 1 (str) */ PORTB &= ~(1 << 2); /* PB2 = 0 (!str) */ // Zeilen ledval = bildspeicher[ebene][12+(col>>2)]; // y 1 und 0 portb = (ledval >> (col%4)*2) & 0x03; ledval = bildspeicher[ebene][col]; // y 9 bis 2 PORTC |= ledval & 0x0f; PORTD |= ledval & 0xf0; PORTB |= portb; col++; if(col>11) { col=0; ebene++; if(ebene == colors) ebene=0; } }
mic
Ein Vorkucker:
Bild hier Bild hier Bild hier
http://www.youtube.com/watch?v=z18KkJU_0Ic
http://www.youtube.com/watch?v=IKszXFViHR8
http://www.youtube.com/watch?v=ngim6DzIcGQ
Die 0,00012 Megapixelkamera:
https://www.roboternetz.de/phpBB2/vi...=531996#531996
Bild hier
Atmel’s products are not intended, authorized, or warranted for use
as components in applications intended to support or sustain life!
Hi, kannst du vielleicht auch einen Schaltplan deines Lochrasteraufbaus online stellen. Was hast du für eine Kamera verwendet?
Hallo
Bild hier Bild hier
Mit den Stiftleisten J1 und J4 kann man zwischen VBat oder Vcc/P1 bzw. GND oder P4 auswählen. J2 und J3 sind Anschlüsse für externe Sensoren oder Aktoren, von links nach rechts Spannung, GND und Signal.
Ursprünglich hatte ich die PingPong-Platine nur in die Verbindungsstiftleisten eingesteckt (siehe Video oben). Nachdem ich aber einen Mega8 abgeschossen habe, sind die Verbindungen nun verlötet. (Trotzdem habe ich inzwischen einen zweiten Mega8 gekillt)
Die 3mm-Klinkenbuchse ist direkt mit P2, P3 und GND verbunden. Zwischen P3 (ADC7) und GND brückt ein Jumper einen Lastwiderstand (im Bild unten), wenn kein Monitor angeschlossen ist.
Ganz unten erkennt man eine achtpinnige Stiftleiste. Diese ist noch nicht angeschlossen und nur gesteckt.
Es ist die 15€-Kamera aus dem Mitmachprojekt und sie hängt am P3 (J2).
Gruß
mic
Bild hier
Atmel’s products are not intended, authorized, or warranted for use
as components in applications intended to support or sustain life!
Hallo mic,
da Du die Pong Platine ja besser kennst als der Hersteller folgende Frage:
ich möchte den Scroller so anpassen, dass ich zwei Platinen (oder mehr) per I2C/TWI verbinde. Ich möchte, dass die Werte, die im Prinzip dann Links Außen herausgeschoben würden auf der zweiten Platte angezeigt werden. Wie kann ich das machen? Kannst Du ein Beispiel in diesen Code von Sascha Bader implementieren:
http://www.elo-web.de/elo/mikrocontr...ng/laufschrift
Ich habe mir auch sechs davon aus dem Regal genommem. 5,- ist ein Schnapper. Konnte auch schon ein wenig herumexperimentieren:
http://www.youtube.com/watch?v=3ck8w9r_Ogs
oder
http://www.youtube.com/watch?v=jk-GG6OIgl8
Ich danke Dir sehr dafür!
Hallo
Mit I2C habe ich noch nichts gemacht und den Code des Zeichenscrollers habe ich auch noch nicht genauer untersucht. Mir ging es bisher in erster Linie um den Aufbau und die Ansteuerung der LED-Matrix.
Der einfachste Ansatz wäre wohl, jedes Modul getrennt scrollen zu lassen und nur die Darstellung zu synconisieren. Dazu müßte das hintere Modul zuerst starten und das vordere Modul müßte abwarten, bis es über eine Signalleitung den Start der Laufschrift und in Folge dann jedes einzelne Weiterscollen mitgeteilt bekommt. Wenn man dazu zwei getrennte Pins verwendet, also Eingang und Ausgang getrennt, kann man sogar mehrere Module kaskadieren. Das erste Modul könnte man z.B. mit einem Jumper am Eingang als solches definieren. Das würde für alle Module das selbe Programm ermöglichen.
Gruß
mic
Bild hier
Atmel’s products are not intended, authorized, or warranted for use
as components in applications intended to support or sustain life!
Lesezeichen