Matlab - Mikrocontroller - serielle Schnittstelle

OP #5300497
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?
OP #5301258
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?
Gast #5301347
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)
OP #5301366
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?
Gast #5301372
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....
Gast #5301376
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....
OP #5301404
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?
#5301435
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.
OP #5301495
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.

???
OP #5301578
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 ...
Angehängte Dateien:
OP #5301599
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???
#5301616
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.
OP #5301623
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?
#5301628
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)
#5302032
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
(Firma: RUB) #5302081
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.
#5302174
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.
Persönliche Seite #5302175
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
OP #5302382
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren