Daten von RS232 auf Webseite darstellen

DFC-Neo

Semiprofi
Thread Starter
Mitglied seit
14.01.2003
Beiträge
1.311
Ort
Trondheim, Norge
Moin zusammen,

Ich muss für mein Studium ein Messgerät bauen und dessen Daten dauerhaft im Internet darstellen.
Genauer gesagt misst das Gerät die Stärke des elektrostatischen Feldes im Freien und sendet den Wert an die RS232 eines Rechners. Dieser Rechner soll mit den Werten dann eine einfache Webseite erstellen auf der die Werte dargestellt werden.
Mir fehlt nur leider jeglicher Ansatz :-/ Über C++ oder VB die Daten von der Schnittstelle auslesen ist denke ich mal noch nicht so ein Problem. Aber wie erstelle ich dann daraus eine Webseite (am besten mit einem grafischen Verlauf der Werte)?
 
Wenn Du diese Anzeige nicht sehen willst, registriere Dich und/oder logge Dich ein.
Hast du das Protokol der Kommunikation zwischen dem Gerät und dem PC?

Wenn ja, dann ist es alles kein Problem.

So wird es aussehen, vom Ablauf her:

1. Du öffnest einen Thread in deinem Programm, der dir permanent die Daten von COM-Schnitstelle liest
2. Den String, den vom Thread bekommst, zerpflückst (parst) du in die einzelnen Werte und schreibst es in einen Struct rein.
3. Ein anderer Thread holt die Daten aus dem Struckt und schreibt sie komma- oder strichpunktsepariert in eine Datei oder Datenbank (würde eher Datenbank nehmen)
4. Du öffnest die Datei mit PHP und liest sie ein.
5. Nimmst die Stringst auseinander und schreibst das ganze in Arrays.
6. Mit PHP lassen sich auch Kurvendiagramme erstellen.

JC
 
Ui, welch seltener Gast ;-) Hab ja schon lang nix mehr von dir gelesen hier.

Also das Protokol kenn ich, der Mikrocontroller schickt einfache 8Bit-Zahlen.
So ungefähr habe ich mir dass auch vorgestellt, allerdings hapert es noch an der konkreten Ausführung.
- Wenn ich das in C(++) programmiere, reicht das ja als Konsolen-Anwendung, weils ja eh nur auf dem Webserver läuft, oder?
- Kann ich als Datenbank einfach MySQL nehmen? Das konnte ich vor ein paar Jahren schon mal ;-)
- Muss ich mich dann um die gleichzeitigen Schreib-& Lesezugriffe selber kümmern oder macht das MySQL?
- Und für das struct (bzw ein Array reicht ja auch) muss ich die Zugriffe regeln (mit Semaphoren oder so wahrscheinlich)?

Und schon mal vielen Dank für deine Hilfe! :)
 
Servus, weisst ja, schlechten Menschen geht es immer gut, naja, hatten npaar Probleme. Ich habe auch meinen Arbeitgeber gewechselt. Egal.

zu 1: Ja, du brauchst sowas wie ein Dienst, der dir die Daten von COM liest und die in die Datei/Datenbank pumpt.

zu 2: Aber sicher doch.

zu 3: Nein, musst du nicht. Ich weiss jetzt nicht ob MySQL Transaktionen kann, wenn ja, musst du sicherstellen, dass dein Programm nach der Transaktion einen "commit" absetzt. Sonst bleiben die neue Einträge für deine Seite unsichtbar bis ein commit durchgeführt wird.

zu 4: Schickt denn der Microkontroller nur die Werte raus oder auch was anderes? Sowas wie ECC oder sowas? Wenn nicht, dann reicht ein Array oder ein AnsiString aus. Den Port macht du exclusiv auf, also nur für dich und blockierst ihn für andere Programme.

Nichts zu danken.

JC
 
Mir ist gestern im Bett noch was eingefallen. Eigentlich brauchst du gar keinen Thread, der dir die COM-Schnittstelle ausliest, du kannst es mit einem Timer realisieren, das klappt auch prima.

JC
 
