Kann ich über SERIAL nur 8 Bit übertragen?

Hallo,
ich teste gerade ein wenig rum:
Habe mir TOUCH OSC füs iPhone geladen, auf meinem PC läuft Processing und am USB hängt ein xbee mit entsprechendem Shield.
Am anderem xbee hängt mein Arduino Mega, der ein TLC 5940 steuern soll.
Heißt: Ich möchte gerne die 12 bit des TLCs mittels iPhone und xbee steuern.

Soweit so gut klappt alles außer dass ich ausgangsseitig in Processing nur 0-255 übertragen kann und nicht 0-4095.
Heißt ich muss im Arduino 0-255 auf 0-4095 mappen, da gehen natürlich einige Bits verloren.

Seh ich das denn richtig dass nur 8Bit gehen oder mach ich was falsch?

Processing code:

import oscP5.*;
import netP5.*;
import processing.serial.*;
Serial myPort;
OscP5 oscP5;
float [] fader = new float [3];
float x;
void setup() {
  oscP5 = new OscP5(this,8000);
  myPort = new Serial(this, "COM13", 19200);
}

void oscEvent(OscMessage theOscMessage) {
String addr = theOscMessage.addrPattern();
    
       if(addr.indexOf("/1/fader") !=-1){ 
       String list[] = split(addr,'/');
     int  xfader = int(list[2].charAt(5) - 0x30);
     if(theOscMessage.get(0).floatValue() !=0){
     fader[xfader]  = theOscMessage.get(0).floatValue();
     }   
    }
       println(theOscMessage.toString());
}


void draw() {
  if (fader[1] >= 0) x=fader[1]*255;
  int a = (int) (x);
  myPort.write(a);
  println(a);  

}

Arduino Code:

#include "Tlc5940.h"
unsigned long val = 0;

#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 2);

int i;

void setup()
{
  Tlc.init(0);
  Tlc.update();
  mySerial.begin(19200);
  Serial.begin(19200);
}

void loop()
{
  if (mySerial.available()) {
    val=mySerial.read();
    i = map(val,0,255,4095,0);
    Tlc.set(1,i);
    Tlc.update();
  }
  Serial.println(i, DEC);

}

Der Code ist noch nicht optimiert - kenne mich mit Processing und der OSC Library nicht so gut aus, daher liefert mir die App aktiuell floats zwischen 0 und 1 die ich dann mit 255 (oder gewünscht 4095) zum int multipliziere.
(Ich weiss noch nicht, wie ich das hier anpassen muss, dass die App auch Werte 0-4095 senden kann

void oscEvent(OscMessage theOscMessage) {
String addr = theOscMessage.addrPattern();
    
       if(addr.indexOf("/1/fader") !=-1){ 
       String list[] = split(addr,'/');
     int  xfader = int(list[2].charAt(5) - 0x30);
     if(theOscMessage.get(0).floatValue() !=0){
     fader[xfader]  = theOscMessage.get(0).floatValue();
     }   
    }
       println(theOscMessage.toString());
}

)

Gruß

Die serielle Schnittstelle überträgt nur max 8 Bit. Du mußt die 12Bit Zahl in zwei 8 Bit Zahlen aufteilen und so übertragen. Am Empfänger mußt Du sie wieder zusammenfügen.
Grüße Uwe

Dann übertrage doch einfach zwei Byte aus Processing (low- und highbyte) die durch entsprechendes Maskieren auf der Empfängerseite wieder zusammensetzt werden. Die XBees sind dabei egal, die übertragen ja nur transparent die Daten.
Prinzipiell ist ein USART-Ausgangsregister der ATMEGA 328/ 2560 nur 8-bit groß, von daher ist dieser Umweg nötig.

Hi,
wie muss ich das verstehen?
Splitte ich die Werte in 2^8 und 2^4?
also in 0-255 und 0-15 und mulltipliziere dann am schluss wieder?
Habt ihr ein kurzes Code Beispiel?
VG

