Hex werte Serial senden

Hallo liebe Arduino Fans und Profis
ich stehe vor ein Problem da ich iwi nix finden kann, nur zum Lesen über den Uart
Folgendes Zenario:
KFZ KI aus einem e34 5ver BMW
dort soll in der CCM LCD anzeige eigener text eingespeist werden
es muss z.b. 1000ms gesendet werden, dann 10ms pause um dann erneut zu senden

Die Übermittlung muss im HEX ( 16 zeilen voll angesprochen werden z.b.
"www.e34.de" (_ steht fürs Leerzeichen)

20h 20h 20h 77h 77h 77h 2Eh 65h 33h 34h 2Eh 64h 65h 20h 20h 20h

Summe: 416h
Prüfsumme: 16h )

soweit so gut
Habe ein Interface gebaut die mit dem KI verbunden ist und auch Funktioniert

Nun aber mein Problem....
Wie programmiere ich das ich den HEX code so sende ?
wie geschrieben, ich finde nur was zum Daten empfangen, aber nicht senden, und dann in HEX
ich muss, so das Protokoll von BMW 16 Hex + 1 Prüfsumme in HEX senden

eine kleine demo wie sowas geht würde mir sehr helfen
Danke

p.s So was änliches gibt es, aber für den Atmega8 und in Asselbler :frowning: nicht meine sprache
könnte aber den Quellcode posten wenn ihn jemand versteht und umbauen mag :smiley:

Einfach Serial.write(). Das ist kein Hexenwerk. Das Format ist nur eine Darstellungssache. Nimm HTerm statt dem Serial Monitor, dann kannst du genau einstellen wie es angezeigt wird (Haken bei Ascii und Hex):

void setup() 
{
  Serial.begin(9600);
  sendHex("   www.e34.de   ");
}

void loop()
{
}

void sendHex(const char* str)
{
  unsigned int checksum = 0;
  
  while(*str)
  {
    checksum += *str;
    Serial.write(*str);
    str++;
  }

  Serial.write((byte)checksum);
}

Liefert:

20 20 20 77 77 77 2E 65 33 34 2E 64 65 20 20 20 16

EDIT:
Man könnte checksum eigentlich auch gleich als byte statt unsigned int deklarieren. Dann geschieht der Überlauf ganz von selbst :slight_smile:

Auch beachten dass du den Arduino nicht gleichzeitig am PC per USB und einem externen Gerät mit Serial verbinden kannst. Das ist die gleiche Schnittstelle. Für sowas bietet es sich oft an eine zweite Schnittstelle in Software zu emulieren. Mit SoftSerial (bei der IDE dabei) oder besser AltSoftSerial (muss man runterladen)

Hallo,

ob dezimal, hexadezimal, oktal ist doch völlig egal. Die Zahl bleibt immer die gleiche. Nur die Darstellung ändert sich.
Wenn Du die Zahl 15 senden möchtest, dann schreibste:

serial.write(15);    // dezimal
serial.write(0x0F);  // hexadezimal

hey,
dem Arduino ist es herzlich egal ob du deine Werte in Hex, Dezimal oder Oktal sendest, der versteht eh nur Bytes.

