Forum: Mikrocontroller und Digitale Elektronik UART läuft unter FreePascal nicht (Kein OutPut)


von Vam L. (vam_l)


Lesenswert?

Hallo liebe Gemeinschaft,

ich habe hier ein Älteres Programm, welches ich seit Jahren unter 
Code::Blocks verwende versucht in Lazarus umzuschreiben.

Soweit auch alles Klar, und wird auch alles ohne Fehler Compiliert.
hier mal das einfachste aller Programme UART-Programme inkl. 
selbstgeschriebender Header.
1
#ifndef SCHNITTSTELLEN_H
2
#define SCHNITTSTELLEN_H
3
4
5
#include <avr/io.h>
6
#include <stdbool.h>
7
#include <util/delay.h>
8
9
10
//#define TAKT            F_CPU                           // 8MHz Systemtakt
11
#define TAKT            8000000ul                       // 8MHz Systemtakt
12
#define UART_NO_DATA    0x0100
13
unsigned long UBAUD;
14
15
void uart(bool fast)                                    // doppelte Bautrate
16
{
17
//  UBAUD =  19200UL;                                       // Akuelle Übertragungsrate
18
  UBAUD =   9600UL;
19
  unsigned char x = 0x00;
20
  if (fast) {
21
    UBRRL = (TAKT / (8 * UBAUD)) - 1;                 // Baudrate mit TAKt und BAUD
22
    UBRRH = 0;
23
    UCSRA |= (1 << U2X);                                // U2X Doppelte Bautrate * 8
24
    }
25
  else {
26
    UBRRL = (TAKT / (16 * UBAUD)) - 1;                // Baudrate mit TAKt und BAUD
27
    UBRRH = 0;
28
    UCSRA |= (0 << U2X);                                // U2X eindache Bautrate * 16
29
    }
30
  UCSRB |= (1 << TXEN) | (1 << RXEN);                   // Sender und Empfänger ein
31
  UCSRC |= (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);  // async 8bit
32
  x = UDR;                                              // Empfänger leeren
33
  }
34
35
void putch(unsigned char x)                       // warten und Zeichen sende
36
{
37
  while (! (UCSRA & (1 << UDRE)));               // warten solange Sender besetzt
38
  UDR = x;                                       // Zeichen nach Sender
39
  }
40
41
unsigned char getch(bool echo)                   // zeichen vom USART holen
42
{
43
  while (!(UCSRA & (1 << RXC)));                 // Warten bis Zeichen da
44
  if (!echo)                                   // Zeichen mit oder Ohne echo holen
45
  {
46
    return UDR;                                  // Zeichen abholen
47
    }
48
  else
49
  {
50
    int x;                                       // Hilfsvariable
51
    x = UDR;                                     // abholen und sichern
52
    while (!(UCSRA & (1 << UDRE)));              // warte bis Sender frei
53
    UDR = x;                                     // Zeichen als echo zurück
54
    return x;                                    // Zeichen zurückgeben
55
    }
56
  }
57
58
unsigned char kbhit(void)
59
{
60
  if (UCSRA & (1 << RXC)) return UDR; else return 0;
61
}
62
63
void putstring(unsigned char *zeiger)             // SRAM_String ausgeben
64
{
65
    while (*zeiger)
66
      putch(*zeiger++);
67
}
68
69
unsigned char getstring(unsigned char *zeiger, unsigned SLAENG)
70
{
71
  unsigned anz = 0;
72
  while (1)
73
  {
74
    *zeiger = getch(false);
75
    if (*zeiger >= 0x20 && anz < SLAENG)
76
    {
77
      putch(*zeiger); anz++; zeiger++;           // Echo Zähler Zeiger erhöhen
78
    }                                            // Ende if
79
    else
80
    {
81
      if (*zeiger != '\b' || anz >= SLAENG)      // Ende der Eingabe
82
      {
83
        anz = *zeiger; *zeiger = 0; return anz;  // Abbruchszeichen
84
      }                                          // Ende if
85
      else
86
      if (*zeiger == '\b' && anz != 0)           // Korrektur mit Rücktaste
87
      {
88
        zeiger--; putch('\b'); putch(' '); putch('\b'); anz--;
89
      }                                          // Ende If
90
    }                                            // Ende else
91
  }                                              // Ende while
92
}                                                // Ende Funktion
93
94
#endif // SCHNITTSTELLEN_H  
95
---------------------------------------------------------------------------
96
97
int main(void)
98
{
99
    uart(false);
100
    _delay_ms(100);
101
102
    while(1)
103
      if (getch(true) == WakeUp)
104
      {
105
        putstring("Hallo Welt!");
106
        putch(0x13);
107
        putch(0x10);
108
      }
109
    return 0;
110
}