Hallo,

ich weis jetzt nicht ob Dir das hilft, aber wenn Du Dir die serielle Schnittstelle per Code nachbaust mit 12Bit?
Von einem anderen µC (Renesas R8C13) habe ich eine Funktion die mittels SPI einen 12Bit von einem Sensor ausliest und die ersten nicht benötigten 3 Bits abschneidet.

// Aliase für Port-Bits definieren für bessere Lesbarkeit
#define    SI    		 p1_addr.bit.b1 	// Ausgangsport für die Datenleitung zum LCD ist Bit 1 von Port 1
#define    CLK    		 p1_addr.bit.b2 	// Ausgangsport für die Taktleitung zum LCD ist Bit 2 von Port 1
#define    RS    		 p1_addr.bit.b3 	// Ausgangsport für die Statusleitung zum LCD ist Bit 3 von Port 1

// SO  von MAX6675 auf P3.0   (R8C13 Pin 22)
// SCK von MAX6675 auf P3.1	  (R8C13 Pin 20)
// CS  von MAX6675 auf P3.2   (R8C13 Pin 18)	

// Deklaration Funktionen
unsigned int read_MAX6675_P32 (void);					// erster MAX6675 mit CS an P3.2
void send_byte_to_lcd(char byte);						// ein Byte zum LCD senden


// Der MAX6675 wird ausgelesen und der 12-Bit-Wert zurückgegeben ********
// P3 = x x x x x CS SCK SO
// max_reg=0 b11 b10 b9 b8 b7 b6 b5 / b4 b3 b2 b1 b0 tco 0 0
unsigned int read_MAX6675_P33 (void)
{
  int i;
  unsigned int data;
  data=0;
  p3_3=0;				            	// CS=Low Port 3.3
  for(i=0;i<16;i++)
  {
    wait_us(100);						// warte 100us
	p3_1=1;								// SCK=High
    wait_us(100);						// warte 100us
    data=((data<<1)|p3_0);				// schiebe nach links und lies SO
    p3_1=0;								// SCK=Low
  }
  wait_us(100);
    p3_3=1;         					// CS=High
  wait_us(100);							// warte 100us
  return (data>>3);						// gib 12-Bit Wert zurück
}

Eine ähnliche nachgebaut SPI Funktion ist das senden von 8 Bits an ein LCD

// 8 Bits eines Bytes hintereinander an das LCD senden (SPI)
void send_byte_to_lcd(char byte)
{
int i;
for (i = 0; i < 8; i++)	   				// Schleife für alle 8 Bits des übergebenen Bytes
	{
 	CLK = 0;				   			// Taktleitung auf LOW setzen
 	SI = ((byte&128) != 0);   			// most significant bit (also das 8. Bit = 0b10000000 = 128) gesetzt? Wenn ja SI = 1, sonst SI = 0
 	byte <<= 1;			   				// Alle 8 Bits des Bytes um eine Stelle nach links schieben. Most significant bit ist jetzt also das vormals 7. Bit
 	CLK = 1; 				   			// Taktleitung auf HIGH setzen: Damit wird das gesendete Bit gültig
 	wait_us(30);
	};
};

Ich weis es nicht, aber da SPI ähnlich funktioniert wie die RS323 kann jemand der mehr Ahnung hat wie ich damit vielleicht eine serielle 12Bit Übertragung bauen. Ich meine bei letztere Funktion müßte sie statt 8x dann 12x durchlaufen werden um 12 statt 8Bits zu übertragen. So stelle ich mir das vor.

Zusammensetzen kannst Du z.B. so;

*** schnipp ***

int byteHigh = incomingByte[1]; // hier die oberen 8 bit
int byteLow = incomingByte[0]; // hier die unteren 8 bit

int value = byteLow + (byteHigh * 256); // 16 bit

*** schnipp ***

