Forum: Mikrocontroller und Digitale Elektronik Matlab - Mikrocontroller - serielle Schnittstelle


von Steff G. (steff_123)


Lesenswert?

Hallo Leute,

ich bin gerade dabei simple Zeichenketten von Matlab an den 
Mikrocontroller zu senden und der soll das wieder zurücksenden.

Habe das ganze schon in HTerm versucht und da klappt es soweit ganz gut.

Verwende ein Mega2560 Board und die Bibliothek von Peter Fleury für 
UART.

Der folgende C-Code ist am Mikrocontroller:
1
#include <avr/io.h>
2
#include <stdlib.h>
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <avr/pgmspace.h>
6
#include <util/delay.h>
7
8
#include "uart.h"
9
10
#define F_CPU 16000000UL
11
12
/* define CPU frequency in Hz in Makefile */
13
#ifndef F_CPU
14
#define F_CPU 16000000UL
15
#endif
16
17
/* Define UART buad rate here */
18
#define UART_BAUD_RATE      9600      
19
20
uint8_t uart_getc_wait()
21
{
22
  unsigned int c;
23
  
24
  do {
25
    c=uart_getc();
26
  }while (c == UART_NO_DATA);
27
  
28
  return (uint8_t)c;
29
}
30
31
void uart_gets( char* Buffer, uint8_t MaxLen )
32
{
33
  uint8_t NextChar;
34
  uint8_t StringLen = 0;
35
36
  NextChar = uart_getc_wait();         // Warte auf und empfange das nächste Zeichen
37
38
                    // Sammle solange Zeichen, bis:
39
                    // * entweder das String Ende Zeichen kam
40
                    // * oder das aufnehmende Array voll ist
41
  while( NextChar != '\n' && StringLen < MaxLen - 1 ) {
42
    *Buffer++ = NextChar;
43
    StringLen++;
44
    NextChar = uart_getc_wait();
45
  }
46
47
                    // Noch ein '\0' anhängen um einen Standard
48
                    // C-String daraus zu machen
49
  *Buffer = '\0';
50
}
51
52
53
54
int main(void)
55
{  
56
  char Line[40];
57
  
58
    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
59
60
    sei();
61
    
62
  while(1)
63
  {
64
    uart_gets (Line, sizeof(Line));
65
    
66
    uart_puts(Line);
67
    uart_puts( "\n" );
68
  }
69
    
70
}

In Matlab hab ich bis jetzt folgendes eingetippt:
1
clc
2
close all;
3
clear all;
4
5
// Aktive Ports löschen
6
delete(instrfindall);
7
8
// USB Port initialisieren
9
Mega2560=serial('COM5');
10
disp('Kommunikation aufgebaut')
11
set(Mega2560,'BaudRate',9600);
12
set(Mega2560,'Terminator','LF');
13
set(Mega2560,'DataBits',8);
14
set(Mega2560,'Parity','none');
15
set(Mega2560,'StopBits',1);
16
17
// Verbindung zum Mikrocontroller
18
fopen(Mega2560);
19
fwrite(Mega2560,'Hallo Welt\n');
20
received = fgets(Mega2560)
21
fclose(Mega2560);

Wenn ich das ganze versuche bekomme ich als Fehlermeldung:

Warning: Unexpected Warning: A timeout occurred before the Terminator 
was reached.

Ergo es muss ja iwie am Terminator liegen.
Habs aber bisher nicht hinbekommen.

Seh ich den Wald vor lauter Bäumen nicht oder warum funktioniert das bei 
mir nicht?

von Walter T. (nicolas)


Lesenswert?

Was steht denn in received drin? Enthält der String 'Hallo Welt\n' ein 
LF? Kannst Du mit double('Hallo Welt\n') überprüfen.

Evtl. macht ein fprintf(MEga2560,'\n') das, was Du erwartest.

von Steff G. (steff_123)


Lesenswert?

>> Was steht denn in received drin?

Es wird der oben genannte Fehler ausgegeben und dann kommt:

