- fchao-Sinus-Wechselrichter AliExpress         
Ergebnis 1 bis 10 von 29

Thema: Senden und empfangen auf dem UART mit ISR kompatibel zur bisherigen RP6lib

Baum-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #17
    Erfahrener Benutzer Roboter-Spezialist Avatar von RolfD
    Registriert seit
    07.02.2011
    Beiträge
    414
    Hallo Dirk,
    also was die testerei angeht... sobald du die lib anstelle der alten nutzt (überschreibst), werden alle Programme mit der neuen lib gebaut.
    Da alle alten Schreibfunktionen über Umleitungen geführt werden, sieht das für dich so aus als wenn du eben die alten Funktionen nutzt.. tatsächlich nutzt du aber schon neue...
    Das siehst du als Beispiel z.B. daran:
    Code:
    /**
     * compatibility implementation
     * Writes a null terminated string or buffer from SRAM to stdio.
     * Example:
     *            writeString("RP6 Robot System\n");
     */
    void writeString(char *string)
    {
        printf (string); //->stdio
    }
    Ein writeString("RP6 Robot System\n"); ruft also tatsächlich schon stdio funktionen auf... , nur merkst du bis auf den Init der stdio nichts davon. Wie man die Init anders löst überlege ich noch, ist aber für mich z.Z. eher eine marginale Frage, hab ich aber im Blick.

    Das bedeutet: Für alte Programme beim schreiben ändert sich nichts...

    Beim einlesen (readChar, readChars) benutzen die Funktionen NICHT die stdio... aber schon andere neue Programmteile der Lib.

    Das bedeutet: Für alte Programme beim lesen ändert sich nichts...

    Ergo.. man kann alle alten Programme mit der Lib compilieren ohne das man erst mal viel davon merkt. (Abgesehen von der Init)
    Hier noch mal zur Erinnerung die Init Sequenz, welche in die Main oder in die Hardwareinit der Unit.. oder ggf. noch früher geladen werden sollte:
    Code:
        static FILE uart_io = FDEV_SETUP_STREAM (uart_putchar, uart_getchar, _FDEV_SETUP_RW);
        static FILE uart_err = FDEV_SETUP_STREAM (uart_putchar, NULL, _FDEV_SETUP_WRITE);
        stdin = stdout = &uart_io;
        stderr = &uart_err;
        UART_Mode(UART_INIT);
    Im UART_RP6 Mode (in dem man sich nach der Init erst mal befindet) ändert sich auch nichts (aus Anwendersicht) gegenüber der alten Lib. Interessant wird das erst wenn man die anderen UART-Modi nutzen will.

    Da gibts zunächst die Binary Modi mit und ohne Echo, welche ALLE Zeichen von '\0x00' bis '\0xff' zuverlässig annehmen können müssen.. und diese im Echo mode (übrigends über stdio, also umlenkbar) auch wieder zurück werfen, vergleichbar mit einem Loop Back device. (kennt man aus brücken von rx/tx oder dem loopback bzw. pingen im Netzwerk) Mehr können die binary Modes auch erst mal nicht - ich hab jedenfalls z.Z. nicht vor irgendwelche Protokolle dafür zu schreiben. (was aber möglich wäre... von hexdump a la Intel bis TCP/IP ist da alles möglich)
    Um die binary Modes zu testen kann man nun einfach ein Terminal wie Realterm oder Zoc nehmen und direkt Daten senden.. bzw. sehen was zurück kommt. Realterm hat ja z.B. auch Zeichen/String Geneartoren, upload von files im Reiter "Send" usw....
    Man könnte z.B. auf dem PR6 eine Prüfsumme aus eingehenden Zeichen errechnen und diese anzeigen.. und diese Prüfsumme auch auf dem PC berechnen und dann vergleichen - es sollten gleiche Ergebnisse bei raus kommen... man kann aber auch einfach ein Binärfile zum RP6 im E-Modus schicken, das Empfangene widerum capturen und speichern und dann inhaltlich vergleichen.
    Es gibt sicher noch mehr Möglichkeiten Datenstöme beider richtungen messbar gegenüber zu stellen. Man kann aber auch einfach den Binary_Mode statt dem RP6_Mode benutzen. Technisch ist der RP6_Mode und der Binary_Mode für die Anwendung fast das Gleiche. Denn man kann mit "alten Funktionen" auch im Binary Mode arbeiten... man kann aber auch die "neuen" stdio Funktionen nutzen.

    Stdio und die UART_Modi haben nichts miteinander zu tun ausser das sie beide in einem File (uart.c) gleichzeitig bereitgestellt werden. Es geht also UART_RP6 mit stdio genau so wie UART_ASCI mit WriteString... Die UART Modi sind verwand mit der Technik wie man files öffnet und schließt... (binary mode, asci mode, schreibend, lesend, wahlfreier zugriff usw...)
    der UART_RP6 mode besagt nur, das er nicht die Sende-ISR nutzt.. und daher z.b. nicht xon/xoff fähig ist und auch weitere Dinge des ASCII Mode nicht unterstützt, dafür aber das Timing der alten Lib einhält. Der UART_Mode und die stdio haben sonst wenig miteinander zu tun.

    Kommen wir nun zum Punkt.. wie teste ich die Ascii modi. Dafür ist die uart.h wichtig zu verstehen/lesen.
    Nun zunächst mal ist der ASCII Modus wenn er per #define remakrt ist, ein Binärmodus in dem nichts passiert ausser das Zeichen gesendet und empfangen werden.
    Schaltet man ihn ein in dem man das Remark entfernt (// davor löschen) wird der Modus aktiv. Man betrachte sich.. am besten mit einem C-fähigen Editor wie notepad++ oder der Amtel Studio umgebung mal an wenn man die #ifdefs in der datei uart.c in der funktion uart_getchar() einklappt...
    Es werden also stück für stück code teile frei gegebn je nach dem wie man den ascii mode konfiguriert.

    Da xon/xoff nur mit einem ASCII Modus funktioniert (ASCII_Mode bedeutet auch, das nur druckbare Zeichen [->siehe macros isachar(), isanum(), usw..<-] verwendung finden, ggf. manchmal sogar nur 7-bit wertig sind), bauen wir uns ein Programm, welches in den UART_ASCII Mode schaltet .. etwa so.. UART_Mode(UART_ASCII); und aktivieren in der uart.h
    #define WENEEDTXXONOFF 1 // bremst die SendeISR auf Anforderung des Terminals
    #define WENEEDRXXONOFF 1 // bremst das fremde Terminal wegen Buffer voll
    falls da ein // vorstehen sollte. Es macht sinn da ein // vor zu stellen wenn man xon/xoff nicht braucht weil das code einspart. So wir haben jetzt xon/xoff in beiden richtungen aktiviert... da man es auch nur pro Richtung separat nutzen könnte...
    Das Programm sieht also bis jetzt so aus:
    Code:
        UART_Mode(UART_ASCII);
    
        uint16_t d;
    
        for (d=0;d<10000;d++)
           printf("RP6 Robot System termtest %d\n",d);
    Das führt jetzt zu einer Ausgabe von 9999 mal 'RP6 Robot System termtest ZAHL \n' untereinander... wenn man sein Terminal auf newlinemode stehen hat.. es könnte aber auch zu einem Versatz in der Ausgabe führen weil dem Terminal das \r in der Ausgabe fehlt. Schalten wir also noch das //#define WENEEDCRLF 1 // erzwingt crlf beim senden -> vorteilhaft bei ZOC/Realterm
    frei in dem wir die // entfernen. Alle anderen defines können remarkt (//) bleiben.

    So... läuft das Programm und man hat ein Terminal wie Realterm angeschlossen und - wichtig - das ebenfalls auf xon/xoff eingestellt sieht man die Zeilen durch rattern...
    drückt man nun strg-s, sendet man ein xoff cvhar an den rp6 und die Ausgabe bleibt stehen... man wartet.. und schickt ein xon mit strg-q .. läuft sie ansatzlos und ohne probleme weiter...
    Und schon hat man xon/xoff in Senderichtung getestet.

    Für den Receiver-xon/xoff muss man eine große! Datei an den RP6 schicken. Dazu geht man in realterm auf den Reiter "send" und trägt in der erste zeile vor dem button send numbers z.b.
    12345678901234567890 ein. Bei repeats etwas tiefer stellt man z.b. 1500 ein.. würde man nun auf send asci drücken, würde man dem RP6 30000 Zeichen aus der sich widerholenden Folge 123... usw. schicken. Da der RP6 nicht einfach so was annimmt, muss man ihm das bei bringen. Z.B. so:

    Code:
        int i=0,j=0,c,z=0;
        printf("RP6 Robot System termtest \n");
            while(1){
    //            delay_us(1000);
                c=getchar();
                z++;
                if (c=='r') z=0;
                if (c=='s') printf("\nTermtest %d chars\n",z);
                if (c=='q') break;
                if (i++>100) {
                    putchar('.');
                    i=0;
                    j++;
                }
                if (j>10) {
                    putchar('o');
                    j=0;
                    i=0;
                }
            }
    Nun.. was macht das Programm? Ich werde dafür kein Nobelpreis bekommen aber es holt chars, vergleicht diese gegen Buchstaben (r,s,q) und zählt ansonsten Zähler hoch bzw. setzt alle 100 Zeichen ein . und alle 1000 Zeichen ein o ins terminal. Startet man das, zeigt es auf Taste s den Zählerwert aller empfangenen Zeichen (incl. dem s), Taste r resettet den Zähler... und Taste q verlässt die Schleife. Nun was kann man damit machen? Wir drücken 5 mal hinter einander s.. und sehen \nTermtest 1 chars\n .. .\nTermtest 2 chars\n usw...
    Ok.. nun resetten wir den Zähler mit r .. verspielte Naturen drücken nochmals s um auch das zu prüfen.. usw...
    wir können aber nun die 30000 Zeichen aus dem Terminal Send-Reiter auf den RP6 loslassen. Die gelbe Lampe am RS232 Adapter leuchtet.. 30 sek später sie geht aus....
    wir drücken s und sehen \nTermtest 30001 chars\n.
    Ok.. der RP6 hat mal eben 30000 chars gelesen.. konnte er vorher mit der alten Lib auch.... aber jetzt ... produzieren wir Prozessorlast ! Viel davon... wir nehmen vor dem Delay das //weg.
    Was passiert? Nach jedem empfangenen Zeichen macht der Prozessor 1000us bzw. 1ms nichts ausser intensiv im Kreis laufen!
    Jetzt eine kleine Rechnung: 38400 Baud entsprechen fast 4000 Zeichen/pro Sek. Wenn ich bei jedem Zeichen 1 ms Pause mache kann ich im Bestfall 1000 Zeichen/sek empfangen. 4000 angebotene Zeichen ist aber deutlich mehr als max 1000 verarbeitbare Zeichen. Ergo... das Terminal überrent uns.. wäre da nicht der xon/xoff modus.. der das terminal bremst. Und mal eine Schätzung: Bei einem Verhältnis von 1:4 und einem Buffer von 32 byte dauert es wie lange bis ein normaler buffer wie in der ursprünglichen uart.c voll bzw. überlaufen ist? Genau.. ca. 40-50 Zeichen. bei 4000 Zechen/sek also ca. 100 mal die Sekunde... selbst mit einem 128er Buffer noch ca. 20 mal die Sek. Und das bei nur einer einzigen Millisekunde CPU Last pro Durchgang!
    Wir probieren das also aus.. und auch bei delay_us(2000);, delay_us(5000); oder delay_us(10000); kommen alle 30001 Zeichen immer zuverlässig an.. es dauert nur eben länger.
    Und schon haben wir den neuen xon/xoff Receiver erfolgreich getestet.
    Wer Spass daran hat kann das auch mal im RP6 oder Binary bzw. ohne xon/xoff mode testen... es kostet ja nur eine Zeile: UART_Mode(UART_RP6);
    Wenn in der aktuellen Fassung die LED3 auf dem M32 schnell blinkt, gabs einen Bufferüberlauf!

    Langer Rede, kurzer Sinn.. man könnte als Beispiel das Windows-Remotrol Programm z.B. auch mit xon/xoff Unterstützung bauen (unter windows muss man so ein Gedöns ja nicht erst komplett neu schreiben) und würde feststellen das man keine Zeichen mehr verliert und so ein quatsch wie "Hardbeats" nicht braucht.. oder man verbindet 2 Bots mittels bluetooth Radio an RS232 die miteinander reden .. ohne Zeichen zu verlieren.... ich glaub es gibt genug Ideen wie man das nutzen kann...
    Die Lib ist für Leute, die nur das (Zeilen)Terminal im Robotloader für Ausgaben nutzen eher weniger interssant. Spannend wirds da, wo ein "richtiges Terminal" wie Realterm oder ZOC zum Einsatz kommt (und man vernünftige Reaktionen vom Terminal bekommt) oder gar Bots mit Bots oder Computer mit Bots reden.
    Das eingebaute Robotloadertermial kann ja nicht mal xon/xoff ... wer aber dann sagt.. "brauch ich auch nicht" ... braucht sich meines Erachtens auch nicht über verlorene Zeichen, "bad Timings" und komische Reaktionen im eigenen Programm zu wundern.

    So.. erst mal genug... die anderen Dinge bin ich z.Z. selbst noch am testen... aber den ASCII Terminal Mode kann man z.B. auch am besten im Realterm testen...
    Dort könnte man z.B. mal ausprobieren, ob strg-d tatsächlich ein EOF sendet oder was weis ich...
    Man kann auch alle defines in der uart.h frei schalten.. nur verbraucht man dann evtl. Codesize, die man nicht braucht. Ein Terminal Mode mit edit Funktion ist für Leute die nur mit getchar arbeiten (readChar ist ja auch nichts anderes) jetzt nicht so interssant und ich glaube auch nicht, das jeder sofort ein Basic- oder noch besser ein Turtle-Interpreter schreiben würde. http://de.wikipedia.org/wiki/Program..._Python_Turtle
    (obwohl letzteres auf dem RP6 noch Sinn machen würde)

    Ich hoffe, ich konnte etwas weiter helfen.
    Es sei aber noch gesagt das die Lib vom Funktionsumfang.. also was sie können soll.. im groben schon so weit fertig ist.. es kommen also keine 1000 Änderungen um NEUES rein zu bringen... es kommen schlimmstenfalls nur noch 1000 fixes damit diese Lib das macht was als Funktionsziel abgesteckt ist.
    Und.. ich bin dankbar für jeden Hinweis auf verbesserungsfähige Dinge. Es gibt Dinge die kann ich (oder will ich) nicht umsetzen... z.B. einige ASCII Einstellunge für den UART_RP6 Modus.. da muss ich passen. Aber ich denke, das die lib genügend Möglichkeiten bietet .. auch im Zusammenarbeit mit weiteren Treibern ..., um der alten Lib nicht all zu lang nachzutrauern.

    Zu printf/scanf und den ganzen stdio Funktionen selbst gibts im Web genug Beispiele... allein die docu zur Winavr Lib wirft schon einiges aus.
    Die Lineinput Funktion ganz am Ende von uart.c ist z.B. aus einer IBM Docu zur stdio entnommen und nur geringstfügig angepasst.
    Man kann aber nun auch mal sowas angucken, umsetzen, lernen... die stdio gilt eigentlich als Grundlage für JEDEN Programmierer.
    http://www.programmingsimplified.com/c-program-examples

    Für weitere Geschichten in Zusammenhang von stdio und anderen Geräten muss ich erst weitere passende Treiber bauen.
    Ich werde wie schon gesagt als nächstes ein LCD Treiber für die M32 umsetzen, interssant wäre aber auch der schon besagte sound Treiber oder noch besser ein Treiber welcher Fileio auf dem internen eeprom (und damit auch ggf. als Prototyp für externe eeproms, sdcrads und andere Dateispeicher dienen kann) unterstützt.

    Neben der stdio über stdin, stdout und stderr gibt es z.B. durchaus Geräte, die stdio komaptibel über 2 Datenströme gleichzeitig gefahren werden.. quasi einem Datensteuerstom und einem Datendatenstrom. Oder 2 Datenströme. Die Frage ist dann nur, wie multiplext man 2 logische Verbindungen (evtl. sogar beide mit unabhängigen schreib und lese Funktion) über ggf. nur eine physische Leitung ohne großen Programmier- und Code Aufwand. Klingt sehr aus den Sternen gegriffen aber eine Kernfrage, wenn ich den TWI/I2C Treiber unter dem Aspekt der stdio noch mal angehen will.

    Gruß

    NACHTRAG_1:

    Es gibt da übrigends noch ein #define WENEEDRP6IO 1 ... irgendwann wenn alles fertig ist und man ein neues Projekt anfängt, wird man damit ALLE "alten Code Teile" auf ein Schlag abschalten KÖNNEN. Ob man.. und wer es.. dann tut, ist jedem selbst überlassen. Der Compiler optimiert zwar mit -o2 jetzt schon ungenutzte Programmteile weg aber das ist dann auch sowas wie "den inneren Schalter umlegen". Obwohl die Lib erst seid ein paar Tagen so läuft, arbeite ich inzwischen lieber mit der stdio (auch weil ich es als EDVler ... nicht ITler - das sind die mit Schlips und Studium welche c# als hardwarenahe Programmierspache lernen - gewohnt bin).

    NACHTRAG_2:

    Wer Speicher sparen muss/will, kann sich übrigends mit den Linkerflags: -Wl,-u,vfprintf -lprintf_min
    eine kleinere Version von der stdio printf laden, allerdings kann die wohl nur nur int und strings verarbeiten.
    Wer dagegen auch Support für float braucht, nimmt die Linkerflags: -Wl,-u,vfprintf -lprintf_flt -lm
    Im Atmel Studio ist per default die mittelgroße Lib ohne float aber sonst mit allem in den Linkereinstellungen
    vorgegeben, braucht man eine andere, nimmt man die bei Linkeroptions raus und trägt sich die andere bei
    Linker->Misc->Other Options von Hand ein. Default ist also: -Wl,-u,vfprintf
    Keine Ahnung ob sich noch jemand mit Makefiles rumschlägt aber das ist dort ggf. auch zu berücksichtigen.
    Die "min Version" spart etwa 1kb code ein, man nimmt sich aber doch einige wichtige konversionen damit.

    NACHTRAG_3:
    Eine wirklich gut gemachte Info Sammlung zum Thema Terminal ist auch folgendes:
    http://www-user.tu-chemnitz.de/~heha...l/terminal.htm
    Dort ist auch zu finden wie man z.B. xmodem, also ein altes(=erprobtes & weit unterstütztes) paketorientiertes Format für Binärübertragung auf Terminals einfach umsetzt.

    NACHTRAG_4:
    Falls jemand die stio selbst auch schon für eigene Zwecke erweitern möchte indem eigene Gerätetreiber dafür geschrieben werden, noch mal das Grundprinzip:
    Mit:
    Code:
        FILE *fp;
        fp = fdevopen(Streamlesefunktion,Streamschreibfunktion);
    oder mit
    Code:
        FILE *fp;
        static FILE stream = FDEV_SETUP_STREAM (Streamschreibfunktion, Streamlesefunktion, Modus); //Funktionsname ohne()
        fp=&stream;
    kann man sich ein Filehandle bauen, welches dann mit den stdio Funktionen angesprochen werden kann. 3 streams (stdin, stdout und stderr) sind dazu im System schon definiert, lassen sich aber überschreiben und man kann weitere Streams selbst anlegen.
    Code:
        fprintf(fp,"foobar");
    Der Modus ist dabei je nach Funktion _FDEV_SETUP_READ, _FDEV_SETUP_WRITE, oder _FDEV_SETUP_RW, Geräte von denen man z.b. nicht liest brauchen auch keine Streamlesefunktion, diese wird dann auf NULL gesetzt und der Modus auf _FDEV_SETUP_WRITE gestellt.
    Wichtig ist dabei eigentlich nur das die Funktionen, die den Stream verarbeiten auch alle "Spezialbefehle" können.. also als Beispiel interpretieren und Anwenden von Formatierungen wie (f)printf, im Gegensatz zu (f)puts, was einfach nur ein unformatierten String ausgibt.
    Sinn und Zweck ist eigentlich, die IO pro "Gerät" auf 2 Funktionen (in und out) zu bündeln und nicht mit 100 Spezialfuktionen irdendwas irgendwo im System zu verstellen. Statt mit einem Pseudocursor in einem LCD rumzuspringen und das LCD von Hand zu löschen kann man nämlich z.B. auch ganz einfach nach Ausgabe von \n das LCD automatisch löschen und/oder auf sonstige Steuerzeichen wie \t (tabulator) mit einem Zeilensprung reagieren. Dafür sind die Steuerzeichen immerhin mal aus gutem Grund erfunden worden - und zwar zu Zeiten als ein Kleiderschrank-großer Computer kaum mehr Speicher hatte als heute ein AMega32 Prozessor.
    Ob man nun von einem UART kilobyteweise Daten im Stream liest.. oder seine 5 Tasten mit einer Einlesefunktion versieht und die mit getchar anspricht, oder seine Sonarentfernungsmessung abfragt , ist dem Programm dann egal. getchar ist getchar...

    NACHTRAG_5:
    In der nächsten Version wird die M32 auf das empfangene BELL Zeichen hin ebenfalls piepen. Die Base kann das natürlich nicht.
    Dafür muss in der uart_getchar() der Bereich:
    Code:
                            case '\a': // BEL / strg-g
    #ifdef RINGSTRING
    #warning ASCII Modus Ersatz fuer das BELL Zeichen wurde mit compiliert
                                data='\x10'; // wenn RINGSTRING angegeben, ist das \a ungültig
                                if (tx_buff.uart_modus==UART_EASCII) printf (RINGSTRING); // stattdessen optisches Signal
    #endif
                            break;
    gegen:
    Code:
                            case '\a': // BEL / strg-g
    #ifdef RP6CONTROLLIB_H
                                sound(230,25,25); // wir laufen auf einer M32 also piepen wir auch
    #endif
    #ifdef RINGSTRING
    #warning ASCII Modus Ersatz fuer das BELL Zeichen wurde mit compiliert
                                data='\x10'; // wenn RINGSTRING angegeben, ist das \a ungültig
                                if (tx_buff.uart_modus==UART_EASCII) printf (RINGSTRING); // stattdessen optisches Signal
    #endif
                            break;
    ausgetauscht werden.

    Gruß
    Geändert von RolfD (11.05.2014 um 11:54 Uhr)
    Sind Sie auch ambivalent?

Ähnliche Themen

  1. IR Senden und Empfangen mit ATtiny
    Von bnitram im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 5
    Letzter Beitrag: 03.03.2012, 12:32
  2. Problem mit dem senden von Zeichen per UART
    Von KingTobi im Forum C - Programmierung (GCC u.a.)
    Antworten: 14
    Letzter Beitrag: 30.10.2008, 20:29
  3. Atmega32/STK500 -UART senden/empfangen klappt nicht
    Von Leuchtturm im Forum C - Programmierung (GCC u.a.)
    Antworten: 12
    Letzter Beitrag: 16.01.2007, 14:02
  4. Uart senden empfangen Interrups
    Von ronald im Forum AVR Hardwarethemen
    Antworten: 15
    Letzter Beitrag: 06.03.2006, 20:24
  5. UART ermöglicht Senden, aber kann nicht Empfangen
    Von batti112 im Forum C - Programmierung (GCC u.a.)
    Antworten: 3
    Letzter Beitrag: 18.09.2004, 15:05

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

fchao-Sinus-Wechselrichter AliExpress