Wenn Du den byteHigh "MSB"-nibble (bits 4-7) auf 0 hast, brauchst Du auch nichts maskieren. Ansonsten müsstest Du die bits 4-7 des byteHigh noch maskieren.

Hallo,

bin dank euch schon mal ein wenig weiter gekommen und kriege die 12 bit übertragen.
Processing sendet:

  if (fader[1] >= 0) x=fader[1];
  int a = (int) (x);
  myPort.write((char)(a / 256)); // MSB
  myPort.write(a & 0xff);  //LSB

arduino empfängt:

{
  if (mySerial.available()) {
    val=mySerial.read() * 256;
    val=val + mySerial.read();    
    Tlc.set(1,val);
    Tlc.update();
  }

Grob klappts, aber die Zusammensetzung der beiden bytes ist fehlerhaft. Hier mal ein Auszug aus meinem Serial Monitor was ankommt:

4095
4095
4095
4095
4095
4095
4095
4095
3839
4294967039
4294967039
4294967039
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
3839
4294967039
4294967039
4095
4095
4095
4095
3839
4294967039
4294967039
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095
4095

Da sind immer wieder extrem große Werte zwischen oder mal ein Ausrutscher von 4095 auf 3893 obwohl ich da am slider nix bewegt habe.

Habt ihr ne Idee was da falsch läuft?

Habt ihr ne Idee was da falsch läuft?

Ne Idee schon:

4095 sind "in Wirklichkeit" 12 gesetzte Bit : 0x0FFF
4294967039 ist 0xFFFFFEFF oder 0xFEFF als negative Zahl interpretiert und das sich ergebende 32Bit integer am PC dann wieder vorzeichenlos ausgegeben.

Die Frage ist also, wo das 0xFE byte anstelle des 0x0F herkommt.

Ne andere Idee hängt an deiner Zeile

val=val + mySerial.read();  Das machst du auch, wenn evtl. noch gar kein zweites Byte angekommen ist. read liefert eine (int)-1 , also 0xFFFF
Das Ergebnis hängt von dem Geheimnis ab, wie val eventuell definiert ist.

 if (mySerial.available() >=2 ) {

wäre eine Abhilfe...

:wink:

Hi,
muss noch mal nachhaken. Ich denke es reicht, wenn ich 1byte übertrage, da ich mit dem touchOSC fader eh nicht so genau steuern kann.
Allerdings werde ich mehrere Fader benutzen, jetzt frag ich mich allerdings, wie ich das am besten hinbekomme?
Habe einen Ansazt, indem ich immer einen Char mit schicke, 'a' wäre dann fader1, 'b' fader2. Frag mich bzw euch allerdings ob man das nicht einfacher oder charmanter hinbekommt?
Hier mal mein Code, so wie er funktioniert. Was mich auch noch stört ist das übertragen des PWM Werts, anders funktiniert es aber leider nicht. Hier mein code:

PROCESSING:

import oscP5.*;
import netP5.*;
import processing.serial.*;
Serial myPort;
OscP5 oscP5;
int whiteAll = 0;
int blueAll = 0;
int redAll;
int purpleAll;
int onOff;

void setup() {
  oscP5 = new OscP5(this,8000);
  myPort = new Serial(this, "COM13", 19200);
}

void oscEvent(OscMessage theOscMessage) {
  String addr = theOscMessage.addrPattern();
  float val = theOscMessage.get(0).floatValue();
  if(addr.indexOf("/1/white") != -1) { 
    whiteAll = int(theOscMessage.get(0).floatValue());
    myPort.write('a');
    myPort.write((char)(whiteAll / 256)); // MSB
    myPort.write(whiteAll & 0xff);  //LSB
   // myPort.write(whiteAll);
    println("LEDwhite: " + whiteAll); 
  } 
  if(addr.indexOf("/1/blue") != -1) { 
    blueAll = int(theOscMessage.get(0).floatValue());
    myPort.write('b');
    myPort.write((char)(blueAll / 256)); // MSB
    myPort.write(blueAll & 0xff);  //LSB
   // myPort.write(whiteAll);
    println("LEDblue: " + blueAll); 
  } 

}


void draw() {

 }

ARDUINO:

#include "Tlc5940.h"
int val1 = 0;
int val2 = 0;
int val[] = {0, 0};
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 2);

void setup()
{
  Tlc.init(0);
  Tlc.update();
  mySerial.begin(19200);
  Serial.begin(19200);
  Serial.println("Start");
}

void loop()
{
  if (mySerial.available()>=3) {
    char message = mySerial.read();
    switch (message) {
      case'a':
        val1=mySerial.read() * 256;
        val1=val1 + mySerial.read();     
        break;
      case'b':
        val2=mySerial.read() * 256;
        val2=val2 + mySerial.read();     
        break;      
      break;
    }
  }
  val[0]=map(val1,0,255,4095,0);
  val[1]=map(val2,0,255,4095,0);
  Tlc.set(1,val[0]);
  Tlc.set(2,val[1]);
  Tlc.update(); 
}

Hi,
hoffe es bleibt hier nicht beim Monolog.
Bin aber etwas weiter gekommen und relativ zufrieden mit meiner Lösung, bis auf eine Sache:
zunächst der aktuelle Code:
PROCESSING

import oscP5.*;
import netP5.*;
import processing.serial.*;
Serial myPort;
OscP5 oscP5;
float [] fader = new float [3];
float button0;
int [] out = new int [3];

void setup() {
  oscP5 = new OscP5(this,8000);
  myPort = new Serial(this, "COM13", 19200);
}

void oscEvent(OscMessage theOscMessage) {
  String addr = theOscMessage.addrPattern();
  float val = theOscMessage.get(0).floatValue();
  if(addr.equals("/1/button0")) { button0 = val; }
  if(addr.equals("/1/fader0")) { fader[0] = val; }
  if(addr.equals("/1/fader1")) { fader[1] = val; }
  if(addr.equals("/1/fader2")) { fader[2] = val; }
}

void draw() {
  if (button0==1) {
    myPort.write('a');
    for (int i=0; i<3; i++) {
      out[i] = (int) (fader[i]);
      println(out[i]);
      myPort.write(out[i]);
    }  
  }
  else if (button0==0){
    myPort.write('b');
    println("AUS");
  }
}

ARDUINO

#include "Tlc5940.h"
byte incomingByte[3] = {0, 0, 0};
int value[3];
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 2);