received = 0x0 empty char array

>> Evtl. macht ein fprintf(MEga2560,'\n') das, was Du erwartest.

Wie meinst du das genau? einfach nach dem 'Hallo Welt' extra den Befehl

von Walter T. (nicolas)


Lesenswert?

Du schickst die Zeichenkette char([72    97   108   108   111    32 
87   101   108   116    92   110]) über den seriellen Port, d.h. \n wird 
als ['\' 'n'] geschickt. Du willst aber \n per printf interpretieren als 
char([10]).

von Steff G. (steff_123)


Lesenswert?

Ok ich weiss was du meinst.

Aber Ist es nicht grundsätzlich so, dass ich durch die Einstellung:
1
set(Mega2560,'Terminator','LF');

die Sache bereinigt habt.

Bzw. ich weiss gerade nicht wie ich es sonst bewerkstelligen könnte.

Steh ich grad voll am Schlauch?

von Walter T. (nicolas)


Lesenswert?

Steff G. schrieb:
> Steh ich grad voll am Schlauch?

Ja.

Tipp: Installier Dir ein Nullmodem-Device und schau Dir die Sachen, die 
Matlab verschickt, in einem Terminal an.

von Steff G. (steff_123)


Lesenswert?

> Tipp: Installier Dir ein Nullmodem-Device und schau Dir die Sachen, die
> Matlab verschickt, in einem Terminal an.

Hab ich gerade installiert und wenn ich folgenden Code mit Matlab 
eingebe:
1
clc
2
close all;
3
clear all;
4
5
// Aktive Ports löschen
6
delete(instrfindall);
7
8
// USB Port initialisieren
9
10
Mega2560=serial('COM5');
11
disp('Kommunikation aufgebaut')
12
set(Mega2560,'BaudRate',9600);
13
set(Mega2560,'Terminator','LF');
14
set(Mega2560,'DataBits',8);
15
set(Mega2560,'Parity','none');
16
set(Mega2560,'StopBits',1);
17
18
// Verbindung zum Mikrocontroller
19
20
fopen(Mega2560);
21
fprintf(Mega2560,'Hallo Welt');
22
received = fgetl(Mega2560)
23
fclose(Mega2560);

Hab also den fwrite-Befehl abgeändert zu fprintf und kein "\n" 
angehängt,
dann zeigt er mir bei Hterm an:

Hallo Welt\n

Müsste somit doch eigentlich passen.

Ich bin jetzt wirklich bisschen überfragt, warum das ganze nicht klappt.

Wenn ich von Hterm zeichen zurücksende, dann empfängt die Daten Matlab 
auch einwandfrei.

Sobald ich das am Board sehen kannn blinkt die RX-LED beim senden, aber 
es kommt anscheinend nichts zurück.

Kann mir bitte jemand helfen?

von Walter T. (nicolas)


Lesenswert?

Was kommt denn zurück, wenn Du aus dem Terminal-Programm ans Board 
sendest?

von Steff G. (steff_123)


Lesenswert?

> Was kommt denn zurück, wenn Du aus dem Terminal-Programm ans Board
> sendest?

Wenn ich in Hterm

Hallo

eingeben bekomme ich zurück:

'Hallo'

Also es sollte alles rund um funktionieren - sobald ich jedoch mein 
Board anstecke bekomme ich nichts zurück??

von Steff G. (steff_123)


Lesenswert?

> Was kommt denn zurück, wenn Du aus dem Terminal-Programm ans
> Board
> sendest?

 Wenn ich in Hterm

 Hallo

 eingeben bekomme ich zurück:

 received = 'Hallo'

 Also es sollte alles rund um funktionieren - sobald ich jedoch mein
 Board anstecke bekomme ich nichts zurück??

von Walter T. (nicolas)


Lesenswert?

Jetzt habe ich die Übersicht verloren.

Du kannst ja jetzt testen:
 Board <-> Terminalprogramm
 Terminalprogramm <-> Matlab

Welches von beidem hast Du getestet? Wie sehen die "Echo"-Einstellungen 
des Terminalprogramms aus?

von Steff G. (steff_123)


Angehängte Dateien:

Lesenswert?

Ich hab beide Richtungen getestet:

Terminalprogram <-> Matlab

von Steff G. (steff_123)


Angehängte Dateien:

Lesenswert?

Und die andere Richtung:

Terminalprogramm <-> Board

von Reiner_Gast (Gast)


Lesenswert?

Steff G. schrieb:
> while(1)
>   {
>     uart_gets (Line, sizeof(Line));
>
>     uart_puts(Line);
>     uart_puts( "\n" );
>   }

Du lässt vom uC lauter leere Zeilen zurücksenden, wenn nicht gerade ein 
Zeichen reinkommt... Da wundert es nicht, wenn beim Empfänger auch nix 
ankommt....

Wie wäre es, wenn du in der While Schleife so vorgehst:

- Liegt ein Zeichen an?
=> Ja, dann lese das aus und schicke es wieder zurück... (Und nur 
dieses... kein \n hintendran)

von Steff G. (steff_123)


Lesenswert?

Reiner_Gast schrieb:

>Du lässt vom uC lauter leere Zeilen zurücksenden, wenn nicht gerade ein
>Zeichen reinkommt... Da wundert es nicht, wenn beim Empfänger auch nix
>ankommt....

Ich habe doch im Code das
1
uint8_t uart_getc_wait()
2
{
3
  unsigned int c;
4
  
5
  do {
6
    c=uart_getc();
7
  }while (c == UART_NO_DATA);
8
  
9
  return (uint8_t)c;
10
}

welches so lange wartet bis ein Zeichen anliegt?
Oder irre ich mich da?

von Reiner_Gast (Gast)


Lesenswert?

Steff G. schrieb:
> Ich habe doch im Code dasuint8_t uart_getc_wait()
> {
>   unsigned int c;
>
>   do {
>     c=uart_getc();
>   }while (c == UART_NO_DATA);
>
>   return (uint8_t)c;
> }
>
> welches so lange wartet bis ein Zeichen anliegt?
> Oder irre ich mich da?

Also ich interpretiere das so, dass der solange Zeichen einliest, bis 
keines mehr anliegt und diesen "Es liegt nix mehr an Code" zurückgibt, 
weil ja die Variable c immer wieder überschrieben wird....

von Reiner_Gast (Gast)


Lesenswert?

Mach's doch erstmal einfacher in dem du Zeichen für Zeichen ausliesst 
und wieder zurücksenden lässt.... Wenn das sicher läuft, kannst du immer 
noch das ganze als Zeichenkette versuchen....

von Walter T. (nicolas)


Lesenswert?

Steff G. schrieb:
> welches so lange wartet bis ein Zeichen anliegt?

Tut es. Das wird Dir später noch Probleme bereiten (wenn der µC 
zusätzlich etwas anderes als Texte senden und empfangen können sollte), 
aber für den Moment reicht es.

Hast Du an Deinem Mega-Boards irgendeine Ausgabemöglichkeit außer dem 
UART? LCD? LED-Reihe oder so?

von Steff G. (steff_123)


Lesenswert?

Walter Tarpan schrieb:

> Tut es. Das wird Dir später noch Probleme bereiten (wenn der µC
> zusätzlich etwas anderes als Texte senden und empfangen können sollte),
> aber für den Moment reicht es.

Genau - das will ich für meinen Ansatz erreichen.
In Matlab werden mehrere Werte eingegeben und diese sollen dann an den 
µC gesendet werden.
Der µC soll so lange warten bis diese Werte alle angekommen sind und 
dann mit dem eigentlichen Programmablauf starten.

> Hast Du an Deinem Mega-Boards irgendeine Ausgabemöglichkeit außer dem
> UART? LCD? LED-Reihe oder so?

Du meinst irgendwie eine LED dranbasteln, damit ich sehe, ob der µC 
zumindest die Daten empfängt?

von Walter T. (nicolas)


Lesenswert?

Steff G. schrieb:
> Du meinst irgendwie eine LED dranbasteln, damit ich sehe, ob der µC
> zumindest die Daten empfängt?

Oder noch besser: Die Daten, die er empfängt, direkt anzeigen.

Ich habe dazu an jedem µC-Board ohne Debuggerzugriff zumindest während 
der Entwicklungszeit zumindest ein kleines LCD.

von Steff G. (steff_123)


Lesenswert?

> Oder noch besser: Die Daten, die er empfängt, direkt anzeigen.
Da hab ich leider momentan nichts zur Hand.

Ich versuche es dann mal mit der LED - meld mich dann nochmal.

von Lenny D. (le-do)


Lesenswert?

Ich hatte sowas ähnliches letztens in Python. Die Daten scheinen vom 
controller ja richtig zurück zu kommen, aber triggern keine neue Zeile 
in matlab und daher gibt er dir ein time out, obwohl er eigentlich schon 
alles empfangen haben sollte.
Bei uns war komischerweise eine Lösung, den Empfang buffer auf 1 Zeichen 
zu setzen, dann hat er was angezeigt.

von Steff G. (steff_123)


Lesenswert?

Also jetzt bin ich dann wirklich bald am verzweifeln.

Habe jetzt eine LED an mein Mega-Board dran gehängt.

Code:
1
...
2
3
int main(void)
4
{  
5
  char Line[40];
6
  
7
    uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) ); 
