Hallo Leute,
ich versuche mich schon seit einiger zeit damit meinen Atmaga mit dem PC
kommunizieren zu lassen, was jedoch nur Manuell mit HTERM gelingt.
Jetzt soll dies Automatisch geschehen, von meinem Server aus in
regelmäßigen Abständen. Als idee kam mir ein einfaches script per
chronjob auszuführen, was daten vom Atmega speichert.
Zum test habe ich für meinen Atmega ein Programm geschrieben was per
UART daten empfängt, die Daten binär auf 8 LEDs anzeigt (zur kontrolle)
und die Daten wieder zurück zum PC sendet.
Nun zum Script...
1
#Name: Write_and_Read
2
#Author: Schmaddy
3
#Version Alpha-zu-Testzwecken Aug. 2011
4
5
#Befehle Atmega:
6
#0xA1 = Naechsten 8bit auf PA ausgeben
7
#0xB0 = Sende PortB
8
#0xF1 = Naechsten 8bit in Register1 schreiben
9
#unbekannt ausgabe auf 8bit led
10
11
use Sys::Syslog;
12
13
$port ="/dev/ttyS0"; # Port festlegen
14
system "stty 1200 ixon < $port"; # Baudrate festlegen mit stopbit
15
16
#Senden
17
open(COM, "+>$port") or die "Kann $port nicht oeffnen."; # geraetedatei oeffnen
18
printf(COM '0xFF'); # Geraet senden/schreiben
19
close(COM); # Verbindeung schliessen
20
21
#Lesen
22
sysopen(COM, "$port", O_RDONLY) or die "Kann nicht Lesen";
23
$bytes=sysread(COM, $buffer, 1);
24
print $buffer, "\n" if $bytes ==1;
25
close(COM);
Das script sendet Daten zu meinem Atmega, was ich an den Kontroll LEDs
feststellen kann.
Aber es empfängt nichts.
Ausgeführt wird es ohne fehlermeldung, aber das script hat eine
unendliche laufzeit. wenn ich es ohne den #Lesen abschnitt ausführe,
sendet es und das script ist beendet. Aber mit beendet es sich nicht.
Ich denke das
1
$bytes=sysread(COM, $buffer, 1);
irgendwie nicht richtig ist, kann das sein?
Ich habe um fehler am Atmega auszuschließen den code mal gekürzt...
sbis UCSRA, RXC // warten bis ein Byte angekommen ist
65
rjmp receive_loop
66
in temp, UDR // empfangenes Byte nach temp kopieren
67
out PORTD, temp // und an Port D ausgeben.
68
rcall seriell_out // Daten zurückschicken
69
rjmp receive_loop // zurück zum Hauptprogramm
70
71
// Senden
72
seriell_out:
73
sbis UCSRA,UDRE // Warten bis UDR für das nächste
74
// Byte bereit ist
75
rjmp seriell_out
76
out UDR, temp
77
ret // zurück zum Hauptprogramm
78
79
// Pause zum Synchronisieren des Empfängers
80
81
// Sub
82
sync:
83
ldi r16,0
84
sync_1:
85
ldi r17,0
86
sync_loop:
87
dec r17
88
brne sync_loop
89
dec r16
90
brne sync_1
91
ret
92
93
// Ende
Mit dem Manuellem auslesem an meinem Windows PC via HTERM habe ich keine
Probleme. Ich sende beispielsweise 0b01010101 an den atmega und die leds
zeigen 01010101 an und auf der konsole empfange ich ebenfalls wieder
0b01010101. Sodass ich den fehler am Perlscript des Servers vermute.
Der Server läuft unter Fedora 14
Kann mir jemand beim Perl script einen guten tipp geben?
Danke und Gruß schmaddy
> Aber es empfängt nichts.
Ich vermute, dass es darauf wartet, bis das vermeintliche Modem einen
Carrier meldet. Dass ein serieller Port nicht für ein Modem (seine
ursprüngliche Zweckbestimmung) sondern für eine Dreidrahtkommunikation
dient, muss man üblicherweise separat festlegen (stty clocal).
Ansonsten:
Serielle Schnittstelle unter Perl
BSDs arbeiten hier übrigens etwas anders: sie haben ein callout
device, /dev/cu*, das sich initial (bis zum ersten Auftreten eines
DCD) so verhält, als wäre implizit CLOCAL gesetzt. Dieses device
bekommt dann üblicherweise das Nutzerzugriffsrecht (bspw. über die
Gruppe uucp), während das dialup device (/dev/tty*) nicht für den
Nutzer zugreifbar ist und beim open() bereits auf DCD blockiert.
Dadurch kann man ein getty auf /dev/tty* ansetzen, das bis zum
(dialin-)carrier des Modems wartet, während zwischenzeitlich das
callout device für abgehenden Traffic in Richtung Modem benutzt
werden kann, ohne dass dieser mit dem getty in Konflikt gerät.
Da Modems allmählich in Vergessenheit kommen, braucht man das kaum
noch; man muss sich lediglich dran erinnern, dass man für derartige
Aufgaben unter einem *BSD nicht auf /dev/tty* zugreift, sondern
auf /dev/cu*.