Forum: Projekte & Code uAC Consolenfunktionalität


von Thomas W. (lodentoni)


Lesenswert?

Ich hatte eine kleine RS232 Console benötigt, einfach um eine 
Benutzer-Controller Schnittstelle zu bekommen. Für den Fall, das noch 
ein anderer so etwas gebrauchen kann, hab ich das ganze ins Wiki 
gestellt (UAC Mikrocontroller ASCII Console).

Kurz die Features:
-Kann auf beliebigen Controllern eingesetzt werden.
-definierbarer New-Line-String und Prompt
-Kommandozeilen Befehle können in die uAC "eingehangen" werden.
-Beliebig viele Kommandos können eingetragen werden.
-Befehle können beliebige Parameter empfangen (argc,args).
-Implementierung einer mini-printf-variante (%i,%s,%c,%u)
-Variabler Anpassung um einen Kompromiss zwischen Speicherplatz und 
Komfort zu finden

Falls das ganze auf Interesse stößt kann ich es noch weiter ausbauen 
(Doku oder Programm).

MfG

von Rene B. (themason) Benutzerseite


Lesenswert?

@Thomas

Ich habs zwar noch nicht getestet aber der Sourcecode sieht schonmal 
sehr gut aus. Auch die Möglichkeiten die du eingebaut hast (History, 
Erkennung auf doppelten Historyeintrag usw) find ich gut.
Einziges Manko (wie ich finde) : Du baust dir die Befehlsliste dynamisch 
auf, und das braucht eben sehr viel RAM. Kleiner Vorschlag dahingehend :
Nimm einen Satz feste Befehle (die dann im FLASH definiert sind, und 
über pgm_read_byte o.ä. im StringCompare verglichen werden) und einen 
Satz dynamische Befehle. So bist du noch flexibel, kannst aber 
gleichzeitig bei immer gleich bleibenden Befehlen RAM einsparen. Wenn du 
nichts dagegen hast würd ich mir das ein oder andere bei dir Abgucken 
für meine uShell bzw meinen Parser.
Ansonsten echt sehr schön gemacht. Weiter so. Gefällt mir (selbst wenn 
ich mir schon selbst ne Console zusammengeklöppelt habe :-))

von Thomas W. (lodentoni)


Lesenswert?

Hallo Rene,

freut mich dass dir der code etwas bringt. Natürlich kannst du ihn 
verwenden oder ausschlachten wie du möchtest. Ich habe nicht vor 
irgendeine Lizenz daran zu knüpfen.

Zur Befehlsliste:
Richtig dynamisch bau ich sie nicht zusammen. Die Befehle liegen in 
einem struct von fest definierter Länge. Jeder Eintrag benötigt nur 2 
Zeiger (einen auf einen String und einen auf die auszuführende 
Funktion). Das sollten 4 Byte pro Befehl sein. Ich denke das ist 
verkraftbar. Nerviger ist da der Puffer für ausgehende Zeichen.

Von dem pgm_read_byte habe ich bisher noch nie etwas gehört. So wie ich 
das verstehe kann man damit Bytes aus dem Flash lesen. Was genau soll 
denn dann im Flash liegen? Die Funktion selbst ist ja bereits da. So wie 
ich den Compiler (avr-gcc) verstanden habe, Belässt er Zeichenketten 
auch im Flash und speichert sie nicht zusätzlich im RAM ab. In der 
Befehlsliste kopiere ich mir ja auch nicht die Zeichenketten. Ich hol 
mir ja nur nen Zeiger darauf.

MfG

von Rene B. (themason) Benutzerseite


Lesenswert?

Zeichenketten (und auch sonstige Daten) die ohne PROGMEM gekennzeichnet 
sind liegen im RAM (und logischerweise auch im Flash). Z.b. :

char text1 [] = "string im flash und RAM";
char text2 [] PROGMEM = "string nur im flash";

Daher ist es sinnig pgm_read_xxx zu verwenden. Erschwert das ganze aber 
auch z.T.
Aber bei dir würd ich in der Datenstruktur für die Befehle evtl ein Flag 
mit reinnehmen wo man unterscheidet ob es aus dem RAM oder dem Flash 
kommt. Das erlaubt dir einerseits feste Befehle, wie dynamische Befehle 
:-). Die Überprüfung bzw verwendeten Stellen können dann ja wahlweise 
mit pgm_read_byte arbeiten oder eben "normal" :-)

Schau dir vllt auch mal meinen Parser an :

Beitrag "uParse - die zweite."

von Thomas W. (lodentoni)


Angehängte Dateien:

Lesenswert?

Endlich hatte ich mal wieder etwas Zeit mich mit dem uAC Projekt zu
beschäftigen:

Ich hab eine neuere Version von uAC anzubieten. Es gab einen Bug bei der
Zahlenausgabe, der ist jetzt behoben. Des Weiteren sind die Funktionen
in Kleinbuchstaben umbenannt (ist sonst nervig). Außerdem kann die
uac_print() jetzt auch float bzw. double.