8
9
    sei();
10
    DDRB |= (1<<PB4);
11
  PORTB &= ~(1<<PB4);
12
  
13
  while(1)
14
  {
15
    
16
    uart_gets (Line, sizeof(Line));
17
    
18
    if (atoi(Line) == 123)
19
    {
20
      PORTB |= (1<<PB4);
21
    }
22
    
23
    if (atoi(Line) == 456)
24
    {
25
      PORTB &= ~(1<<PB4);
26
    }
27
    
28
  }
29
    
30
}

Wenn ich nun über das Terminalprogramm "123" an das Board schicken geht 
die LED an - schicke ich "456" geht die LED aus.

Versuche ich das gleiche mit Matlab - passiert wieder mal garnix.
Im Terminalprogramm wird aber die von Matlab verschickte Zeichenfolge 
angezeigt.

???

von Walter T. (nicolas)


Lesenswert?

a) Wie sieht denn die Matlab-Zeile zum Senden aus?
b) Wie sieht das Ergebnis im Terminal aus?

Evtl. sendet Matlab nach jedem einzelnen Zeichen schon einen 
String-Terminator.

von Steff G. (steff_123)


Angehängte Dateien:

Lesenswert?

Walter Tarpan schrieb:

> a) Wie sieht denn die Matlab-Zeile zum Senden aus?
1
clc
2
close all;
3
clear all;
4
5
t=[123];
6
7
% Aktive Ports löschen
8
delete(instrfindall);
9
10
% USB Port initialisieren
11
Mega2560=serial('COM1');
12
13
disp('Kommunikation aufgebaut')
14
15
set(Mega2560,'BaudRate',9600);
16
%set(Mega2560,'Terminator','LF');
17
set(Mega2560,'DataBits',8);
18
set(Mega2560,'Parity','none');
19
set(Mega2560,'StopBits',1);
20
21
% Verbindung zum Mikrocontroller
22
fopen(Mega2560);
23
24
25
fprintf(Mega2560,'%d\n',t);
26
27
fclose(Mega2560);
28
disp('Kommunikation abgebrochen')