So wichtig ist die Sache auch nicht dass sie dich noch im Bett beschäftigen muss ;-)

Ich werde es wahrscheinlich trotzdem mit Threads machen, da in der einen Vorlesung an der FH mal einen Ringspeicher in C geschrieben habe, der sollte dafür eigentlich sehr gut passen.

Das mit den Graphen in PHP klappt übrigens sehr gut, wieder was neues gelernt :)
 
Cool :) Ist zwar schon ein bisschen spät, aber trotzdem alles Gute noch ;-)

Der Teil mit den Daten aus MySQL eine Grafik zu erstellen ist schon fertig. Das Programm mit dem COM-Port konnte ich noch nicht testen da mein Laptop so etwas nicht hat :-/ Kann ich erst heute in der Hochschule machen.
 
Danke, danke, danke. Und eine Tochter haben wir auch. :grins:

Du bist einer von ganz schnellen Sorte. Aber schick wenn es funktioniert. Kannst mir mal bei Gelegenheit PHP-Code schicken? Wäre cool.

JC
 
ja, das hab ich schon gelesen :)

Hab mal einen Screenshot und den Code angehängt.
 

Anhänge

  • JPGraph_Example.zip
    31,2 KB · Aufrufe: 65
So, ein Problemchen habe ich noch ;-)
Ich will nur ca. alle 30s Sekunden einen Messwert speichern, damit die Datenmenge nicht zu groß wird. Nur wie stell ich dass an?!
Mein erster Versuch war einfach das C-programm, welches die Schnittstelle ausliest und dann den Wert in die DB speichert, immer 30s warten zu lassen bis es den Wert liest. Nachdem der uController aber die ganze Zeit sendet, hat das Programm dann eins nach dem anderen den Buffer ausgelesen :-/

Wenn ich den UController bremse, aber das Programm dauert auslesen lasse, dann bekomme ich halt andauernd den gleichen Wert, bis was neues angekommen ist und müsste dass dann irgendwie Filtern.

Gibt es vielleicht eine Möglichkeit über das C-Programm den Buffer vor jedem Lesevorgang zu löschen? Dann könnte ich den uC munter schreiben lassen, wenn das Programm sich Daten holen will, löscht es vorher den Buffer und list dann einen aktuellen Wert aus dem Buffer aus.
 
Halli hallo,

sorry, dass ich mich erst so spät melde, war auf den Testfahrten.

Wie schreibst du die Werte in die Variable rein? Hast du eine Methode, sowas wie "set_value" oder sowas? Wenn ja, dann kannst du sie alle 30 Sek (zum Beispiel timergesteuert) aufrufen und NULL reinschreiben. Dann wird sie ja von dem Thread gefüllt und du kannst den Wert auslesen. So hätte ich es gemacht.

JC
 
Zuletzt bearbeitet:
Kein Problem,
Warst du mit deinem Auto unterwegs oder "dienstlich" ? ;-)

Das mit dem Timer habe ich auch schon überlegt, aber ich hab noch keine halbwegs verständliche Anleitung dazu gefunden. Und das mit Threads und so wollte ich mir eigentlich wenn möglich sparen...
Ich hab schon einen Befehl gefunden wie ich den Input-Buffer löschen kann, vielleicht löst dass dann schon mein Problem. Kann ich nur erst am Montag in der FH testen weil mein Laptop keinen COM-Port hat :-/
 
Nene, ich war dienstlich unterwegs, waren mit drei Fahrzeugen in Frankreich, in der Nähe von Paris. War cool. Leider darf ich nicht mehr selber fahren, wegen meinem Nacken.

Wie hast du es denn jetzt gemacht, mit oder ohne den "Lesethread"? Wie hast du es denn realisiert?

JC
 
Ich hab es jetzt so gemacht dass ich den uC dauernd senden lasse und meine Funktion dann erst den Input-Buffer leert, 2 Sekunden wartet und dann den Wert ausliest. Damit sollte es klappen, werde ich Montag dann testen ob es so auch funktioniert.

Hier mal der ganze Code, ist zwar nicht schön, aber es läuft :d Und da nur der Aufbau des Messgerätes bewertet wird und die Software "nur laufen muss", ist dass Programmieren nicht so wichtig...

