gesucht: Assembler-Routine für UART mit 1Mbps

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

    • gesucht: Assembler-Routine für UART mit 1Mbps

      Hallo Bascomer,

      habe folgende Nuss zu knacken:
      Mit einem Atmega8 und internem 8MHz Takt möchte ich an Port D0 (UART RxD) kontinuierliche Daten aus einem externen SDR-Empfänger einlesen und auf einem LCD-Modul mit I2C-Anschluss darstellen. Die Darstellung von Analogwerten auf dem 4x20 Zeichen LCD-Modul funktioniert in einem BASCOM-Programm bereits bestens. Zusätzlich sollte die am UART-Port eingelesene Frequenz ebenfalls angezeigt werden. Dazu sollte diese per Assembler-Unterprogramm letztendlich in einer Variablen landen. Versuche mit BASCOM-Befehlen waren bis dato negativ, da BASCOM vermutlich die 1Mbps-Daten zu langsam einliest und daher nur teilweise und falsch darstellt.

      Das SDR-Modul sendet die eingestellte Frequenz (10 kHz - 150 MHz) alle 200ms im 5 Byte-Modus und mit 1 Mbps Datenrate in folgendem Format:
      die ersten 4 Bytes stellen die eingestellte Frequenz dar und zwar im Binär-Format mit dem LSB als erstes Byte. Das letzte (5.) Byte dient als Rx/Tx indicator (0x80 = Tx und 0x00 = Rx).
      Beispiel der Hex-Bytefolge 1-4 für die Frequenz 1MHz = 1.000.000 Hz
      0x40, 0x42, 0x0F, 0x00
      Nach dem Einlesen der 4 Bytes soll durch eine Umwandlungs-Routine der Binärwert (hier: "11110100001001000000") errechnet und in einer Variablen (z.B. FRQ) abgelegt werden.
      Mit
      Frequenz = Binval(FRQ)
      und
      Locate 4 , 1 : Lcd " F: " ; Frequenz
      kann die Variable "Frequenz" auf dem LCD angezeigt werden.

      Leider bin ich kein ausgebuffter Assembler-Spezi und hoffe, dass sich hier jemand findet, der das gesuchte Assembler-UP vielleicht schon in der Schublade liegen hat und hier postet. Bin für jeden Tip dankbar.

      Mit vielen Grüssen aus dem Badnerländle
      Rolf
      Wissen ist Macht, nix wissen macht auch nix.
    • Hi,
      mit einem ATmega8 wird das nicht gehen.
      Bei 8MHZ hat der laut Datenblatt (S.163 bei der Version die mir vorliegt) max. 250kbs. Und das bedeutet noch nicht, das es funktioniert. Stichwort "Fehlerrate"...
      Hatte das Problem selbst. ATmege256 16Mhz hats dann geschafft.
      Aber welches Protokoll haben die gesendeten Bits? RS232 heißt 8 Datenbits n-Stopbits und n-Paritätbits.
      Oder meinst du Protokollloses Bit-Banging? Das könnte (ohne UART-Funktionalität) bei 200ms Telegramm-Abstand gehen.
      cu zipp

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

    • Also Bascom liest die Daten nicht zu langsam ein, die Daten liest (hoffentlich) dein HW Uart ein. Läuft der denn mit der Hardware oder doch als Soft routine?
      Als Software wird das wahrscheinlich eher nix. Zeig mal ein Testprogramm von dir wie du die 5 Byte einliest und direkt auf dem Display anzeigen würdest, ohne grosses gerechne.
      Auch das I2C Display kann zu langsam sein wenn es nicht als HW läuft. Warum assembler wenn wahrscheinlich ein selbst gestricktes problem ist.

      Tobias

      p.s. ...natürlich hat die Forumssoftware mal wieder meine Antwort gefressen :thumbdown:
    • Hallo Rolf,
      ich habe mir mal simple Programme geschrieben.
      Eines schreibt den Wert 1.000.000 auf den UART mit 1MHz und erhöht den Wert in einer Schleife.
      Das zweite liest den UART mit 1MHz ein und gibt den Wert binär und in Hex auf das LCD aus.
      Beide Controller laufen mit 8MHz interner Osc.
      Das funktioniert ganz sauber.

      BASCOM-Quellcode

      1. $regfile = "m16def.dat"
      2. $crystal = 8000000 ' used int osc frequency
      3. $baud = 1000000
      4. $hwstack = 100
      5. $swstack = 100
      6. $framesize = 100
      7. Dim Freq As Long
      8. Freq = 1000000
      9. Do
      10. Waitms 200
      11. Printbin Freq
      12. Incr Freq
      13. Loop
      14. End
      Alles anzeigen

      BASCOM-Quellcode

      1. $regfile = "m8adef.dat"
      2. $crystal = 8000000 ' used int osc frequency
      3. $baud = 1000000
      4. $hwstack = 100
      5. $swstack = 100
      6. $framesize = 100
      7. Config Lcd = 20 * 2 'configure lcd screen
      8. Config Lcdpin = Pin , Db4 = Portc.3 , Db5 = Portc.2 , Db6 = Portc.1 , Db7 = Portc.0 , E = Portc.5 , Rs = Portc.4
      9. Dim Freq As Long
      10. Do
      11. Inputbin Freq
      12. Locate 1 , 1 : Lcd Bin(freq)
      13. Locate 2 , 1 : Lcd Hex(freq)
      14. Loop
      15. End
      Alles anzeigen

      Im Moment sehe ich noch nicht, wo dein Problem liegt.
    • Hallo Bascom-Gemeinde,

      zunächst mal vielen Dank an alle für die Antworten.
      Als Input-Port habe ich den Hardware-UART-Port vom Atmega8 verwendet.
      Das Prog-Beispiel von Guenther war sehr hilfreich.
      Da ich ein 4x20 I2C-Display verwende, habe ich es wie folgt übernommen:

      BASCOM-Quellcode: UART-Testprogramm

      1. $regfile = "m8adef.dat" 'Atmega8A config data
      2. $programmer = 19 'USBASP-Programmer
      3. $prog &HFF , &HC4 , &HD9 , &H00 ' generat Fuse Bits, CLK 8MHz intern
      4. $crystal = 8000000 'intern 8MHz clock
      5. $hwstack = 100
      6. $swstack = 100
      7. $framesize = 100
      8. $baud = 1000000
      9. $lib "YwRobot_Lcd_i2c.lib" 'I2C Lib for 4x20 LCD Display
      10. Config Pinb.0 = Output 'PA on/off
      11. Config Pinb.1 = Output 'SDA
      12. Config Pinb.2 = Output 'SCL
      13. Config Pinb.3 = Output 'PA Power on/off
      14. Config Pinb.4 = Output 'Prog Pin 9 MISO
      15. Config Pinb.5 = Output 'Prog Pin 7 SCK
      16. Config Pinb.6 = Output 'Signal B-DIO5
      17. Config Pinb.7 = Output 'Signal A-DIO4
      18. Config Portc = Input '6x Analog-Input + Reset
      19. Config Pind.0 = Input 'OSA TxD
      20. Config Pind.1 = Input 'N.C.
      21. Config Pind.2 = Input 'OSA PTT-D2
      22. Config Pind.3 = Input 'S4 down
      23. Config Pind.4 = Output 'Signal C-DIO6
      24. Config Pind.5 = Output 'N.C.
      25. Config Pind.6 = Input 'S2 up
      26. Config Pind.7 = Input 'S3 ok
      27. Config Scl = Portb.2 'config I2C
      28. Config Sda = Portb.1
      29. Config I2cdelay = 1
      30. Config Lcd = 20 * 4
      31. Const Pcf8574_lcd = 78 'Address of I2C-LCD
      32. Dim Lcd_backlight As Byte '1 = on; 0 = off.
      33. 'Dim Freq As Dword
      34. Dim Freq As Long
      35. '######################## Program start
      36. Cls 'clear LCD display
      37. Cursor Off Noblink
      38. Locate 1 , 1 : Lcd " Test " 'Intro 1
      39. Locate 2 , 1 : Lcd " Interface 1.2 "
      40. Locate 3 , 1 : Lcd " (C) DJ7TH "
      41. Locate 4 , 1 : Lcd " Made in BADEN "
      42. Wait 2
      43. Cls
      44. Do
      45. Inputbin Freq
      46. Locate 1 , 1 : Lcd Bin(freq)
      47. Locate 3 , 1 : Lcd Hex(freq)
      48. Waitms 200
      49. Loop
      50. End
      Alles anzeigen
      ##################################

      Als Ergebnis wurde der Wert für Hex(freq) so angezeigt:
      bei 1MHz - 40000F420010 (erwartet habe ich 0x40, 0x42, 0x0F, 0x00)
      bei 2MHz - 80001E840100
      bei 3MHz - C0002DC60110
      bei 4MHz - 00003D091001

      Offensichtlich werden mehr als 5 Bytes gesendet und auch in einer mir unerklärlichen Reihenfolge. Das Auslesen der Frequenz arbeitet stabil, auch wenn man die Baudrate z.B. auf 999000 reduziert oder den Wert für "Waitms" variert oder auf Null setzt. Eine Baudrate grösser 1000000 ist nicht zulässig und wird vom Compiler angemeckert.

      Vielleicht hat jemand eine Erklärung für die eingelesenen Werte und eine Idee, wie man diese in eine lesbare Variable verwandelt, welche ich weiter auswerten kann, um eine vorhandene und funktionierende frequenzabhängige Filterumschaltung zu steuern.
      Wissen ist Macht, nix wissen macht auch nix.
    • Long sind aber auch nur 4 bytes. Probier doch mal sowas
      Inputbin ar(1) , 4 ' will fill 4 bytes starting at index 1, wobei du natürlich das array größer machen musst. Das ist jetzt aus der Hilfe heraus kopiert. Was kommt den dann an?
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • ich sehe da eher immer noch ein grumdsatzproblem: Du schreinst ja das die 5 byte alle 200ms ankommen, in deinem programm wartest du auch 200ms. Du weisst doch aber gar nicht wann genau die ersten Daten kommen und deine Verarbeitung dauert auch noch zeit die von den 200ms abgezogen werden müssen.

      Meiner Meinung nach ist es besser für den seriellen Port auf einen Interrupt umzusteigen, dann kannste anhand der 200ms Pause des Senders ja auch den beginn des neuen strings feststellen.
      Schau mal hier für Seriell int:
      halvar.at/elektronik/kleiner_b…art_rs232_vom_computer_2/

      Tobias
    • Was ich auch noch zum Bedenken gebe, die Anzeige auf das Lcd ist linksbündig. Wenn der neue Text angezeigt wird, können am rechten Ende noch Textteile vom alten evtl längerem Text befinden. Man sollte den alten Text vor dem Anzeigen von dem neuen Text mit entsprechend vielen Leerzeichen 'löschen'.
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • nach etwas Knobeln und Lesen der BASCOM-Hilfe (hätte ich gleich tun sollen) ist das Problem gelöst:

      Quellcode: 2. Teil Testprogramm UART

      1. Config Scl = Portb.2 'config I2C
      2. Config Sda = Portb.1
      3. Config I2cdelay = 1
      4. Config Lcd = 20 * 4
      5. Const Pcf8574_lcd = 78 'Address of I2C-LCD
      6. Dim Lcd_backlight As Byte '1 = on; 0 = off.
      7. Dim Freq As Long
      8. Dim Anf As String * 3
      9. Dim Anfhexval As Integer
      10. Dim Filter As Byte
      11. '######################## Program start
      12. Wait 1
      13. Cls 'clear LCD display
      14. Cursor Off Noblink
      15. Locate 1 , 1 : Lcd " Test " 'Intro 1
      16. Locate 2 , 1 : Lcd " UART "
      17. Wait 1
      18. Cls
      19. Do
      20. Inputbin , Anf , Freq
      21. Filter = 0
      22. If Freq > 1600000 Then Filter = 1
      23. If Freq > 4000000 Then Filter = 2
      24. If Freq > 8000000 Then Filter = 3
      25. If Freq > 12000000 Then Filter = 4
      26. If Freq > 18000000 Then Filter = 5
      27. If Freq > 25000000 Then Filter = 6
      28. Anfhexval = Hexval(anf)
      29. Locate 1 , 7 : Lcd " " 'clear Freq
      30. Locate 1 , 1 : Lcd "Freq: " ; Freq;
      31. Locate 2 , 1 : Lcd "ANF: " ; Anfhexval
      32. Locate 4 , 1 : Lcd "Filter-Nr: " ; Filter
      33. Waitms 200
      34. Loop
      35. End
      Alles anzeigen

      Entscheidend war die Entdeckung, dass an Anfang 3 mir unbekannte Bytes (meist mit dem Inhalt 0) gesendet werden, welche ich beim Einlesen per Inputbin mit dem String Anf abgefangen habe, um dann die nächsten 4 Bytes in die Long-Variable Freq einzulesen und auszuwerten. Das funktioniert bis zur Frequenz 2147.483.647 Hz problemlos, dann kehrt der Wert um ins Negative, typisch für eine Long-Variable (grins).

      Damit ist für mich der Fall auf recht einfache Weise gelöst, trotz diverser Unkenrufe und ich habe mir das Gehampel mit einem Unterprogramm in Assembler gespart, was vielleicht auch nicht verkehrt gewesen wäre.

      Mit sonnigen Grüssen aus dem Badnerländle
      Rolf
      Wissen ist Macht, nix wissen macht auch nix.

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

    • Und warum verwendest du nicht ein dword (statt long)? Deine Frequenz wird doch nie negativ, da musst du auch keinen negativen Zahlenraum verwenden.
      Raum für Notizen

      -----------------------------------------------------------------------------------------------------

      -----------------------------------------------------------------------------------------------------
    • Hi tschoeatsch,
      hast recht, mit Dword verdoppelt sich der positive Bereich. Vielen Dank für den Tipp. Habe ich gleich mal abgeändert.
      ich verwende in dieser Anwendung zwar nur Frequenzen bis ca. 500 MHz, aber man weiss ja nie, wann man es mit Bereichen über 2000 MHz zu tun hat. :D
      Wissen ist Macht, nix wissen macht auch nix.