Forum: PC-Programmierung Tachoanzeige in Qt programmieren


von Flat (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

zurzeit beschäftige ich mit dem Programm Qt, habe gesehen das man 
grafische Oberflächen damit programmieren kann. Nun habe ich einen 
Tachoinstrumenten programmiert und bin wie folgt vorgegangen.
Habe mir in Gimp die Bilder eines Tachos zusammen geschnitten und mit 
dem QT Designer die einzelnen png Bilder plaziert ein die Nadel jetzt 
auch zum laufen gebracht. Ich habe für die Programmierung slider benutzt 
mit der man durch ziehen des des Buttons der Geschwidisgkeitszeiger 
bewegt wird.

Nun zu meiner Frage ich möchte gerne die Pfeiltaste auf der Tastatur 
benutzen damit sich der Zeiger bewegt, habe in der bibliothek nicht 
gescheites gefunden, was mich weiterbringt, vielleicht könnt ihr mir 
weiterhelfen??



Hier ist der Code für die Rotaion des Zeigers:

[

 Image {
        id: zeiger
        x: 218; y: 0
        height: 215
        smooth: true
        source: "geschw_zeiger.png"
        transform: Rotation {
            id: zeigerRotation
            origin.x: 5; origin.y: 215
            //! [needle angle]
            angle: Math.min(Math.max(-150, root.value*3.5 - 200), 150)
            Behavior on angle {
                SpringAnimation {
                    spring: 0.4
                    damping: .15
                }
            }
            //! [needle angle]
        }
    }

]

ich danke euch schonmal im Voraus.

Gruss
Flat

: Verschoben durch User
von ich (Gast)


Lesenswert?

Hallo,

sollte der gezeigte Code "QML" darstellen, dann würde ich die Verwendung 
von "QML Keys Element" (http://doc.qt.nokia.com/qml-keys.html) 
empfehlen.

von Flat K. (flat)


Lesenswert?

Hi,

Danke nochmal für deine Antwort. Nun habe ich jetzt das Problem, dass 
ich nicht genau weis wie ich das eingeben soll.
Wo ich noch den Slider benutzt habe wurde der Zeiger mit einem 
Eingabewert Value bewegt.
Ich will das der Value wert, wenn ich jetzt auf die Up Taste drauf 
drücke, hoch zählt.
Ich hoffe ich konnte mich verständlich ausdrücken.
Hier ist ein Abschnitt vom Code:


Zeiger {
        id: zeiger
        x: 420
        y: 80
        anchors.verticalCenterOffset: 0
        anchors.horizontalCenterOffset: 0
        anchors.centerIn: parent
        value: 20
        Keys.onPressed: { if (event.key == Qt.Key_Up);

            ???

        }

Ich bin neu in Qml, deshalb würde ich mich eure Hilfe freuen.
Ich danke schonmal im Voraus.

von Flat (Gast)


Lesenswert?

Hi,

habe das jetzt so gelöst indem ich den value wert mit der Up taste auf 
100 rotiert lasse
und mit der Down Taste auf 0. Hier ist der Code:
1
focus: true
2
    Keys.onPressed: { if (event.key === Qt.Key_Up)
3
4
            root.value= 100;
5
6
     else if (event.key ===Qt.Key_Down)
7
8
            root.value= 0
9
             }

Nun möchte ich aber nur eine Taste benutzen.
Sprich wenn ich auf Up drücke soll es auf den Value wert = 100 laufen 
und wenn ich loslasse dann soll es auf den value wert = 0 zurück 
rotieren.
Und ich habe gleich noch eine frage, wie kann ich den Value wert 
anzeigen lassen, sodass man z.B nicht auf die Nadelstellung achten muss 
sondern den Wert direkt ablesen kann.

Ich danke für eure Tipps

Gruss
Flat

von ich (Gast)


Lesenswert?

z.B.
1
// Text anzeigen
2
Text {
3
        id: myText
4
        text: root.value
5
        font.family: "Helvetica"
6
        font.pointSize: 24
7
        color: "red"
8
}
9
10
Keys.onPressed: {
11
         if (event.key == Qt.Key_Right) {
12
             root.value = 100;
13
         }
14
}
15
Keys.onReleased: {
16
        if (event.key == Qt.Key_Right) {
17
            root.value = 0;
18
        }
19
}

von ich (Gast)


Lesenswert?

Da die Pfeiltasten "auto repeat Keys" sind, besser so:
1
Keys.onPressed: {
2
         if (event.key == Qt.Key_Up && !event.isAutoRepeat) {
3
             root.value = 100;
4
         }
5
}
6
Keys.onReleased: {
7
        if (event.key == Qt.Key_Up && !event.isAutoRepeat) {
8
            root.value = 0;
9
        }
10
}

von asdf (Gast)


Lesenswert?

Wenn das laufen nach und nach passieren soll musst du halt zusätzlich 
noch einen Timer zum hoch/runterzählen verwenden.

von Flat K. (flat)


Lesenswert?

Hi,

ich bins nochmal weiß hier jemand wie ich den Timer integrieren kann, 
sodass ich den digitalen Wert von Tacho zählen lassen kann.
Ohne Timer wird bei mir nur 100 und 0 angezeigt.
Es ist vielleicht ne Triviale Frage für euch aber würde mich auf eine 
Hilfestellung trotzdem freuen.

Gruss
Flat

von asdf (Gast)


Lesenswert?

Was geht denn nicht?

von Flat (Gast)


Lesenswert?

Hi,

du meintest ja wenn das laufen nach und nach passieren soll, muss man 
einen Timer integrieren, ich weiß nur nicht wie. Hast du vielleicht ein 
Beispiel Code, wie man das realisieren kann.
Wenn die Nadel bei 200 steht soll als digitalen Wert auch 200 angezeigt 
werden.

Kann mir hier einer helfen?

Gruss

Flat

von Karl H. (kbuchegg)


Lesenswert?

Flat schrieb:
> Hi,
>
> du meintest ja wenn das laufen nach und nach passieren soll, muss man
> einen Timer integrieren, ich weiß nur nicht wie.

Hast du denn schon gefunden, wie ein Timer hier prinzipiell 
funktioniert?

Ein Timer ist nichts anderes, als eine Möglichkeit, wie du in 
regelmässigen Zeitabständen Code ausführen lassen kannst.

Und das kannst du jetzt mit einer zusätzlichen Variablen dazu benutzen, 
eine nachlaufende Variable zu erzeugen.

Deine Tastendrücke setzen nicht mehr root.value auf einen bestimmten 
Wert, sondern eine andere Variable. Nennen wir sie mal den Sollwert.

In der Timerfunktion vergleichst du bei jedem Aufruf diesen Sollwert mit 
root.value und wenn root.value kleiner als der Sollwert ist, dann 
erhöhst du es um zb. 1. Ist es größer dann verringerst du root.value um 
1.

Was erreichst du dadurch: der für die Funktionalität 'Zeigerrotation' 
zuständige Wert ändert sich in diskreten Zeiteinheiten (die durch den 
Timer vorgegeben sind) immer nur um 1 Einheit. Und zwar nur dann, wenn 
es eine Abweichung von diesem Sollwert gibt. root.value 'läuft diesem 
Sollwert' hinterher.

Beispiel. root.Value sei 0
In deinen Tastenfunktionen setzt du den Sollwert auf 100 und die 
Timerfunktion wird alle 0.01 Sekunden aufgerufen

Sekunden    Sollwert    root.value
0.00           0             0             Ausgangszustand
0.01           0             0             Jetzt drückst du die Taste
                                           und setzt den Sollwert auf
                                           100
0.02         100             0             value ist kleiner als der
                                           Sollwert, Also wird value
                                           erhöht
0.03         100             1
0.04         100             2
0.05         100             3
...
1.01         100            99
1.02         100           100             value und Sollwert sind
                                           gleich, also passiert
                                           nichts weiter
1.03         100           100
1.04         100           100             Du lässt die Taste los
                                           und dein Code setzt daher
                                           den Sollwert auf 0
1.05           0           100             jetzt ist value größer
                                           als Sollwert, daher wird
                                           in der Timerfunktion value
                                           um 1 verringert
1.06           0            99
1.07           0            98
...

in der Timerfunktion wird value langsam dem Sollwert nachgeführt. Ist 
value kleiner als der Sollwert, dann wird value um 1 erhöht. Beim 
nächsten Aufruf der Timerfunktion kurze Zeit später passiert ja wieder 
das gleiche, da wird dann value erneut erhöht, wenn es immer noch 
kleiner ist. Ist value größer als der Sollwert den wird value 
verringert.

Von Ausserhalb setzt du nicht mehr den value sondern den Sollwert. Der 
Timermechanismus sorgt dann dafür, dass value langsam und in Schritten 
sich diesem Sollwert annähert.

Im Endeffekt bedeutet das dann für dich: Du drückst eine Taste und der 
Zeiger bewegt sich in kleinen Schritten auf den zugehörigen Wert. Sind 
die Schritte klein genug und erfolgen sie schnell genug, dann "dreht" 
dein Zeiger entsprechend auf den Sollwert.

Aber erst mal musst du rausfinden, wie du da einen Timer ins System 
kriegst, wie du ihm sagst, in welchen Zeitabständen welcher Code 
ausgeführt werden soll. Jetzt bist du drann die Doku zu durchforsten, 
wie das geht.

von Flat (Gast)


Lesenswert?

Hi,

sorry das ich mich so spät melde, hatte noch eine Menge zu tun.

Super!!! Vielen dank nochmal für deine Antwort. Jetzt kann ich es mir 
wenigstens vorstellen, wie das geht. Ich mach mich die Tage dann an die 
Arbeit, ich schreib dann den Quellcode hier rein, wenn ich was 
gescheites zusammengebastelt habe :)

Was ich immer Fragen wollte, also folgendes bei meinem Rechner zu Hause 
ruckelt der Zeiger wenn es bewegt wird. Und wenn ich beide Zeiger bewege 
ist es meist schlimmer. Die Zeiger bleiben stehen und es stürzt ab.
Doch auf meinem Laptop  funktioniert das ganze flüssig, okey es hat 
etwas mehr Leistung als mein Rechner und hat eine Grafikkarte.
Der Rechner zu Hause, der hat nur eine OnBoard Grafikkarte, hat aber 4GB 
Arbeitsspeicher und ein Prozessor mit 3GHz Dual Core, es ruckelt stark.

Liegt es an der Grafikkarte oder meint ihr der Prozessor ist auch 
schwach?
Eventuell werde ich mir dann eine Grafikkkarte kaufen müssen.

Ich danke schonmal für eure Antworten.
Muss diese Seite echt loben, habe auch das gleiche in ein qt Forum 
gepostet und mir wurde nicht oder unzureichend geholfen. Ihr seid super 
:)

von Karl H. (kbuchegg)


Lesenswert?

Flat schrieb:

> Der Rechner zu Hause, der hat nur eine OnBoard Grafikkarte, hat aber 4GB
> Arbeitsspeicher und ein Prozessor mit 3GHz Dual Core, es ruckelt stark.

Könnte eine Sache des Grafiktreibers sein.

Grundsätzlich hast du mit 3Ghz eine Rechenleistung an der Hand, die für 
die meisten Menschen unvorstellbar hoch ist. OK, das BS frisst dir da 
wieder vieles weg und durch die diversen Softwareschichten wird das 
ganze auch nicht schneller. Aber meistens ist das eine Treibersache und 
ob der Treiber die vorhandene Hardware gut ausnutzt.

von Flat (Gast)


Lesenswert?

Hmm an den treibern kann es nicht liegen, Ich habe die aktuellsten 
Treiber installiert schon vor dem aufsetzen von Windows, und das ist 
grad mal ein Monat her. Vielleicht liegt es ja doch an der 
Onboard-Grafikkarte.

Ich weiß ich frag zuviel aber kam bei diesen Sache nicht weiter.
Ich habe auch einiges im Internet darüber gefunden aber, hat nicht so 
recht funktioniert. Es geht darum, dass ich die Anwendung die ich 
erstellt habe an einem anderen Rechner ausführen möchte. So nun habe ich 
herausgefunden, dass ich das dynamisch linken muss und die dazugehörigen 
dlls in den Ordner mit einfügen muss, habe ich auch soweit gemacht. Wenn 
ich jetzt die exe Datei starte bekomme ich ein weißes Fenster. Was mache 
ich falsch.

Habe die folgenden Dlls reingepackt:

libgcc_s_dw2-1.dll
mingwm10.dll
QtCore4.dll
QtDeclarative4.dll
QtGui4.dll
QtNetwork4.dll
QtScript4.dll
QtSql4.dll
QtXmlPatterns4.dll

Wenn ich diese Dlls nicht reinmache, gibt der mir ne Fehlermeldung, 
nachdem ich sie alle nacheinander reingemacht habe, zeigt es mir nun ein 
weißes Fenster an. Wisst ihr was noch fehlt?

von ich (Gast)


Lesenswert?

Starte die .exe mal über die Komandozeile (cmd.exe), dann solltest du 
eigentlich eine Fehlermeldung bekommen, welche dir eventuell 
weiterhilft.

von Flat (Gast)


Angehängte Dateien:

Lesenswert?

Hi,


hab es jetzt hinbekommen, die zeigerstellung digital anzeigen zu lassen,
dafür habe ich die Winkelstellung des Zeigers genommen.
Doch jetzt habe ich das Problem das es mir den Wert in Komma anzeigt,
also wie im Bild angezeigt. Wie kann ich es ohne Komma darstellen 
lassen?
1
   Text {
2
       id: myText
3
       x: 167
4
       y: 139
5
       width: 107
6
       height: 45
7
       text: zeigerRotation.angle
8
       font.family: "Helvetica"
9
       font.pointSize: 24
10
       color: "red"
11
   }

@ ich
danke für deine Antwort,
ich bekomme leider keine Fehlermeldung, der mich weiterbringt.
Es öffnet sich wieder ein weißes Fenster, doch es tut sich nichts...
Weisst du vielleicht was noch fehlt oder was ich falsch mache?

von Flat (Gast)


Lesenswert?

Kann mir denn hier keiner weiterhelfen?
Die Antwort ist möglicherweise trivial aber ich komme nicht darauf..

von ich (Gast)


Lesenswert?

Zur Ausgabe sollte
1
zeigerRotation.angle.toPrecision(0)
helfen.

Ansonsten würde es helfen, wenn du das komplette Projekt hier anhängen 
würdest.

von ich (Gast)


Lesenswert?

Nachtrag:

benutze Math.round(x) anstatt .toPrecision(x).

Zum Ausführen auf einem anderen Rechner:

hast du die .qml Dateien und die verwendeten Bilder auch auf den anderen 
Rechner kopiert?

von Flat (Gast)


Angehängte Dateien:

Lesenswert?

Hi,


Vielen Dank für deine Antwort.
Habe das jetzt das mit der digital Anzeige hinbekommen, indem ich
1
zeiger2Rotation.angle.toFixed()
 geschrieben habe.

Kannst du vielleicht noch reinschauen, wie ich das mit dem dynamisch 
linken machen muss. Ich stell dir das Projekt hier zur Verfügung.

Der Blinker funktioniert auch nicht so richtig, wollte es eigentlich so 
machen das wenn ich auf Links drücke auf der Tastatur das es Links 
blinkt, wenn ich nochmal Links drücke soll das blinken aufhören. mit 
Rechts das gleiche.

Für Anregungen, Ratschläge und Tipps wäre ich euch sehr dankbar :)