Code:
// MySQL_Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#if defined __WIN32__ || _MSC_VER
#include <windows.h>
#endif
#include "include/mysql.h"
#include <time.h>
#include <iostream>
#include <conio.h>
using namespace std;

//Prototypen deklarieren
void check_error(void);
void verbinden(void);
HANDLE open_com(void);
void verbindung_schliessen(void);
void db_waehlen(char *);
void daten_anfuegen(int);
void daten_loeschen(void);
int get_value(HANDLE);
int get_rand_value(int);
MYSQL  *mysql;


int main (int argc, char **argv) {
//Zur Datenbank verbinden
int value=0;
printf("Baue verbindung zur Datenbank auf ...\n\n");
verbinden();
db_waehlen("femue");
HANDLE hCom = open_com();

    
	/* Hier befindet sich der Code für die Arbeit mit MySQL */
while (!kbhit())
{
	value = get_value(hCom);
	//value = get_rand_value(value);
	daten_loeschen();
	//value = 0;
	daten_anfuegen(value);
	Sleep (3000);
	
} 
	

   /* Verbindung trennen */
	verbindung_schliessen();
	
   
   system("PAUSE");
   return EXIT_SUCCESS;
}

/* Bricht bei Fehler (mysql_error != 0) das Programm ab */
void check_error(void)  {
   if (mysql_errno(mysql) != 0) {
      fprintf(stderr, "Fehler: %s\n", mysql_error(mysql));
	  system("PAUSE");
      exit(EXIT_FAILURE);
   }
}
/* Baut eine Verbindung zum Datenbankserver auf.
 * Passen Sie ggf. Usernamen und Passwort und, sofern
 * andere Parameter benötigt werden, diese Ihren
 * Umständen selbst an
 */
void verbinden(void)  {
   mysql=mysql_init(mysql);
   check_error();
   mysql_real_connect(mysql, "localhost", "root",
                      NULL, NULL, 0, NULL, 0);
   check_error();
}
/* Serververbindung wieder schließen und den Speicher für die
 * Struktur MYSQL wieder freigeben */
void verbindung_schliessen(void)  {
   mysql_close(mysql);
}
/* Daten mit mysql_real_query() in die Datenbank schreiben */
void daten_anfuegen(int value) {
   int i,  size=0;
   char *str[3], *query;
   /* Jetzt wird der Anfragestring erstellt */
   str[0] = "INSERT INTO `feld` ( `Datum` , `Value` ) VALUES (UNIX_TIMESTAMP() , '";
   str[1] =(char *) malloc(6);
   sprintf(str[1], "%6d", value);
   str[2] = "')";
   /* Speicherplatz für den Anfragestring reservieren */
   for (i=0;i<3;i++)size+=strlen(str[i]);
   query =(char *) malloc(size);
   strcpy(query, str[0]);
   for(i = 1; i < 3; i++)
      strcat(query, str[i]);
   /* Zum Testen für die Konsole  */
   printf("Anfrage 1: %s\n",query);         
   /* Jetzt die Anfrage an den Datenbankserver */
   mysql_real_query(mysql, query, strlen(query));
   check_error();
   for (i=0;i<3;i++)free(str[i]);

   free(query);
}
/* Falls die Datenbank bei der Funktion verbinden() nicht 
 * angegeben wurde oder Sie die Datenbank wechseln wollen, dann
 * verwenden Sie diese Funktion */
