Forum: Mikrocontroller und Digitale Elektronik Messschieber mit µc auslesen


von Andreas W. (Gast)


Lesenswert?

Hallo,

ich habe mir die Schaltung von Hans Borngraeber nachgebaut.
http://www.roehrenkramladen.de/DRO/Projektmappe_MAS_V1_0.htm

Zunächst habe ich es mit dem ~10 Euro Messschieber von Reichelt 
probiert. Nichts zu machen. Da war nur wirres Zeug auf dem Terminal zu 
sehen. Die Anzeige hat ständig von Inch nach mm umgeschaltet und die 
Zahlen passten überhaupt nicht.
Zum testen habe ich dann noch die Firmware von Sven Hummel getestet.
(http://www.svens-projekte.de/3.html) Die Version 6.0.
Auch das hat nicht funktioniert.

Dann habe ich mir Messschieber von Pollin gekauft. Angeblich soll die 
Schaltung von H.B. damit gestestet sein.
Aber auch hier funktioniert es nicht. H.B. bietet ja zwei hex files an.
Einmal für Pollin und einmal für Lidl.
Die Pollin Vatriante zeigt ähnliches (unbrauchbares) Zeug an wie beim 
Reichelt Messschieber.
Die Lidl Variante hingegen, zeigt immerhin Werte an, die linear steigen. 
Sie passen zwar ganz und gar nicht zum Display vom Messschieber, aber 
sie sind vom Wertebereich her "gültig". Das heißt: auf 150mm werden mir 
Werte von +0,00mm bis irgendwas um die 5,00mm angezeigt. Die Werte 
steigen jedoch linear zur Verschiebebewegung des Messschiebers.

So langsam weiß ich nicht mehr was ich noch machen soll.
Hat vielleicht der R22 (welcher auf 0,7-0,9V) eingestellt werden soll 
etwas damit zu tun? Wenn ich die Spannung ändere, passiert leider nichts 
sichtbares.

Ich verwende 16Mhz Quarz und geschirmtes Kabel. Abgesehen von den 
Messwerten, wird im Terminal alles angezeigt wie es soll.

Irgendwo muss da doch der Wurm drin sein, wer kann mir da helfen? Wo 
kann ich noch Fehler suchen?

Ich habe also beide Messschieber mit allen drei Hex files getestet. (2X 
H.B. und 1X S.H.)

Gruß, Andreas

von Mechanikus (Gast)


Lesenswert?

Hallo Andreas

Mit den Billig-Teilen von Lidl, Aldi, Pollin habe ich mich selber schon 
herumgeärgert.

Bei diesen billigen China-Messschiebern gibt es mittlerweile mindestens 
drei völlig verschiedene Protokolle der Datenübertragung. Welches 
Protokoll deine Messlatte benützt ist leider Glückssache. Ich hatte auch 
schon welche, die zwar die Anschlüsse für den Stecker auf der Platine 
draufhatten, die Kontaktflächen waren aber nicht angeschlossen und 
völlig funktionslos.

Anscheinend werden diese Dinger von immer mehr verschiedenen 
China-Firmen produziert, von denen jede ihr eigenes "geheimes" Protokoll 
verwendet. Eine Dokumentation dazu gibts vermutlich nur, wenn du die 
Dinger Containerweise bestellst.

Einzige Abhilfe:

Nicht bei Billig-Händlern wie Lidl oder Aldi oder Pollin kaufen. Was du 
dort bekommst, ist reiner Zufall und meistens nicht für das Auslesen per 
µC geeignet.

Nur bei namhaften Werkzeughändlern bestellen und dir vorher schriftlich 
bestätigen lassen, welches Protokoll die Messschieber verwenden. Wenn's 
dann nicht klappt, hast du zumindest ein Rückgaberecht.

von Carsten M. (carsten_m52)


Lesenswert?

Hallo Andreas,

ich habe dasselbe Problem mit meinen Messschiebern (von zujeddeloh).Die 
hatten auch ein komplett unschiedliches Protokoll als das von Pollin und 
Lidl (die hatte ich auch getestet).

Um dem ganzen etwas näher zu kommen bin ich folgendermaßen vorgegangen:
Auf das Umstellen der Modi (Fast, etc.) am besten erst einmal verzichten 
und aufs Lesen fokussieren. Wenn Werte kommen (auch wenn sie erst einmal 
falsch scheinen ist das auch schon ein gutes Zeichen;-)


Dann bin ich wie folgt vorgegangen:

1. Festen Wert auf dem Meßschieber einstellen
2. Den eingestellten Wert in Binär umrechnen (z.B. mit 
http://www.arndt-bruenner.de/mathe/scripts/Zahlensysteme.htm)
3. Kleines Programm z.B in Bascom mit "Shiftin PINB.0 , Pinc.1 , <Wert> 
, 6 , 24" schreiben, welches den Messschieber im Loop ausliest und auf 
der seriellen Schnittstelle ausgibt.

Dann nach dem Bitmuster in der Ausgabe suchen und den Schieber mal 
verstellen, schauen ob das neue Bitmuster an derselben Stelle dann dem 
eingestellten Wert entspricht.

So hat es zumindest bei mir geklappt die Werte zu ermitteln. Aktuell 
kämpfe ich allerdings mit solchen Wiedrigkeiten wie Stromsparmodi der 
Messschieber, etc.
Grüße
Carsten

von R. W. (quakeman)


Angehängte Dateien:

Lesenswert?

Ich habe mir vor nicht allzu langer Zeit selber eine Schaltung zum 
Auslesen von Schieblehren gebaut, welche die Werte von bis zu vier 
Schieblehren auf einem 16x4 LCD anzeigt. Zum Glück habe ich hier nur 
namhafte Schieblehren zur Verfügung, welche alle das gleiche Protokoll 
benutzen. Damit funktioniert das Auslesen und Umstellen der Modes völlig 
problemlos.

Ich habe mich vorher aber vergewissert, dass das Protokoll auch korrekt 
ist, indem ich per Logikanalyzer die Ausgabe für drei verschiedene 
Messwerte gespeichert habe. Ich habe mal Screenshots der Ausgabe für 
-10mm, 0mm und 10mm mit angehängt.

Dann habe ich die Software für den Controller geschrieben, welche heute 
noch problemlos funktioniert. Dazu habe ich mir auch eine Hilfsfunktion 
(signal.ini) erstellt, welche das Protokoll der Schieblehre emuliert und 
an mein Programm liefert. Damit konnte ich die Software testen ohne 
dauernd die Hardware anschliessen zu müssen. :)

Falls es euch hilft, könnt ihr unter [1] das gesamte Programm von mir 
einsehen.

Ciao,
     Rainer

[1] 
https://quakeman.homelinux.net/viewvc/uVision/trunk/Schieblehre_Anzeige/

von Andreas W. (Gast)


Lesenswert?

Hallo,

ich bin, wie Carsten M. es vorgeschlagen hat vorgegangen. Nun bin ich 
soweit, dass mir der Messwert via Rs232 an den Pc gesendet wird.

Wen es interessiert: Der Messwert liegt auf Bit 18 bis 31. Das 
Vorzeichen kann mit Bit 11 ermittelt werden. Maßeinheit habe ich nicht 
herausbekommen, ist für mich aber auch nicht wichtig, da ich nur mit mm 
arbeite.

Jetzt würde mich interessieren, wie man nullen kann.
Im Originalprogramm von H.B. wurde das mit Impulsen gemacht à la:
Config Portd.3 = Output    'Schaltport Takt X-Achse
..
..
Portd.3 = 1
Waitms 300
Portd.3 = 0

Meinen eingesetzten Messschieber interessiert das nicht sonderbar.
Gibt es eine Chance herauszufinden was man da senden muss?

Ich würde nur ungern mit Optokopplern die Hardkeys des Messschiebers 
anzapfen wollen...

Gruß, Andreas

von Carsten M. (carsten_m52)


Lesenswert?

Hallo, freut mich dass es klappt.
Das nullen habe ich auch nicht hinbekommen, da ich aber ohnehin nicht am 
Messschieber ablesen möchte mache ich das auch einfach in meinem 
Micrcontroller (aktuellen Wert als Nullwert merken und dann einfach 
immer die Differenz ausgeben). So habe ich zB. Auch vor die 
Radiusanzeige des Plansupportes zu realisieren, denn da muss man den 
Wert ja auch umrechnen.
Grüße Carsten

von Sebastian H. (pic_freak)


Lesenswert?

Moin zusammen,

schaut mal unter

http://www.steamboating.de/caliper/cal-main.html

nach. Dort gibt es eine Anzeige für die billig Messschieber. Habe diese 
mit den 10€ Messschieber von Alpha Tools (Bauhaus) ausprobiert. 
Funktioniert ganz gut.

Gruß


Sebastian

von Rigi Taler (Gast)


Lesenswert?


von Andreas W. (Gast)


Lesenswert?

Bin nun etwas weiter. Ich habe die Firmware so umgeschrieben, das ich 
auf das HyperTerminal verzichten kann.

Zum ersten Mal habe ich zwei Messschieber angeschlossen und 
festgestellt, das die Messwerte zwischendurch nicht ganz passen. D.h. er 
misst den richtigen Wert, z.B. 50.xx mm, macht einen Sprung nach 130.xx 
und dann zeigt er wieder den ursprünglichen (korrekten) Wert an.
Das tritt aber nur auf, wenn ich einen zweiten Messschieber anschließe.

Kann das Hardware-bedingt sein? Oder sieht jemand etwas "verdächtiges" 
in der Hauptschleife?

Hier mal der Quellcode der Hauptschleife:

Do

  Gosub Tastatur

  '****** X-Achse
  If Xflag = 0 Then
    Start Watchdog
    Shiftin Pinc.0 , Pinc.1 , L , 7 , 32                    'Daten 
einlesen X-Achse
    Reset Watchdog
    Gosub Dekoder                                           'Daten 
dekodieren
    Ausgabe = "x" + Vz_text + Mw_text
    If Ausgabe <> Oldvalx Then
    Print Ausgabe
    End If
    Oldvalx = Ausgabe
    Waitms 10
  End If


  '****** Y-Achse
  If Yflag = 0 Then
    Start Watchdog
    Shiftin Pinc.2 , Pinc.3 , L , 7 , 32                    'Daten 
einlesen Y-Achse
    Reset Watchdog
    Gosub Dekoder                                           'Daten 
dekodieren
    Ausgabe = "y" + Vz_text + Mw_text
    If Ausgabe <> Oldvaly Then
    Print Ausgabe
    End If
    Oldvaly = Ausgabe
    Waitms 10
  End If


    '****** Z-Achse
  If Zflag = 0 Then
    Start Watchdog
    Shiftin Pinc.4 , Pinc.5 , L , 7 , 32                    'Daten 
einlesen Z-Achse
    Reset Watchdog
    Gosub Dekoder                                           'Daten 
dekodieren
    Ausgabe = "y" + Vz_text + Mw_text
    If Ausgabe <> Oldvalz Then
    Print Ausgabe
    End If
    Oldvalz = Ausgabe
    Waitms 10
  End If

Loop

von Carsten M. (carsten_m52)


Lesenswert?

Hallo,
Soweit ich mich erinnere verwerfen die sonstigen Programme immer den 
ersten gelesenen Wert und nehmen dann den 2..
Für Dich würde das bedeuten die Shiftin Zeile einfach zu duplizieren.
Du solltest noch bedenken, dass Shiftin den Prozessor blockiert. Sollte 
also einer Deiner Messchieber keine Daten mehr senden (ich hatte das bei 
meinem, der ging nämlich in den Standbymodus) bekommst Du auch keine 
Anzeige vom anderen mehr.
Sollte das ein Problem sein melde Dich einfach, hatte da eine Shiftin 
mit Timeout Funktion geschrieben.
Grüße
Carsten

von R. W. (quakeman)


Lesenswert?

Carsten M. schrieb:
> Soweit ich mich erinnere verwerfen die sonstigen Programme immer den
> ersten gelesenen Wert und nehmen dann den 2..

Das wird genau das Problem sein.
Du liest ja immer den ersten Wert ein, rechnest ihn um, gibst ihn aus 
und gehst zur nächsten Schieblehre. Dabei berücksichtigst du aber nicht, 
ob du beim Einlesen der nächsten Schieblehre unter Umständen gerade 
mitten in einem Datenpaket anfängst. Du liest dann unter Umständen nur 
noch die restlichen Bit des Datenpakets ein, was natürlich kein 
sinnvolles Ergebnis gibt.
Ich habe in meinem Programm dafür extra eine Synchronisierungsmethode 
erstellt, welche immer als erstes nach dem Umschalten der Schieblehre 
aufgerufen wird. Diese stellt sicher, dass ich nicht mitten in einem 
Datenpaket anfange einzulesen.

Ciao,
     Rainer

von Carsten M. (carsten_m52)


Lesenswert?

Hallo,

ich hatte das damals wie folgt gemacht.

Ich hatte nur kleine Probleme mit dem Beginn eines Datenpaketes,denn 
wenn man die komplette Bitlänge liesst bekommt man ja (ggf. mit Pause 
und nicht ganz so schön) trotzdem einen kompletten Wert. Das hat dann 
nur nicht mehr funktioniert, wenn man den Schieber bewegt (da ergibt 
sich tatsächlich das Problem, dass man das Ende des ersten und ggf. den 
Anfang des zweiten unterschiedlichen Wertes bekommt).

Diese Routine funktionierte damals zumindest um das Timeout Problem zu 
lösen:
1
Config Portc.0 = Input                                      'Takt-Eingang X-Achse
2
Config Portc.1 = Input                                      'Daten-Eingang X-Achse
3
4
Config Timer1 = Timer , Prescale = 1024
5
On Timer1 Overflow
6
Timer1 = 56000 ' Zeit bis Abbruch des Leseversuches 
7
' Die Zeit muss so gross sein, dass man ggf. die Pause zwischen zwei 'Signalen überbrücken kann und trotzdem noch mit der Geschwindigkeit 'zufrieden ist
8
9
Dim Overflow_bit As Bit ' Glob Variable zur Anzeige, dass keine Daten geliefert werden
10
11
12
13
' hier kommt Dein  Haupprogramm ...
14
'
15
' Ergebnis=Shiftintimeout(20)    
16
'if Overflow Bit=0 'Dann war alles Erfolgreich
17
' then <Ergebnis umrechnen>
18
19
20
21
22
23
'Interrupt Routine zum Abbruch falls keine Daten kommen
24
Overflow:
25
       Overflow_bit = 1
26
Return
27
28
29
30
End
31
32
Function Shiftintimeout(byval Timeout As Integer) As Long
33
Local P As Long
34
Local C As Byte
35
Dim X As Bit
36
P = 0                                                       'Variable für den Wert
37
C = 0                                                       'Dies Ist Der Bitzaehler
38
Overflow_bit = 0                                            '  Globale Variable zum Prüfen ob der Timer übergelaufen ist->abbruch, keine Daten
39
X = 0
40
41
Timer1 = 56000
42
Enable Timer1
43
Enable Interrupts
44
Do
45
   Do
46
      If Pinc.1 = 1 Then X = 1
47
      If Overflow_bit = 1 Then X = 1
48
      Loop Until X = 1                                      ' Auf steigende Flanke Warten
49
   X = 0
50
   If Overflow_bit = 0 Then
51
      Do
52
      X = Pinc.1
53
      If Overflow_bit = 1 Then X = 0
54
      Loop Until X = 0                                      ' Auf fallende Flanke Warten
55
   End If                                                   'Platz machen für nächstes Bit in ZielVariable
56
   Rotate P , Right
57
   P = P + Pinc.0                                           ' Aktuellen Wert lesen
58
   C = C + 1
59
   If Overflow_bit = 1 Then
60
      C = 24
61
   End If
62
63
Loop Until C = 24
64
65
If Overflow_bit = 0 Then
66
   Shift P , Right , 9
67
End If
68
69
Disable Timer1
70
Disable Interrupts
71
72
Shiftintimeout = P
73
74
End Function

von Andreas W. (Gast)


Lesenswert?

Ich habe mal Carsten`s Funktion in ein Testprogramm eingebaut.
Das klappt irgendwie so ganz und gar nicht.
Es werden keine Werte ausgelesen.
Wenn ich z.B. die Waitms700 kleiner mache, stürzt der Controller sofort 
ab.
Overflow_bit ist bei mir immer 1.

Zum testen habe ich in der Hauptschleife mal den Timeout erhöht.
Overflow_bit war immer 1 und bei 65xxx stürzt der Controller dann ab.





$regfile = "m8def.dat"                                      'Atmega 8 
CPU
$crystal = 16000000                                         '16Mhz 
Quarztakt
$baud = 38400                                               'RS232 
38400,8,n,1
$hwstack = 32
$swstack = 16
$framesize = 24

'****** Variable definieren
Dim L As Long 
'Einlesevariable
Dim Lng As Long
Dim Ausgabe As String * 16
Dim Oldvalx As String * 16
Dim Oldvaly As String * 16
Dim Oldvalz As String * 16
Dim Keyinput As String * 16
Dim Tmp As Integer
Dim Mw_text As String * 6                                   'Ausgabe 
Text
Dim Xflag As Byte                                           'Einschalt 
Flag X-Achse
Dim Yflag As Byte                                           'Einschalt 
Flag Y-Achse
Dim Zflag As Byte                                           'Einschalt 
Flag Z-Achse
Dim Exflag As Eram Byte                                     'Einschalt 
Flag Speicherwert X-Achse
Dim Eyflag As Eram Byte                                     'Einschalt 
Flag Speicherwert Y-Achse
Dim Ezflag As Eram Byte                                     'Einschalt 
Flag Speicherwert Z-Achse

Declare Function Shiftintimeout(byval Timeout As Integer , Byval Achse 
As String) As Long


'Config Watchdog = 1024                                      'Watchdog 
Wert ca. 1sec
Config Single = Scientific , Digits = 3                     'Einstellen 
der Variable für den seriellen Messwert
Config Portc.0 = Input 
'Takt-Eingang X-Achse
Config Portc.1 = Input 
'Daten-Eingang X-Achse
Config Portc.2 = Input 
'Takt-Eingang Y-Achse
Config Portc.3 = Input 
'Daten-Eingang Y-Achse
Config Portc.4 = Input 
'Takt-Eingang Z-Achse
Config Portc.5 = Input 
'Daten-Eingang Z-Achse
Config Portd.2 = Output                                     'Schaltport 
Daten X-Achse
Config Portd.3 = Output                                     'Schaltport 
Takt X-Achse
Config Portd.4 = Output                                     'Schaltport 
Takt Y-Achse
Config Portd.5 = Output                                     'Schaltport 
Daten Y-Achse
Config Portd.6 = Output                                     'Schaltport 
Takt Z-Achse
Config Portd.7 = Output                                     'Schaltport 
Daten Z-Achse

Config Timer1 = Timer , Prescale = 1024
On Timer1 Overflow
Timer1 = 56000                                              ' Zeit bis 
Abbruch des Leseversuches
' Die Zeit muss so gross sein, dass man ggf. die Pause zwischen zwei 
'Signalen überbrücken kann und trotzdem noch mit der Geschwindigkeit 
'zufrieden ist

Dim Overflow_bit As Bit                                     ' Glob 
Variable zur Anzeige, dass keine Daten geliefert werden


'**** Schaltausgänge zurücksetzen
Portd.2 = 0
Portd.3 = 0
Portd.4 = 0
Portd.5 = 0
Portd.6 = 0
Portd.7 = 0

'****** Einlesen der Messschieber Konfiguration aus dem EERAM
Xflag = Exflag
Yflag = Eyflag
Zflag = Ezflag

If Xflag = 255 Then
 Exflag = 0
 Xflag = 0
End If
Print "rdy"
Wait 1
Print "co:" ; Xflag ; ":" ; Yflag ; ":" ; Zflag

Lng = 56000
Do

  '****** X-Achse
  If Xflag = 0 Then
    L = Shiftintimeout(20 , "x")
    If Overflow_bit = 0 Then
     Mw_text = Bin(l)
     Print "X" ; Mw_text
    End If
  End If


  Print Overflow_bit ; " L: " ; Lng
  'If Overflow_bit = 1 Then
  ' Lng = Lng + 100
  'End If
  Waitms 700
Loop

'Interrupt Routine zum Abbruch falls keine Daten kommen
Overflow:
       Overflow_bit = 1
Return


Function Shiftintimeout(byval Timeout As Integer , Byval Achse As 
String) As Long
Local P As Long
Local C As Byte
Dim X As Bit
P = 0                                                       'Variable 
für den Wert
C = 0                                                       'Dies Ist 
Der Bitzaehler
Overflow_bit = 0                                            '  Globale 
Variable zum Prüfen ob der Timer übergelaufen ist->abbruch, keine Daten
X = 0

Timer1 = Lng
Enable Timer1
Enable Interrupts

If Achse = "x" Then
Do
   Do
      If Pinc.1 = 1 Then X = 1
      If Overflow_bit = 1 Then X = 1
      Loop Until X = 1                                      ' Auf 
steigende Flanke Warten
   X = 0
   If Overflow_bit = 0 Then
      Do
      X = Pinc.1
      If Overflow_bit = 1 Then X = 0
      Loop Until X = 0                                      ' Auf 
fallende Flanke Warten
   End If                                                   'Platz 
machen für nächstes Bit in ZielVariable
   Rotate P , Right
   P = P + Pinc.0                                           ' Aktuellen 
Wert lesen
   C = C + 1
   If Overflow_bit = 1 Then
      C = 24
   End If
Loop Until C = 24
End If
If Overflow_bit = 0 Then
   Shift P , Right , 9
End If
Disable Timer1
Disable Interrupts
Shiftintimeout = P
End Function

End

von Carsten M. (carsten_m52)


Lesenswert?

Hallo,

ein paar Sachen an deen es liegen könnte sind mir aufgefallen:

Wenn ich Deine letzten Sources richtig verstanden habe, dann ist bei Dir 
die Länge eines Wertes 32 Bit
> Shiftin Pinc.0 , Pinc.1 , L , 7 , 32         'Daten einlesen X-Achse
Damit müsstest Du die Zeilen
1
   If Overflow_bit = 1 Then
2
      C = 24 '<-HIER 32
3
   End If
4
Loop Until C = 24  '<-HIER 32
entsprechend anpassen.


Hier kommt glaube das eigendlich Wichtige!

Wenn Deine Schaltung so ist:
1
Config Portc.0 = Input
2
'Takt-Eingang X-Achse
3
Config Portc.1 = Input
4
'Daten-Eingang X-Achse

Bei mir ist Takt und Daten genau umgekehrt, also entweder umstecken oder 
Du tauscht in der "ShiftInTimeout" alle Pinc.1 geben pinc.0 und 
andersrum.

Dann sollte es zumindest schon mal etwas mehr ausgabe erzeugen.

Viele Grüße
Carsten
-------------------
Der Code müsste dann in etwa so aussehen:
1
Function Shiftintimeout(byval Timeout As Integer , Byval Achse As
2
String) As Long
3
Local P As Long
4
Local C As Byte
5
Dim X As Bit
6
P = 0                                                       'Variable
7
für den Wert
8
C = 0                                                       'Dies Ist
9
Der Bitzaehler
10
Overflow_bit = 0                                            '  Globale
11
Variable zum Prüfen ob der Timer übergelaufen ist->abbruch, keine Daten
12
X = 0
13
14
Timer1 = Lng
15
Enable Timer1
16
Enable Interrupts
17
18
If Achse = "x" Then
19
Do
20
   Do
21
      If Pinc.0 = 1 Then X = 1
22
      If Overflow_bit = 1 Then X = 1
23
      Loop Until X = 1                                      ' Auf
24
steigende Flanke Warten
25
   X = 0
26
   If Overflow_bit = 0 Then
27
      Do
28
      X = Pinc.0
29
      If Overflow_bit = 1 Then X = 0
30
      Loop Until X = 0                                      ' Auf
31
fallende Flanke Warten
32
   End If                                                   'Platz
33
machen für nächstes Bit in ZielVariable
34
   Rotate P , Right
35
   P = P + Pinc.1                                           ' Aktuellen
36
Wert lesen
37
   C = C + 1
38
   If Overflow_bit = 1 Then
39
      C = 32
40
   End If
41
Loop Until C = 32
42
End If
43
If Overflow_bit = 0 Then
44
   Shift P , Right , 9
45
End If
46
Disable Timer1
47
Disable Interrupts
48
Shiftintimeout = P
49
End Function

von Andreas W. (Gast)


Lesenswert?

Hallo,

die Pins 0 und 1 habe ich schon mal vertauscht. Die sind schon bei H.B. 
verkehrt herum. Zumindest, wenn ich der Doku von dem org. SHIFTIN Befehl 
glauben darf. Ob ich da 24 oder 32 eingebe bringt keinen Unterschied.

Ich habe mal Versuche gemacht. Dazu habe ich am Anfang der Funktion 
Shiftintimeout
ein print "read" eingebaut. In der Hauptschleife habe ich am Ende ein 
Waitms eingebaut. "Read" heißt nur das die Funktion aufgerufen wurde. 
Wenn es ein Messergebnis gab, steht es dabei. In der ersten Zeile die 
"Konfig" und ab dann die Ausgabe in meiner Konsole am PC.

Timer 56000-65000 und WAITMS50 oder WAITMS700
rdy
co:0:255:255
read
read
read
read
read
usw.


Timer 70000 und WAITMS700
rdy
co:0:255:255
read
read
nichts mehr


Timer 56000 und WAITMS10 oder keine Pause
rdy
co:0:255:255
zufällig, nicht reproduzierbare reads, manchmal ein (korrektes) 
messergebnis


Timer 56000 und keine Pause und kein Print "read"
rdy
co:0:255:255
zufällig, selten ein (korrektes)Messergebnis nach ca. 6 sekunden.
Meist resetet sich der Controller nach ca. 2-3 sekunden.


Der Watchdog war bei allen Versuchen deaktiviert.

von Carsten M. (carsten_m52)


Lesenswert?

Hallo....
Komisch und wenn Du die Funktion zum Test mal direkt ins Hauptprogramm 
einbaust und nicht als Funktion aufrufst ?
Grüße
Carsten

von Andreas W. (Gast)


Lesenswert?

Ich verstehe die Welt nicht mehr.

Wenn ich in der Hauptschleife die Bedingung:
"If Xflag = 0 Then"
herausnehme, geht es ohne Probleme.

Auszug aus der Definition:
Xflag = Exflag
Yflag = Eyflag
Zflag = Ezflag

If Xflag = 255 Then
 Exflag = 0
 Xflag = 0
End If

Hiernach ist Xflag (auch nach dem flashen) immer 0.
Ein "Print Xflag" hat mir das bestätigt.
Was hat der denn für ein Problem zu prüfen, ob das 0 oder was auch immer 
ist?

von Andreas W. (Gast)


Lesenswert?

Hallo,

ich werde das mit BASCOM dann sein lassen. Vielleicht klappt es mit c 
besser.

Dazu habe ich leider noch weniger gefunden. Aus diversen Threads und 
älteren Programmen von mir habe ich folgendes zusammengebastelt (siehe 
unten).
Die Ausgabe über USART funktioniert soweit.

Dummerweise bekomme ich auf 10er Basis immer 61 und bei 2er Basis immer 
111101 ausgegeben. Egal was ich am Messschieber einstelle.
Das ist leider so gar nicht das was ich möchte. Auch ein vertauschen der 
beiden Pins Pc1 und Pc0 bringt das selbe Ergebnis: 61.
Ich benötige "einfach nur" die Binärzahl als array of char, bzw. auf dem 
Pc als String. Dort pflücke ich das dann auseinander.

Meine Frage ist, liegt das falsche Ergebnis an der Funktion 
read_caliper, oder an mir, da ich die Daten möglicherweise falsch 
aufbereite?

Die Funktion read_caliper habe ich hier her: 
Beitrag "24 Bit über Pin auslesen Takt/Daten ohne Interrupt"





#include <avr/io.h>
#ifndef F_CPU
#warning "F_CPU war noch nicht definiert, wird nun mit 16000000 
definiert"
#define F_CPU 16000000UL     /* Quarz mit 16.0000 Mhz */
#endif
#include <util/delay.h>
#include <inttypes.h>
#include <stdlib.h>
#include <avr/interrupt.h>
#include <string.h>
#include <util/atomic.h>
#include "sbit.h"
#define UART_BAUD_RATE 38400L
#define UART_BAUD_CALC(UART_BAUD_RATE,F_CPU) 
((F_CPU)/((UART_BAUD_RATE)*16L)-1L)
#define CR "\r\n"

uint32_t read_caliper( void );
uint32_t ermval;

#define CLK_PIN         SBIT( PINC, 1 )
#define DATA_PIN        SBIT( PINC, 0 )
char wert[30];


//RS232------------------------------------------------------
void USART_putc(uint8_t byte)
{
while(bit_is_clear(UCSRA,UDRE)); //warten auf Datenregister empty
UDR=byte;
}

void USART_puts(char *s)
/* print string on USART (no auto linefeed) */
{
while (*s!=0)
  {
  USART_putc(*s);
  s++;
  }
}
//RS232------------------------------------------------------




uint32_t read_caliper( void )
{
  uint32_t val = 0;

  ATOMIC_BLOCK(ATOMIC_FORCEON){
    for( uint8_t i = 20; i; i-- ){
      _delay_us( 4 );
      if( CLK_PIN == 0 )                        // if CLK = 1 for >80us
        i = 20;
    }
    for( uint8_t i = 24; i; i-- ){
      while( CLK_PIN == 0 );                    // wait until CLK = 1
      val <<= 1;
      while( CLK_PIN == 1 );                    // wait until CLK = 0
      if( DATA_PIN )                           // read data
        val |= 1;                               // lsb first
    }
  }
  return val;
}



  int main(void)
{

UBRRH = (uint8_t) (UART_BAUD_CALC(UART_BAUD_RATE,16000000)>>8);
UBRRL = (uint8_t) UART_BAUD_CALC(UART_BAUD_RATE,16000000);
UCSRB = (1<<RXEN) | (1<<TXEN);
UCSRC = (1<<URSEL)|(3<<UCSZ0);

DDRD |= ( 1 << PD2) |  (1 << PD3) |  (1 << PD4) |  (1 << PD5) |  (1 << 
PD6) |  (1 << PD7);  // als Ausgang setzen
DDRC &= ~( 1 << PC0) |  (1 << PC1) |  (1 << PC2) |  (1 << PC3) |  (1 << 
PC4) |  (1 << PC5);  // als Eingang setzen

USART_puts("hallo");
USART_puts(CR);

while (1)
{
 ermval=read_caliper;
 itoa(ermval,wert,10);
 USART_puts(wert);
 USART_puts(CR);
 _delay_ms(900);
}
}

von Rigi Taler (Gast)


Lesenswert?

ohne Interrupt darfst du nur hoffen oder beten .

von R. W. (quakeman)


Lesenswert?

Andreas W. schrieb:
> uint32_t read_caliper( void )
> {
>   uint32_t val = 0;
>
>   ATOMIC_BLOCK(ATOMIC_FORCEON){
>     for( uint8_t i = 20; i; i-- ){
>       _delay_us( 4 );
>       if( CLK_PIN == 0 )                        // if CLK = 1 for >80us
>         i = 20;
>     }
>     for( uint8_t i = 24; i; i-- ){
>       while( CLK_PIN == 0 );                    // wait until CLK = 1
>       val <<= 1;
>       while( CLK_PIN == 1 );                    // wait until CLK = 0
>       if( DATA_PIN )                           // read data
>         val |= 1;                               // lsb first
>     }
>   }
>   return val;
> }

Ich denke, die Methode ist nicht ganz korrekt. Denn sie überspringt das 
erste Bit (welches das LSB im Protokoll ist).

Wenn man die Methode durchgeht sieht man, dass als erstes nach einer CLK 
1-Phase von >80µs gesucht wird. Ist diese aufgetreten wird nach der 
nächsten positiven Flanke val um eins nach links geschoben. Dann bei der 
nächsten negativen Flanke wird der Daten Pin eingelesen. Aber die erste 
negative Flanke nach der >80µs 1-Phase ist schon das erste Bit, welches 
nicht eingelesen wird. Dafür wird am Ende ein falsches 24. Bit 
eingelesen, welches nicht mehr zum Messwert gehört.

Das Problem mit dem Versatz der Flanke kann man sich einfach an den 
Screenshots von mir weiter oben herleiten.
In dem Screenshot für 10mm ist der zweite 24Bit Wert 
010000010000011111111111 (LSB...MSB). In richtiger Reihenfolge also 
111111111110000010000010 (MSB...LSB, anschließend negiert ist es 
000000000001111101111101 und in dezimal 8061, noch normiert sind es dann 
8061*25,4mm/2048 = 9,997529296875mm.

Wenn man nun die Bits um eins verschiebt kommt unter Umständen nur noch 
Murks raus. :)

Ciao,
     Rainer

von Andreas W. (Gast)


Lesenswert?

Hallo,

Zunächst zur BASCOM Version:
Nachdem ich XFLAG als INTEGER definiert habe und komplett vom EEPROM 
getrennt habe, weise ich jetzt zwei Werte zu. Frei ausgedacht: 66=Lesen 
99=Nicht lesen.
Dabei habe ich herausgefunden, warum die IF-Abfrage dazu führt, das es 
nach dem ersten Durchlauf nicht mehr geht. Ganz einfach, weil die 
Variable XFLAG nach dem ersten Durchlauf nicht mehr gleich 66 ist. Auch 
nicht 99. Nein, sie hat den Wert 12336.
Und das Beste: An keiner Stelle im Programm weise ich das zu. Und die 
Krönung ist, das der Controller leider nicht kaputt ist. Als PonyProg 
meinte "Verify successful" wußte ich nicht ob ich lachen oder weinen 
soll...



Zur C Version:
@Rainer
Du glaubst gar nicht wie froh ich wäre, wenn ich wenigstens falsche 
Werte hätte. Dann gäbe es etwas wo ich ansetzen kann. Aber leider ist 
der Wert "61" immer "61". Völlig egal was ich am Messschieber einstelle.

Ich habe mal testweise die BASCOM-Variante von Carsten, in c 
umgeschrieben. Der Bit-Zähler "C" ist nach dem einlesen auf 0. Der hat 
also gar nichts von dem Signal mitbekommen.
Danach habe ich mal folgendes in die main geschrieben:

ok=0;

while(1){

if (PC0){
 if (ok==0){
 ok=1;
 USART_puts("1");
 USART_puts(CR);
 }
}
else {
 if (ok==1){
 ok=0;
 USART_puts("0");
 USART_puts(CR);
 }
}

}

Einmal mit PC0 und einmal mit PC1.
Wildes 1,0 geflackere? Pustekuchen!
Der eine Pin immer auf 1, der andere immer auf 0.
Wenn da tatsächlich was empfangen wird, hätte wenigstens zufällig mal 
das Bit umspringen müssen, oder nicht?
Natürlich habe ich während des "Versuchs" den Messschieber bewegt.


Gibt es für all diese Sachen eine logische Erklärung? Ich weiß echt 
nicht wo ich jetzt noch Fehler suchen soll.

von Rigi Taler (Gast)


Lesenswert?

Zeichne dir die Impulszuege auf Papier auf.
Wenn ich mich richtig erinnere gab es bei dem Protokoll eine Laengere 
Pause, dann die Messdaten, dann eine kuerzere Pause und nochmals 
Messdaten.
Du musst also immer an der richtigen Flanke zB nach der langen Pause 
anfangen, sonst wird das nichts.
Ich habe vor Jahren anfangs ohne Interrupt (mit 89C4051 ) immer die 
ersten Bits verpasst.
Mit Int. ging es dann problemlos. Auch das Nullen ,das Umschalten von 
schnell auf langsam...kein Problem.

von R. W. (quakeman)


Lesenswert?

Rigi Taler schrieb:
> Zeichne dir die Impulszuege auf Papier auf.
> Wenn ich mich richtig erinnere gab es bei dem Protokoll eine Laengere
> Pause, dann die Messdaten, dann eine kuerzere Pause und nochmals
> Messdaten.
> Du musst also immer an der richtigen Flanke zB nach der langen Pause
> anfangen, sonst wird das nichts.
> Ich habe vor Jahren anfangs ohne Interrupt (mit 89C4051 ) immer die
> ersten Bits verpasst.
> Mit Int. ging es dann problemlos. Auch das Nullen ,das Umschalten von
> schnell auf langsam...kein Problem.

Wieso aufzeichnen?
Ich habe doch drei Screenshots meines Logikanalyzers weiter oben 
angehängt, auf denen man das Protokoll genau sehen kann.

Ich habe in meiner Methode nicht extra nach der langen Pause zwischen 
dem relativen und absoluten Messwert gesucht, was schnell in die Hose 
gehen kann. Ich habe einfach beide Messwerte, den Relativen sowie den 
Absoluten direkt hintereinander eingelesen. Wichtig ist nur 
sicherzustellen, dass man nicht gerade mitten in einem Messwert drin 
ist, wenn man anfängt Werte einzulesen. Danach braucht man nur noch 48 
negative Flanken auszuwerten, wovon die letzten 24 der absolute Messwert 
ist. Ich mache es übrigens auch mit einem 89C4051 per Interrupt Flag, 
aber ohne extra ISR. :)

Andreas wenn du die Nase noch nicht voll hast von neuem Code, dann schau 
dir mal meine Methode bt_Scan() unter [1] an. Diese läuft stabil auf 
einem fertigen System in meiner Werkstatt und liest bis zu vier 
Schieblehren gleichzeitig ein. Die Aufteilung der 24 Bit in drei 
Schleifen mache ich nur deswegen, weil sich 8 Bit Variablen viel 
schneller schiften lassen als eine 32 Bit Variable.

Man könnte auch die ersten 24 Flanken per Zähler einfach verfallen 
lassen und danach erst anfangen die Werte einzulesen.

Ciao,
     Rainer

[1] 
https://quakeman.homelinux.net/viewvc/uVision/trunk/Schieblehre_Anzeige/Schieblehre.c?view=markup

von Andreas W. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

habe heute mal mein Scope an den Messschieber angeschlossen, da ich die 
Pause zwischen den 2 Datenpaketen nicht erwische.

Nun ja, wie soll ich sagen...Die Wellenform ist etwas abweichend von 
meiner Erwartung.

Zum Bild: Davor und dahinter ist nichts mehr. Man erkennt aber kurze 
Pausen, welche alle 4 Bits erfolgen.
Also das 24*2 wird es wohl nicht sein, 7 BCDs auch nicht.
Es müsste ein 1*24 Protokoll sein.
Das ganze Signal ist ca. 9ms lang.

Habt ihr das schonmal gesehen?

von Andreas W. (Gast)


Lesenswert?

So, habe nun den Fehler in dem BASCOM-Code gefunden. Man schaue sich die 
deklaration von Mw_text an. Ich habe es aber auch nur zufällig gesehen, 
da mir die "falschen" Werte von xflag und co. irgendwie bekannt 
vorgekommen sind :-)

Das ermittelte Protokoll macht es mir sehr einfach den Anfang eines 
Paketes zu erkennen.
Ich prüfe einfach, ob in einem Zeitinterval von 600µs (längste Pause in 
einem Paket=~400µs) Clock auf low bleibt und weiß dann ganz sicher, das 
ich in der recht langen Pause zwischen zwei Paketen bin.

Hat funktioniert. Keine Aussetzer mehr.

von Rigi Taler (Gast)


Lesenswert?

Genau -so- hatte ich es einst auch gemacht.

von Carsten M. (carsten_m52)


Lesenswert?

Hallo Andreas,
Kannst Du diese Prüfroutine (600us) evtl. Mal posten, würde mich auch 
interessieren.
Danke
Grüße
Carsten

von Andreas W. (Gast)


Lesenswert?

Hallo

@Carsten
Hier der Code-Snippet für die X-Achse. Ich habe es zu beginn in Deine 
Funktion zum einlesen gesetzt.
In meiner Grafik vom Scope sieht man, das Clock (pos. 2) im 
"Ruhezustand" auf 1 ist.
Die Schleife wird verlassen, wenn in einem Zeitraum von mind. 599µs 
Clock auf 1 ist.
Gibt es währenddessen einen Takt, so beginnt das Warten erneut.


If Achse = "x" Then
While V < 599
 If Pinc.1 = 1 Then
  V = V + 8
 Else
  V = 0
 End If
 Waitus 8
Wend
End If

von R. W. (quakeman)


Lesenswert?

Hi,

eventuell ist der selbst programmierte Analyzer für das 2x24 Bit 
Schieblehren Protokoll für den einen oder anderen hier hilfreich. :)

Der Thread zu meinen Tools ist unter [1] zu finden.

Ciao,
     Rainer

[1] Beitrag "Tools für Logicport LA1034 und GTKwave"

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.