Das mit den Zeichenketten im Flash abspeichern verstehe ich irgendwie
nicht. Hast du eine Literaturempfehlung. Ich habs auf der Seite von
avr-gcc probiert bin dort aber nicht richtig fündig geworden.

MfG

Link: 
http://www.mikrocontroller.net/articles/UAC_Mikrocontroller_ASCII_Console

von Rene B. (themason) Benutzerseite


Lesenswert?

Schau mal hier im AVR-GCC Tutorial nach.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Speicherzugriffe

Das Ausgangsproblem liegt darin :

Der AVR hat eine Harvard-Architektur was bedeutet das der Programm und 
Datenspeicher über GETRENNTE Adress und Datenbusse angesprochen wird. 
Demnach kann man nicht wie in einem klassischen von Neumann System den 
gesamten Speicher linear durchadressieren, sprich das RAM und ROM (bzw 
Flash) im selben Speicher liegen. Dadurch benötigt man für Zugriffe auf 
den Programmpeicher spezielle Befehle.
Wenn du in C programmierst werden Daten die nicht mit einem PROGMEM 
gekennzeichnet sind erst ins RAM kopiert. Danach kannst wie du es 
gewohnt bist darauf zugreifen. So "arbeitet" ein printf z.b. beim 
Formatstring NUR mit Daten aus dem RAM. Ein printf_P holt sich den 
Formatstring NUR aus dem Flash (wohlgemerkt nur den Formatstring). Da 
das RAM aber sehr schnell voll ist (gerade wenn man viele Zeichenketten, 
Tabellen oder sonstige Daten hat), ist es sinniger die fixen Daten (die 
sich ja nicht mehr ändern sollen zur Laufzeit) im Flash zu belassen und 
eben nicht erst ins RAM kopieren (zu lassen) und dann damit zu arbeiten. 
Und genau das bewirkt das PROGMEM. Ein Verhindern des Kopierens der 
Daten vom Flash ins RAM. Zugreifen kannst du dann nur (dadurch das es 
zwei völlig von einander unabhängige Speicher sind) über die 
pgm_read_xxx Funktionen bzw Funktionen mit dem Zusatz "_P".
Hoffe ich habe es einigermaßen erklären können.

von Thomas W. (lodentoni)


Lesenswert?

Alles klar.

Ich hab mir das mal durchgelesen und habe erste Experimente positiv 
abgeschlossen. Mein Fehler beim ersten Mal war, das ich "static" nicht 
angegeben habe. Dadurch hatte es nicht funktioniert und ich dachte ich 
hätte etwas flasch verstanden.

Ok, du schlägst also vor das user interface so zu gestalten, dass man 
quasi einmal eine uac_print() und einmal eine uac_print_flash() funktion 
definiert? Eine andere Variante hätte ich auch nicht auf lager. Man 
könnte höchstens ein define machen, dass entscheidet ob die uac_print() 
den string aus dem ram oder dem flash liest. Das hätte aber den 
Nachteil, dass im ganzen Programm nur eine Variante verfügbar wäre.

Vielen Dank!
Thomas

von Rene B. (themason) Benutzerseite


Lesenswert?

Jups. Das ist mein Vorschlag :-))

Bei einem printf machen auf einem AVR beide Funktionen (also den 
Formatstring aus dem RAM oder dem Flash zu benutzen) sinn.
Bei Systemen die entweder von-Neumann-Architektur haben, oder aber in C 
transparent auf den Flash/RAM zugreifen können obwohl es getrennte 
Speicherbereiche sind wäre das nicht nötig.
Vllt noch ne kleine Anregung für die Namensgebung :
Häng bei der "Flash"-Funktion einfach ein _P an. Also das du 
"uac_print(f)" und "uac_print(f)_P" hast. Dann kann man ganz normal mit 
printf "runtertippen" und beim umstellen auf deinen uAC einfach ein uac_ 
vor jedem printf schreiben (ich gestehe ich würd es ohnehin über ein 
#define machen um nicht alle printf's ersetzen zu müssen :-))

Über ein define welches entscheidet ob du aus dem RAM oder Flash liest 
wäre in der tat nicht so gut. Vor allem wenn sich dein Formatstring 
ändert bzw du Text aus dem RAM ausgeben möchtest. Man kann dann zwar 
immer noch mit einem festen String "%s" arbeiten, aber es ist einfacher 
nur uac_printf (textimram) anzugeben als uac_printf (PSTR ("%s"), 
textimram).

von Thomas W. (lodentoni)


Lesenswert?

Ok, ich habe deine Vorschläge alle berücksichtigt und sie in der Version 
0.3 eingebaut: 
http://www.mikrocontroller.net/articles/UAC_Mikrocontroller_ASCII_Console

Nochmals vielen Dank für deine Tips und Anregungen

MfG
Thomas

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
Noch kein Account? Hier anmelden.