Ob ich die Zeile
1
%set(Mega2560,'Terminator','LF');

auskommentiere oder nicht macht im Terminal keinen Unterschied.

Walter Tarpan schrieb:
> b) Wie sieht das Ergebnis im Terminal aus?

hab ich gerade angehängt.

Ich weiss einfach nicht was ich hier falsch mache ...

von Steff G. (steff_123)


Lesenswert?

Ok es ist jetzt nochmal etwas komisches passiert.

Ich hab mit dem Terminal die LED angeschaltet.
Nun habe ich zu Matlab gewechselt und egal ob ich hier "123" oder "456"
versende geht die LED aus.

Dan in meinem C-Code defaultmäßig die LED ausgeschaltet ist würde ich 
jetzt drauf schließen, dass sich das Board iwie abschaltet und wieder 
anschaltet, sobald ich mit Matlab irgendwas sende.

Aber wieso???

von Walter T. (nicolas)


Lesenswert?

Steff G. schrieb:
> auskommentiere oder nicht macht im Terminal keinen Unterschied.

Das ist in Ordnung. Matlab merkt sich die Einstellung des COM-Ports. LF 
ist zudem der Default-Wert.


Ich habe mal versucht, Dein Setting nachzubauen. Matlab schickt den 
String-Terminal erst als letztes Zeichen. Von Matlab in die Konsole und 
zurück geht einwandfrei mit Deinem Quelltext.