Gruss

Flat

von Flat (Gast)


Lesenswert?

Okey das mit dem Blinker habe ich jetzt hinbekommen es geht.

hier der code :
1
   
2
3
    onArrowChangedChanged:{
4
  //  console.log("in arrow change");
5
    blinkerTimer1.stop();
6
    blinkerTimer2.stop();
7
    blinkerTimer3.stop();
8
    if (arrowChanged == 3){
9
        leftArrowOn = true;
10
        rightArrowOn = false;
11
        blinkerTimer3.start();
12
        return;
13
    }else if (arrowChanged == 2){
14
        leftArrowOn = false;
15
        rightArrowOn = true;
16
        blinkerTimer2.start();
17
        return;
18
    }else if (arrowChanged == 1){
19
        leftArrowOn = true;
20
        rightArrowOn = true;
21
        blinkerTimer1.start();
22
        return;
23
    }else if (arrowChanged == 0){
24
        leftArrowOn = false;
25
        rightArrowOn = false;
26
        return;
27
    }
28
29
}
30
31
32
    Timer {
33
        id:blinkerTimer1
34
        interval: 500;
35
        repeat: true
36
        onTriggered: {
37
            if (leftArrowOn == false || rightArrowOn == false ){
38
                leftArrowOn = true;
39
                rightArrowOn = true;
40
            }
41
            else {
42
                leftArrowOn = false;
43
                rightArrowOn = false;
44
            }
45
        }
46
    }
47
48
49
    Timer {
50
        id:blinkerTimer2
51
        interval: 500;
52
        repeat: true
53
        onTriggered: {
54
            if (rightArrowOn == false ||
55
                rightArrowOn == false && leftArrowOn == true){
56
                leftArrowOn = false;
57
                rightArrowOn = true;
58
            }
59
            else{
60
                leftArrowOn = false;
61
                rightArrowOn = false;
62
            }
63
        }
64
    }
65
66
    Timer {
67
        id:blinkerTimer3
68
        interval: 500;
69
        repeat: true
70
        onTriggered:{
71
            if (leftArrowOn == false ||
72
                rightArrowOn == true && leftArrowOn == false){
73
                leftArrowOn = true;
74
                rightArrowOn = false;
75
            }
76
            else{
77
                leftArrowOn = false;
78
                rightArrowOn = false;
79
            }
80
        }
81
    }

Einfach in die Blinker.qml Datei rein kopieren

In die Main.qml kommt das rein. Dann muss es funktionieren.
1
    Blinker {
2
        id: blinker1
3
        x: 0
4
        y: 4
5
        anchors.verticalCenterOffset: 4
6
        anchors.horizontalCenterOffset: 0
7
        anchors.centerIn: parent
8
        focus: true
9
10
        Keys.onRightPressed:{
11
12
                     blinker1.arrowChanged = 2;
13
14
        }
15
        Keys.onLeftPressed: {
16
17
                    blinker1.arrowChanged = 3;
18
        }
19
        Keys.onDownPressed: {
20
                    blinker1.arrowChanged = 0;
21
        }
22
        Keys.onSpacePressed:{
23
                    blinker1.arrowChanged = 1;
24
        }
25
26
    }


Vielleicht habe ich es etwas umständlich gemacht aber hauptsache es 
funktioniert erst einmal :)

Könnt ihr mir vielleicht noch helfen, wie ich das mit dem dynamisch
linken machen muss. Das Projekt steht zur Verfügung. Ich wäre euch sehr 
dankbar dafür.


Gruss

Flat

von ich (Gast)


Lesenswert?

Dein Problem ist nicht das dynamische linken, sondern vermutlich die 
Tatsache das QML eine Interpretersprache ist. Was heißt, dass deine QML 
Dateien erst zur Programmlaufzeit interpretiert werden.

Wenn du die kompilierte Programmdatei (*.exe) an einem anderen Ort 
ausführen möchtest, hast du nun zwei Möglichkeiten.

Zum einen kannst du deinen QML/ Ordner (*) zusammen mit den DLL Dateien, 
in den selben Ordner wie deine Programmdatei kopieren.

Falls du lieber alles in einer Datei hast, kannst du stattdessen auch 
das Qt Ressourcen System nutzen, um deinen QML/ Ordner als Binärdaten 
mit in deine Programmdatei zu packen (linken).

Eine Anleitung dazu findest du unter:
http://doc.qt.nokia.com/4.7-snapshot/qtbinding.html#managing-resource-files-with-the-qt-resource-system

* Der Ordner welcher die gesamten .qml Dateien sowie die verwendeten 
Bilder enthält.

von Flat (Gast)


Angehängte Dateien:

Lesenswert?

@ ich

Vielen dank für deine ausführliche Antwort.

Ich habe noch ein anderes Problem, was ich nicht gebacken bekomme.
Und zwar möchte ich die Tacho nadel mit einem Mikrocontroller 
ansprechen, sprich wenn ich auf ein Taste vom Mikrocontroller drücke 
soll die Nadel rotieren, habe bis jetzt immer die Tastatur benutzt.

Über die serielle Schnittstelle RS-232 soll der Mikrocontroller 
angesprochen werden.
Die Kommunikation über die Mikrocontroller seite habe ich soweit,
Nun möchte ich die Daten, die vom Mikrocontroller geschickt werden über 
den ComPort mit QT lesen. Ich habe einige Programme gefunden, doch ich 
bekomme bei jedem Programm, die ich kompiliere eine Fehlermedlung, dass 
die include Dateien nicht gefunden werden können, obwohl sie in dem 
richtigen Ordner vorhanden sind.

Ich lade euch mal das Programm hier hoch.

Ich bin genau den schritten gefolgt wie im Link. Ich verstehe irgendwie 
nicht wie ich das mit dem Build Ordner und qmake und make ausführen 
soll.
Nachdem ausführen kommt die Fehlermedlung

Warnung:Unable to find file for inclusion \src\qt4support\serialport.prf

[[http://qt-project.org/wiki/QtSerialPort#b55bbb687c599634cc785869b9167639]]

Vielleicht habt ihr auch andere funktionierende Programme.

Ich hoffe ihr könnt mir weiterhelfen, bin hier am verzweifeln...

Gruss

Flat

von Michael J. (jogibaer)


Lesenswert?

Hallo Flat,

bei QT Fragen ist das qtforum.de besser geeignet.

Zur Kommunikation eignet sich anscheinend qextserialport am besten.
Suche mal danach.
In der qextserialport sollte es sogar über Signale und Slots 
funktionieren.
Ich bin auch gerade dabei diese zu testen.Ich habe erstmal die Version 
1.2
für QT4 benutzt.

Oder:

Irgendwo im Netz gibt es eine Qarduino 2.zip Datei.
Dort ist auch eine Kommunikation mit rs232 eingebaut.
Allerdings wie ich gesehen habe nicht mit Signale und Slots.


Links:

http://docs.qextserialport.googlecode.com/git/1.2/qextserialport.html
http://docs.qextserialport.googlecode.com/git/1.2/index.html

Allerdings mußte ich auch in den .h Dateien etwas herausnehmen,da ich
unter Linux entwickle.

Jogibär

von ich (Gast)


Lesenswert?

Die Anleitung auf die Du verlinkt hast ist wohl etwas älter und stimmt 
nicht mehr ganz.


Erstelle im Ordner mit der serialport.pro einen neuen Ordner mit z.B. 
dem Namen build.

Wechsle in den eben erstellten Ordner:
1
 cd build

Führe qmake aus:
1
 qmake ../serialport.pro

Führe make aus:
1
 make
2
 make install

unter Windows musst du das ganze eventuell dann nochmal mit Config= 
release ausführen. (Den Inhalt des Ordners build vorher löschen.)

Also:
1
 qmake ../serialport.pro CONFIG+=release

und nochmal make wie gehabt:
1
 make
2
 make install

Dann sollte es eigentlich funktionieren.

von Flat (Gast)


Lesenswert?

Hi Jogibär,

danke für deine Antwort.
Ich kenne die Seite qtforum.de auch, habe da auch mal da Fragen 
reingestellt aber mir wurde nicht bzw. unzureichend geholfen.
Hier wurde mir immer geholfen, auch wenn es keine explizite Seite für QT 
ist.
Wir sollten vielleicht die Seite umbenennen, mikrocontroller_QT.net oder 
so :)
Spass bei Seite kannst du mir vielleicht dein Programm zukommen lassen, 
wenn du es zum laufen bekommen hast.

Werde die Sachen mir mal genau anschauen und hier rein posten wenn es 
funktioniert.

Gruss

Flat

von Michael J. (jogibaer)


Lesenswert?

Flat schrieb:
> Hi Jogibär,
>
> danke für deine Antwort.
> Ich kenne die Seite qtforum.de auch, habe da auch mal da Fragen
> reingestellt aber mir wurde nicht bzw. unzureichend geholfen.

Ja,das kann ich leider auch bestätigen.
Die sind dort etwas elitär.
Aber ab es gibt auch Personen, die ausgezeichnet antworten.

> Hier wurde mir immer geholfen, auch wenn es keine explizite Seite für QT
> ist.
> Wir sollten vielleicht die Seite umbenennen, mikrocontroller_QT.net oder
> so :)
> Spass bei Seite kannst du mir vielleicht dein Programm zukommen lassen,
> wenn du es zum laufen bekommen hast.
Das Projekt ist etwas größeres.
Frag in ein paar Jahren noch mal nach ;-).


> Werde die Sachen mir mal genau anschauen und hier rein posten wenn es
> funktioniert.
>
> Gruss
>
> Flat

Jogibär

