Verfasst am: 21.02.2014, 17:13
Titel: Plot-Schleife in GUI übertragen
Hallo,
ich hoffe mein Titel ist aussagekräftig genug... Ehrlich gesagt bin ich nicht sicher ob er es trifft ;-/
Naja... zu meinem Problem:
ich möchte Messwerte von einem Mikrocontroller per serieller Schnittstelle auslesen und die Daten "in Echtzeit" plotten. Der Graph soll also mit der Zeit durch das Plotfenster wandern.
Als kleine Vorübung habe ich mal versucht einen solchen plot mit hilfe eines m-Files und einer Schleife zu erstellen. Die Schleife läuft zwar nur bis zum Zählwert 25 aber der Code soll so gestrickt sein, dass es die Zahl der Durchläufe variabel ist, da ich später auch nicht weiß wie lange meine Messung läuft.
Code:
strom(1,1)=0;
zeit(1,1)=0;
i=1;
while i<25 tic
i=i+1;
strom(i,1)=rand(1);
zeit(i,1)=i-1;
anz=length(strom);
if anz<=8 figure(1);
plot(zeit,strom);
axis([010-11]);
else
plot_strom=strom([anz-8]:anz);
plot_zeit=zeit([anz-8]:anz);
figure(1);
plot(plot_zeit,plot_strom);
axis([anz-8 anz+2-11]);
end grid on
t=toc;
pause(1-t);
end
Das Ergebnis sieht genau so aus wie ich es mir vorgestellt habe.
jetzt möchte ich das Ganze in eine GUI übertragen, mit der ich meinen Messchip steuere, aber leider funktioniert das nicht! Anstelle einer Schleife nutze ich in der GUI einen Timer, dessen TimerFcn den "Schleifeninhalt" enthält und dadurch zyklisch den Plot aktualisieren soll.
Code:
%TimerFcn
global t_periode count
count=count+1;
%fprintf(handles.IC,'spannung');
%spannung=str2double(fscanf(handles.IC));
%bar(handles.axes1,spannung);
fprintf(handles.IC,'strom');
handles.strom(count,1)=str2double(fscanf(handles.IC));
handles.zeit(count,1)=handles.zeit([count-1],1)+t_periode;
anz=length(handles.strom);
if anz<=8 plot(handles.axes2,handles.zeit,handles.strom);
axis(handles.axes2,[0100250]);
else plot(handles.axes2,handles.zeit([anz-8]:anz),handles.strom([anz-8]:anz));
axis(handles.axes2,[anz-8 anz+20250]);
end
Die drei auskommentierten Zeilen realisieren ebenfalls einen selbstupdatenden plot, allerdings als Bar-Diagramm. Das habe ich zuvor getestet und der Teil funktioniert.
Wenn ich den Code ausführe, bekomme ich folgende Fehlermeldung:
Hat jemand einen Vorschlag was ich verändern müsste, damit es funktioniert? Ich bin auch für alle weiteren Tipps dankbar, da ich noch nicht sonderlich lange mit GUI's arbeite und nicht ausschließen möchte, dass manche Dinge einfach nicht "sexy" programmiert sind
das Problem liegt einfach darin dass, Timer nichts über handles Feld Zeit weiß, wurde das vorinitialisiert? Wie hast du deine TimerFcn definiert? Bitte auch diese Stellen posten
Versuch die Globale Variable zu vermeiden, z.B in Timer count, kann man in UserData, von Timer setzen
Danke für deine Antwort. So ganz folgen kann ich dir leider nicht...
1)Was genau meinst du mit vorinitialisiert? Ich habe ähnlich wie in dem ersten Code den anfangswert von Handels.zeit und Handels.strom auf 0 gesetzt. Das geschieht in einer Callback meines Start_messung_Button
2)Die TimerFcn habe ich gepostet... Das fehlt nur die erste Zeile, die mit function <Name> beginnt. Ich kann heute leider keinen Code posten, da ich von zu Hause aus keinen Zugriff darauf habe.
3)Das mit dem Speichern der Counter-Variable in der userData ist nen sehr guter Tipp. Vielleicht kannst du mir, als Newbie, noch kurz erklären WARUM ich globale Variablen vermeiden sollte. Ich hab schon ein paar mal gelesen, dass man es nicht machen sollte aber leider noch nirgends weshalb das Mist ist oder welche Probleme man sich dadurch ins Haus holt.
ich habe mal einen Breakpoint nach dem Call meiner TimerFcn gesetzt, sodass ich per VARARGIN prüfen kann, was an die Funktion übergeben wird.
Die Handles-Strktur wird übergeben, allerdings ist dort keines der von mir erstellten Felder (handles.IC, handles.strom, handles. zeit,...) enthalten! genutzt werden sie aber, da die serielle Schnittstelle geöffnet wird und auch Daten gesendet werden.
Hier mal mein vollständiger Code und im Anhang das m-File und fig-File
Code:
functionvarargout = Test_6(varargin) % TEST_6 M-file for Test_6.fig % TEST_6, by itself, creates a new TEST_6 or raises the existing % singleton*.
%
% H = TEST_6 returns the handle to a new TEST_6 or the handle to % the existing singleton*.
%
% TEST_6('CALLBACK',hObject,eventData,handles,...) calls the local % function named CALLBACK in TEST_6.M with the given input arguments.
%
% TEST_6('Property','Value',...) creates a new TEST_6 or raises the % existing singleton*. Starting from the left, property value pairs are % applied to the GUI before Test_6_OpeningFcn gets called. An % unrecognized property name or invalid value makes property application % stop. All inputs are passed to Test_6_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one % instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help Test_6
% Last Modified by GUIDE v2.5 24-Feb-2014 10:59:57
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @Test_6_OpeningFcn, ...
'gui_OutputFcn', @Test_6_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
ifnargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
% --- Executes just before Test_6 is made visible. function Test_6_OpeningFcn(hObject, eventdata, handles, varargin) % This function has no output args, see OutputFcn. % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % varargin command line arguments to Test_6 (see VARARGIN)
% UIWAIT makes Test_6 wait for user response (see UIRESUME) % uiwait(handles.figure1);
% --- Outputs from this function are returned to the command line. functionvarargout = Test_6_OutputFcn(hObject, eventdata, handles) % varargout cell array for returning output args (see VARARGOUT); % hObject handle to figure % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure varargout{1} = handles.output;
function PlotCellFcn(timerObj,timerEvent,handles) % function is called by MessTimer and gets data from BMS, % ploting (Updating) Cell Voltages and Cell Temperature in axes=Cell_plot % as well as current in axes=current
count=get(handles.zeit,'UserData');
t_periode=get(handles.timer,'UserData');
count=count+1;
fprintf(handles.IC,'spannung');
handles.spannung(count,1)=str2double(fscanf(handles.IC));
bar(handles.axes1,handles.spannung(count,1));
fprintf(handles.IC,'strom');
handles.strom(count,1)=str2double(fscanf(handles.IC));
handles.zeit(count,1)=handles.zeit([count-1],1)+t_periode;
anz=length(handles.strom);
if anz<=8 plot(handles.axes2,handles.zeit,handles.strom);
axis(handles.axes2,[0100250]);
else plot(handles.axes2,handles.zeit([anz-8]:anz),handles.strom([anz-8]:anz));
axis(handles.axes2,[anz-8 anz+20250]);
end set(handles.zeit,'UserData',count);
function UpdateTimeFcn(clockObj,clockEvent,handles)
time=datestr(now,'HH:MM:SS');
set(handles.clock_box,'String',time);
function default_Values(hObject, eventdata, handles) % set the default Values for several Items set(handles.LED_rot,'Value',0);
set(handles.LED_gruen,'Value',0);
set(handles.LED_gelb,'Value',0);
set(handles.connect,'String','Verbinden');
set(handles.start,'String','Start');
set(handles.LED_rot,'Enable', 'Off');
set(handles.LED_gruen,'Enable', 'Off');
set(handles.LED_gelb,'Enable', 'Off');
% --- Executes on button press in connect. function connect_Callback(hObject, eventdata, handles) % hObject handle to connect (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of connect
state=get(hObject,'Value');
if state == 1 fopen(handles.IC);
set(hObject,'String','Trennen');
set(handles.LED_rot,'Enable', 'On');
set(handles.LED_gruen,'Enable', 'On');
set(handles.LED_gelb,'Enable', 'On');
fprintf(handles.IC,'Status');
status=fscanf(handles.IC);
ifstrcmp('Verbunden',status(1:end-2)) set(handles.start,'ForegroundColor',[010]);
else set(handles.start,'ForegroundColor',[100]);
end else set(handles.start,'ForegroundColor',[100]);
all=instrfindall;
fclose(all);
default_Values(hObject, eventdata, handles);
end
% --- Executes on button press in start. function start_Callback(hObject, eventdata, handles) % hObject handle to start (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of start
state=get(hObject,'Value');
if state == 1
start(handles.timer);
set(hObject,'String','Stop');
fprintf(handles.IC,'spannung');
handles.spannung(1,1)=str2double(fscanf(handles.IC));
else
stop(handles.timer);
set(hObject,'String','Start');
end
% --- Executes during object creation, after setting all properties. function axes1_CreateFcn(hObject, eventdata, handles) % hObject handle to axes1 (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles empty - handles not created until after all CreateFcns called % Hint: place code in OpeningFcn to populate axes1 % set 'NextPlot' to 'replacechildren to remain axis property axis([020250]);
axis manual;
grid on;
% --- Executes on button press in LED_gruen. function LED_gruen_Callback(hObject, eventdata, handles) % hObject handle to LED_gruen (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of LED_gruen
state=get(handles.LED_gruen,'Value');
if state==1 fprintf(handles.IC, 'G') else fprintf(handles.IC,'g') end
% --- Executes on button press in LED_gelb. function LED_gelb_Callback(hObject, eventdata, handles) % hObject handle to LED_gelb (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of LED_gelb
state=get(handles.LED_gelb,'Value');
if state==1 fprintf(handles.IC, 'Y') else fprintf(handles.IC,'y') end
% --- Executes on button press in LED_rot. function LED_rot_Callback(hObject, eventdata, handles) % hObject handle to LED_rot (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA) % Hint: get(hObject,'Value') returns toggle state of LED_rot
state=get(handles.LED_rot,'Value');
if state==1 fprintf(handles.IC, 'R') else fprintf(handles.IC,'r') end
% --- Executes during object deletion, before destroying properties. function figure1_DeleteFcn(hObject, eventdata, handles) % hObject handle to figure1 (see GCBO) % eventdata reserved - to be defined in a future version of MATLAB % handles structure with handles and user data (see GUIDATA)
stop(handles.clock);
all=instrfindall;
fclose(all);
1)Was genau meinst du mit vorinitialisiert? Ich habe ähnlich wie in dem ersten Code den anfangswert von Handels.zeit und Handels.strom auf 0 gesetzt. Das geschieht in einer Callback meines Start_messung_Button
Ja genau das meine ich, das muss du aber vor dem Timer Definition machen, da deine übergeben handles-Struktur wird nicht upgedatet
Zitat:
3)Das mit dem Speichern der Counter-Variable in der userData ist nen sehr guter Tipp. Vielleicht kannst du mir, als Newbie, noch kurz erklären WARUM ich globale Variablen vermeiden sollte. Ich hab schon ein paar mal gelesen, dass man es nicht machen sollte aber leider noch nirgends weshalb das Mist ist oder welche Probleme man sich dadurch ins Haus holt
Das ist Problem der Wartbarkeit/Lesbarkeit, da globale Variable überall verändert werden können. Bei Fehlern ist dann schwierig nachvollziehen, an welcher Stelle wurde dann der Wert verändert.
Anderes Problem bei Globalen Variablen, wenn z.B. 2 unabhängige Programme hat, welche gleichzeitig laufen, und zufällig hat man gleiche benannte Globale Variablen, dann kann es durchaus zu Seiteneffekten, kommen, wie die Fehler in der Berechnungen oder Grafiken stimmen plötzlich nicht, oder noch schlimmer zur Abstürzen.
Ich denke in TimerFcn musst du GUIDATA verwenden um aktuelle handles zu haben. Ich kann das nicht testen aber schaue in Anhang
Ja genau das meine ich,das muss du aber vor dem Timer Definition machen, da deine übergeben Handels-Struktur wird nicht geupdated
In meinem heutigen Versuch habe ich die Variablen in der Opening-function gesetzt und noch vor dem GUIDATA, welches schon durch das guide gesetzt wurde. Dennoch fehlen alle Handels-Felder, die nicht durch ein GUI-Element (Button, etc.) erstellt wurden. Ich werde deinen Tipp morgen trotzdem durchspielen und eine GUIDATA in die timerFcn einfügen.
Deine Erklärung zu den globalen Variablen ist sehr schlüssig und hilfreich - vielen Dank für die Erklärung! Durch die Möglichkeit ganze Arrays in der UserData zu speichern, sollten globale Variablen auch nicht nötig sein!
Vielen Dank für deine Hilfe und deinen Code.
Beste Grüße, Stephan
Einstellungen und Berechtigungen
Du kannst Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen. Du kannst Dateien in diesem Forum posten Du kannst Dateien in diesem Forum herunterladen
MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.