du kannst mit der String Methode Zahlen in Hex konvertieren
(https://www.arduino.cc/en/Reference/StringConstructor)
Du könntest dann die Bytes (als Hex) zu einem String zusammenfügen

Ich weiß jetzt nicht genau wie dein Aufbau aussieht ob du neben dem Arduino ein LCD oder ein PC Programm verwendest, aber wäre es nicht einfacher erst mal alles als Byte Array zu übertragen.

Nachher bei der Auswertung der Daten kannst du sie immernoch konvertieren :wink:

Die Daten Müssen in Hex an das KI übermittelt werden, Anders wird es nicht akzeptiert
also muss gesendet werden "20 20 20 77 77 77 2E 65 33 34 2E 64 65 20 20 20 16" 16 + 1 Prüfziffer

Das Programm Oben ( demo ) ist schon gut nur iwi will das nicht so recht
Die Sende LED blinkt nicht
ich hatte iwo per zufall mal was gefunden, finde es nimmer, da blinkte die Sende LED aber zeigte nix an
weil die Übertragung selber ( kein HEX ) falsch war

sry, Programmieren nist nicht so mein ding
aber die LOOP funktion Oben sagt doch das es Ständig wiederholt wird oder ?

Das Programm oben ist ja nur ein Test. Es wird einmal nach dem Reset gesendet. Das reicht um zu sehen was abläuft (mit einem Serial Terminal wie HTerm).

Ständig in loop() kannst du auch nicht senden. Da muss schon noch irgendeine Verzögerung rein. 1000ms Dauersenden geht nicht, oder was du da gemeint hast. Bei 9600 Baud brauchst du ca. 1ms pro Zeichen und wenn der Ausgangspuffer voll ist, ist erst mal Pause.

Und wie hinzugefügt: du kannst nicht ein externes Gerät an 0/1 anschließen während der Arduino per USB am PC hängt

Und lass doch nicht von JuliusCaesar89 verwirren. Als String willst du es nicht senden!

Danke Serenify
Aber es Muss ca 1000ms gesendet werden Da das Display Nichts anzeigt
dann kommt eine 10ms Pause

Das ist typisch BMW protocoll, das display braucht für eine anzeige ~1000ms
die Pause von 10ms kommt daher, fals sich adere Geräte wie CCM oder BC an der Datenleitung sich anmelden um was zu senden, z.b. Uhr, datum, Tüt auf etc etc ect

dieses funktioniert mit einem Atmega8 in assembler
aber ich habe anderes damit vor um mir was anderes anzeigen zu lassen

Leider bin ich in sachen Programmiern.... naja eher ne niete

ah. der Arduino hängt an einem NT, abgekoppelt vom PC

Ich bekomm das iwi nicht gebacken
hab es soweit das die Test LED 1x flackert
das ist aber nur 1x senden, das muss aber öfters gesendet werden ~1-2 sekunde
Aber wenn ich das in ein LOOB baue kommt nur fehler im script
wie baue ich das in ein Loop oder in eine schleife ??

Na ja. Du kannst ja mal 1s ständig senden, auch wenn das eben nicht wirklich dauernd gemacht wird, weil der Ausgangspuffer voll läuft:

const unsigned int SEND_DURATION = 1000;
const unsigned int SEND_PAUSE = 10;

unsigned long previousMillis;
bool sending;
byte checksum;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if (!sending)
  {
    checksum = getChecksum("   www.e34.de   ");
    sending = true;
    previousMillis = millis();
    //Serial.print("Start: "); Serial.println(millis());
  }
  else
  {
    Serial.write("   www.e34.de   ");
    Serial.write(checksum);
    
    //Serial.println();
    
    if (millis() - previousMillis > SEND_DURATION)
    {
      //Serial.print("Stop: "); Serial.println(millis());
      
      delay(SEND_PAUSE);      //mal ganz einfach. 10ms sind hier nicht so schlimm
      sending = false;
    }
  }
}

byte getChecksum(const char* str)
{
  byte checksum = 0;
 
  while(*str)
  {
    checksum += *str;
    str++;
  }

  return checksum;
}

Da ist auch Alternativ die Checksumme einmal im vorraus berechnet. Macht das etwas schneller.

Da sind drei ausgekommentierte Debug Zeilen drin. Wenn man die reinmacht geht es auch auf dem normalen seriellen Monitor. Dann sieht man wann er anfängt und aufhört zu senden. Zum Test kann man auch gut eine Zeit von 500ms Senden und 500ms Pause einstellen

Ansonsten, musst du programmieren lernen und verstehen wie die serielle Schnittstelle funktioniert. Was du hier machen willst ist nicht wirklich was für völlige Anfänger.

Danke, damit werd ich mal Experimentieren

Häng doch den Atmega8, der korrekt sendet, an das Hterm und schau dir an, was der sendet.

So…
erst mal vielen dank an die Lösungsversuche
aber irgendwie will das nicht wirklich
ich sehe anhand des Interface das der Arduino uno sendet, das Display aber Unbeeindruckt
nun hab ich ein Raspberypi Logik/Oszillator dran gehangen. man kann sehen wie abgefragt wird ob die leitung auf High ist die benötigt wird um senden zu dürfen
wenn das also OK ist sendet der Arduino seinen “Text” in HEX
Das aber nichts passiert habe ich den Atmega8 mit dem Demo Assembler script gestartet
dabei habe ich nun Folgendes festgestellt:
bei dem Atmega8 sendet dieser wenn die Freigabe Leitung auf HIGH ist ← Richtig
der Arduino uno (Atmega328) sendet bei LOW, beziehungsweise zieht diese auf LOW ← Falsch
Wieso keine Ahnung, ich habe eine abfrage eingebaut gehabt das er Nur senden soll wen HIGH
das funktionierte aber sobald er sendet ist die Leitung sofort LOW. :frowning:
nun meine idee das vorhandene Assembler script zu nehmen, da dies ja funktioniert, und das zu erweitern
Nur… mein Problem das ich von der Programmiersprache keinen Schimmer habe
und daher meine frage und Bitte ob mir da jemand das umschreiben könnte
ich poste hier gerne das Demo script wenn da jemand zu Lust hat oder unter die arme zu greifen
ich weiß zzt nicht wie ich nen Taster abfrage um z.b. einen Text anzeigen zu lassen ( programm sprung o.ä )
Das Demoscript zaubert zzt ständig einen Text in HEX auf das display
selber kann ich da aber nicht rumdoktern
beim Komilieren kommen sofort zig Fehler :frowning:

Danke