Sprich: Die Matlab-Seite funktioniert.


Für eine Ferndiagnose bin ich auch mit meinem Latein am Ende, wenn Du in 
HTERM und Matlab das Gleiche sendest, aber unterschiedliche Sachen 
interpretiert werden.

Noch ein kleiner Test: Versuch mal, die Zeichenkette mehrmals zu senden.
1
fprintf(Mega2560,'%d\n',t);
2
fprintf(Mega2560,'%d\n',t);

Eventuell ist noch ein Rest im Serial-Puffer, daß das erste 
Datentelegramm noch Müll am Anfang enthält.

von Steff G. (steff_123)


Lesenswert?

Ich habe es versucht mehrmals zum versenden, aber es hat sich wieder 
nichts geändert.

Vielen Dank für deine bisherigen Mühen.

Ich glaube ich kann meinen Fehler jetzt auf die Folgende frage 
eingrenzen:

Warum resetet sich das Mega Board, wenn ich via Matlab etwas an das 
Board versende?


Ich hoffe es hat sonst noch jemand eine Idee??

Oder soll ich lieber einen neuen Beitrag dafür aufmachen, weil sich 
nicht jeder das ganze bisherige durchlesen wird?

von Walter T. (nicolas)


Lesenswert?

Ist der Arduino-Bootloader noch auf dem ATmega? Dann könntest Du das 
hier testen, um ein Hardware-Problem auszuschließen:
1
Auio = arduino('Com5','Mega2560');
2
pin = 'D10';
3
4
Auio.configurePin(pin,'DigitalOutput');
5
6
while(1)
7
   Auio.writeDigitalPin(pin,1);
8
   pause(0.5);
9
   Auio.writeDigitalPin(pin,0);
10
   pause(0.5);
11
    
12
end
(ungetestet - habe keinen Arduino hier)

von Steff G. (steff_123)


Lesenswert?

Du meinst das ganze in Matlab rein und den Arduino ansteuern?

von Lenny D. (le-do)


Lesenswert?