unter C läuft es alles OHNE Probleme, jedoch nach dem Umbau in Lazarus 
scheint der OutPut nicht richtig zu laufen.
1
unit uart;
2
3
{$mode objFPC}
4
5
interface
6
7
const
8
//  CPU_Clock   = 16000000; // µC Takt = 16MHz
9
  CPU_Clock   =  8000000; // µC Takt =  8MHz
10
  Baud        =     9600; // Baudrate
11
12
procedure UARTInit;                            // Inizialisieren
13
function  UARTReadChar: char;                  // Zeichen Empfangen
14
procedure UARTSendChar(value: char);           // Zeichen Senden
15
procedure UARTSendString(Value: shortString);  // String Senden;
16
17
implementation
18
19
procedure UARTInit;
20
begin
21
  UBRRH       := ((CPU_Clock div (16 * Baud)) - 1) shr 8;
22
  UBRRL       := byte((CPU_Clock div (16 * Baud)) - 1);
23
  UCSRA       := (0 shl U2X);
24
  UCSRB       := (1 shl TXEN) or (1 shl RXEN);
25
  UCSRC       := (1 shl URSEL) or (%011 shl UCSZ);
26
end;
27
28
function  UARTReadChar: char;
29
begin
30
  while UCSRA and (1 shl RXC) = 0 do begin     // Warte, bis Zeichen ankommt
31
  end;
32
  Result      := char(UDR);
33
end;
34
35
procedure UARTSendChar(value: char);
36
begin
37
  while UCSRA and (1 shl UDRE) = 0 do begin
38
  end;
39
  UDR         := byte(c);
40
end;
41
42
procedure UARTSendString(value: ShortString);
43
var
44
  i: Integer;
45
begin
46
  for i := 1 to length(value) do begin
47
    UARTSendChar(value[i]);
48
  end;
49
end;
50
51
end.
52
53
-------------------------------------------------------------------------------
54
program SerTest;
55
56
uses uart;
57
58
begin
59
  UARTInit;
60
  repeat
61
    if UARTReadChar = #32 then begin