void setup()
{
  Tlc.init(0);
  Tlc.update();
  mySerial.begin(19200);
  Serial.begin(19200);
  Serial.println("Start");
}

void loop()
{
  if (mySerial.available() >= 4) {
    if (mySerial.read() == 'a') {
      for (int i=0; i<3; i++) {
        incomingByte[i] = mySerial.read();
        value[i]=map(incomingByte[i],0,255,4095,0);
        Tlc.set(i,value[i]);
        Tlc.update();
        Serial.print(incomingByte[i]);
        Serial.print(" / ");      
      }
      Serial.println(""); 
    }
    else Serial.println("AUS");
  }
}

Funktioniert soweit alles: Über button0 kann ich die Steuerung de-/aktivieren. Dazu übergebe ich einen CHar der vom Arduino entsprechend interpretiert wird.
Die Fader werden durchgängig ausgelesen und geben einen Wert zwischen 0-255 über XBEE an den Arduino, der für den TLC auf 4095 gemapped wird.

Das einzige Problem: Alle paar Sekunden wird auf einem der drei Fader genau der Wert 128 gelesen und entsprechend blinkt die LED kurz auf. Sieht im SerialMonitor so aus:

0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
128 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 128 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
128 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 / 
128 / 0 / 0 / 
0 / 0 / 0 / 
0 / 0 / 0 /

Leider kann ich nicht reproduzieren, woher der Wert kommt.