Jump to content

uwew

Members
  • Gesamte Inhalte

    13
  • Benutzer seit

  • Letzter Besuch

Alle erstellten Inhalte von uwew

  1. Guten Morgen Jürgen. Vielen Dank für Deine Info. Ich habe zum Thema "Thread" mal ein Video (c++ Tutorial von Pilzschaf Nr. 68) angeschaut. Jetzt weiss ich so ungefähr, was man unter einem Thread versteht. Machen Threads auch beim "SingleCore"-Prozessor des RED-Bricks (Cortex A8) Sinn? Meinen aktuellen Source-Code habe ich mal als Datei angehängt. Das Programm compiliert fehlerfrei und läuft auch fehlerfrei. _P202007MS02_Dosiersystem.cpp. Allerdings tritt folgendes Problem auf: Wenn ich eine der Pumpen im Intervall-Betrieb (LCD-Button "Inter" auf dem angehängten Bild) starte, dann macht diese Pumpe genau das, was sie soll. Das LCD ist jedoch für weitere Eingaben blockiert. Erst nach einer unreprodzierbaren Zeitspanne, sind dann plötzlich Eingaben möglich. Die zugehörige Funktion: /** * Die folgende Funktion startet die Pumpe und macht die Anzahl Schritte, die übergeben wurde. * Die Motorsteps per second werden ebenfalls zuvor berechnet und übergeben. * Über die Callbackfunktion wird sie nach einer gewissen Zeit (Delay-Time) wieder aufgerufen. * */ void PumpMotorStartIntervalMode(PeristalticPump *DummyPump) { /* Anfang - Variablen lediglich zur Kontrolle und nicht für Betrieb */ uint16_t currVel; int32_t currPos; int32_t remainSteps; uint16_t stackVolt; uint16_t externVolt; uint16_t currConsumpt; char retPos; /* Ende Variablen zur Kontrolle */ uint16_t DosingFactor = 1; uint16_t MotorSpeedmLPerHour; uint16_t MotorSpeedStepsPerSecond; uint32_t NumberOfStepsPerHour; uint32_t NumberOfStepsPerDosingPeriod; uint8_t mode = STEPPER_STEP_MODE_EIGHTH_STEP; DosingFactor = (DummyPump->DosingIntervalTimeMinute_Value + DummyPump->DelayIntervalTimeMinute_Value) / DummyPump->DosingIntervalTimeMinute_Value; NumberOfStepsPerHour = PUMP_FULL_STEPS_PER_ROUND * mode * DummyPump->RoundsPer100mL / 100 * DummyPump->FlowMLPerHour_Value * DummyPump->CalibrationFactorPercent_Value / 100; NumberOfStepsPerDosingPeriod = NumberOfStepsPerHour * (DummyPump->DosingIntervalTimeMinute_Value + DummyPump->DelayIntervalTimeMinute_Value) / 60; MotorSpeedStepsPerSecond = NumberOfStepsPerHour / 3600 * DosingFactor; stepper_set_motor_current(DummyPump->pStepper, STEPPER_CURRENT); stepper_set_step_mode(DummyPump->pStepper, mode); stepper_set_max_velocity(DummyPump->pStepper, MotorSpeedStepsPerSecond); stepper_enable(DummyPump->pStepper); for (uint16_t i = 1; i < DosingFactor; ++i) { stepper_set_current_position(DummyPump->pStepper, 0); // stepper_drive_forward(DummyPump->pStepper); stepper_set_steps(DummyPump->pStepper, NumberOfStepsPerDosingPeriod); millisleep(DummyPump->DelayIntervalTimeMinute_Value * 6000); } // stepper_set_steps(DummyPump->pStepper, 5000); /** Kontrollausgabe zur Überprüfung am Bildschirm */ std::cout<< std::endl << "PumpMotorStartIntervalMode(PeristalticPump *DummyPump)\n"; sprintf(text03, "Dos: %2d\tDel: %2d\t DF: %2d\t Steps/h: %d\t Steps/Period: %d\t, Step/sec: %d", DummyPump->DosingIntervalTimeMinute_Value, DummyPump->DelayIntervalTimeMinute_Value, DosingFactor, NumberOfStepsPerHour, NumberOfStepsPerDosingPeriod, MotorSpeedStepsPerSecond); std::cout << "text03: " << text03 << std::endl; /* Ende Kontrollausgabe*/ } Vielleicht liegt die Ursache des Problems aber gar nicht in der Funktion selbst, sondern in den CallBack-Einstellungen in der main(): lcd_128x64_register_callback(&pLCD128x64, LCD_128X64_CALLBACK_GUI_TAB_SELECTED, (void (*)(void))cb_gui_tab_selected, &ActivePump ); lcd_128x64_register_callback(&pLCD128x64, LCD_128X64_CALLBACK_GUI_BUTTON_PRESSED, (void (*)(void))cb_gui_button_pressed01, &LCDTabIndex ); rotary_encoder_v2_register_callback(pump[0].pEncoder, ROTARY_ENCODER_V2_CALLBACK_COUNT, (void (*)(void))cb_InputEncoder, &pump[0]); rotary_encoder_v2_register_callback(pump[1].pEncoder, ROTARY_ENCODER_V2_CALLBACK_COUNT, (void (*)(void))cb_InputEncoder, &pump[1]); rotary_encoder_v2_register_callback(pump[2].pEncoder, ROTARY_ENCODER_V2_CALLBACK_COUNT, (void (*)(void))cb_InputEncoder, &pump[2]); rotary_encoder_v2_set_count_callback_configuration(pump[0].pEncoder, 200, true, 'x', 0, 0); rotary_encoder_v2_set_count_callback_configuration(pump[1].pEncoder, 200, true, 'x', 0, 0); rotary_encoder_v2_set_count_callback_configuration(pump[2].pEncoder, 200, true, 'x', 0, 0); lcd_128x64_set_gui_button_pressed_callback_configuration(&pLCD128x64, 300, true); lcd_128x64_set_gui_tab_selected_callback_configuration(&pLCD128x64, 300, true); Noch eine Anmerkung: Derzeit compiliere und starte ich das Programm noch auf einem Windows-PC mit Code::Blocks. Herzlichen Dank für weitere Tips im Voraus. Uwe
  2. Hallo Markus. Vielen Dank für Deine Infos. Ich schau mir die Thread-Geschichte und das Projekt mal an. Gruss Uwe
  3. Hallo Markus. Vielen Dank für Deine Rückmeldung. Das Problem ist, dass ich eigentlich noch Programmier-Anfänger bin. Was ich suche: Wenn das Dosiersystem gestartet ist, brauche ich für jede Pumpe einen Timer, der sagt "Dosiere jetzt x Min, danach pausiere bitte y min". Ich weiss, dass es eine sleep-Funktion gibt. Den Begriff "Thread" habe ich zwar schon gehört, hab mich aber bisher nicht damit beschäftigt. Mir fehlt im Moment die Idee, wie man solche Timer in C/C++ erstellt und in ein Programm einbindet (Stichwort Interrupt?) Grüsse Uwe
  4. Hallo Ich habe ein Dosiersystem mit drei Peristaltikpumpen, gesteuert mit je einem Stepper Brick. Die Software ist in C/C++ geschrieben. Das Ganze funktioniert grundsätzlich. Bei folgender Problemstellung komme ich aber nicht weiter: Wenn die Dosiervolumina sehr klein sind, drehen sich die Motoren auch entsprechend langsam. Dann würde ich gerne auf Intervallbetrieb umstellen (d.h. 1 Minute dosieren, 9 Minuten Pause, 1 Minute dosieren, 9 Minuten ....). Hat jemand eine Idee, wie man das umsetzen kann? Zusatzinfo: Der TF-Stapel besteht aus Step-Down Power Supply, RED-Brick, 3 Stepper-Bricks, 3 Rotary Encoder 2.0 und 1 LCD128x64-Display. Ein Real Time Clock Bricklet wäre vorhanden ist aber bisher nicht integriert. Herzlichen Dank für eure Tips Uwe
  5. Das Problem mit dem Encoder-Bricklet kriege ich jetzt durch die Warteschleife in den Griff und ich kann an meiner Dosierstation weiterarbeiten. Sollte ich dabei noch auf nützliche Informationen stossen, dann schreibe ich es hier ins Forum. Nochmals vielen Dank für die Unterstützung. Gruss Uwe
  6. Problem Nr. 1 ist erledigt - ich habe die aktuelle Version des Brick-Viewers draufgespielt🙂. Zu Problem Nr. 2, Farbenspiel: Das Joy-It-Display ist vollflächig weiss, rot, grün, blau, dunkel im 2-sec-Abstand, wenn beim Einschalten das Joy-It-Display über den HDMI-Port mit dem RED-Brick verbunden und eingeschaltet ist. Trenne ich dann HDMI-Verbindung, so erscheint beim erneuten Einstecken des HDMI-Kabels der gewohnte TF-Desktop. Boote ich den RED-Brick über den grünen Kreis unten rechts auf dem Desktop, gelange ich zum erwähnten Farbenspiel. Starte ich den Brick-Viewer auf dem RED-Brick und führe ich dort einen Reboot durch komme ich zum gleichen Ergebnis. Abhilfe schafft nur das Trennen der Verbindung zwischen Joy-It und RED-Brick. .An dieser Stelle muss ich mal ein herzliches Dankeschön für die kompetente und schnelle Hilfestellung loswerden.
  7. Guten Morgen. Vielen Dank für die Rückmeldungen. Zum Tipp mit dem Warten in der main(): Habe einfach eine for-Schleife mit printf("a") eingebaut. Mit dieser Schleife funktioniert es, d.h. das Programm reagiert auf den Encoder, auch wenn der RED-Brick nicht an einem Computer hängt. Welche Infos wären noch nützlich für die Ursachenforschung?
  8. Danke für die Rückmeldung. Wenn ich das Programm vom PC aus starte dann liefert printf("return value: %d \n",rotary_encoder_v2_set_count_callback_configuration(&RotEnc01, 500, false, 'x', 0, 0)); auf der Console: "return value: 0" Im Brick Viewer Log hat es folgende Einträge drin: wobei "KcD" die UID meines Rotary Encoders 2.0 ist. Leider weiss ich nicht, wo der RED-Brick den printf-Befehl ausgibt. Deshalb habe den Wert auf dem LCD128x64 ausgeben lassen. Auch da liefert die Funktion den 0 als return-value, wenn ich das Dosiersystem ohne den PC starte. Ich hoffe, diese Infos bringen etwas Licht ins Dunkel. Dann habe ich noch zwei kleine Probleme: 1. Im Moment ist der RED-Brick nicht in der Lage das C/C++-Update durchzuführen. Er meldet zwar nach Ewigkeiten (>45 min) dass das Update erfolgreich war. Es ist aber nach wie vor Version 2.1.30 installiert. Suche ich dann erneut nach Updates, dann meldet er wieder, dass eine neue Version vorhanden ist. Das Spiel beginnt von vorn. 2. Wenn ich ein LCD-Display von Joy-It anschliesse (nur HDMI, nicht USB für touch), dann sehe das Farbenspiel, egal ob ich zuerst den Brick oder das Display einschalte. Erst wenn ich den HDMI-Anschluss trenne und neu verbinde, erscheint der Linux-Desktop und das blaue TF. Hat da jemand eine Idee? Gruss Uwe
  9. Hallo. Ich habe in C/C++ ein "Programm" geschrieben, welches die Counts eines Rotary Encoders als Eingabe für verschiedene Parameter benutzt. Die Parameter werden auf einem LCD128x64 über Buttons ausgewählt (s. Anhang IMG_6043.jpg). Hardware: Redbrick mit Silent Stepper Brick. An letzterem hängt ein LCD128x64 und ein Rotary Encoder V2. Das Programm macht das was es soll, solange ich es auf meinem PC starte, der über USB mit dem RED Brick verbunden ist (soweit ich das verstehe, läuft dann das Programm über den Brick Daemon). Compiliere ich das Programm auf dem RED-Brick, und stelle "Autostart" ein, dann läuft das Programm ohne Fehlermeldung, die Bedienung des LCD128x64 funktioniert auch, nur das Drehen am Encoder wird nicht erkannt. Starte ich den Brick-Viewer auf dem RED-Brick, dann reagiert der wie erwartet, wenn man am Rotary Encoder dreht. Nachdem ich die FAQs durchgelesen habe, habe ich den Verdacht dass es an der Callback-Funktion liegt - aber ich kann mir keinen Reim drauf machen Das "Programm" ist momentan im Prototypen-Status. Die globalen Definitionen und main() sieht folgendermassen aus. #include <iostream> #include <sstream> #define IPCON_EXPOSE_MILLISLEEP #include "ip_connection.h" #include "bricklet_lcd_128x64.h" #include "brick_silent_stepper.h" #include "bricklet_rotary_encoder_v2.h" #define HOST "localhost" #define PORT 4223 #define UID_LCD128x64 "R2d" #define UID_SILENTSTEPPER01 "6Sy4c8" #define UID_rotEnc01 "KcD" #define STEPPER01_ACCELERATION 5000 #define STEPPER01_DEACCELERATION 5000 #define STEPPER01_CURRENT 800 #define STEPPER01_MAX_Umin 120 #define LCD128x64_TABHOME 0 #define LCD128x64_TABREG1 1 #define LCD128x64_TABREG2 2 #define LCD128x64_TABNH3 3 #define LCD128x64_ButtonStart 1 #define LCD128x64_ButtonStop 2 #define LCD128x64_ButtonAus 3 #define LCD128x64_ButtonFlow 4 #define LCD128x64_ButtonCalFactor 5 #define LCD128x64_ButtonDosingInterval 6 #define LCD128x64_ButtonDelayInterval 7 IPConnection ipcon; LCD128x64 lcd01; bool lcd01_created; SilentStepper SilentStepper01; RotaryEncoderV2 RotEnc01; int32_t countRotEnc01; uint8_t ID_LCD128x64_MenuePunkt; uint8_t ID_LCD128x64_Tab; char text01[22]; char text02[22]; char text03[22]; char text04[22]; struct PeristalticPump { uint8_t PumpID; char PumpName[4]; char LiquidName[6]; char FlowMLPerHour_Name[11]; uint16_t FlowMLPerHour_Value; char DosingIntervalTimeMinute_Name[11]; uint8_t DosingIntervalTimeMinute_Value; char DelayIntervalTimeMinute_Name[11]; uint8_t DelayIntervalTimeMinute_Value; char CalibrationFactorPercent_Name[11]; uint8_t CalibrationFactorPercent_Value; uint16_t RoundsPer100mL; // float TubeInnerDiameterMM; // bool FlowDirectionClockwise; SilentStepper *SilentStepper01; LCD128x64 *lcd01; uint8_t TabIndex; uint8_t ButtonIndex; }; PeristalticPump pump; void cb_count02(int32_t count, PeristalticPump &ActivePump); void cb_ispressed01(PeristalticPump &ActivePump); void cb_gui_button_pressed01(uint8_t index, bool pressed, PeristalticPump &ActivePump); void cb_gui_tab_selected(int8_t index, PeristalticPump &ActivePump); void LCD128x64_HomeScreen(PeristalticPump &ActivePump); void LCD128x64_REG1(PeristalticPump &ActivePump); void Motor(PeristalticPump &ActivePump); void MotorContinuousModeStart(PeristalticPump &ActivePump); void MotorStop(PeristalticPump &ActivePump); int main(void) { ipcon_create(&ipcon); lcd_128x64_create(&lcd01, UID_LCD128x64, &ipcon); silent_stepper_create(&SilentStepper01, UID_SILENTSTEPPER01, &ipcon); rotary_encoder_v2_create(&RotEnc01, UID_rotEnc01, &ipcon); if(ipcon_connect(&ipcon, HOST, PORT) < 0) { fprintf(stderr, "Could not connect\n"); return 1; } lcd_128x64_register_callback(&lcd01, LCD_128X64_CALLBACK_GUI_TAB_SELECTED, (void (*)(void))cb_gui_tab_selected, &pump); lcd_128x64_register_callback(&lcd01, LCD_128X64_CALLBACK_GUI_BUTTON_PRESSED, (void (*)(void))cb_gui_button_pressed01, &pump); rotary_encoder_v2_register_callback(&RotEnc01, ROTARY_ENCODER_V2_CALLBACK_COUNT, (void (*)(void))cb_count02, &pump); rotary_encoder_v2_set_count_callback_configuration(&RotEnc01, 500, false, 'x', 0, 0); lcd_128x64_set_gui_button_pressed_callback_configuration(&lcd01, 1000, true); lcd_128x64_set_gui_tab_selected_callback_configuration(&lcd01, 1000, true); pump.lcd01 = &lcd01; LCD128x64_HomeScreen(pump); printf("Press key to exit\n"); getchar(); silent_stepper_stop(&SilentStepper01); // Request motor stop silent_stepper_set_speed_ramping(&SilentStepper01, STEPPER01_ACCELERATION, STEPPER01_DEACCELERATION); millisleep(400); // Wait for motor to actually stop: max velocity (2000 steps/s) / decceleration (5000 steps/s^2) = 0.4 s silent_stepper_disable(&SilentStepper01); // Disable motor power silent_stepper_destroy(&SilentStepper01); lcd_128x64_destroy(&lcd01); rotary_encoder_v2_destroy(&RotEnc01); ipcon_destroy(&ipcon); // Calls ipcon_disconnect internally return 0; } Hat jemand eine Idee, warum alles funktioniert bis auf den Encoder? Gruss Uwe
  10. Hi Bernhard. Vielen Dank für den Tip. So funktioniert es! Gruss Uwe
  11. Derzeit versuche ich eine Benutzerführung zur Steuerung von 2 Peristaltikpumpen (Schrittmotoren) auf einem LCD128x64 in C zu programmieren. Dazu verwende ich sechs Pushbuttons. Dabei hänge ich im Moment an folgendem Problem fest: Mit folgendem Callback registriere ich das Drücken eines buttons: lcd_128x64_register_callback(&lcd01, LCD_128X64_CALLBACK_GUI_BUTTON_PRESSED, (void (*)(void))cb_button01_pressed, NULL); Die Funktion cb_button01_pressed hat nur folgenden Inhalt: void cb_button01_pressed(void *user_data) { printf("Hello Button01\n"); } Mein Problem: Wie stelle ich fest, welcher der sechs Pushbuttons gedrückt wurde und wie übergebe ich diese Information an die Funktion "cb_button01_pressed()" damit ich jeweils unterschiedliche Funktionen ausführen kann? Herzlichen Dank für eure Hilfe
  12. Du warst auf der richtigen Spur. Ganz herzlichen Dank für den Tipp!! Uwe
  13. Hallo, ich arbeite mich gerade in die Tinkerforge-Welt und die C++-Programmierung ein. Als Hardware verwende ich das Starterkit "Wetterstation (indoor)" mit einem RED-Brick. Momantan komme ich beim folgenden Problem nicht weiter: Wenn ich den Beispielcode auf den RED-Brick hochlade und compiliere erhalte ich folgende Meldungen: Executing make... Script error 2: cc -o WetterstationV02 _Wetterstation_V02.o bricklet_ambient_light.o bricklet_ambient_light_v2.o bricklet_ambient_light_v3.o bricklet_barometer.o bricklet_barometer_v2.o bricklet_humidity.o bricklet_humidity_v2.o bricklet_lcd_20x4.o ip_connection.o ip_connection.o: In function `semaphore_create': ip_connection.c:(.text+0x2094): undefined reference to `sem_init' ip_connection.o: In function `semaphore_destroy': ip_connection.c:(.text+0x20ae): undefined reference to `sem_destroy' ip_connection.o: In function `semaphore_acquire': ip_connection.c:(.text+0x20c8): undefined reference to `sem_wait' ip_connection.o: In function `semaphore_release': ip_connection.c:(.text+0x20f0): undefined reference to `sem_post' ip_connection.o: In function `thread_create': ip_connection.c:(.text+0x2140): undefined reference to `pthread_create' ip_connection.o: In function `thread_join': ip_connection.c:(.text+0x21a6): undefined reference to `pthread_join' collect2: error: ld returned 1 exit status makefile:2: recipe for target 'WetterstationV02' failed make: *** [WetterstationV02] Error 1 ...error Hat jemand eine Idee, woran das liegen könnte?
×
×
  • Neu erstellen...