62
      UARTSendString('Hello World!'#13#10);
63
      UARTSendString('Ich bin ein Test deiner UART'#13#10);
64
      end;
65
    until 1 = 2;
66
end.

Der C Code wurde erstell mit Code::Blocks IDE 17.12, der Pascal Code 
unter Lazarusfpcupdeluxe 2.0.10 und fpc 3.0.4. (Beides läuft auf einem 
Laptop mit RPI Desktop, bei dem µC handelt es sich um einen ATmega16 mit 
8MHz.)

Über einen Wink mit einem Ziegel, so der Fehler liegen könnte wäre ich 
durchaus dankbar.

Wünsche euch allen ein Entspanntes Weihnachtsfest.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Die Parameter zur Baudrate lässt man normalerweise von der avr libc 
berechnen. Auf die kann man sich verlassen.

Siehe 
https://www.nongnu.org/avr-libc/user-manual/group__util__setbaud.html

Der Titel verwirrt zusammen mit dem Text:
> UART läuft unter FreePascal sauber
> unter C läuft es alles OHNE Probleme,
> jedoch nach dem Umbau in Lazarus scheint der OutPut nicht richtig zu laufen.

Was heißt denn "scheint"?

Sende mal einfach wiederholt den gleichen Buchstaben (ohne zu empfangen) 
und zeige mal, was dabei am Tx Pin heraus kommt. Dazu wirst du einen 
Logic Analyzer besorgen müssen, falls du keinen hast. Bei Amazon Prime 
gibt es welche innerhalb von 24 Stunden für nur 10 Euro.

von Vam L. (vam_l)


Lesenswert?

Stefan ⛄ F. schrieb:
> Der Titel verwirrt zusammen mit dem Text:
>> UART läuft unter FreePascal sauber
>> unter C läuft es alles OHNE Probleme,
>> jedoch nach dem Umbau in Lazarus scheint der OutPut nicht richtig zu laufen.

Danke für den Hinweiß, gleich mal geändert

> Was heißt denn "scheint"?
>
> Sende mal einfach wiederholt den gleichen Buchstaben (ohne zu empfangen)
> und zeige mal, was dabei am Tx Pin heraus kommt. Dazu wirst du einen
> Logic Analyzer besorgen müssen, falls du keinen hast. Bei Amazon Prime
> gibt es welche innerhalb von 24 Stunden für nur 10 Euro.

also mit Zeigen wird es dann auf die schnelle def. nix, weil KEIN Amazon 
habe.
Ja sowas soll es auch noch geben.

Ungeachtet dessen, gehe ich eher von einer Code-Unstimmigkeit aus, da 
die C erstellte HEX ihren Text ausgibt, die Lazarus-erstellte Hex 
allerdings nicht.

Ergo liegt wohl ein Softwareproblem vor, welches ich gerade nicht sehe.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Kommt denn überhaupt etwas am Tx Pin heraus, wenn du nur eine 
forlaufende Ausgabe (ohne Eingabe) machst?

Stelle zum Test die Baudrate auf einen niedrigen Wert und schließe eine 
LED an. Die müsste man flackern sehen.

von Vam L. (vam_l)


Lesenswert?

Stefan ⛄ F. schrieb:
> Kommt denn überhaupt etwas am Tx Pin heraus, wenn du nur eine
> forlaufende Ausgabe (ohne Eingabe) machst?
>
> Stelle zum Test die Baudrate auf einen niedrigen Wert und schließe eine
> LED an. Die müsste man flackern sehen.

OutPut unter PicoCom mit dem C-Code = Hallo Welt
OutPut unter PicoCom mit dem Lazarus erstelltenn Code = ''

von Carl D. (jcw2)


Lesenswert?

Vam L. schrieb:
> Ergo liegt wohl ein Softwareproblem vor, welches ich gerade nicht sehe.

Ich würde zuerst mal 1:1 übersetzen und erst danach bei der 
Initialisierung der UART "Verbesserungen" einzuführen.

Ps: Ich persönlich würde würde mich bei dem Quelltext an die 80er 
erinnern, als ich noch jung war und den funktionierenden Code einfach 
weiter benutzen.

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

Nur aus Interesse gefragt, ich kenne die Programmiersprache nicht - 
woher weiß der Compiler eigentlich an dieser Stelle, was c ist?
1
procedure UARTSendChar(value: char);
2
begin
3
  while UCSRA and (1 shl UDRE) = 0 do begin
4
  end;
5
  UDR         := byte(c);
6
end;

von Stefan F. (Gast)


Lesenswert?

Ich glaube kaum, dass deine LED "Hallo Welt" ausgegeben hat. Jetzt mal 
im Ernst, mach das mal wie beschrieben. Die Frage ist, ob der Serielle 
Port überhaupt irgend etwas ausgibt.

Falsche Konfiguration der Baudrate, Parity, Bits und Stopbits kann 
nämlich auch dazu führen, dass dein PC nichts anzeigt obwohl etwas 
gesendet wird.

Ich möchte jetzt erstmal wissen, ob überhaupt etwas gesendet wird, um 
die Fehlerbeschreibung zu komplettieren. Vorher gucke ich mir deinen 
Quelltext gar nicht an.

Teste mit diesem Code:
1
baud = 300;
2
...
3
begin
4
  UARTInit;
5
  repeat
6
    UARTSendString('Hello World!'#13#10);
7
  until 1 = 2;
8
end.

von Georg G. (df2au)


Lesenswert?

Vam L. schrieb:
> while UCSRA and (1 shl RXC) = 0

ich kenne Lazarus nicht. Aber solche Konstrukte schreibt nur der 
absolute Könner. Praktiker setzen ein paar Klammern für die Dummerchen, 
die nicht sofort wissen, welcher Operator zuerst kommt.

while ((UCSRA and (1 shl RXC)) = 0) ist imho lesbarer.

von Vam L. (vam_l)


Lesenswert?

S. Landolt schrieb:
> Nur aus Interesse gefragt, ich kenne die Programmiersprache nicht -
> woher weiß der Compiler eigentlich an dieser Stelle, was c ist?
>
>
1
> procedure UARTSendChar(value: char);
2
> begin
3
>   while UCSRA and (1 shl UDRE) = 0 do begin
4
>   end;
5
>   UDR         := byte(c);
6
> end;
7
>

genau das war der Treffer, welchen ich nicht gesehen habe...
1
   UDR         := byte(value);
schaut auch sinnvoller aus.

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

Wie jetzt - und da bringt der Compiler keine Fehlermeldung?

von GeraldB (Gast)


Lesenswert?

Kann das überhaupt funktionieren?
1
UDR         := byte(value);
Wird die byte-Funktion nicht schon beim Compilieren ausgewertet und der 
zufällige Wert von value fest im Code hinterlegt?

Korrekt müßte es doch so sein:
1
UDR         := ord(value);

von c-hater (Gast)


Lesenswert?

GeraldB schrieb:
> Kann das überhaupt funktionieren?
>
1
UDR         := byte(value);
> Wird die byte-Funktion nicht schon beim Compilieren ausgewertet

Das ist keine Funktion, sondern ein Typecast.

Entspricht c'isch:

>
1
UDR         = (byte)(value);

von Maxe (Gast)


Lesenswert?

Georg G. schrieb:
> Vam L. schrieb:
>> while UCSRA and (1 shl RXC) = 0
>
> ich kenne Lazarus nicht. Aber solche Konstrukte schreibt nur der
> absolute Könner. Praktiker setzen ein paar Klammern für die Dummerchen,
> die nicht sofort wissen, welcher Operator zuerst kommt.
In Pascal ist das unproblematisch, da while einen Boolean-Wert erwartet. 
Waere die Reihenfolge falsch, dann gaebe es eine Fehlermeldung, da die 
Typen nicht mehr stimmen/zusammenpassen.

von W.S. (Gast)


Lesenswert?

Vam L. schrieb:
> UCSRC       := (1 shl URSEL) or (%011 shl UCSZ);

Erstens: könntest du mal erklären, was du mit %011 meinst? Ist mir 
nämlich nicht geläufig. Stattdessen wäre mir $11 nicht unbekannt.

Zweitens: Du beziehst dich massiv auf irgendwelche Konstanten, die aber 
nicht sichtbar sind, da sie irgendwo in anderen Quellen definiert sind. 
Sowas macht mich immer mißtrauisch. Könnte ja sein, daß es da 
Diskrepanzen gibt zwischen dem Zeugs in C und dem Zeugs in Pascal.

W.S.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

S. Landolt schrieb:
> Wie jetzt - und da bringt der Compiler keine Fehlermeldung?

Das wundert mich auch. Gerade in Pascal ist es nicht üblich, aus dem 
Nichts eine Variable zu erzeugen, was bei manchen Sprachen ja geht. 
Mögl. ist Lazarus da anders als die anderen Pascal Varianten, die ich so 
kenne.

von Einer K. (Gast)


Lesenswert?

Matthias S. schrieb:
> Gerade in Pascal ist es nicht üblich, aus dem
> Nichts eine Variable zu erzeugen,

Das ist so sicher wie das Amen in der Kirche!
Der Kompiler haut dir den Kram um die Ohren.
Es sei denn, es dümpelt noch ein c in den übergeordneten 
Geltungsbereichen rum.
Dann nimmt er dieses.

von Zeno (Gast)


Lesenswert?

S. Landolt schrieb:
> Nur aus Interesse gefragt, ich kenne die Programmiersprache nicht -
> woher weiß der Compiler eigentlich an dieser Stelle, was c ist?

So wie der Quellcode gepostet wurde müßte da eigentlich ein Fehler 
kommen, weil c an keiner Stelle deklariert wurde.

von Zeno (Gast)


Lesenswert?

Georg G. schrieb:
> ch kenne Lazarus nicht. Aber solche Konstrukte schreibt nur der
> absolute Könner. Praktiker setzen ein paar Klammern für die Dummerchen,
> die nicht sofort wissen, welcher Operator zuerst kommt.

Das hat nichts mit Könner zu tun, das ist ganz normale Pascalquelltext. 
Du kennst offensichtlich auch Pascal nicht.

Allerdings wäre es schon hilfreich, wenn er in seinem Codeschnipsel die 
Variablendeklarationen korrekt geschrieben hätte.
Was ist denn USRC?

Georg G. schrieb:
> while ((UCSRA and (1 shl RXC)) = 0) ist imho lesbarer.
Deine vielen Klammern sind völlig unnötig und erhöhen die Lesbarkeit an 
dieser Stelle nicht, im Gegenteil es wird unübersichtlicher. In dem 
Konstrukt soll UCSRA (was vermutlich vom Datentype Byte ist) auf die 
Bitmaske (1 shl RXC) abgeprüft werden.

W.S. schrieb:
> Erstens: könntest du mal erklären, was du mit %011 meinst? Ist mir
> nämlich nicht geläufig. Stattdessen wäre mir $11 nicht unbekannt.
Naja % ist ja eigentlich die Kennzeichnung von Binärzahlen, aber da 
schreibt man das dann eigentlich so: %00000011 für ein Byte.
Ich bvin aber über die gleiche Stelle gestolpert. Der ganze Quelltext 
ist irgendwie nur hingerotzt , das geht schon mit den unvollständigen 
Variablendeklationen los. Man kann nur erahnen welche Datentypen er 
meint. Wenn das ganze Programm in dem Stil wie der gepostete Quelltext 
geschrieben wurde, braucht er sich nicht zu wundern wenn es nicht 
funktioniert.

von Vam L. (vam_l)


Lesenswert?

W.S. schrieb:
> Vam L. schrieb:
>> UCSRC       := (1 shl URSEL) or (%011 shl UCSZ);
>
> Erstens: könntest du mal erklären, was du mit %011 meinst? Ist mir
> nämlich nicht geläufig. Stattdessen wäre mir $11 nicht unbekannt.
>
> Zweitens: Du beziehst dich massiv auf irgendwelche Konstanten, die aber
> nicht sichtbar sind, da sie irgendwo in anderen Quellen definiert sind.
> Sowas macht mich immer mißtrauisch. Könnte ja sein, daß es da
> Diskrepanzen gibt zwischen dem Zeugs in C und dem Zeugs in Pascal.
>
> W.S.

Ich trenne sehr wohl meine c Programme von Pascal
C ist meine Spielwiese Pascal meine Arbeitsumgebung ändert aber an den 
verwendeten Registern eines ATmega16 an Ende Null, Null.

Zeno schrieb:
> Naja % ist ja eigentlich die Kennzeichnung von Binärzahlen, aber da
> schreibt man das dann eigentlich so: %00000011 für ein Byte.

Funktioniert sowohl als auch die kurze Variante.
Leidlich der Lesbarkeit ist %00000011 von Vorteil.

Wobei
1
(%011 shl UCSZ)
 sich explizit auf das Register-Paar UCSZ (UCSZ0 - 2) bezieht.

: Bearbeitet durch User
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.