von Flat (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

ich habe endlich ein funktionierendes Programm gefunden, dass auf die 
serielle Schnittstelle zugreifen kann. Habe auch schon mit einem 
Mikrocontroller Daten gesendet und mit dem Beispielprogramm die Daten 
empfangen.

Nun zu meiner Frage, da ich mich nicht sonderlich mit C++ auskennen und 
mich dafür in QML eingearbeitet habe, möchte ich wissen, ob ich nun was 
ich in QML erzeugt habe in die c++ datei integrieren kann. Sprich mit 
Signals und Slots

Ich möchte wenn ich jetzt vom Mikrocontroller auf die Taste draufdrücke 
eine byte verschicken sagen wir mal (1111 1111), der Zeiger soll jetzt 
bei diesem code anfangen zu laufen und wenn ich wieder loslasse soll es 
wieder runterlaufen (0000 0000).


Ich habe im Programm das Beeispiel mit dem PortListener 
herausgeschrieben.
Jetzt möchte ich wenn ich ein Signal von 1111 1111 bekomme den Zeiger, 
was ich qml geschrieben habe per Signal und Slot bewegen.


Es hört sich vielleicht trivial an aber für mich der nicht so gute 
Kenntnisse in c++ Programmieren hat ist es schon etwas aufwändiger, 
daher würde ich mich für eure Tipps und Lösungsvorschläge freuen.
Ich habe das BeispielProgramm mit der Serielle Schnittstelle angehängt.
Das andere Programm womit die Zeiger bewegt werden können sind auch 
weiter oben im Thread enthalten.

1
#include "PortListener.h"
2
#include <QtDebug>
3
4
PortListener::PortListener(const QString & portName)
5
{
6
    qDebug() << "hi there";
7
    this->port = new QextSerialPort(portName, QextSerialPort::EventDriven);
8
    port->setBaudRate(BAUD9600);
9
    port->setFlowControl(FLOW_OFF);
10
    port->setParity(PAR_NONE);
11
    port->setDataBits(DATA_8);
12
    port->setStopBits(STOP_2);
13
14
    if (port->open(QIODevice::ReadWrite) == true) {
15
        connect(port, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
16
        connect(port, SIGNAL(dsrChanged(bool)), this, SLOT(onDsrChanged(bool)));
17
        if (!(port->lineStatus() & LS_DSR))
18
            qDebug() << "warning: device is not turned on";
19
        qDebug() << "listening for data on" << port->portName();
20
    }
21
    else {
22
        qDebug() << "device failed to open:" << port->errorString();
23
    }
24
}
25
26
void PortListener::onReadyRead()
27
{
28
    QByteArray bytes;
29
    int a = port->bytesAvailable();
30
    bytes.resize(a);
31
    port->read(bytes.data(), bytes.size());
32
    qDebug() << "bytes read:" << bytes.size();
33
    qDebug() << "bytes:" << bytes;
34
}
35
36
void PortListener::onDsrChanged(bool status)
37
{
38
    if (status)
39
        qDebug() << "device was turned on";
40
    else
41
        qDebug() << "device was turned off";
42
}


Ich danke euch schonmal im Voraus

Freundliche Grüsse
Flat

von Flat (Gast)


Lesenswert?

Hab nun das Problem, dass ich nicht weiß wie ich die Zeiger zum laufen 
bringe, da ich alles in qml geschrieben habe und der Serial Port in c++ 
geschrieben ist.

Könnt ihr mir vielleicht sagen wie ich das mit einander verknüpfen kann.
Habe auch schon danach gegoogelt aber wurde nicht so richtig fündig bzw. 
der Lösungsansatz ist mir nicht so richtig klar.

Habe das hier gefunden : 
http://doc.qt.nokia.com/4.7-snapshot/qtbinding.html


Das was ich haben möchte ist den root.value Wert in c++ ändern wenn ein 
Signal von der Seriellen Schnittstelle kommt.

Hier ist der Qml Code vom Zeiger:
1
    Image {
2
        id: zeiger
3
        x: 235; y: 12
4
        width: 11
5
        height: 228
6
        smooth: true
7
        source: "GeschwZeiger.png"
8
        transform: Rotation {
9
            id: zeigerRotation
10
            origin.x: 5; origin.y: 225
11
            //! [needle angle]
12
            angle: Math.min(Math.max( root.value * 3 -150 ), root.value +50)
13
14
                //Math.min(Math.max(-150, root.value*3.5 - 200), 150)
15
            Behavior on angle {
16
                SpringAnimation {
17
                    spring: 0.08
18
                    damping: .25
19
                }
20
            }
21
            //! [needle angle]
22
        }
23
    }

von Flat (Gast)


Lesenswert?

Kann mir denn hier keiner weiterhelfen?
Die Antwort ist möglicherweise trivial aber ich komme nicht darauf..

von Flat (Gast)


Lesenswert?

@ ich

du konntest mir bis jetzt immer bei meinen Fragestellungen helfen.
hast du vielleicht ein Tipp wie man das Problem lösen kann.
Wäre dir sehr dankbar.

Freundliche Grüße

Flat

von ich (Gast)


Lesenswert?

Hallo,

auf QML Properties kannst du z.B. mit QDeclarativeProperty zugreifen.

Beispiel:

Du erstellst in deinem QML root Objekt eine Property und weist diese 
dann z.B. deinem Zeiger zu.

z.B. main.qml
1
import QtQuick 1.0
2
//! [imports]
3
4
//! [0]
5
Rectangle {
6
    color: "#545454"
7
    width: 1280
8
    height: 600
9
    focus: true
10
    property int zeigerVal
11
12
    // Dial with a slider to adjust it
13
    Zeiger {
14
        id: zeiger
15
        anchors.centerIn: parent
16
        value: zeigerVal
17
18
    }

Im C++ Code kannst du nun mit QDeclarativeProperty diesen Wert 
verändern:

#z.B. main.cpp
1
#include <QtGui/QApplication>
2
#include <QtDeclarative>
3
#include "qmlapplicationviewer.h"
4
5
Q_DECL_EXPORT int main(int argc, char *argv[])
6
{
7
    QApplication app(argc, argv);
8
9
10
    QDeclarativeView view;
11
    view.setSource(QUrl("qml/tacho/main.qml"));
12
    view.show();
13
14
    QDeclarativeProperty property(view.rootObject(), QString("zeigerVal"));
15
    property.write(50);
16
    return app.exec();
17
}

von Flat (Gast)


Lesenswert?

@ ich

Du bist mein Held.
Es funktioniert :)
Danke Vielmals.

Nun habe ich das Problem mit dem Byte senden, da ich später die Blinker 
und die Zeiger einzeln ansteuern möchte, brauche ich einen kleinen 
Quellcode mit dem ich dies Realisieren kann.

Wie kann ich die Propertys nun ändern wenn ich sagen wir mal ein byte 
von 0x01 sende?

Ich hoffe ich habe mich verstandlich ausgedrückt.
Hoffe du kannst mir hierbei auch helfen.

Gruss
Flat

von ich (Gast)


Lesenswert?

Wenn ich dich jetzt richtig verstanden habe und abhängig davon wie dein 
C++ Programm aufgebaut ist, könnte die Datenübergabe in etwa so 
aussehen:
1
//main
2
int main(int argc, char *argv[])
3
{
4
    QApplication app(argc, argv);
5
6
7
    QDeclarativeView view;
8
    view.setSource(QUrl("qml/tacho/main.qml"));
9
    view.show();
10
    
11
    MyQmlInterface interface(view);
12
13
    return app.exec();
14
}
15
16
//MyQmlInterface 
17
class MyQmlInterface : public QObject
18
{
19
   Q_OBJECT
20
   
21
public:
22
    MyQmlInterface(const QDeclarativeView &view, QObject *parent = 0)
23
        //Verbindungen zu den Propertys initialisieren
24
        : myProp1(view.rootObject(), "zeigerVal"),
25
          myProp2(view.rootObject(), "..."),
26
          ...
27
    {
28
        ...
29
    }
30
public slots:
31
    void newData(int type, int val)
32
    {
33
        //abhängig von type, den Wert val in die gewünschten Property schreiben  
34
        switch (type)
35
        {
36
        case 1:
37
            myProp1.write(val);
38
            break;
39
        case 2:
40
            myProp2.write(val);
41
            break;
42
        ...
43
        }
44
    }
45
    
46
private:
47
    QDeclarativeProperty myProp1;
48
    QDeclarativeProperty myProp2;
49
    ...
50
}
51
52
//in der Klasse, welche die Dtaen vom uC empfängt, erstellst ein entsprechendes Signal
53
// z.B.
54
Signal: void sendNewData(int type, int val);
55
56
//Dann verbindest du das Signal und den Slot, an entsprechender Stelle und dann kannst 
57
//du in deiner Empfangsroutine, nachdem du die empfangenen Daten dekodiert hast, das Signal versenden:
58
emit sendNewData(typeFromUc, valFromUc);

von Flat (Gast)


Angehängte Dateien:

Lesenswert?

@ ich

danke für deine ausführliche Antwort.
Da ich nicht mich nicht so gut auf C++ basis auskenne, würde es mir sehr 
helfen, wenn du mal in mein Programm reinschauen könntest.
Habe es mir ehrlich gesagt etwas einfacher vorgestellt oder ich sehe die 
sache zu kompliziert.

Ich habe ein Klasse erstellt, die du vorgeschalgen hast, doch nun weiss 
ich nicht genau, wie ich das mit dem Signals and slots verbinden soll 
und dann noch die Empfangsroutine anpassen soll.

Für Tipps würde ich mich sehr freuen.
Als Anlage habe ich das gesamte Projekt angehangen, was ich bis jetzt 
gemacht habe, lass dich nicht von den vielen qml Dateien irritieren, 
habe sie nicht alle benutzt. Die Haupt Qml Datei ist die main.qml

Gruss
Flat

von Flat (Gast)


Lesenswert?

Guten Morgen,

kann mir hier jemand behiflich sein. Habe das Projekt angehangen.

Der Mikrocontroller schickt hier 0x10 für den Zeiger
und 0x20 für den Warnblink.
1
int main(void)
2
{
3
//##### INIT ########
4
  uint8_t state = 0;
5
  UART_Init();
6
  sei(); //Global interrupt ein  
7
  
8
//  EMD("\nInitialisiert\n");
9
//##### ENDE INIT ########  
10
11
  DDRD=0; //Tasten-PORT auf Eingang
12
  PORTD=255; //pullup
13
14
  DDRB=255; //LED-PORT auf Ausgang
15
  PORTB=255; //LED aus
16
17
  // Initialisierung wie oben
18
19
  while(1) {
20
    if ((PIND & (1<<4)) == 0) { // Schalter gedrückt
21
    //  state = (state + 1) % 2; // Zustand ändern
22
    //  PORTB = state?255:0; // und ausgeben (alle Pins)
23
    //  _delay_ms(1000); // 1 s warten
24
    
25
      UART_sendByte(0x10); // Geschwindigkeitszeiger
26
    
27
    }
28
    if ((PIND & (1<<7)) == 0) {
29
      
30
      UART_sendByte(0x20); //Warnblink
31
32
    }
33
  }  
34
           
35
}

Nun möchte ich in der Empfangsroutine die den Code anpassen und die 
Signals und Slots einfügen.
Kann mir einer dabei behilflich sein. Das gesamte Projekt habe ich 
angehangen.

Gruss
Flat

von Flat (Gast)


Lesenswert?

ich habe den zeiger nun versucht mit dem folgenden Code zu bewegen, hat 
leider nicht funktioniert :(
Ich kann den string auslesen mit dem Portlistener, doch der Zeiger 
bewegt sich nicht

Mikrocontroller Seite:


  while(1) {
    if ((PIND & (1<<4)) == 0) { // Schalter gedrückt

      UART_sendString("Zeiger");
    }
    if ((PIND & (1<<7)) == 0) {


      UART_sendString("Warnblink");

    }
  }

Empfang des  der  main.cpp

QDeclarativeProperty property(view.rootObject(), QString("zeigerVal"));


    QByteArray bytes;
    if(bytes == "Zeiger" ){

        property.write(100);
    }
    if (bytes == "" ) {

        property.write(0);

    };


Das Problem liegt wahrscheinlich das ich einen String wert schicke und 
QByteArray char Werte weiterverarbeitet.
Wie kann ich jetzt die String Werte in char umwandeln oder char werte in 
String.
Lieg ich mit meiner Vermutung richtig oder bin ich auf dem ganz flaschen 
Weg??

von Karl H. (kbuchegg)


Lesenswert?

Flat schrieb:

> Empfang des  der  main.cpp
>
> QDeclarativeProperty property(view.rootObject(), QString("zeigerVal"));
>
>
>     QByteArray bytes;
>     if(bytes == "Zeiger" ){
>

mir erschliesst sich nicht, wie da jetzt der Zusammenhang ist, dass in 
'bytes' irgendwie magisch die Werte von der UART auftauchen. Warum 
sollen die das tun?



Generell: verzichte darauf, ganze Wörter zu verschicken. Du hast keine 
Garantie, dass von einem Leseversuch auf dem PC zum nächsten auch 
tatsächlich das ganze Wort schon übertragen wurde. D.h. das ist 
zusätzlicher Aufwand sicherzustellen, dass der Empfänger auch weiß, wann 
eine Übertragung zu Ende ist und nichts mehr kommt. Der Sender hätte ja 
auch "Zeigerlager" schicken können.

Am einfachsten ist es immer noch, wenn du dich auf 1-buchstabige 
Kommandos beschränkst. Dann fällt dieses 'Problem' erst mal flach, denn 
1 Buchstabe wird immer komplett übertragen, ehe ihn der Empfänger zu 
Gesicht bekommt.


PS: Hast du eigentlich schon getestet, ob deine UART Übertragung 
grundsätzlich funktioniert? Sprich: In einem Terminal-Progamm 
nachgesehen, ob da auch wirklich das ankommt, was ankommen sollte? Das 
ist nämlich keineswegs selbstverständlich und wenn die Kommunikation 
grundsätzlich nicht funktioniert, dann brauchst du auf höheren Ebenen 
erst mal nicht weiter machen, solange dieses Problem nicht gefixt ist.

Auch solltest du schrittweise vorgehen. Nicht gleich die komplette Kette 
vom µC zum Zeigerinstrument in Betrieb nehmen und hoffen, das da alles 
funktioniert. Und hinterher großes Kopfkratzen, warum nichts 
funktioniert. Erst mal mit einem Terminalprogramm nachsehen, ob die 
Kommunikationsebene funktioniert. Dann mit einem Programm sich an diese 
Kommunikation binden und empfangene Zeichen einfach so wie sie empfangen 
wurden ausgeben. Und erst dann mit einem Programm die Werte (sofern die 
vorhergehenden Tests erfolgreich waren) an das Zeigerinstrument 
weitergeben. Auf die Art baut jede Erweiterung immer auf bereits 
getesteten Komponenten auf von denen man weiß, dass sie funktionieren. 
Gehts trotzdem nicht, dann muss das Problem irgendwo in dem Teil sein, 
der gerade neu dazu gekommen ist. Und je weniger neu dazu kommt, desto 
weniger Möglichkeiten für Probleme und Fehler gibt es.

von ich (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Flat schrieb:
>
>> Empfang des  der  main.cpp
>>
>> QDeclarativeProperty property(view.rootObject(), QString("zeigerVal"));
>>
>>
>>     QByteArray bytes;
>>     if(bytes == "Zeiger" ){
>>
>
> mir erschliesst sich nicht, wie da jetzt der Zusammenhang ist, dass in
> 'bytes' irgendwie magisch die Werte von der UART auftauchen. Warum
> sollen die das tun?
>
> ...

Ergänzung:

Du hast in deiner Empfangsroutine ja bereits den passenden Emfangsslot 
mit entsprechender Ausgabe.
1
//PortListener.cpp
2
3
void PortListener::onReadyRead()
4
{
5
    QByteArray bytes;
6
    int a = port->bytesAvailable();
7
    bytes.resize(a);
8
    port->read(bytes.data(), bytes.size());
9
    qDebug() << "bytes read:" << bytes.size();
10
    qDebug() << "bytes:" << bytes;
11
12
}
13
14
// Wenn du alle vorhandenen Bytes lesen möchtest, ist es allerdings sinnvoller es so zu schreiben:
15
16
void PortListener::onReadyRead()
17
{
18
    QByteArray bytes = port->readAll();
19
    qDebug() << "bytes read:" << bytes.size();
20
    qDebug() << "bytes:" << bytes;
21
22
}

Nachdem du also festgestellt hast, dass die Kommunikation mit einem 
Terminalprogramm funktioniert, kannst du damit feststellen, ob dein 
Programm die korrekten Daten empfängt.

Wenn das dann funktioniert, kannst du die weiter oben beschriebene 
Klasse MyQmlInterface auch einfach weglassen und "view" direkt an 
PortListener durchreichen. Die Implementierung erfolgt dann entsprechend 
wie in MyQmlInterface dargestellt, nur das du die Signal-Slot Verbindung 
nicht benötigst.

Allgemein:
1
//Wenn du Objekte mit new erzeugst, 
2
PortListener::PortListener(const QString & portName)
3
{
4
    ...
5
    this->port = new QextSerialPort(portName, QextSerialPort::EventDriven);
6
    ...
7
}
8
//dann solltest du den Speicher auch irgendwann wieder freigeben.
9
10
// Also z.B. einen Destruktor implementieren.
11
PortListener::PortListener(const QString & portName)
12
{
13
    delete port;
14
}

von Mark B. (markbrandis)


Lesenswert?

1
PortListener::~PortListener(const QString & portName)

So klappt es besser mit dem Destruieren :)

von Karl H. (kbuchegg)


Lesenswert?

Wenn du jetzt auch noch das Argument zum DTor wegnimmst, dann passts.

von Mark B. (markbrandis)


Lesenswert?

Ach ja! 's ist bald Feierabend.

von ich (Gast)


Lesenswert?

Mark Brandis schrieb:
> PortListener::~PortListener(const QString & portName)
> So klappt es besser mit dem Destruieren :)

Zumindest fast :)
1
PortListener::~PortListener()

von ich (Gast)


Lesenswert?

zu spät ...

von Flat (Gast)


Lesenswert?

Hi,

danke für die Antworten habe das mit den Terminal Programm getestet und 
es funktioniert alles einwandfrei.

Ich habe jetzt beim senden eine 500ms delay eingesetzt, da das Programm 
sonst mehrere Bytes empfangen hat statt nur "Z" .

hier ist das Beispiel
1
  while(1) {
2
    if ((PIND & (1<<4)) == 0) { // Schalter gedrückt
3
4
      UART_sendString("Z");
5
      _delay_ms(500);
6
    }
7
    if ((PIND & (1<<7)) == 0) {
8
9
10
      UART_sendString("W");
11
      _delay_ms(500);
12
    }
13
  }

Im Programm funktioniert die Übertragung auch
also es zeigt mit in bytes read: 1
              und         bytes: Z   an.



Doch ich weiss nicht wie ich die "view" an die den Portlistener 
durchreichen soll. Also in main.cpp habe ich das reingeschrieben, doch 
die bytes werden dann nicht zur Laufzeit aktualisiert. Ich möchte die 
Property in Portlistener verändern können. Ich habe es bis jetzt nicht 
hinbekommen.
1
QByteArray bytes;
2
    if(bytes == "Zeiger" ){
3
4
        property.write(100);
5
    }
6
    if (bytes == "" ) {
7
8
        property.write(0);
9
10
    };


Würde mich freuen, wenn du mir hierbei auch helfen könntest.

Gruss

Flat

von Flat (Gast)


Lesenswert?

Habe es oben falsch geschrieben meinte natürlich nur "Z"
So ist es richtig.
1
QByteArray bytes;
2
    if(bytes == "Z" ){
3
4
        property.write(100);
5
    }
6
    if (bytes == "" ) {
7
8
        property.write(0);
9
10
    };

von ich (Gast)


Lesenswert?

Du kannst es im Prinzip so machen, wie ich es in
Beitrag "Re: Tachoanzeige in Qt programmieren"
für MyQmlInterface beschrieben habe.

Also:
- Du erstellst dir in PortListener entsprechende Membervariablen für 
deine QML Properties.
- Du erweiterst den PortListener Konstruktor entsprechend, um dein QML 
View zu übergeben.
- Du initialisierst im PortListener Konstruktor deine Property Variablen 
entsprechend mit der übergebenen View.
- Nun kannst du in PortListener::onReadyRead, deine Propertys schreiben 
und lesen.

von Flat (Gast)


Lesenswert?

Ich habe das bis jetzt so gemacht, hier der Quellcode

Portlistener.h
1
#ifndef PORTLISTENER_H_
2
#define PORTLISTENER_H_
3
4
#include <QObject>
5
#include "qextserialport.h"
6
#include "QDeclarativeView"
7
8
class PortListener : public QObject
9
{
10
Q_OBJECT
11
public:
12
    PortListener(const QString & portName);
13
    PortListener(const QDeclarativeView &view, QObject *parent = 0);
14
 
15
16
private:
17
    QextSerialPort *port;
18
    QDeclarativeProperty myProp1;
19
20
private slots:
21
    void onReadyRead();
22
    void onDsrChanged(bool status);
23
24
};
25
26
#endif /*PORTLISTENER_H_*/

hier ist der quellcode für den Portlistener.cpp
1
#include "PortListener.h"
2
#include <QtDebug>
3
#include "QDeclarativeProperty"
4
#include "QDeclarativeView"
5
#include <QByteArray>
6
#include <QObject>
7
#include <QGraphicsObject>
8
9
10
PortListener::PortListener(const QString & portName)
11
{
12
    qDebug() << "hi there";
13
    this->port = new QextSerialPort(portName, QextSerialPort::EventDriven);
14
    port->setBaudRate(BAUD115200);
15
    port->setFlowControl(FLOW_OFF);
16
    port->setParity(PAR_NONE);
17
    port->setDataBits(DATA_8);
18
    port->setStopBits(STOP_1);
19
20
    if (port->open(QIODevice::ReadWrite) == true) {
21
        connect(port, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
22
        connect(port, SIGNAL(dsrChanged(bool)), this, SLOT(onDsrChanged(bool)));
23
24
        if (!(port->lineStatus() & LS_DSR))
25
            qDebug() << "warning: device is not turned on";
26
        qDebug() << "listening for data on" << port->portName();
27
    }
28
    else {
29
        qDebug() << "device failed to open:" << port->errorString();
30
    }
31
}
32
33
PortListener::PortListener(const QDeclarativeView, QObject *parent)
34
{
35
36
    QDeclarativeView view;
37
    view.setSource(QUrl::fromLocalFile("qml/TachoNEU/main.qml"));
38
    view.show();
39
    QDeclarativeProperty myProp1(view.rootObject(), QString("zeigerVal"));
40
41
42
}
43
44
45
void PortListener::onReadyRead()
46
{
47
    QByteArray bytes = port->readAll();
48
    //int a = port->bytesAvailable();
49
    //bytes.resize(a);
50
    //port->read(bytes.data(), bytes.size());
51
    qDebug() << "bytes read:" << bytes.size();
52
    qDebug() << "bytes:" << bytes;
53
54
    if(bytes == "Z" ){
55
56
        myProp1.write(100);
57
    }
58
    else if (bytes == "" ) {
59
60
        myProp1.write(0);
61
62
    };
63
64
}
65
66
67
void PortListener::onDsrChanged(bool status)
68
{
69
    if (status)
70
        qDebug() << "device was turned on";
71
    else
72
        qDebug() << "device was turned off";
73
}


Der Quellcode für dei main.cpp
1
#include <QtGui/QApplication>
2
#include "qmlapplicationviewer.h"
3
#include "PortListener.h"
4
5
#include <QDeclarativeProperty>
6
#include <QByteArray>
7
#include <QObject>
8
#include <QGraphicsObject>
9
10
11
12
Q_DECL_EXPORT int main(int argc, char *argv[])
13
{
14
    QScopedPointer<QApplication> app(createApplication(argc, argv));
15
16
  /*  QmlApplicationViewer viewer;
17
    viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
18
    viewer.setMainQmlFile(QLatin1String("qml/TachoNEU/main.qml"));
19
    viewer.showExpanded();
20
*/
21
    QString portName = QLatin1String("COM1");              // update this to use your port of choice
22
    PortListener listener(portName);        // signals get hooked up internally
23
24
25
    //QDeclarativeView view;
26
    // view.setSource(QUrl::fromLocalFile("qml/TachoNEU/main.qml"));
27
    // view.show();
28
29
  //  QDeclarativeProperty myProp1(view.rootObject(),QString("zeigerVal"));
30
31
32
    return app->exec();
33
}


Ich habe das "view" in Portlistener eingesetzt , doch ich bekomme keine 
Fenster wenn ich in der main.cpp das "view" auskommentiere. Und wenn ich 
die view in main einsetze dann klappt es nicht die myProp1 Werte in 
Portlistener zu ändern. Ich habe dein Lösungsansatz glaub ich nicht 
richtig verstanden. Sorry nochmal wenn ich viele doffe Fragen stelle...

1
   //QDeclarativeView view;
2
    // view.setSource(QUrl::fromLocalFile("qml/TachoNEU/main.qml"));
3
    // view.show();
4
5
  //  QDeclarativeProperty myProp1(view.rootObject(),QString("zeigerVal"));

Irgendwas habe ich falsch gemacht, könntest kurz reinschauen was ich 
falsch gemacht habe.
Danke nochmal für deine hilfe.

von ich (Gast)


Lesenswert?

Du kannst für eine Klasse zwar mehrere Konstruktoren definieren, beim 
Erstellen des Objekts, wird aber immer nur einer dieser Konstruktoren 
ausgeführt. Da du beim Erzeugen eines PortListener Objekts allerdings 
sowohl die serielle Schnittstelle, als auch deine QML Properties 
initialisieren möchtest, benötigst du einen Konstruktor, welcher sowohl 
die serielle Schnittstelle, als auch deine QML Properties initialisiert.

Das Erzeugen und Anzeigen deiner QML view erfolgt also weiterhin in main 
und PortListener wird mit dessen Konstruktor nur eine Referenz auf das 
view Objekt übergeben, mit welcher er seine QDeclarativeProperty Member 
initialisiert.

Alternativ kannst du in PortListener auch eine Initialisierungsmethode 
für deine QDeclarativePropertys erstellen, welche genauso als Parameter 
eine Referenz auf dein QML view erhält. Allerdings musst du dann 
sicherstellen, dass die QDeclarativePropertys in PortListener erst 
verwendet werden, nachdem Sie auch initialisiert wurden.

von Flat (Gast)


Lesenswert?

Ja ich hab verstanden das im main.cpp das Object nur von der Qml 
initalisiert wurde. Die Frage ist jetzt, wie ich die Serielle 
schnittstelle auch in main initialisiere sodass die Werte verändert 
werden.

Ich komme nicht mehr weiter.
Kannst du eventuel einen kurzen quellcode schreiben, wäre dir sehr 
dankbar.

von ich (Gast)


Lesenswert?

Main bleibt im Grunde so wie gehabt. Du musst nur dem Konstruktor von 
PortListener zusätzlich noch view übergeben und die PortListener Klasse 
natürlich noch entsprechend anpassen.

main() sieht dann in etwa so aus:
1
    QDeclarativeView view;
2
    view.setSource(QUrl::fromLocalFile("qml/TachoNEU/main.qml"));
3
    view.show();
4
5
    
6
    QString portName = QLatin1String("COM1");         // update this to use your port of choice
7
    PortListener listener(portName, view);                  // signals get hooked up internally

von Flat (Gast)


Lesenswert?

Ich habe jetzt die main.cpp wie du beschrieben hast erstellt.

Die Portlistener.h habe ich so wie du es beschrieben hast erstellt
Beitrag "Re: Tachoanzeige in Qt programmieren"

Doch die myProp1 kann ich in public nicht so schreiben, wie du es 
definiert hast.
1
: myProp1(view.rootObject(), "zeigerVal"),

hier der Quellcode:
1
#include <QObject>
2
#include "qextserialport.h"
3
#include "QDeclarativeView"
4
#include "QDeclarativeProperty"
5
6
class PortListener : public QObject
7
{
8
Q_OBJECT
9
10
public:
11
    PortListener (const QDeclarativeView & view , QObject *parent = 0);
12
    PortListener(const QString & portName);
13
14
private:
15
    QDeclarativeProperty myProp1;
16
    QextSerialPort *port;
17
18
private slots:
19
    void onReadyRead();
20
    void onDsrChanged(bool status);
21
22
};

die Portlistener.cpp sieht so aus
Ich weiss nicht ob ich es so richtig geschrieben habe.
Kannst du bitte in den Code reinschauen und mich eventuel verbessern.
Ich danke dir schonmal im voraus.
1
void PortListener::onReadyRead()
2
{
3
    QDeclarativeView view;
4
    QDeclarativeProperty myProp1(view.rootObject(), QString("zeigerVal"));
5
    bytes = port->readAll();
6
    qDebug() << "bytes read:" << bytes.size();
7
    qDebug() << "bytes:" << bytes;
8
9
    if(bytes == "Z" ){
10
11
        myProp1.write(100);
12
    }
13
    else if (bytes == "W" ) {
14
15
        myProp1.write(0);
16
    }
17
}
18
19
PortListener::PortListener(const QDeclarativeView & view , QObject *parent)
20
{
21
    QDeclarativeProperty myProp1(view.rootObject(), "zeigerVal");
22
}

von Flat (Gast)


Lesenswert?

Hallo,

Du meintest das nur ein Konstruktor ausgeführt wird.
Wie kann ich also die view in dem Konstruktor Portname ausführen?
Also wie initaliere ich die Propertys in Portname?

So wie ich es geschrieben habe funktioniert es nicht
Ich komme ehrlich gesagt nicht weiter:(

Kannst du mir bitte helfen ?

von Flat (Gast)


Lesenswert?

Ich habe es jetzt doch hinbekommen.
Danke nochmal vielmals für deine Hilfestellung :)

Ich habe den Zeiger jetzt auf zwei Tasten zugewiesen.
Ich möchte gerne wenn ich auf eine Taste drücke das der Zeiger hoch geht 
und wenn ich loslasse, dass es wieder runterläuft.

Hat einer ne Idee wie man es machen könnte?

von Flat (Gast)


Lesenswert?

Es funktioniert jetzt alles,
-----*Freu mich :) *----
Danke an alle die mir geholfen haben und einen besonderen dank an Ich.

von Flat (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe noch ne Frage.
Es geht darum das ich die Anwendung jetzt auf meinem Display anzeigen 
möchte. Das Display ist ein Chinch display wobei ich die Auflösung 
anpassen muss, damit das Rundtacho auch Kreisförmig angezeigt wird. Ich 
habe nun das Bild so weit gedämpft das das Rundtacho jetzt auf dem 
Display Kreisrund dargstellt wird, doch jetzt habe ich Probleme mit dem 
Zeiger, da der Tacho in wirklichkeit Eiförmig ist, laufen die Zeiger aus 
dem Tacho raus.

Gibt es ne routine, wo ich den Zeiger entsprechend dem Tacho rotieren 
lassen kann. Ich hoffe ihr habt mich richtig verstanden.
Ich wäre sehr dankbar, wenn ihr mir auch hierbei helfen könntet.

Der Code für die Zeiger rotation bei einem Kreisrundem Tacho.
Ich brauch einen Code für für das entsprechende TAcho das eingefügt 
worden ist.
1
Item {
2
    id: root
3
    property int value : 0
4
    property int angle : 0
5
    width: 338
6
    height: 518
7
8
    Image {
9
        id: zeiger
10
        x: 167; y: 114
11
        width: 11
12
        height: 190
13
        smooth: true
14
        source: "GeschwZeiger.png"
15
        transform: Rotation {
16
            id: zeigerRotation
17
            origin.x: 0; origin.y: 150
18
            //! [needle angle]
19
            angle: Math.min(Math.max(root.value * 3.5 -160 ), root.value +50)
20
21
             
22
            Behavior on angle {
23
                SpringAnimation {
24
                    spring: 0.1
25
                    damping: .25
26
                }
27
            }
28
            //! [needle angle]
29
        }
30
    }
31
32
}

von Flat (Gast)


Lesenswert?

Hi,

habe hier in youtube sowas ähnliches

http://www.youtube.com/watch?v=6QZBft8lBOI

Die Nadel läuft nicht über das Rundinstrument.
Es passt sich an die Struktur des Rundinstrumentes an.

Weiss vielleicht einer wie man so etwas realisiert ?
Ich suche schon so lange danach, habe leider nichts gefunden

Gruss

Flat

von Flat (Gast)


Lesenswert?

Weiss den keiner wie das funktioniert ?

von Flat (Gast)


Lesenswert?

Hallo,

Habe mein Problem jetzt so gelöst indem ich mein Rundtacho als Ellipse 
genommen habe, sodass das es auf dem Display, was ich habe als Kreis 
angezeigt wird.

Damit der Zeiger nicht über die Ellipse läuft, habe ich über die 
Ellipsengleichung die Zeigerlänge berechnet und es passt sich an das 
Rundtacho an.

Ellipsengleichung: (x²/a²) + (y²/b²) = 1
a und b sind die Durchmesser des Rundinstruments, wo der Zeiger entlang 
laufen soll.

x = a* cos (Winkel)
y = b* sin (Winkel)

Nun habe ich die Zeigerhöhe ausgerechnet indem ich die Formel auf y 
umgestellt habe und durch den Satz des Pythagoras habe ich die 
Zeigerhöhe herausgefunden.

z = Wurzel(b² + cos(Winkel)² (a²-b²))   z:Zeigerhöhe
1
Item {
2
    id: root
3
    property int value : 0
4
    property int angle : 0
5
    property in a: 550
6
    property in b: 366
7
    width: 338
8
    height: 518
9
10
    Image {
11
        id: zeiger
12
        x: 167; y: 114
13
        width: 366
14
        height: Math.sqrt((root.b*root.b) + (Math.cos(tachoZeigerRotation.angle) * ((root.a*root.a)-(root.b*root.b))))
15
        source: "GeschwZeiger.png"
16
        transform: Rotation {
17
            id: zeigerRotation
18
            origin.x: 183; origin.y: 1
19
            //! [needle angle]
20
            angle: Math.min(Math.max(root.value * 3.5 -160 ), root.value +50)
21
22
             
23
            Behavior on angle {
24
                SpringAnimation {
25
                    spring: 0.1
26
                    damping: .25
27
                }
28
            }
29
            //! [needle angle]
30
        }
31
    }
32
33
}

In der Theorie sollte es funktionieren. Doch als ich die Formel versucht 
habe zu implementieren, beim drehen des Zeigers, verändert sich zwar die 
höhe aber es wird ständig größer und kleiner.
Ich bin mir sicher das der Fehler mit dem Winkel und der cos funktion 
was zun tun hat, aber ich weiss nicht was falsch gemacht habe.
Ich wäre euch sehr dankbar wenn ihr reinschauen und mir sagen könntet, 
was genau flasch ist?
Danke

Gruss
Flat

von Flat (Gast)


Lesenswert?

Ich habe den Fehler jetzt gefunden, Qt berechnet die Winkel in radiant.
Ich habe den Winkel von von Grad in Radiant umgewandelt und jetzt 
funktioniert es.

rad = 90 * pi /180


Gruss
Flat

von Flat (Gast)


Lesenswert?

Hallo,


habe noch ne Frage wegen der Zeigerstellung, die ich digital Anzeigen 
lassen möchte.
Ich habe tachoZeigerRotation.angle also den Winkel genommen um die 
Zeigerstellung digital Anzeigen zu lassen. Doch der Winkel geht von -160 
bis 160 Grad. Ich möchte jetzt die Minima und maxima so wählen das ich 
min 0 und max 240 km/h haben möchte.

Hier ist die der Code für die Rotation von -160 bis 160 Grad
1
    Image {
2
        id: tachoZeiger
3
        x: 0
4
        y: 275-tachoZeiger.height/2
5
6
        width: 366
7
        height: Math.sqrt(c+ (Math.pow(Math.cos(tachoZeigerRotation.angle.toFixed(1)*Math.PI/180),2)*e))
8
9
        source: "zeiger480x480.png"
10
        smooth: true
11
        transform: Rotation {
12
            id: tachoZeigerRotation
13
            origin.x: 183; origin.y:  tachoZeiger.height/2
14
            angle: Math.min(Math.max( root.value*3.5 -160 ), 160)
15
16
            Behavior on angle {
17
                SpringAnimation{
18
                    spring: 0.03
19
                    damping: .1
20
21
22
                }
23
            }
24
25
        }
26
    }

Hier der Code für die Anzeige in Digital.
Wie kann ich mit der Funktion Math.min und Math.max die minima und 
maxima einstellen so das ich am Ende  bei der Zeigerstellung bei -160° = 
0 km/h und bei +160°= 240 km/h habe?
1
    Text {
2
            id: myText1
3
            x: 156
4
            y: 144
5
            text:  tachoZeigerRotation.angle.toFixed(0)
6
            anchors.verticalCenterOffset: -97
7
            anchors.horizontalCenterOffset: -8
8
            anchors.centerIn: parent
9
            style: Text.Outline
10
            font.italic: true
11
            font.bold: true
12
            rotation: 0
13
            font.family: "Arial Black"
14
            font.pointSize: 35
15
            color: "red"
16
17
    }
Ich danke euch für eure Hilfe
Gruss
Flat

von Flat (Gast)


Lesenswert?

Kann mir denn keiner hier helfen?

Wäre euch sehr dankbar für einen hilfreichen tipp.
Danke.

Gruss
Flat

von Andreas M. (amesser)


Lesenswert?

Vorweg, ich finde es super mit welcher Geduld und Beharrlichkeit Du 
deine Probleme löst. Ich denke Du kommst mit dem folgenden Tips selbst 
auf die Lösung: Du möchtest 0..240 nach -160..160 Umrechnen. Das ist 
eine relative simple Abbildung, um genau zu sein musst Du dazu einmal 
Multiplizieren und einmal subtrahieren. Denkanstoß:

0   * A - B = -160
240 * A - B =  160

von Flat (Gast)


Lesenswert?

Ich danke für deine Antwort,
doch ich habe zur Zeit einen hänger,
weiss ehrlich gesagt nicht wie du das meinst...
Kannst du es mir vielleicht verständlicher erläutern ?

von Andreas M. (amesser)


Lesenswert?

Naja, Du musst deine Geschwindigkeit nehmen, diese mit 'A' 
multiplizieren und danach 'B' davon abziehen und schon hast du den 
Winkel. 'A' und 'B' sind zwei Zahlen die Du mit den beiden Gleichungen 
oben bestimmen kannst.

von Flat (Gast)


Lesenswert?

Ich habe dich schon verstanden aber ich weiss nicht wie man das 
implementiert , habe es schon versucht aber meine versuche sind leider 
gescheitert. Kannst du vielleicht ein paar Zeilen quellcode hier 
anhängen, das wäre super von dir.
Ich danke dir schon mal im Voraus.

Gruss
Flat

von Andreas M. (amesser)


Lesenswert?

Jetzt bin ich etwas verwirrt. Die Zeiger funktionieren also wie 
gewünscht? Dein Problem ist die Digitale Ausgabe? Das hat aber erstmal 
nichts mit den Minimum- und Maximum-Werten des Zeigerwinkels zu tun. 
Diese hängen ja nur von deiner Tachografik ab. Du willst also vom Winkel 
auf die Geschwindigkeit umrechnen? Das ist wie oben nur andersherum 
gerechnet. Du musst also in deinem Text Element für den Text eintragen: 
((Winkel + B) / A).toFixed(0)
Denke daran, A und B sind nur Zahlen.

von Flat (Gast)


Lesenswert?

Ich danke dir es hat jetzt funktioniert jetzt.
Was man alles mit der Mathematik lösen kann :)
Ich habe etwas zu kompliziert gedacht glaube ich:)
Danke vielmals.

Gruss
Flat

von Flat (Gast)


Lesenswert?

Hallo,

habe nochmal eine Frage, wo ich nicht genau weiss, wie ich es machen 
soll.
Es geht darum, dass ich jetzt vom Mikrocontroller bytes schicke. Es 
zählt von 0-240 hoch und dann wieder runter in einer Schleife, diese 
möchte ich in
1
myProp1.write(bytes);
  reinschreiben, sodass der GeschwZeiger von 0 bis 240 läuft, doch ich 
bekomme wenn ich die bytes Empfange Ascii Code, doch ich möchte es in 
Dezimal haben.
In
1
 bytes
 sind die empfangenen Zahlen drin

Hier ist der Code, wo ich
1
void PortListener::onReadyRead()
2
{
3
    
4
    myProp1.write(bytes);
5
    bytes = port->readAll();
6
    qDebug() << "bytes read:" << bytes.size();
7
    qDebug() << "bytes:" << bytes;
8
}

Kann mir vielleicht jemand helfen, wie das geht.

von adsf (Gast)


Lesenswert?

die bytes zu einem Zahltyp casten?

von Flat (Gast)


Lesenswert?

hmm ich weiss nicht genau was du meinst , bin neu in c++.
Kannst du mir vielleicht ein Stück quellcode aufschreiben, wie das geht 
?

von Flat (Gast)


Lesenswert?

Mit
1
bytes.toHex()
  kann man in HEx ausgeben, mit welchem Befehl kann man in Dezimal 
umwandeln?? Mit
1
bytes.toInt()
 habe ich schon versucht, doch es funktioniert nicht :(
Kann mir jemand helfen ?

von adsf (Gast)


Lesenswert?

5 monate = neu? Sorry, aber guck mal in ein Buch oder Tutorial unter dem 
Stichwort.
(Ergänzung: ist nicht 100 % perfekt wie mir inzwischen auffällt, da 
theoretisch die Codierung nicht ASCII sein muss... aber tuts definitiv)

von Flat (Gast)


Lesenswert?

Denkst du wenn ich was gefunden hätte , würde ich es hier aufschreiben 
!?

von adsf (Gast)


Lesenswert?


von Flat (Gast)


Lesenswert?

Ich habe hier ein Beispielprogramm gefunden namens speedo.

http://community.qnx.com/sf/discussion/do/listPosts/projects.qt/discussion.general.topc21389?_pagenum=1

Es ist ein Tachoinstrument programmiert worden.
Ich bekomme leider das Prgramm nicht zum laufen.
Ich habe reingeschaut und habe festgestellt das der Pfad für die qml 
Datei
nicht richtig ist habe es entsprechend geändert aber zeigt mir nur ein 
weisses Fenster an wenn ich starte.

Kann mir vielleicht jemand sagen, wo der Fehler ist.
Danke im Voraus

von Flat (Gast)


Lesenswert?

Funktioniert jetzt doch, musste nur die content Ordner in den Build 
Ordner reinkopieren :)

von Flat (Gast)


Angehängte Dateien:

Lesenswert?

Hi ,

habe das Problem, dass die Analog Anzeige nicht mit der Digitalen 
Anzeige übereinstimmt da ich den Kreis als Oval dargestellt habe.

Ich habe die Geschwindigkeiten in Excel aufgenommen und habe es in einem 
Diagramm dargestellt. Man sieht das die Kennlinie bei 0°,90°,180°,270° 
und 360° einen Nulldurchgang hat , also das die Digitale Werte mit dem 
analogen Zeigerinstrument bei diesen Winkeln übereinstimmmen.

Nun zu meiner Frage kann ich die Kennlinie linearisieren , wenn ja wie 
kann ich den Winkel in Qt Mathematisch so beschreiben das es mit der 
digitalen Anzeige passt.

Ich danke für jeden Lösungsvorschlag

hier ist der Code für das Zeigerinstrument
1
    Image {
2
        id: tachoZeiger
3
        x: 178
4
        y: 270
5
6
        width: 11
7
        height: Math.sqrt(c+ (Math.pow(Math.cos(tachoZeigerRotation.angle.toFixed(1)*Math.PI/180),2)*e))
8
        source: "GeschwZeiger.png"
9
        smooth: true
10
        transform: Rotation {
11
            id: tachoZeigerRotation
12
13
            origin.x: 5.5; origin.y:  1;
14
15
            angle:     25.714+root.value*9/7 
16
            Behavior on angle {
17
                SpringAnimation{
18
                    spring: 0.3 
19
                    damping: 0.1 
20
                }
21
22
            }
23
24
        }
25
    }


Freundliche Grüsse

Flat

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.