Hm du hast ein Arduino-Board, richtig?
Der Arduino verwendet den DTR-Pin am Usb-Serial chip (nach den 
Schematics wird beim Mega Board hierfür ein kleinerer Atmega verwendet, 
https://www.arduino.cc/en/uploads/Main/arduino-mega2560_R3-sch.pdf) als 
RESET Leitung um den großen Mega in den Bootloader zu bringen.

Vielleicht triggered Matlab den irgendwie im Gegensatz zu HTerm. 
Versuche mal in Matlab FlowControl auszuschalten. Sollte möglicherweise 
gehen mit:
1
s = serial('COM5');
2
s.FlowControl = 'none';
oder
1
set(Mega2560,'FlowControl','none');

https://de.mathworks.com/help/matlab/matlab_external/using-control-pins.html

von Kaj G. (Firma: RUB) (bloody)


Lesenswert?

Anstatt da irgendwo LEDs dranzu basteln, wuerde ich einfach mal gucken 
was wirklich ueber die Leitung geht.
Besorg dir einen USB-UART-Wandler (z.B. sowas: 
https://shop.in-circuit.de/product_info.php?cPath=38&products_id=80 ), 
und klemm den an die Leitung. Dann machst du HTerm auf, und verbindest 
dich damit mit dem Wandler. Dann machst du Matlab auf, und startest dein 
Programm. Dann sieht du exakt was da ueber die Leitung geht, und ob das 
auch das ist, was du erwartest. Dann siehst du auch, ob das Problem am 
Matlabcode, oder am C-Code liegt.

Lenny D. schrieb:
> Vielleicht triggered Matlab den irgendwie im Gegensatz zu HTerm.
Das kann tatsaechlich sein. Kann passieren, wenn das Programm den 
serielle Port schliesst.

von Walter T. (nicolas)


Lesenswert?

Steff G. schrieb:
> Du meinst das ganze in Matlab rein und den Arduino ansteuern?

Ja, aber nur kurz. Zum Testen. Das ist ja in 2 Minuten gemacht. Wenn es 
funktioniert, sind sowohl die LED als auch die serielle Verbindung 
hardwareseitig ausreichend zuverlässig.

Lenny D. schrieb:
> Versuche mal in Matlab FlowControl auszuschalten. Sollte möglicherweise
> gehen mit:

Die Idee ist gut. Bei mir:
1
>> get(Mega2560,'FlowControl')
2
3
ans =
4
5
none
aber: Die Default-Einstellung ist die aus dem Gerätemanager.

von Daniel V. (voda) Benutzerseite


Lesenswert?

Oje, ich hatte mal das selbe Problem. Probiere mal folgenden 
Lösungsvorschlag.

Hinweis: Diese ist aus meiner GUI, als ich Bilddaten eines ADNS-Sensors 
über eine USART ausgelesen habe, daher muss diese angepasst werden.

Erstelle eine Funktion:
1
function serialPort = initSerialPort(hObject, eventdata, handles, portName)
2
3
serialPort = serial(portName);
4
5
% Set the baud rate
6
str = get(handles.baud_rate_pop, 'String');
7
ind = get(handles.baud_rate_pop, 'Value');
8
serialPort.BaudRate = str2num(str{ind}(1:end-4)); %4%
9
%serialPort.Terminator = 'CR/LF'; 
10
str = get(handles.buffer_size_pop, 'String'); 
11
ind = get(handles.buffer_size_pop, 'Value'); 
12
serialPort.InputBufferSize = str2num(str{ind}(1:3))*str2num(str{ind}(5)); 
13
14
% Add a callback function to be executed whenever 1 byte is available
15
% to be read from the port's buffer.
16
serialPort.BytesAvailableFcn = {@readPort, hObject, eventdata, handles};
17
serialPort.BytesAvailableFcnMode = 'byte';
18
serialPort.BytesAvailableFcnCount = serialPort.InputBufferSize;
19
end

Gruß
Daniel

von Steff G. (steff_123)


Lesenswert?

Hallo nochmal - vielen Dank für eure weiteren Tipps.

Hab das mit dem float control probiert und war leider auch nix.

Über die Arduino Software auf Matlab hat es funktioniert.

Hab jetzt nochmal weiter recherchiert und bin auf die Lösung gekommen:

Der Fehler:
1
fopen(Mega2560);
2
pause(2);

Anscheinend benötigt Matlab eine Weile den Com-Port einzurichten und 
wenn ich in dieser Zeit schon Zeichen rüber schicke, dann erhält es das 
Mega-Board nicht.

Jetzt funktioniert es!

Vielen vielen Dank an die Leute, die mir geholfen haben und ihre Zeit 
investierten.

von Walter T. (nicolas)


Lesenswert?

Auch wenn mich die Ursache wundert:

Glückwunsch!

von derjaeger (Gast)


Lesenswert?

Danke für die Rückmeldung. Das wird in Zukunft sicher nur nicht dir 
passieren und dann ist es schön wenn man hier eine Lösung über Google 
nachlesen kann.

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.