PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : FIFO Ringbuffer



michi8725
30.03.2005, 07:14
Hallo zusammen ich hab folgendes Problem:

Also ich habe ein CCS Compiler mit dem PIC 18F452 und ich brauche für diesen einen FIFO ich weiss aber nicht wie ich diesen realisieren muss. Also als erstes wüsste ich gerne ob der irgend wie Hardware mässig in einem PIC integrierrt ist oder man den rein Software mässig realisiert?
Ich brauche einen Struct oder ein Variabelnfeld der ein Zuganscode(dem Zugangscode der max. int16 ist ) mit folgenden Daten verknüpft: dem Datum und der Zeit verknüpft.


Das Datum und die Zeit werden mit diesem void ausgelesen :




void rtc_get_date(BYTE& day, BYTE& mth, BYTE& year, BYTE& dow) //Void






rtc_get_date(day,mth,year,dow) //Das ist die funktion fürs auslesen

und die Zeit mit:



void rtc_get_time(BYTE& hr, BYTE& min, BYTE& sec) // Void

rtc_get_time(hr,min,sec) // Funktion für die Zeit




So und dann noch ein Bit ob dieser Benutzer einen Alarm ausgelöst hat.

Dann sollten die letzten 50 Benutzer über RS232 ausgeben werden etwa so


Benutzer:..................Datum:................. ...Zeit:..................... Alarm:
-----------------------------------------------------------------------------------
98457998................16.05.2005.............17. 30 Uhr..............Nein
45235345................16.05.2005.............17. 00 Uhr..............Nein
34523452................14.05.2005.............12. 30 Uhr..............JA
32454567................13.05.2005.............09. 30 Uhr..............Nein


Also so ungefähr sollte das Aussehen kann mir da jemand weiterhelfen? Hab schon n paar theaders gelesen aber bin noch nicht so ganz schlau draus geworden.

Gruss Michael

Mobius
30.03.2005, 08:18
Also, ich weiß nicht ganz, was du mit FIFO meinst (auch google hat nicht wirklich etwas ausgespuckt...). Ich schätz mal, es ist ein Sicherheitssystem (oder etwas in der Art).
Wenn du in CCS arbeitest, kannst du Structs erstellen und musst dich nicht mit dem Assembler herumschlagen. Dann erstellst du ein Array mit 50 solchen Structuren und füllst diese auf (für eine Structur brauchst du 9 Bytes + 1 bit, also werden es ~450 Bytes all in all; vielleicht musst die das Array spalten, damit es in die Memory-Banken passen). Der PIC18F452 verfügt über einen RS232-Schnittstelle, über welchen du:

a) Einfach die Daten, getrennt durch ein ;/#/etc. an den PC schickst, der dann diese Daten schön ausgibt.
b) die ganze Tabelle schön ausgibt indem du errechnest, wie viele Punkte, Striche, etc. du brauchst.

Bei einem Frequenz von 40MHz/4 müsste diese Errechnung kein Problem sein.

Leider hab ich noch nie mit dem CCS gearbeitet (ich mach mir nicht die Mühe, die spezifischen Befehle zu erlernen, wenn das Demo schon nach 30 Tagen abläuft und ich ca. die Hälfte der Zeit mit Lernen herumschlage).

MfG
Mobius

P.S.: Also, das Thema wäre im PIC-Forum besser aufgehoben, aber egal ^^

vish
30.03.2005, 08:50
Hallo!

Ich hab zwar von PICs keine Ahnung, dafür weiß ich was FIFO bedeutet! ;)
Und zwar ist FIFO eine Abkürzung für First In, First Out.
Wenn man also zum Beispiel ein Byte an erster Stelle im Speicher speichert, wird man dieses Byte auch als erstes wieder auslesen müssen.

Grüße,
Jonas

30.03.2005, 08:55
FIFO heisst first in first out. Das gibt ein Protokoll in dem immer die letzten 50 User die sich angemeldet haben speichert. Das heisst also wenn sich nun 50 Leute angemeldet haben kommt der 51 an die erste stelle und alle rutschen eins nach, wobei der sich als 1 angemeldet hat rausfliegt. Man kann das natürlich mit einem überschreiben machen und alle werte im speicher um eine Position überschreiben, was jedoch hohe Rechenleistung benötigt. Die elegantere Lösung ist da der FIFO auch Ringbuffer genannt der Speichert das ganze in einem Virtullen Ring der mit 2 Zeigern die erste und letze Position angibt ... nur ich weiss nicht wie ich das im C umsetzen muss :) und wie dann die ganze Liste über RS232 ausgeben. Das ist mein Hauptproblem.

