RS232 mit cc65


  • schnucke
  • 1048 Aufrufe 20 Antworten

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • RS232 mit cc65

    Hallo, jetzt geht es weiter mit cc65 für die RS232.
    Wo gibt es dort ein Beispiel für Daten senden über die serielle Schnittstelle.
    Dieses unten möchte ich gerne in cc65 so umsetzen, das es läuft. Finde aber den cc65-Befehl "open/close" nicht :

    Quellcode

    1. 10 rem *************** einstellungen steuer-register
    2. 20 br=6: rem 300 baud
    3. 30 db=0: rem 8 daten bits
    4. 40 sb=0: rem 1 stopp-bit
    5. 50 rem *************** einstellungen befehlsregister
    6. 60 hs=0 : rem rem 3-draht
    7. 70 ua=0 : rem vollduplex
    8. 80 pa=0 : rem keine parität - keine
    9. 100 rem ************** einstellungen allgemein
    10. 110 lf=2 : rem logische dateinummer
    11. 120 ga=2 : rem geräteadresse der rs-232-schnittstelle
    12. 130 sa=0 : rem sekundäradresse
    13. 200 open lf,ga,sa, chr$(br+db+sb) + chr$(hs+ua+pr)
    14. 220 for a=65 to 70
    15. 225 for b=0 to 1000
    16. 226 next b
    17. 230 print#2,chr$(a);
    18. 240 next a
    19. 250 close 2
    Alles anzeigen
  • Wie wird eine Struct aufgerufen?

    Die "serial.h" sieht so aus:

    Quellcode

    1. #ifndef _SERIAL_H
    2. #define _SERIAL_H
    3. /*****************************************************************************/
    4. /* Data */
    5. /*****************************************************************************/
    6. /* Baudrate settings */
    7. #define SER_BAUD_45_5 0x00
    8. #define SER_BAUD_50 0x01
    9. #define SER_BAUD_75 0x02
    10. #define SER_BAUD_110 0x03
    11. #define SER_BAUD_134_5 0x04
    12. #define SER_BAUD_150 0x05
    13. #define SER_BAUD_300 0x06
    14. #define SER_BAUD_600 0x07
    15. #define SER_BAUD_1200 0x08
    16. #define SER_BAUD_1800 0x09
    17. #define SER_BAUD_2400 0x0A
    18. #define SER_BAUD_3600 0x0B
    19. #define SER_BAUD_4800 0x0C
    20. #define SER_BAUD_7200 0x0D
    21. #define SER_BAUD_9600 0x0E
    22. #define SER_BAUD_19200 0x0F
    23. #define SER_BAUD_38400 0x10
    24. #define SER_BAUD_57600 0x11
    25. #define SER_BAUD_115200 0x12
    26. #define SER_BAUD_230400 0x13
    27. /* Data bit settings */
    28. #define SER_BITS_5 0x00
    29. #define SER_BITS_6 0x01
    30. #define SER_BITS_7 0x02
    31. #define SER_BITS_8 0x03
    32. /* Stop bit settings */
    33. #define SER_STOP_1 0x00 /* One stop bit */
    34. #define SER_STOP_2 0x01 /* Two stop bits */
    35. /* Parity settings */
    36. #define SER_PAR_NONE 0x00
    37. #define SER_PAR_ODD 0x01
    38. #define SER_PAR_EVEN 0x02
    39. #define SER_PAR_MARK 0x03
    40. #define SER_PAR_SPACE 0x04
    41. /* Handshake settings. The latter two may be combined. */
    42. #define SER_HS_NONE 0x00 /* No handshake */
    43. #define SER_HS_HW 0x01 /* Hardware (RTS/CTS) handshake */
    44. #define SER_HS_SW 0x02 /* Software handshake */
    45. /* Bit masks to mask out things from the status returned by ser_status.
    46. * These are 6551 specific and must be mapped by drivers for other chips.
    47. */
    48. #define SER_STATUS_PE 0x01 /* Parity error */
    49. #define SER_STATUS_FE 0x02 /* Framing error */
    50. #define SER_STATUS_OE 0x04 /* Overrun error */
    51. #define SER_STATUS_DCD 0x20 /* NOT data carrier detect */
    52. #define SER_STATUS_DSR 0x40 /* NOT data set ready */
    53. /* Error codes returned by all functions */
    54. #define SER_ERR_OK 0x00 /* Not an error - relax */
    55. #define SER_ERR_NO_DRIVER 0x01 /* No driver available */
    56. #define SER_ERR_CANNOT_LOAD 0x02 /* Error loading driver */
    57. #define SER_ERR_INV_DRIVER 0x03 /* Invalid driver */
    58. #define SER_ERR_NO_DEVICE 0x04 /* Device (hardware) not found */
    59. #define SER_ERR_BAUD_UNAVAIL 0x05 /* Baud rate not available */
    60. #define SER_ERR_NO_DATA 0x06 /* Nothing to read */
    61. #define SER_ERR_OVERFLOW 0x07 /* No room in send buffer */
    62. #define SER_ERR_INIT_FAILED 0x08 /* Initialization failed */
    63. #define SER_ERR_INV_IOCTL 0x09 /* IOCTL not supported */
    64. /* Struct containing parameters for the serial port */
    65. struct ser_params {
    66. unsigned char baudrate; /* Baudrate */
    67. unsigned char databits; /* Number of data bits */
    68. unsigned char stopbits; /* Number of stop bits */
    69. unsigned char parity; /* Parity setting */
    70. unsigned char handshake; /* Type of handshake to use */
    71. };
    72. /*****************************************************************************/
    73. /* Code */
    74. /*****************************************************************************/
    75. unsigned char __fastcall__ ser_load_driver (const char* driver);
    76. /* Load and install a serial driver. Return an error code. */
    77. unsigned char __fastcall__ ser_unload (void);
    78. /* Uninstall, then unload the currently loaded driver. */
    79. unsigned char __fastcall__ ser_install (void* driver);
    80. /* Install an already loaded driver. Return an error code. */
    81. unsigned char __fastcall__ ser_uninstall (void);
    82. /* Uninstall the currently loaded driver and return an error code.
    83. * Note: This call does not free allocated memory.
    84. */
    85. unsigned char __fastcall__ ser_open (const struct ser_params* params);
    86. /* "Open" the port by setting the port parameters and enable interrupts. */
    87. unsigned char __fastcall__ ser_close (void);
    88. /* "Close" the port. Clear buffers and and disable interrupts. */
    89. unsigned char __fastcall__ ser_get (char* b);
    90. /* Get a character from the serial port. If no characters are available, the
    91. * function will return SER_ERR_NO_DATA, so this is not a fatal error.
    92. */
    93. unsigned char __fastcall__ ser_put (char b);
    94. /* Send a character via the serial port. There is a transmit buffer, but
    95. * transmitting is not done via interrupt. The function returns
    96. * SER_ERR_OVERFLOW if there is no space left in the transmit buffer.
    97. */
    98. unsigned char __fastcall__ ser_status (unsigned char* status);
    99. /* Return the serial port status. */
    100. unsigned char __fastcall__ ser_ioctl (unsigned char code, void* data);
    101. /* Driver specific entry. */
    102. /* End of serial.h */
    103. #endif
    Alles anzeigen



    Mein Programm sieht so aus zur Zeit :

    C-Quellcode

    1. #include <stdio.h>
    2. #include <time.h>
    3. #include <conio.h>
    4. #include <cbm.h>
    5. #include <stdlib.h>
    6. #include <serial.h>
    7. int main()
    8. {
    9. struct ser_params z;
    10. z.baudrate=SER_BAUD_300;
    11. z.databits=SER_BITS_8;
    12. z.stopbits=SER_STOP_1;
    13. z.parity=SER_PAR_NONE;
    14. z.handshake=SER_HS_NONE;
    15. ser_open(???);
    16. cgetc();
    17. }
    Alles anzeigen


    Wenn ich diese Struct :

    struct ser_params {
    unsigned char baudrate; /* Baudrate */
    unsigned char databits; /* Number of data bits */
    unsigned char stopbits; /* Number of stop bits */
    unsigned char parity; /* Parity setting */
    unsigned char handshake; /* Type of handshake to use */
    };

    mit : ser_params.baudrate=SER_BAUD_300; anspreche, wird es nicht compiliert, nur wenn ich vorher die Struct umbenenne :

    struct ser_params z;

    und dann diese Werte reinsetze:

    z.baudrate=SER_BAUD_300;

    wird das Programm compiliert.

    Wie wird jetzt diese Struct aufgerufen aus meinem Programm :
    ser_open (const struct ser_params* params);

    Mit "ser_open(z);" wird es wieder nicht umgesetzt bzw compiliert:

    Wer kann weiterhelfen?

    mfg
  • Ich kenne mich mit dem CC65 nicht so aus. Aber es sieht eigentlich ganz easy aus:


    Du musst die Struktur deklarieren und befülen und dem open übergeben. Etwa so:

    Quellcode

    1. const struct ser_params k = {SER_BAUD_300, SER_BITS_8, SER_STOP_1, SER_PAR_NONE, SER_HS_NONE};
    2. ser_open ((const struct ser_params*)&k);
    Letztlich ist alles nur Illusion
    Es gibt hier nichts von Bedeutung
  • Ist im Emu VICE.
    Im Basic wird die serielle Schnittstelle in Vice 2.1 wunderbar angesprochen und funktioniert.
    Im cc65 gibt es noch Schwierigkeiten. Dort gibt es 2 Rs232-haeder, einmal "rs232.h" und die "serial.h".
    Bloss in der rs232.h stimmen die einzelnen Werte-Zahlen für den c64 nicht um die Schnittstelle anzusprechen.

    Ein Beispiel für die baudrate:
    rs232.h > #define RS_BAUD_300 0x03
    serial.h >#define SER_BAUD_300 0x06

    Also 2 verschiedene Angaben...hmmm..

    Der Wert 0x06 ist gemäss Wiki richtig für 300 baud.


    mfg
  • Irgendwie ist der seriell treiber nicht aktuell: c64-swlink.ser

    Hallo sauhund, kannst du irgend wie mal rausbekommen ob der Treiber vom cc65 aktuell und funktionsfähig ist.

    Oder wie kann man das in ASM umsetzen, ich meine dieses "open ...., print#2 usw... :

    Quellcode

    1. 10 rem *************** einstellungen steuer-register
    2. 20 br=6: rem 300 baud
    3. 30 db=0: rem 8 daten bits
    4. 40 sb=0: rem 1 stopp-bit
    5. 50 rem *************** einstellungen befehlsregister
    6. 60 hs=0 : rem rem 3-draht
    7. 70 ua=0 : rem vollduplex
    8. 80 pa=0 : rem keine parität - keine
    9. 100 rem ************** einstellungen allgemein
    10. 110 lf=2 : rem logische dateinummer
    11. 120 ga=2 : rem geräteadresse der rs-232-schnittstelle
    12. 130 sa=0 : rem sekundäradresse
    13. 200 open lf,ga,sa, chr$(br+db+sb) + chr$(hs+ua+pr)
    14. 210 print#2,chr$(65);
    15. 220 close 2
    Alles anzeigen
  • Habe ich hier mal versucht, nur einen wert "65" ausgeben, wenn ich das Programm starte, wird kein Wert an die serielle Schnittstelle ausgegeben sondern nur 1 "A" auf dem Bildschirm .

    Das einfache Beispiel in Basic :

    200 open 2,2,0, 6 : rem chr$(br+db+sb) + chr$(hs+ua+pr) ergibt als Summe den Wert "6"
    210 print#2,chr$(65);
    220 close 2

    Wer kann weiterhelfen?

    Quellcode

    1. !to "rs232.prg",cbm
    2. *=$c000
    3. start
    4. lda #2
    5. ldx #2
    6. ldy #0
    7. jsr $ffba
    8. jsr $ffc0
    9. lda #1
    10. ldx #<(befehl)
    11. ldy #>(befehl)
    12. jsr $ffbd
    13. ldy #0
    14. lda puffer,y
    15. jsr $ffd2
    16. lda #2
    17. jsr $ffc3
    18. rts
    19. befehl: !byte 6 ; chr$(br+db+sb) + chr$(hs+ua+pr) ergibt als Summe den Wert "6"
    20. puffer: !byte 65
    Alles anzeigen

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von schnucke ()

  • Wenn ich mir das ROM Listing des C64 so anschaue, dann sehe ich dass es schon gehen müsste mit standard open/close/bsout.

    Du setzt die Geräteadresse korrekt mit jsr $ffba und erreichst so das RS232 Open auf $f409, aber du vergisst den Dateinamen:

    Quellcode

    1. FFBA 4C 00 FE JMP $FE00 ; set file parameters
    2. FFBD 4C F9 FD JMP $FDF9 ; set filename parameters



    Setze den Open String in deinen Assembler Code (.byte data) und übergib die Adresse in X/Y und die Länge im AC. Danach jsr $FDF9 und gut.

    Der Filename ist chr$(br+db+sb) + chr$(hs+ua+pr), nur damit wir uns richtig verstehen ... :winke:
    Letztlich ist alles nur Illusion
    Es gibt hier nichts von Bedeutung
  • Geht noch nicht, oder habe ich deine Hilfe falsch verstanden ?

    Der Filename ist chr$(br+db+sb) + chr$(hs+ua+pr), nur damit wir uns richtig verstehen

    Der Filename ist ja der Wert 6, der sich aus der gesamten Summe ergibt, oder müssen da 2 Werte stehen, ohne die beiden chr$ zu addieren? chr$(br+db+sb) ergibt "6" und chr$(hs+ua+pr) ergibt "0".
    Oder muss das irgendwie als Text gesetzt werden?

    Schau doch mein Code nochmal durch und verbesser ihn mal.

    Danke.

    mfg


    Quellcode

    1. !to "rs232.prg",cbm
    2. *=$c000
    3. start
    4. lda #2
    5. ldx #2
    6. ldy #0
    7. jsr $ffba
    8. lda #1
    9. ldx #<(befehl)
    10. ldy #>(befehl)
    11. jsr $fdf9
    12. ldy #0
    13. lda puffer,y
    14. jsr $ffd2
    15. lda #2
    16. jsr $ffc3
    17. rts
    18. befehl: !byte 6
    19. puffer: !byte 65
    Alles anzeigen
  • In Basic ergibt das einen String der Länge 2. chr$(65) + chr$(66) ist dasselbe wie "AB". Es müsste also in etwa so aussehen:

    Quellcode

    1. lda #2
    2. ldx #<(befehl)
    3. ldy #>(befehl)
    4. jsr $fdf9
    5. ldy #0
    6. lda puffer,y
    7. jsr $ffd2
    8. lda #2
    9. jsr $ffc3
    10. rts
    11. befehl: !byte 6, 0
    Alles anzeigen
    Letztlich ist alles nur Illusion
    Es gibt hier nichts von Bedeutung
  • Geht noch nicht.
    Der Wert wird als "A" auf dem Screen ausgegeben.

    Hier eine komische Sache:

    Quellcode

    1. 200 open 2,2,0,chr$(6)+chr$(0)
    2. 220 for a=65 to 70
    3. 225 for b=0 to 1000
    4. 226 next b
    5. 230 print#2,chr$(a);
    6. 240 next a
    7. 250 close 2


    Das Basicprogramm läuft oben und gibt den Wert über die serielle Schnittstelle aus, aber wenn ich dieses :
    "200 open 2,2,0,chr$(6)+chr$(0)"durch "200 open 2,2,0,6,0" ersetze, passiert das gleiche bei im ASM-Progamm, es werden die Buchstaben nur auf dem Screen ausgegeben.
    Also muss es doch eine Möglichkeit geben chr$(6)+chr$(0) in ASM durchzuführen.

    !byte geht nicht, !text "60" und !text "6","0" geht auch nicht. Wird zwar compiliert, aber wird immer der Buchstabe auf dem Screen ausgegeben.


    mfg
  • Hallo sauhund, kannst du irgend wie mal rausbekommen ob der Treiber vom cc65 aktuell und funktionsfähig ist.


    an der stelle würde ich empfehlen mal auf der cc65 mailingliste zu fragen... die rs232 treiber wurden zu irgendeinem zeitpunkt mal komplett überarbeitet, daher kommen auch die zwei unterschiedlichen header files die du gefunden hast ... eins davon ist veraltet. ist aber schon viel zu lange her das ich damit rumgemacht hab als das ich mich an details erinnern würde :)
  • Diddl schrieb:

    Die serielle Unterstützung im C64 ist rein durch Software umgesetzt, der C64 hat keinen UART (6551).

    Die standardmäßige Unterstützung: Ja, nur per Software.

    Es gibt allerdings auch Module, die einen 6551 nachbilden. VICE 2.1 kann das auch. In WinVICE im Menü per: Settings / Cartridge I/O Settings / ACIA settings, dann "Enable ACIA".

    Allerdings funktionieren damit die Kernel-Routinen nicht mehr, man muss den 6551 per Hand programmieren. Die Zuverlässigkeit ist es aber wert!

    Gruß,
    Spiro
  • Wer kann mir mal meinen Code oben als ASM zum laufen bringen.

    Ich bekomme es nicht hin. Habe schon zig mal das ASM-File umgestellt, die "jsr" vertauscht.
    Ich weiss auch nicht genau, in welcher Reihenfolge das alles aufgerufen werden muss.

    Kann das mal als Lauffähig erstellt werden.

    Der ASM-Code ist ja nicht lang, bekomm es nicht gebacken.
    Die ganze choose läuft unter Basic mit dem Vice hervorragend.


    Danke.

    mfg
  • Jetzt erscheint der Buchstabe nicht mehr auf dem Screen, gesendet über die serielle Schnittstelle wird er auch nicht.
    Hmm...., woran liegt das.

    Habe alle erdenklichen Vorschläge eingearbeitet. Oder ist da noch ein Fehler drin?

    Kann das einer mal bitte von Null an Erbauen von meinem ASM-Code?

    Danke.

    mfg
  • schnucke schrieb:

    Oder ist da noch ein Fehler drin?


    Ja, aber einer, den ich selbst erst länger suchen mußte. Der Debugger in VICE hat mich dann letztendlich weitergebracht.

    Quellcode

    1. ; !to "rs232.prg",cbm
    2. *= $c000
    3. start
    4. lda #2
    5. ldx #2
    6. ldy #0
    7. jsr $ffba
    8. lda #2
    9. ldx #<(befehl)
    10. ldy #>(befehl)
    11. jsr $ffbd
    12. jsr $ffc0
    13. ldx #2
    14. jsr $ffc9
    15. ldy #0
    16. lda puffer,y
    17. jsr $ffd2
    18. jsr $ffcc
    19. ; Warten auf das Senden aller Zeichen im Puffer (ausser des letzten)
    20. WaitForLastChar
    21. lda $029d
    22. cmp $029e
    23. bne WaitForLastChar
    24. ; auf Senden des letzten Zeichens warten! (50ms - reicht bei 300bps und höher, bei weniger könnte es was knapp sein)
    25. ldx #50
    26. loop
    27. jsr $eeb3 ; etwa 1 ms warten
    28. dex
    29. bne loop
    30. lda #2
    31. jsr $ffc3
    32. rts
    33. befehl: !byte 6,0
    34. puffer: !byte 65
    Alles anzeigen


    Das relevante hier ist die zusätzliche Wartezeit, die ich durch die Schleife um Loop herum aufbaue.

    Der KERNAL des C64 wartet nämlich nicht, bis das aktuelle Zeichen gesendet wurde. Stattdessen wird beim CLOSE einfach die Übertragung mittendrinnen abgebrochen - IMHO ein klarer Bug des KERNALs.

    Dir wäre das möglicherweise aufgefallen, wenn du mehr als ein Zeichen senden willst - dann wären nämlich wohl die ersten durchgekommen, aber hinten einige weggefallen.

    Meine obige Warteschleife um 50ms, die ich ergänzt habe, muss nur einmal, vor dem Schließen des Kanals, kommen - also nicht etwa zwischen den Zeichen.

    Wenn jemand eine Möglichkeit kennt festzustellen, ob die RS232-Übertragung fertig ist: Bitte melden! Auf die Schnelle habe ich nichts gefunden... Bei mehr als einem Zeichen kann man testen, ob $029D und $029E gleich sind - falls nicht, dann gibt es noch mehr als ein Zeichen zu lesen. Das mache ich in ab WaitForChar oben - obwohl es bei *diesem* Beispiel keinen Sinn macht, sondern nur dann, wenn mehr als ein Zeichen zu senden ist.

    In BASIC fällt das Problem übrigens nicht auf, weil BASIC "langsam genug" ist, so dass die notwendige Verzögerung immer da ist.

    HTH,
    Spiro
  • Man...,oh....man...., Danke, es funktioniert. :roll2:

    Da wär ich nie im Leben drauf gekommen. Soweit wäre ich nie in dem Sumpf eingestiegen.

    Danke für deine unerbittliche Prüferei.

    mfg

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von schnucke ()