script (ps. ggf unsauber gecodet (stammt nicht von mir :smiley: stammt aus einem ~8 jahre alten projekt))

; Created: 14.10.2016 16:58:45
; Author : Proto
;


;	PORTB.0	Eingang, angeschlossen an LAC
;	PORTD.1	I/O, angeschlossen an DAC
;	PORTC.0   Taster 1 Wischwasser
;	PORTC.1   Taster 2 Kühlwasser
;	PORTC.2   Taster 3 Ölstand

.include "m8def.inc"				; Lade ATmega8 Definitionen
 
.def temp = r16					; Register 15 wird als variabel temp benutzt
.def tc1 = r25					; Register 25 wird als variabel tc1 benutzt
.def tc2 = r26					; Register 26 wird als variabel tc2 benutzt
.def sum = r20					; Register 20 wird als variabel sum benutzt

.equ UBRRVAL = 25				; Baudrate 9600 bei 4MHz
 
		;Stackpointer initialisieren
		ldi temp, LOW(RAMEND)		; Lade RAM Endaddresse (Low) in Stackpointer (Low)
		out SPL, temp			
		ldi temp, HIGH(RAMEND)		; Lade RAM Endaddresse (High) in Stackpointer (High)
		out SPH, temp
 
		; Baudrate einstellen
		ldi temp, LOW(UBRRVAL)		; Lade Baudratenwert (Low) in UART Statusregister (Low)
		out UBRRL, temp
		ldi temp, HIGH(UBRRVAL)		; Lade Baudratenwert (High) in UART Statusregister (High)
		out UBRRH, temp
 
		; Frame-Format: 8 Bit
		ldi temp, 0b10100110		; Lade Datenformat für UART
		out UCSRC, temp
 
		sbi UCSRB,TXEN			; Aktiviere TX am UART

		ldi	temp,$0C		; Aktiviere PORTB.0 (4-7) als Eingang und PORTB.1-3 auf Ausgang
		out	DDRB,temp

Start:

		;Positive Flanke erkennen
fl1:		sbic PINB, 0				; Eingang Low?
		rjmp fl1				; Falls nicht springe nach fl1
fl2:	sbis PINB, 0				; Eingang High?
		rjmp fl2				; Falls nicht springe nach fl2

		rcall t10ms				; Zeitschleife, warte 40ms
		rcall t10ms
		rcall t10ms	
		rcall t10ms	

		sbis PINB, 0				; Eingang Low? -> Andere Nachricht akiv?
		rjmp Start				; Falls ja, springe nach Start
		
		ldi sum,0				; Prüfsumme initialisieren
		ldi temp, $20				; Erstes Schriftzeichen laden
		add sum, temp				; Schriftzeichen zur Prüfsumme addieren
		rcall serout				; Sendeunterprogramm aufrufen
		ldi temp, $20
		add sum, temp
		rcall serout
		ldi temp, $48
		add sum, temp
		rcall serout
		ldi temp, $61
		add sum, temp
		rcall serout
		ldi temp, $6c
		add sum, temp
		rcall serout
		ldi temp, $6c
		add sum, temp
		rcall serout
		ldi temp, $6f
		add sum, temp
		rcall serout
		ldi temp, $20
		add sum, temp
		rcall serout
		ldi temp, $50
		add sum, temp
		rcall serout
		ldi temp, $72
		add sum, temp
		rcall serout
		ldi temp, $6f
		add sum, temp
		rcall serout
		ldi temp, $74
		add sum, temp
		rcall serout
		ldi temp, $6f
		add sum, temp
		rcall serout
		ldi temp, $20
		add sum, temp
		rcall serout
		ldi temp, $20
		add sum, temp
		rcall serout
		ldi temp, $20
		add sum, temp			
		rcall serout				; Sendeunterprogramm aufrufen
		inc sum					; add checksumm
		mov temp, sum				; Prüfsumme laden
		rcall serout			; Sendeunterprogramm aufrufen
		rcall t10ms				; Zeitschleife, warte 10ms
		
		rjmp Start				; Rücksprung, Ende des Programms 
 
serout:	
		; Sendeunterprogramm
		sbis UCSRA,UDRE				; Warten bis UDR für das nächste Byte bereit ist
		rjmp serout
		out UDR, temp				; Inhalt von temp auf UDR ausgeben
		ret					; zurück zum Hauptprogramm 

t10ms:	
		; 10ms Zeitschleife
		ldi  tc1, $42
tloop1:		ldi  tc2, $C9
tloop2:		dec  tc2
		brne tloop2
		dec  tc1
		brne tloop1
		ret

p.s. als Porteingang hab ich Portc gewählt Ob das aber machbar ist… keine Ahnung
da las ich Freie Wahl
einzig ist fest definiert TX zum senden
und port PB0 für den Eingang um zu schauen ob die Leitung auf HIGH ist (Sendefreigabe)