PIC Forum hmm ja das wärs wohl hab ich irgendwie übersenen ;)

30.03.2005, 08:56
Ok Jonas du warst wohl schneller ;)

eFFex
30.03.2005, 09:13
wie wärs mit nem array [of structs, in denen deine Daten drinne stehen].
Dann noch ne int: pointer. diese zeigt immer auf das zuletzteingefügte Array-field, wenn neue daten reinsollen, pointer +1 und diese arrayfeld nehmen, falls pointer = 50 pointer = 0, fertig!
Ausgabe:
wenn du den pointer (oder besser einen anderen, da bleibst konsistenter) einmal durchwandern lässt von "aktueller pointer" +1 bis aktueller pointer (mit dem Übergang bei pointer = 50 => pointer = 0, werden alle DAten in Eingabereihenfolge ausgegeben.
Soviel zum Ringpuffer, zur seriellen Ausgabe kann ich dir nciht viel sagen.

Mobius
30.03.2005, 09:27
falls pointer = 50 pointer = 0, fertig

Naja, dann hast das Problem, dass der neuste Eintrag plötzlich an erster Stelle steht. Eleganter ist:


if(pointer==50)
for(int i=0;i<50;i++)
{
array[i]=array[i+1];
}
array[50]=new_val;

Wir schieben alle Einträge einz nach unten und ersetzten den letzten Eintrag mit dem neuen Wert.

@Ringbuffer: Achso... Naja, man lernt nie aus :D... Ist ein interessant Konzept. Also, Hardwaremäßig ist in einem PIC sowas net verankert. Bleibt nur die softwaremäßige Lösung. Ich hab mal ein wenig gesucht. Vielleicht hilft dir diese (http://www.zeiner.at/c/ringbuffer.html)Seite ein wenig weiter... Eigentlich ist es nichts anderes, als du zwei Laufvariablen hast, die durch das Array laufen (einer liest, der andere schreibt). Wenn die schreib/lese-Variable den maximalen Wert erreicht wird sie auf null decrementiert und sie läuft wieder von forme los.
Dabei hast du das oben beschriebene Problem, dass plötzlich der neuste Eintrag am Anfang steht (meist kein Problem, aber es macht einige nervende Sort-Probleme). Ansonsten köntest du eine 3. Variable einführen, die den ältesten Eintrag enthält. Wenn die Schreibe-Variable überläuft, musst du diese oldest-Var um eins (1) incrementieren und immer im Kopf behalten, dass, wenn du die Sachen ausliest, immer bei dieser anzufangen.


MfG
Mobius

michi8725
30.03.2005, 09:53
Hat ein Arry nicht in jeder Zeile gleichviele Zeichen? Weil ich brauch ja für den Zuganscode ca. 8 Zeichen, für den Tag,Monat, und Wochen Tag 2 Zeichen u.s.w. es wäre ja Speicherverschwendung wenn ich dann für alle 8 Zeichen reserviere. Der Pointer wäre dann ja trozdem ein INT?

eFFex
30.03.2005, 10:33
@mobius:
und was soll dran schlimm sein, wenn am Anfang der zuletzt eingefügte Eintrag steht?
Bei deinem Ansatz macht man für Anzahl der Elemente > 50, in jedem Einfügeschritt 50 Arrayzugriffe, was vlt etwas aufwendig ist.
Sortieren muss man ja nichts, da man sich die Daten ja wie oben von mir beschrieben in Einfügereihenfolge ausgeben lassen kann.
@michi
Also du hast ein struct in dem es eben die felder (zugangscode, datum, alarm) gibt. Von diesen Structs ist in jedem Arrayfeld eins gespeichert.
Der Pointer gibt die Nummer vom Arrayfeld an.
Bsp: Arraygröße 3
-volles Array
pointer=3
A[0]=(12345,01.03.2005,no)
A[1]=(23456,03.04.2005,yes)
A[2]=(34567,04.04.2005,no)
-neues Element hinzufügen:
pointer erhöhen => pointer = 3
pointer = Arraygröße!!! => pointer = 0
Array nach einfügen in A[0]
A[0]=(45678,01.05.2005,yes)
A[1]=(23456,03.04.2005,yes)
A[2]=(34567,04.04.2005,no)
Prinzip verstanden?

michi8725
30.03.2005, 10:38
Ja prinzip ist klar danke nur versteh ich noch nicht ganz wie ich das Array/Struct definieren muss. Also das Struct ist das selbe wie Array?

Mobius
30.03.2005, 10:44
Naja, alle Elemente eines Arrays sind gleich groß, da kannst du nicht viel machen. Bei dem Zugangscode kannst du ein Byte in low und high teilen (d.h. ein Byte enthält dann 2 Zeichen des Zugangscodes), dann brauchst du "nur" 4 Bytes um den ganzen Code abzuspeichern.
Beim Datum kannst du nicht viel sparen, außer, wenn du die low-Bytes des Jahres weglässt (also statt 2004 nur 04 abspeichern). Um diese 4 Bytes kommt man nicht umhin.
Für die Zeit brauchst du 2 Bytes (Minute, Stunde).

Das wären insgesammt 10 Bytes, bei 50 Einträgen ergiben sich 500 Bytes. In einem PIC18F452 hast du 1536 Bytes frei. Also nimmst du damit "nur" 1/3 des vorhandenen Speichers in Anspruch.

naja, als Pointer würde ich die "Anfangs-" und "Endszeichen" nicht bezeichnen. Weil in C ein Pointer die Andresse einer Memoryblockes beinhaltet. Eher als Laufvariable.

Naja, wie du in C eine Structur in ein Array haust:


#define MAXCOUNT 50

struct DATA
{
char ID76;
char ID54;
char ID32;
char ID10;

char day;
char month;
char year;

char hour;
char minute;
}data;

data Daten[MAXCOUNT];



MfG
Mobius

michi8725
30.03.2005, 15:49
ok noch eine andere Frage. Ich habe einen DTMF-Decoder der hat 4 Anschlüsse an denen der Wert angegeben wird und ein Controll anschluss der ist high wenn ein neuer Ton dedektiert wurde.

also wird ein Ton detektiert z.B. die 1 dann sieht das so aus:

Q4----Q3----Q2-----Q1----Std Taste
-0------0-----0-------1------1-- 1
-0------0-----1-------0------1-- 2
... bis
-1------0-----1-------1------1-- *
-1------1-----0-------0------1-- #

Wie soll ich das Lösen wenn ich 4 Zahlen hintereinander so einlesen muss und dann zu einem INT (4 Stellen) zusammen setzen muss? Die # Taste soll als eingabe bestätigung gelten. Wie kann ich das lösen? habt ihr irgend welche vorschläge wie ich das Programmieren könnte in C?

gruss michael

PS: schon mal vielen Dank an die die mir bis her so weitergeholfen haben.

Mobius
30.03.2005, 16:59
Also, ich nehm mal an, das Auslesen der Tasten ist kein Problem (also TRICx richtig setten, auslesen, etc.).

Wenn du nun eine Zahl eingelesen hast, musst du deine vorherigen mit 10 multiplizieren und die neue Zahl hinzuaddieren (zum Beispiel, hast du in dein TR 2 eingegeben, dann sag ma 5:

2

2*10 = 20

20+5 =25

genau, wie es dein TR ausschreibt :D)



short alle_zahl=0;

void addchar(char chara)
{
if(alle_zahl==0)
{
alle_zahl=chara;
return;
}
alle_zahl=alle_zahl*10+chara;
}


Wenn du dann ein # bekommst (die "Codierung" dafür kennst du ja), musst du nur noch die Zahl in deinem Byte mit deinem Pincode (etc.) vergleichen.

Hier habe ich absichtlich ein "short" (also 16 bit Variable) verwendet, weil die größe von ints von Compiler zu Compiler verschieden definiert wird (ich habe schon welche gesehen, die als int 16 bits genommen haben, aber auch einen, der 32 bits dafür reserviert hat). :)

MfG
Mobius

P.S.: Was wird darauß, wenn ich fragen dürfte? Weil die Neugierde bringt mich langsam echt um. Ein System mit Zugangskontrolle und Zahlenschloss, schätz ich mal. ^_^

30.03.2005, 17:56
Natürlich also es gibt eine "intelligente" Türsteuerung. Also die Code eingabe erfolgt über die Tastatur des eigenen Handys man muss natürlich die Tastentöne einstellen aber praktisch jedes Handy hat diese DTMF Töne. Man hält das handy einfach vor das kleine Microphon und gibt den code ein. Es gibt einen Mastercode mit dem man neue Codes hinzufügen kann löschen und den RTC stellen. Geführt wird der Benutzer über einen Lautsprecher der Ihm anweisungen zum Bedienen gibt. Der Microcontroller steuert einen Sprachspeicher auf dem diese Anweisungen gespeichert sind. Der sprachspeicher wird entweder über das Microfon das ich auf der Platine plaziert hab oder über einen normalen audio eingang (Soundkarte CD Player oder was auch immer) gefüllt. Da jeder Benutzer einen eigenen Zugangscode haben soll können spezielle nachrichten/begrüssungen ausgegeben werden. Ach ja und eben die Liste mit der 50 Letzten Zugangscodes kann ja noch über RS232 ausgegeben werden. ICh hab jetzt noch überlegt direkt ein menü über RS232 auf den PC auszugeben, das man auch so über den PC (Hypertreminal) gesteuert werden kann, sprich codes hinzufügen und löschen. Nur meine programmierkenntnisse kommen langsam aber sicher an die grenze.

Ich hab jetzt 2 Platinen fertigen lassen, wenn du interesse hast mit zumachen würd mich natürlich freuen.

Gruss Michael

Mobius
30.03.2005, 19:06
Hört sich echt interessant an, doch muss ich leider verneinen, auch wenn ich Lust hätte mitzuhelfen. :( Leider steht die Abi vor der Tür und alles ist stressig bis zum geht-nicht-mehr. Es ist jetzt schon echt knapp mit meinem Hobby und dem Büffeln, da wäre so ein Projekt leider keine Erlösung.

MfG
Mobius

30.03.2005, 20:53
Tja schade vieleicht hat sonst jemand interesse ;)

FoCus
16.04.2005, 19:01
Meine Güte stellt euch doch nicht so an! ;-)
Bei einem Ringbuffer werden Daten in einen Speicherbereich geschrieben, wobei während des Befüllens gleichzeitig auch ein Lesen erlaubt ist. Kritische Punkte stellen dabei der Randpunkt, das obere Ende des Speichers und das „Überholen“ des Auslesezeigers, sowie das Auslesen, über den Speicherrand dar. Erreicht der Schreibezeiger das Ende, muss am Anfang weitergeschrieben werden. Erreicht der Lesezeiger das Ende, muss eine zusammengesetzte Zeichenkette zurückgegeben werden. Überholt der Schreibzeiger den Lesezeiger, muss dieser auf den nächsten gültigen Eintrag weitergesetzt werden, bevor eingefüllt werden kann!
Sowas in c zu schreiben stellt nun nicht wirklich ein Problem dar oder?!
In deinem Fall würdest du halt fixe Blockgrössen nehmen, dann tust du dir auch beim Berechnen des Weitersetzens leichter. Der Speicher sollte nach Möglichkeit ein Vielfaches der Grösse der Struktur sein.
Mit einem Array zu arbeiten ist die andere, meines Erachtens nicht so hübsche Methode, da du sonst so abhängig von der Struktur bist. Wenn du blanken Speicher nimmst kannst du im Prinzip alles Reinschreiben. Als Leseparameter einfach nur einen Datenblock mit Grösse rein und beim Lesen eben einen Block mit bestimmter Grösse rauslesen.
==> Wiederverwendbarkeit ;-)

Noch eine Alternative ist:
Du verwendest in deiner Struktur magic Cookies. Die kann man dann leicht im Speicher finden. Stichwort Überschreiben des Auslesezeigers..


Gruss
Michael

PS: Gott war der Beitrag schon alt =)