void db_waehlen(char *db) {
   mysql_select_db(mysql, db);
   check_error();
}
void daten_loeschen(void) {
   MYSQL_RES *mysql_res;
   MYSQL_ROW row;
   int i, size = 0;
   char *str[3], *query;
   str[0] = "SELECT * FROM `feld` ORDER BY `Datum` ASC LIMIT 0 , 1";
   /* Jetzt die Anfrage an den Datenbankserver */
   mysql_real_query(mysql, str[0], strlen(str[0]));
   check_error();
   /* Daten der Anfrage abholen */
   mysql_res = mysql_store_result(mysql);
   check_error();
   row = mysql_fetch_row (mysql_res);
   str[0] = "DELETE FROM feld WHERE `Datum` = '";
   str[1] =(char *) malloc(19);	
   sprintf(str[1],"%19s",row[0]);
   str[2] = "' LIMIT 1";
   for (i=0;i<3;i++)size+=strlen(str[i]);
   query =(char *) malloc(size);
   strcpy(query, str[0]);
   for(i = 1; i < 3; i++)
      strcat(query, str[i]);
   //printf("8.%s\n", query2);
   /* Zum Testen für die Konsole  */
   printf("Anfrage 2: %s\n",query);         
   /* Jetzt die Anfrage an den Datenbankserver */
   mysql_real_query(mysql, query, strlen(query));
   check_error();
   for (i=0;i<3;i++)free(str[i]);
   free(query);
}
HANDLE open_com(){
	DCB dcb;
	HANDLE hCom;
	BOOL fSuccess;
	char *pcCommPort="Com1";  //Hier die Schnittstelle auswählen
	   
	   
	// Mit CreateFile die Schnittstelle als File generieren
	hCom = CreateFile( pcCommPort,
						GENERIC_READ | GENERIC_WRITE,
						0,    // must be opened with exclusive-access
						NULL, // no security attributes
						OPEN_EXISTING, // must use OPEN_EXISTING
						0,    // not overlapped I/O
						NULL  // hTemplate must be NULL for comm devices
						);
	//Nun den DCB Block modifizieren
	// Fill in DCB: 9,600 bps, 8 data bits, no parity, and 1 stop bit.
	// DCB ermitteln ;d.h. Standardeinstellungen laden und diese verändern
	fSuccess=GetCommState(hCom,&dcb);
	if(!fSuccess)printf("%d Fehler beim Ermitteln des DCB Blocks \n",fSuccess);
		   
	dcb.BaudRate = CBR_9600;     // set the baud rate
	dcb.ByteSize = 8;             // data size, xmit, and rcv
	dcb.Parity = NOPARITY;        // no parity bit
	dcb.StopBits = ONESTOPBIT;    // one stop bit
	//Nun die Daten zurückschreiben auf den DCB zurückschreiben,
	//so dass diese Eisntellungen auch gültigkeit erlangen
	fSuccess=SetCommState(hCom,&dcb);
	if(!fSuccess)printf("%d Fehler beim Uebermitteln des DCB Blocks \n",fSuccess);
	else printf ("Serieller Port %s erfolgreich eingestellt und geöffnet.\n\n\n", pcCommPort);
	return hCom;
}
int get_rand_value(int old){
	int value = 0;
	/* Daten per Zufallsgenerator erzeugen */
	//	=C23521++ZUFALLSBEREICH(-5;5)*10
	int random = (int)(((double)rand() / RAND_MAX) * (10 + 1 - -10) + -10);
	value = old+random;
	printf ("Zufallswert: %4d\n", value);
	return value;
}
int get_value(HANDLE hCom){
	int value = 0;
	
	/*  Daten aus als 8-Bit-Zahl vom COM-Port einlesen
		und umwandeln */
	void DiscardInBuffer ();
   	sleep(2000);
   	fSuccess = ReadFile(hCom,&ausgabe,1,&dwBytesRead,0);
   	//char_traits<char>::char_type ch3 = 'a';

   	printf("erhaltene Zeichenkette: %s entspricht %d \n",ausgabe, ausgabe[0]);
	value = ausgabe[0];*/
	return value;
}
;
 
Sieht doch ganz brauchbar aus.

Noch eine Empfehlung von mir. Wenn du Variablen deklarierst, dann setze sie auch auf einen bestimmten Wert. Am besten NULL, 0 oder false. Dann kannst du nämlich beim debugen gleich sehen, ob deine Methoden die Variablen umschmeissen oder nicht.

Desweiteren vermeide die Methoden mit void als Rückgabewert, das kommt nicht gut. Eine Methode sollte immer einen Wert zurückgeben, auch wenn es nur ein true oder false ist (ob es geklappt hat oder nicht).

