Guten Morgen, ich wollte ein Programm für den PIC16F887 schreiben und habe mich dazu entschieden "Schiffe versenken" in Assembler zu programmieren. Da ich die LEDs der LED-Matrix durch Multiplexing ansteuer, habe ich mir überlegt, erstmal eine kleine Matrix mit dem PIC16F84A aufzubauen. Dies funktioniert auch soweit schon. Ich kann jede LED einzeln ansteuern. Für die Koordinaten (z.B. A5, C7 etc.) habe ich jeweils eine LED-Reihe oben und eine links als Cursor. Um eine bestimmte Koordinate auszuwählen, benutze ich drei Taster (obere Reihe nach rechts, nebenstehende Reihe nach unten und den letzten Taster zum Bestätigen). Dies funktioniert ebenfalls. Die eingegebene Koordinate müsste ja mit einem gespeicherten Wert verglichen werden, damit entschieden werden kann, ob ein Schiff getroffen wurde oder nicht (ich benutze zweifarbige LEDs, wo jede durch einen Port angesteuert wird). Doch nun habe ich ein Problem: Ich weiß nicht wie ich den EEPROM für den PIC16F84A/PIC16F887 beschreiben, bzw. abrufen und darstellen soll. Da ich ja nacheinander jede ausgewählte LED individuell anzeigen (getroffen/nicht getroffen) und gleichzeitig auch noch mit den Cursor-LEDs ansteuern möchte. Ist das überhaupt zu realisieren? Und kann die Matrix überhaupt problemlos durchlaufen und gleichzeitig noch ein Taster abgefragt werden? Wenn ja, könntet ihr mir vielleicht einen Tipp geben? MfG circle
Hi, du hast jetztnicht gesagt, wie groß die Matrix werden soll, dann hätte ich den 16F84 schon mal völlig ausschließen können... ABER TROTZDEM: Lasse die Finger von diesem OPA, der war zu seiner Zeit nicht schlecht, ist aber seit sicher 10Jahren und mehr durch bessere und leistungsfähigere ersetzt. Wenn du nicht diekt mit den dicken (und teuren) Brummern wie dem 16F887 arbeiten willst, dann nehme zum beispiel dem zum 16F84 Pinkompatiblen 16F628. Der hat mehr Speicher, EEPROM und kann schneller laufen. Ausserdem ist das Verhalten des EEPROM Zugriff hier mehr mit dem des 16F887 vergleichbar. Aber grundsätzlich: Der EEPROM Zugriff ist bei den 16er Pics sehr "langsam". Zuindest der Schreibzugriff! Du musst dein Program bei diesen Zugriffen ein wenig "bremsen". Dies geschieht mit einem Status Bit, das das jeweilige Zugriffsende anzeigt. Das lesen erfordert zwar keine künstlichen Programmselbstkontrolle, ist aber trotzdem etwas aufwendig weil du mehrere Register verändern musst, bevor du EINEN Wert zurückbekommst. Dies ist natürlich genau das was man bei einer Sache wie einer Matrix verhindern will. Natürlich, fast alles bis auf das ausbremsen beim Schreiben kann man so implementieren das man keine Probleme mit dem Display hat, aber das ist wirklich aufwendig. DAHER: Schaue ob du nicht auf das EEPROM verzichte kannst, bzw. nutze dieses nur als statischen Speicher, aus dem zum Beispiel beim Programmstart oder unterbrechungen einmal die Daten ins RAM gelesen werden. Ist dir das RAM zu klein und du willst eine richtig große Matrix bauen, dann würde ich statt auf den EEPROM einfach auf dem Programspeicher zugreifen und dort eine oder mehrere Tabellen vorkonfigurieren, diese zur Laufzeit abändern und dann im Ausgabeteil (Matrixdaten) einfach mit "Table Read" die Daten holen. Das ändern des Programmspeicher ist aber auch gefährlich, denn wenn etwas schief geht ist wenn es ganz dumm läuft das Programm gecrasht. Geht auch nicht mit allen PICs. Zum Zugriff auf das EEPROM (und dem Programmspeicher) findest du die vorgehensweise im jeweiligen Datenblatt und EEPROM zugriff. Das ganze incl. Codebeispiel. Beim PIC16F887 zum Bleistift ab seite 113. Als Ergänzung hier auch mal Codeschnipsel die ich gerade aus einem Jahrealten Programm von mir gezogen habe. (Eine Morsebake wem das was sagt) Dort stand ein zu morsender Text im EEPROM, einmal mit PC Anwendung eingestellt, beim Einschalten wurde der dann jeweils ins RAM Kopiert und im programmierten Abstand gemorst. ISt nicht die eleganteste Lösung aber funktioniert. auf jeden Fall. Im Ergebniss hast du dann eine Kopie des eingestellten EEPROM Bereiches im RAM
1 | ; Hier werden die Daten ins RAM Kopiert |
2 | ; Die Daten stehen dann später ab Adresse Im Ram |
3 | |
4 | movlw 0x30 ; Variablen |
5 | movwf zähl ; mit Vorgabewerten |
6 | movwf FSR ; Initialisieren |
7 | movlw 0x00 |
8 | movwf e2prom ; EEPROM Adresse 0 Vorladen (erste Speicherzelle |
9 | |
10 | lesen |
11 | bsf PORTB, 6 ; Debug LED an |
12 | movf e2prom, 0 |
13 | call EERead |
14 | incf e2prom, 1 |
15 | movwf INDF |
16 | incf FSR, 1 |
17 | bcf PORTB, 6 ;Debug LED aus |
18 | |
19 | decfsz zähl, 1 |
20 | goto lesen |
21 | |
22 | ;************************************************************ |
23 | ;* SUB EEREAD |
24 | ;* Inhalt der Zelle deren Adresse in W steht nach W kopieren |
25 | ;*********************************************************** |
26 | EERead |
27 | BSF STATUS, RP0 ; EEADR liegt in der Bank 1 |
28 | MOVWF EEADR ; schreibe die Adresse in EEADR |
29 | BSF EECON1, RD ; EEPROM Leseprozeß starten |
30 | MOVF EEDATA, W ; Die Daten der EEPROM Zelle nach W |
31 | incf EEADR, 1 |
32 | BCF STATUS, RP0 ; Bank 0 |
33 | return |
34 | end |
Einen Code mit Schreibzugriff müsste ichjetzt raussuchen, sind alle auf der alten Archivplatte. Steht aber alles ausführlich im Datenblatt. Einen kompletten Code für eine LED Matrix mit Tastenabfrage und Table REad habe ich auch noch, aber den müsste ich auch noch raussuchen, kann ich aber gernem machen, den gibts aber dann nur per Mail. Zur Umsetzung allegemein: Du musst ja folgende Daten Speichern und Anzeigen: 1x Wo sind die Schiffe, Wo wurde getroffen, wo wurde danebengechossen. Eine DUO Led reicht dafür ja aus, wenn dir der Unterschied zwischen den drei Farben reicht. (Z.B. Grün-"noch kein Schuss", GrünRot "DANEBEN" und ROT "Treffer") Im "Programmiermodus halt nur ROT für die Schiffe) Oder man nimmt für "unprobiert" Grün und schaltet bei einem Nichttreffer die LED ganz aus, dann könnte man am ende des Spiels die nichtgetroffenen Schiffsteile von den Getroffenen abziehen. Gefällt mir fast noch besser! Das könnte man so machen: Die jeweiligen LED Farben betrachtet man als getrennte Matrixen, also so als würde man für Rot und Grün (oder gelb..) eine eigene Matrix bauen. Den Inhalt dieser Matrixen bildet man im Speicher dann in Tabellen nach. Dazu brauchst du dann noch eine Tabelle in der die Schiffe abgelegt sind. Ich würde das dann als erste Idee so verwirklichen das ich Spaltenzahl so lege das ich acht, (oder ein ganzes Vielfache von acht habe).Habe ich zum Beispiel zum einstieg nur acht Spalten, dann stellt je ein Bit eine LED dar. Meine Tabellen haben dann jeweils soviele Bytes wie ich Zeilen habe. In der ersten Tabelle speichere ich dann die Position der Schiffe. (0kein Schiff, 1 hier ist ein Teil von einem Schiff) Tabelle zwei enthält die ungetesteten Felder (1 Ungetestet, 0= Schuss), tabelle drei = Treffer. Im eigendlichen Programm schließlich hast du dann zwei Teile, einmal die Eingabe und berechnung der Spielzüge, quasi den Spielablauf - und die Darstellung des Bildschirms. Ich würde im Spiel dann die Tastenabfrage und kontrolle der Ergebnisse/Manipulation der Tabellen in einer Schleife laufen lassen. Daneben würde ich den internen Timer mittels Vorteiler so auslegen das alle paar ms ein Interrupt ausgelöst wird. In der Interruptschleife wird dann jeweils die nächste Zeile deines "multiplexbildes" gechrieben. Wie oft nun der Interrupt ausgelöst wird hängt von deiner MAtrix ab. Hast du mehr als 8 Spalten, dann sind deine Tabellen jeweils ein Bypte pro 8 Spalten (* Zeilen) groß. Wird ein Spielzug gemacht, dann wird zuerst überprüft ob der Wert für dieses Feld noch in der "FREI" TABELLE gesetzt ist (Grüne LED noch an?). Ist er das nicht, so ist der Zug ungültig, ist der Wert aber noch gesetzt wird dieser nun gelöscht - Anschließend wird in der Schiffstabelle geprüft ob dieser Wert dort gesetzt ist. Ist er das dann wird auch der der Wert in der Trefferdatenbank gesetzt. Am ende des Spiels kann dann die Anfrage der nichtgetroffenen Felder dadurch realisisert werden das einfach alle Felder der "Grün" Tabelle mit den Feldern der Schifftabelle VerODERt werden (Ergebniss dann in die ROT Tabelle eintragen). Alternativ könnte man natürlich auch eine Spaltenanzahl von 4*X als sinnvoll annehmen und die Werte für "Rot" und "Grün" jeweils im oberen und unteren Nibble unterbringen. Die Positionstabelle für die Schiffe kann man dann genauso aufbauen wobei dann jeweils ein Nibble leer bleibt, oder man rechnet die um. ISt aber nur ein Vorschlag zur Realisierung! Sicher gibt es noch andere Wege und Ideen! Gruß Carsten
Vom 16F84 kann ich nur abraten, das ist der Urvater aller Flash-PICs. Statt des 16F628 würde ich zum 16F886/887 raten, der hat neben 8 kWord Flash vor allem mehr RAM (368) und mehr EEPROM (256) als der 16F826, der auch schon 8 Jahre auf dem Buckel hat. Und die vielen Pins des 16F887 sind bei "Schiffe versenken" auch nicht zu verachten.
usuru schrieb: > Vom 16F84 kann ich nur abraten, das ist der Urvater aller Flash-PICs. > > Statt des 16F628 würde ich zum 16F886/887 raten, der hat neben 8 kWord > Flash vor allem mehr RAM (368) und mehr EEPROM (256) als der 16F826, der > auch schon 8 Jahre auf dem Buckel hat. Und die vielen Pins des 16F887 > sind bei "Schiffe versenken" auch nicht zu verachten. Also grundsätzlich hast du natürlich recht, der 16F887 IST der mit mehr Möglichkeiten. Vom TE (eher von der TEin?) ist deshalb ja ausdrücklich auch der 16F887 als Zielprozessor vorgesehen. Der 16F84 soll anscheinend nur für erste Gehversuche dienen. Ich habe jetzt einfach mal vermutet, das dies evtl. entweder aufgrund des wesentlich geringeren Kaufpreises oder dem geringeren Hardwareaufwand so vorgesehen war. Immerhin kostet der 887 je nach Händer das doppelte bis das dreifache vom F84. Das tut schon weh wenn man dem Schrottet. Daher meine Empfehlung für den 16F628. Der ist Pinkompatibel mit dem F84, das anscheinend schon vorhandene erste Testsystem kann ohne Änderung weiterbenutzt werden, der Code muss auch nur minimal verändert werden und er ist auch noch billiger als der F84, damit deutlich billiger als der F887. Gruß Carsten
> Immerhin kostet der 887 je nach Händer das doppelte bis das > dreifache vom F84. ????? Reichelt-Preise von heute (DIP-Gehäuse) 16F84A-20 3.15 16F628-20 2.75 16F887 2.65
Erstmal vielen Dank an Carsten für diese schnelle und ausführliche Antwort. Den PIC16F84A habe ich nur zur Probe benutzt, da ich zum ersten Mal mit einer LED-Matrix und somit mit dem Multiplexing arbeite. Anfangs hatte ich auch leider nicht die erforderliche Software um den PIC16F887 zu brennen. Nun habe ich zwar die Software und auch schon ein Testprogramm geschrieben, bei der jede LED der Reihe nach kurz aufleuchtet, allerdings wird am PORTB nichts ausgegeben. Im Datenblatt steht zwar eine Initialisierung für den PORTB, doch will die einfach nicht funktionieren. Irgendwas mach ich da wohl noch falsch. Die Größe der Matrix hatte ich zuerst mit 9x9 LEDs realisiert, hinzukommend jeweils eine extra Reihe und Spalte für die Curser-LEDs (Beim 16F84A eine 3x3 LED-Matrix + Cursor-LEDs). Die Matrix habe ich nun allerdings auf 8x8 LEDs (+ Cursor-LEDs) reduziert, da es mit einem Byte (8 Bit) pro Spalte, bzw. Reihe leichter ist. Für die Eingänge (rechts, runter und bestätigen) benutze ich PORTE,0 bis PORTE,2. Die Reihen (Koordinate A-H) habe ich mit dem PORTD bestimmt. Für getroffen (rote LEDs / Koordinate 1-8) den PORTB und für Wasser (grüne LEDs / Koordinate 1-8) den PORTC. Von PORTA benutze ich nur Bit 0 und 1 für die Cursor-LEDs. Die Idee mit den Tabellen finde ich super, allerdings wüsste ich nicht genau wie ich das zu programmieren habe. Es wäre sehr nett, wenn du mir den Programmausschnitt schicken würdest. MfG circle
> Nun habe ich zwar die Software und auch schon ein > Testprogramm geschrieben, bei der jede LED der Reihe nach kurz > aufleuchtet, allerdings wird am PORTB nichts ausgegeben. Im Datenblatt > steht zwar eine Initialisierung für den PORTB, doch will die einfach > nicht funktionieren. Irgendwas mach ich da wohl noch falsch. Ein Problem weniger. Das mit PORTB habe ich nun doch noch hinbekommen (Google sei Dank XD). =) MfG circle
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.