Ansonsten sieht okay aus. Okay, ich habe einen etwas anderen Stil, aber das ist nun wirklich Geschmacksache.

JC
 
Danke :-)

Das mit den Rückgabewerten und den Startwert für die Variablen werde ich noch ändern, sowas lernt man in der FH leider nicht :-/
Am Montag werde ich berichten ob es geklappt hat!

Schönes Wochenende!!
 
Ich weiss nicht, ob man sowas lernen kann. Mir haben es auch die Kollegen bei BMW Motorsport beigebracht. An der FH/Uni werden einem nur die Gründzüge beigebracht, den Stil arbeitet man dann selber aus.

Jö, dann fummele das Programm fertig und jag es durch den Kompiler. So auf den ersten Blick sollte es eigentlich tun.

Ebenfalls ein schönes WE, meine Frau schimpft schon, dass ich so lange vor'm Rechner sitze. grins

JC
 
So, jetzt lass ich auch mal wieder was hören ;-)
Mittlerweile läuft das Programm so wie ich mir dass vorgestellt habe. Ich lese nach ca. 30s immer den gesamten Inputbuffer der seriellen Schnittstelle ein, sind ca. 30 Byte. Dann wird ein Mittelwert gebildet und abgespeichert. :-)
Dafür nervt mich jetzt der mechanische Aufbau :-/ Sowas liegt mir gar nicht, erst recht wenn ich so im Zeitdruck bin...
 
So, gestern hab ich den ersten Test mit der aufgebauten Hardware gefahren... Und sobald die Messsignale größer werden, stürzt das Programm ab??

Code:
int get_value(){
    int count=0,i=0;
    long avg=0,wert=0;
    char ausgabe[10];
    DWORD dwBytesRead=0;
    //Spaeter wieder auf 30 Sekunden setzen!!!!
    sleep(10000);
    ReadFile(hCom,&ausgabe,90,&dwBytesRead,0);
    count = dwBytesRead;
    //printf("Schleife für %s starten\n",ausgabe);
    avg = 0;
    for (i=0;i<count;i++){
          if (ausgabe[i] < 0){
                    wert = ausgabe[i]+128;
                    }
                    else
                    {
                    wert = ausgabe[i];
                    };  
          if (debug != 1){
                    printf("Wert %d empfangen: %c = %d; Summe=%d\n", i, ausgabe[i], wert, avg);
                    };
          avg=avg+wert;
          };
    
    if (debug != 1){
       printf("%d Werte erhalten, Mittelwert = %d / %d = %d\n\n\n",count,avg,count,avg/count);
       };
    return avg/count;
}

Die Funktion wird in dieser Endlos-Schleife aufgerufen:
Code:
while(!kbhit()){
    value = get_value();};
In der Schleife passiert normal noch mehr, aber der Fehler tritt auch so auf.

Der einzige Unterschied der den Absturz hervorruft ist das etwas mehr Daten (ca. 45 statt 30) im Buffer sind beim Auslesen und das die etwas größer sind. Aber dann stürzt dass Programm bei der letzten Zeile hier ab :(
Weiß jemand warum?
 
Hab das Problem mittlerweile gelöst. Der Softwareteil der Aufgabe funktioniert jetzt, nur das Messgerät selber hat nicht ganz so getan wie geplant :-/ Aber jetzt habe ich das Ganze abgegeben müssen, mal sehen was draus wird ;-)
Und nachher gehts eh erstmal für ein Jahr nach norwegen zum Studieren !!!! :-)
 
Hardwareluxx setzt keine externen Werbe- und Tracking-Cookies ein. Auf unserer Webseite finden Sie nur noch Cookies nach berechtigtem Interesse (Art. 6 Abs. 1 Satz 1 lit. f DSGVO) oder eigene funktionelle Cookies. Durch die Nutzung unserer Webseite erklären Sie sich damit einverstanden, dass wir diese Cookies setzen. Mehr Informationen und Möglichkeiten zur Einstellung unserer Cookies finden Sie in unserer Datenschutzerklärung.


Zurück
Oben Unten refresh