K-BUS TRanciever Melexis TH3122

mhh da meckert er rum,. unknown statement,. ".EQu not found for UCSRB"

ok lag wohl daran das ich die def 2313def.dat geladen hatte anstatt attiny2313.dat
 
zurück hier im thema, da wir woanders ein bisschen abgedriftet sind,.

empfangen
Code:
Dim I As Byte
Dim I2 As Byte

'BUS
Dim I_message As Byte                                       'nachrichtenlaenge
'Dim I_dmessage As Byte
Dim I_total As Byte
Dim Puffer As Byte
Dim Serial_flag As Bit                                      'Empfang
Dim Recieved(6) As Byte                                     'empfangende daten
Dim Startadress As Byte At Recieved + 1 Overlay
Dim Messagelength As Byte At Recieved + 2 Overlay
Dim Zieladress As Byte At Recieved + 3 Overlay
Dim Data_1 As Byte At Recieved + 4 Overlay
Dim Data_2 As Byte At Recieved + 5 Overlay
Dim Xorcheck As Byte At Recieved + 6 Overlay

do
If Ischarwaiting() = 1 Then                              'es gibt was zu empfangen
         Puffer = Inkey()                                   'byte abholen
         If Serial_flag = 0 Then                            'start des empfangens
            If Puffer = &H50 Or Puffer = &H3F Or Puffer = &H0 Then       'es kommt sogar was vom Lenkrad oder PDC oder lichtsteuergeraet
              I_message = 1                                 '1zeichen abgeholt, zaehler =1
              'pufferbyte ist schon 1byte vom empfangenen code
              Gosub Ibus_empfangen                          'empfang was
            End If
         Else                                               'empfange den rest der zeichenkette, weil serial_flag =1
            Incr I_message
            Gosub Ibus_empfangen                            'empfang den Rest
         End If
   End If

loop

Ibus_empfangen:
      Serial_flag = 1

      Recieved(i_message) = Puffer

      If Recieved(2) <> 0 Then

         I_total = Recieved(2) + 2
         If I_message = I_total And I_message > 2 Or I_message > 6 Then

            'Print #1 , "Quellid " ; ; " | " ; "Länge " ; " | " ; "Zielid " ; " | " ; "Data 1 " ; " | " ; "Data 2 " ; " | " ; "Xor"
            'Print #1 , Hex(recieved(1)) ; " | " ; Hex(recieved(2)) ; " | " ; Hex(recieved(3)) ; " | " ; Hex(recieved(4)) ; " | " ; Hex(recieved(5)) ;
            

            If Recieved(6) <> xorprüfbyte Then
               For I = 1 To 6                               'empfangenes verwerfen, da xor prüfung <>1
                  Recieved(i) = 0
               Next I
            End If

            I_message = 0                                   'ende der nachricht
            Serial_flag = 0
         End If
      End If
Return

hab allerdings immernoch problemebei der checksumme,.
lt bascom hilfe sollte checksum() äquivalt zu diesem code sein
Code:
Function Calc_CheckSum(Message) As Integer
   ' calc XOR checksum for iBus protocol
   Dim n As Integer ' counter
   Dim Chk As Integer ' Checksum - will work for up to msg length of 255 bytes
   ' XOR all bytes in message
   For n = 1 To Len(Message)
       Chk = Chk Xor Asc(Mid$(Message, n, 1))
   Next
   ' get least significant byte by ANDing with FF
   ' and return it
   Calc_CheckSum = (Chk And &HFF)
End Function

bekomme damit aber immer anstatt 1F, AF als prüfsumme ausgespuckt,..
 
Das mit der checksum-Funktion ist mir so nicht klar:
-Warum Integer? Die Message ist doch eigentlich eine Kette von Bytes, (bitweises) verXORren von Bytes liefert ebenfalls ein Byte.
-Muß chk nicht erstmal mit irgendwas (0?) initialisiert werden?
-Was soll das verANDen mit 0xFF am Ende? Ein Byte wird da ja quasi mit 1 multipliziert, bei einer mehr-byte-Variable werden die oberen bytes so 0 gesetzt (was mich also wieder zur ersten Frage bringt).
Tu Dir den Gefallen, und trage mal alles zu den Telegrammen, den Anforderungen an die Checksumme (da hattest Du mMn mal angedeutet, daß nicht alle Bytes miteingehen) usw zusammen, und dann strick Dir eine eigene geeignete, sinnige Empfangsroutine zusammen, die den Check gleich miterledigt, ggf uninteressante Sender/Empfänger ignoriert, und Dir nur interessante Inhalte übermittelt...
Du willst nicht so langsam mal auf ASM umsteigen? ;)

P.S.:Wenn Du willst, erklär ich gern mal ein paar fundamentals zum Hardware UART - dann wird auch einiges mit inkey und ischarwaiting und input klarer.
 
Um CRC zu berechnen werden beim IBus alle Bytes der Botschaft verXORt und das CRC-Byte am Ende der Nachricht mitgeschickt.

So sieht die Sendemethode in C aus (Nur als Beispiel für XOR):

Code:
#define UART0_RXOFF	UCSR0B = (1<<TXEN0); 
#define UART0_RXON	UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);

void uart0_putchar(char Data)
{
	while (!((UCSR0A) & (1<<UDRE0))) { }	// warte auf UART0 Sender bis senden möglich ist						
	UDR0 = Data;				// sende die Daten	
}

void uart_sendibus(PGM_P pData)
{
	//long long i;
    //unsigned int len = pgm_read_byte(pData+1) + 2;		// ermittele die Nachrichtenlänge
	unsigned char b, csum = 0;

	while (1)							// Schleife bis alles gesendet wurde
	{		
		if (uart0_ibusclear())				// wenn Bus im Leerlauf
		{
			UART0_RXOFF					// schalte UART Empfang aus
			b = pgm_read_byte(pData++);
			while (b != csum)
			{
				// hole ein Byte aus dem Flash
				uart0_putchar(b);		// und sende es
				csum ^= b;				// aktualisiere die Prüfsumme
				b = pgm_read_byte(pData++);
			}
			uart0_putchar(csum);			// übermittele die Prüfsumme
			UART0_RXON					// schalte UART Empfang ein
			return;						
		}
	}
}

Ist doch eigentlich ganz einfach zu implementieren.

Die Botschaft ist wie folgt aufgebaut:

<Quell-ID - 1Byte><Länge* - 1Byte><Ziel-ID - 1Byte><Daten bis 32Byte><CRC>

Bei der Länge werden alle Bytes ab Ziel bis CRC gezählz, sprich Ziel-ID + Daten + CRC.

Ich habe damals das Empfangen über ISR gemacht. Das Unterscheiden der Botschaften habe ich so gemacht, dass ich ein Timer laufen lassen habe. Wenn ein Byte empfangen wurde, habe ich den Timer resettet. Dann kam nächstes Byte rein, dann habe ich nachgeschaut wo der Timer steht. Ist der Abstand zwischen zwei Bytes > 1,7ms (Prio 1 Botschaftabstand), so gehört das aktuelle Byte zu der neuen Botschaft, ist der Abstand kleiner, so ist es noch die alte Botschaft. Diese Methode hat zuverlässig funktioniert, auch in einem vollausgebauten IBus wo richtig was los war.

Dann während des Empfangs habe ich die Bytes dann in den botschaftorientierten Puffer geschoben. Ist lediglich ein zweidimensionales Array. Ich kann npaar Code-Passagen posten, wenn Interesse besteht. Muss sie nur suchen und finden.

Grüße
Heinrich
 
Generell gehe ich da mit. Interruptbasiert usw. Struktur der Telegramme nehme ich so auch hin. Ok. Aber warum das mit dem Timer? Du weißt doch eigentlich jederzeit, wo Du bist - nach dem ersten Byte wird Dir gesagt, wieviele noch kommen...
Folgende Vermutungen/Vorraussetzungen (bitte zustimmen/korrigieren):
-die UART-Konfiguration ist fest vorgeschrieben (Baudrate, start/stopp/Datenbits, Parität, Handshake usw), und ändert sich nicht
-Bonze will nur empfangen, nicht (auf diesem Bus) senden
-Darf ein Telegramm abgebrochen werden - muß das erkannt werden? (Dein Timer)
-Es darf immer nur gesendet werden, wenn alle anderen schweigen - das juckt uns aber als Empfänger nicht.
-Hemis Telegramm-Struktur gilt.
-ich erwarte, kein (also auch nicht das erste) Byte zu verpassen, und nie den Anschluß zu verlieren (ansonsten braucht man den "Synchronisations-Timer"

Ansatz wär dann in etwa so:
Der UART wird initialisiert, mit RXC-Interrupt und so. Außerdem einen (vorerst leeren) Puffer-String, und ein Byte als Bytezähler;)
(Der Bytezähler soll die noch zu empfangenden Bytes dieses Telegrammes runterzählen. Da wir mit den maximal 36 Bytes den 1-Byte-Zähler nie ausschöpfen, können wir ihn auch gleich als Statusflag verwenden. Wurde eine korrekte Checksumme empfangen, geht der Zähler auf 0, und im HP kann der Strinpuffer verwendet werden. Stimmt die Checksumme nicht, kann man ihn auf einen anderen sinnigen Wert laden (255), und den Puffer löschen (dann wird der im HP automatisch ignoriert). Wenn das Hauptprogramm den Puffer verarbeitet hat, kann es seinerseits den Zähler auf 255 setzen - als ACK sozusagen. Damit könnte man in der ISR das verschlucken von Telegrammen detektieren, falls nötig. Wurde die Restlänge empfangen (also Zähler=254), wird der Zähler mit dieser überschrieben. Zähler=0 ist in der ISR also ein Fehler, Zähler=254 holt die Länge, Zähler=1 verarbeitet/prüft die Checksumme, alle anderen fließen in den Puffer. Zähler=1 wird gesondert bearbeitet, da er nicht in die Checksumme eingeht.
In der ISR wird das empfangene Byte aus dem UDR geholt, Jetzt wird mit Fallunterscheidung für den Bytezähler entschieden, wie's weitergeht.
Im HP pollt man den Zähler (=0?), und holt den empfangenen, vorbereiteten String (SenderID|EmpfängerID|Datenbyte|...|Datenbyte) aus dem Puffer (wenn nötig in einen Ringpuffer oder so), und quittiert das über den Zähler (=255).
Die eventuell zwischengepufferten Strings kann man jetzt über irgendwelche festen IF-Then-Konstrukte, Tabellen oder sonstwas (ist select-case auch auf strings anwendbar?) mit den Vorgaben verglichen werden, und das Senden des entsprechenden NEC starten.
Ist zum debuggen irgendeine Kommunikationsleitung vorgesehen? (Print #1 läßt darauf schließen)? Dann könnte man wenns irgendwo knallt (und halt ein Puffer nötig/zu klein ist) 'ne entsprechende Fehlermeldung schicken (zB wenn der UART ein Byte empfangen hat, derZähler aber noch 0 ist, oder wenn nach einem verarbeiteten K-Bus-Telegramm ein NEC-Telegramm gesendet werden soll, dieser mit dem letzten aber noch nicht fertig ist.)
Da ja eigentlich am K-Bus nur gehorcht werden soll, kann man den (-selben) HW-UART dann zum senden solcher Infos an einen PC oder so verwenden. (allerdings mit denselben UART-Settings).
Soweit erstmal meine Überlegungen/Vorschläge...
 
Generell gehe ich da mit. Interruptbasiert usw. Struktur der Telegramme nehme ich so auch hin. Ok. Aber warum das mit dem Timer? Du weißt doch eigentlich jederzeit, wo Du bist - nach dem ersten Byte wird Dir gesagt, wieviele noch kommen...

Ja, das bekommst Du gesagt. Der Ansatz, wie man es macht, ist egal. Es gibt eben mehrere Lösungen für das Problem.

Das mit dem Timer ist dazu da, damit ich weiß, gehört das Byte, was ich gerade empfangen habe, zu der alten Botschaft oder zu der neuen.

Folgende Vermutungen/Vorraussetzungen (bitte zustimmen/korrigieren):
-die UART-Konfiguration ist fest vorgeschrieben (Baudrate, start/stopp/Datenbits, Parität, Handshake usw), und ändert sich nicht

Korrekt, 9600, 8-E-1, ist fest vorgegeben.

-Bonze will nur empfangen, nicht (auf diesem Bus) senden

Richtig.

-Darf ein Telegramm abgebrochen werden - muß das erkannt werden? (Dein Timer)

Ja, darf sie. Busmaster kann jeder Zeit den Bus für sich beanspruchen und dann halten die Slaves die Klappe. Aber auch da muss der Botschaftabstand eingehalten werden, sprich 1,7ms bei Prio 1 Botschaften.

Dem Timer ist es egal. Er misst nur die Anzahl der Klicks zwischen den Bytes.

-Es darf immer nur gesendet werden, wenn alle anderen schweigen - das juckt uns aber als Empfänger nicht.

Korrekt.

-Hemis Telegramm-Struktur gilt.

Na das sowieso. :D

-ich erwarte, kein (also auch nicht das erste) Byte zu verpassen, und nie den Anschluß zu verlieren (ansonsten braucht man den "Synchronisations-Timer"

Und genau hier liegt ja das Problem. Bei IBus hast Du keinerlei Synchronisierung der Teilnehmer. Beim CAN zum Beispiel hast Du im Header ein "Start of Frame". Beim IBus hast Du eben sowas gar nicht. Aber Du brauchst etwas um Dich auf den Bus aufzusynchronisieren. Und genau das mache ich mit dem Timer. Ich messe den Abstand zwischen den empfangenen Bytes und entscheide anhand dessen ob es eine neue oder alte Botschaft ist.

Ansatz wär dann in etwa so:
Der UART wird initialisiert, mit RXC-Interrupt und so. Außerdem einen (vorerst leeren) Puffer-String, und ein Byte als Bytezähler;)
(Der Bytezähler soll die noch zu empfangenden Bytes dieses Telegrammes runterzählen. Da wir mit den maximal 36 Bytes den 1-Byte-Zähler nie ausschöpfen, können wir ihn auch gleich als Statusflag verwenden. Wurde eine korrekte Checksumme empfangen, geht der Zähler auf 0, und im HP kann der Strinpuffer verwendet werden. Stimmt die Checksumme nicht, kann man ihn auf einen anderen sinnigen Wert laden (255), und den Puffer löschen (dann wird der im HP automatisch ignoriert). Wenn das Hauptprogramm den Puffer verarbeitet hat, kann es seinerseits den Zähler auf 255 setzen - als ACK sozusagen. Damit könnte man in der ISR das verschlucken von Telegrammen detektieren, falls nötig. Wurde die Restlänge empfangen (also Zähler=254), wird der Zähler mit dieser überschrieben. Zähler=0 ist in der ISR also ein Fehler, Zähler=254 holt die Länge, Zähler=1 verarbeitet/prüft die Checksumme, alle anderen fließen in den Puffer. Zähler=1 wird gesondert bearbeitet, da er nicht in die Checksumme eingeht.
In der ISR wird das empfangene Byte aus dem UDR geholt, Jetzt wird mit Fallunterscheidung für den Bytezähler entschieden, wie's weitergeht.
Im HP pollt man den Zähler (=0?), und holt den empfangenen, vorbereiteten String (SenderID|EmpfängerID|Datenbyte|...|Datenbyte) aus dem Puffer (wenn nötig in einen Ringpuffer oder so), und quittiert das über den Zähler (=255).
Die eventuell zwischengepufferten Strings kann man jetzt über irgendwelche festen IF-Then-Konstrukte, Tabellen oder sonstwas (ist select-case auch auf strings anwendbar?) mit den Vorgaben verglichen werden, und das Senden des entsprechenden NEC starten.
Ist zum debuggen irgendeine Kommunikationsleitung vorgesehen? (Print #1 läßt darauf schließen)? Dann könnte man wenns irgendwo knallt (und halt ein Puffer nötig/zu klein ist) 'ne entsprechende Fehlermeldung schicken (zB wenn der UART ein Byte empfangen hat, derZähler aber noch 0 ist, oder wenn nach einem verarbeiteten K-Bus-Telegramm ein NEC-Telegramm gesendet werden soll, dieser mit dem letzten aber noch nicht fertig ist.)
Da ja eigentlich am K-Bus nur gehorcht werden soll, kann man den (-selben) HW-UART dann zum senden solcher Infos an einen PC oder so verwenden. (allerdings mit denselben UART-Settings).
Soweit erstmal meine Überlegungen/Vorschläge...

Dieser Ansatz funktioniert genau so. Ist halt nur etwas anders.

Grüße
Heinrich
 
Sicherheitshalber frage ich nochmal: vor beginn eines jeden Telegrammes herrschen immer(!) mindestens 1,7ms Ruhe? (oder 0,55ms?)
9600-8-E-1 heißt 1Startbit, 8 Datenbits, 1Paritätsbit(even), 1Stoppbit (also 11Bits pro Byte)? - macht bei 9600baud also ca 1,146ms pro "Byte"
Wenn der Master die sendenden Slaves abwürgen kann (das empfangene Telegramm also verworfen werden muß), reicht die Auswertung des Längenbytes nicht - dann braucht man den Timer. Durch das Längenbyte kann man aber direkt nach dem empfangenen Checksum-Byte den Puffer freigeben, und muß nicht erst auf den Ablauf des Timers warten.
Wenn der Timer also immer nur bei der Auswertung eines gerade empfangenen Bytes von Interesse ist ("Beginn eines neuen Telegrammes?"), würde ich das in etwa so angehen:
Prescaler und Vorladewert sind so zu wählen, daß der Timer irgendwo in der Mitte zwischen den 1,2 und 1,7 ms überläuft, bei1,5ms z.B.
Beim Eintritt in die RXC-ISR wird der Timer auf den Reload zurückgesetzt, dann wird das Timer-Überlauf-Flag geprüft. Ist dieses gesetzt, handelt es sich also um ein neues Byte. Da man jetzt eh den (eventuellen) Pufferinhalt löschen, und den Bytezähler zurücksetzen muß (vorher wollten wir aber ggf das Ack aus dem HP auswerten), kann man sich das eigentlich nach dem XOR-Byte sparen. Danach ist dann das TOV-Flag zu löschen (durch 1-setzen).
Dann folgt der Rest, wie oben ...

Edit: Das Problem ohne Synchronisations-Timer ist wie gesagt nicht erst, daß ich kein Byte verpassen darf (das traue ich den Interrupts durchaus zu, erst recht bei nur 9600 baud), und alle Fehlerfrei erkennen muß (Parität könnte sogar auch noch bewertet werden) - sondern daß ich nach einem abgebrochenen Telegramm sicher danebenliege.
 
Sicherheitshalber frage ich nochmal: vor beginn eines jeden Telegrammes herrschen immer(!) mindestens 1,7ms Ruhe? (oder 0,55ms?)

Ja, so ist es.

Ablauf: Eine Botschaft fliegt vorbei ---> Pause --> nächste Botschaft --> Pause --> nächste Botschaft.

Anhand der Pause wird entschieden um welche Prio handelt es sich bei der kommenden Botschaft. Beträgt die Pause 1,7ms, handelt es sich um Prio 1 Botschaft. Ist die Pause 2,3ms und bei Prio 3 sind es 10ms. Das bedeutet, dass der Bus mindestens eine Leerlaufzeit von 1,7ms hat, immer.

Insgesamt läft das beim IBus so ab:

1. Der Bus wacht auf, sagen wir mal das Fahrzeug wurde aufgeschlossen.
2. Busmaster sendet einen Broadcast um zu erfahren, wer alles am Busangeschossen ist. (das nennt sich "Device status request")
3. Die Busteilnehmer beantworten dieses Request mit einem "Device status ready". Bei dieser Botschaft ist allerdings der Flag "after reset" gesetzt. Damit melden sich die Busteilnehmer beim Master an.
4. Der Master hat jetzt die Liste der Busteilnehmer.
5. Alle (glaube ich) 30 Sekunden kommt wieder das "Device status request", allerdings ist es an den jeweiligen Teilnehmer gerichtet. Dieses Request muss mit einem "Device status ready" ohne "after reset" Flag quitiert werden. Wird das dritte Request dieser Art vom Teilnehmer nicht quitiert, so wird der Teilnehmer deaktiviert. Das heißt man kann beispielsweise den CD-Wechsler nicht mehr im Menü anwählen.

9600-8-E-1 heißt 1Startbit, 8 Datenbits, 1Paritätsbit(even), 1Stoppbit (also 11Bits pro Byte)? - macht bei 9600baud also ca 1,146ms pro "Byte"

Ja, genau so ist.

Wenn der Master die sendenden Slaves abwürgen kann (das empfangene Telegramm also verworfen werden muß), reicht die Auswertung des Längenbytes nicht - dann braucht man den Timer. Durch das Längenbyte kann man aber direkt nach dem empfangenen Checksum-Byte den Puffer freigeben, und muß nicht erst auf den Ablauf des Timers warten.
Wenn der Timer also immer nur bei der Auswertung eines gerade empfangenen Bytes von Interesse ist ("Beginn eines neuen Telegrammes?"), würde ich das in etwa so angehen:
Prescaler und Vorladewert sind so zu wählen, daß der Timer irgendwo in der Mitte zwischen den 1,2 und 1,7 ms überläuft, bei1,5ms z.B.
Beim Eintritt in die RXC-ISR wird der Timer auf den Reload zurückgesetzt, dann wird das Timer-Überlauf-Flag geprüft. Ist dieses gesetzt, handelt es sich also um ein neues Byte. Da man jetzt eh den (eventuellen) Pufferinhalt löschen, und den Bytezähler zurücksetzen muß (vorher wollten wir aber ggf das Ack aus dem HP auswerten), kann man sich das eigentlich nach dem XOR-Byte sparen. Danach ist dann das TOV-Flag zu löschen (durch 1-setzen).
Dann folgt der Rest, wie oben ...

Genau so habe ich es auch gelöst. Bis auf den Punkt, dass ich den Timer einfach mit einem 1024-Prescaler laufen lassen habe. Wenn ein Byte angeflogen kam, habe ich den Timer resettet. Dann kam das nächste Byte rein, ich habe den Timerwert ausgelesen und mit einem (vorher ausgerechnetem Wert) verglichen. Für Prio 1 war es glaube ich 23 oder sowas., eben etwas weniger als 1,7ms.

Edit: Das Problem ohne Synchronisations-Timer ist wie gesagt nicht erst, daß ich kein Byte verpassen darf (das traue ich den Interrupts durchaus zu, erst recht bei nur 9600 baud), und alle Fehlerfrei erkennen muß (Parität könnte sogar auch noch bewertet werden) - sondern daß ich nach einem abgebrochenen Telegramm sicher danebenliege.

Ja, genau das ist der Punkt. Du brauchst etwas um Dich zu synchronisieren. Mit einem Ansatz hat es 1A funktioniert, auch wenn auf dem Bus richtig Verkehr war, als mein Bus vollständig ausgebaut war.

Grüße
Heinrich.
 
Hmm... Wenn bei Dir jetzt aber ein Slave (warum auch immer) abbricht, aber nicht gleich ein anderes Telegramm gesendet wird (der Timer also (vielleicht sogar mehrfach) überläuft), dann kann er doch beim nächsten Byte zufällig kleiner als Deine 23 sein - dann würdest Du den Abbruch und das korrupte Telegramm übersehen, oder nicht?
Oder wird irgendwo garantiert, daß da sofort (vor einem Überlauf) ein Byte (eines neuen) Telegrammes gesendet und empfangen wird?
Ansonsten finde ich meinen Vorschlag mit dem Überlauf-Flag ... ähm ... sicherer
 
naja wär schon nich schlecht , wenn ich senden koennte,.
dann koennte ich blinkerbestätigung beim öffnen usw, einprogrammieren,

geschickt waers also, nicht nach gewissen vorkommenden code bloecken zu suchen, sondern den timer mit einzubeziehen,.
puh, dann muss ich mich ganz schoen bemuehen,. hab naemlich nur nen tiny2313,. das wird dann eng :D
 
So Leute, ich habe etwas Code gefunden zum meinen alten Projekt.

Erstmal die Timergeschichte:

Code:
void TIMER0_start(void)
{
  //set presacler to 1024
  TCCR0B = (1 << CS00) | (1 << CS02);
}

unsigned char TIMER0_getValue(void)
{
  if(TIFR0 & (1<<TOV0)) {
    return 0xFF;
  }
  return TCNT0;
}

void TIMER0_reset(void)
{
  //reset overflow flag
  TIFR0 = (1<<TOV0);
  //reset counter value
  TCNT0 = 0;
}

Wie man sieht habe ich den Overflow ebenfalls berücksichtigt.

Nun wird es interessant, hier kommt die ISR:

Code:
enum {
  RxActive,
  WaitForlen,
  standby,
  standby_after_error
} eIrqState;

unsigned char irqState;

ISR(USART_RXC_vect)			// ISR UART0
{
  //*** DEFINITON ***
  static u8 RXlen;
  static u8 curRxPos;
  u8 t;
  u8 byte;

  //*** INITIALIZATION ***

  byte = UDR0;

  //*** PARAMETER CHECK ***
  //*** PROGRAM CODE ***
  
  t = TIMER0_getValue();

  // is it the start of a new frame
  if(t > IBUS_PRTY1_DELAY) {
    //it is a new frame, remember the destionation address
    BUFFER_writeRXEntry(0, byte);
    irqState = WaitForlen;
  }
  else {
    switch(irqState) {
      case WaitForlen:
        if(byte < MAX_FRAME_SIZE-2) {
          RXlen = byte;
          BUFFER_writeRXEntry(1, byte);
          curRxPos = 2;
          irqState = RxActive;
        }
        else {
          irqState = standby_after_error;
        }
        break;
        
      case RxActive:
        if(curRxPos < RXlen+2) {
          BUFFER_writeRXEntry(curRxPos, byte);
        }
        curRxPos++;
        if(curRxPos == RXlen+2) {
          BUFFER_insertRXEntry();
          irqState = standby;
          //DBG_ALTER_PIN0();
        }
        break;
    }
  }
  TIMER0_reset();  
}

@Bonze: Was hindert Dich daran eine vernünftige MCU zu nehmen? Damit ist der kleine Tiny doch gnadenlos überfordert. Ich habe damals einen Atmega2561. Okay, ich hatte auch zwei TH3122 dran hängen gehabt und es war alles doppelt.

Grüße
Heinrich
 
Nunja, so ein Tiny hat ja auch so seine Vorteile:
-teilweise geringerer Preis
-gibts meist als SOIC (wenn man TQFP oder anspruchsvoller nicht verlöten will)
-ggf geringere Göße

Wenn er also ausreicht - warum nicht...

Normalerweise faßt man doch erst zusammen, was man so alles will, und sucht sich dann (mit mehr oder weniger Reserven) einen geeigneten Controller raus (wobei natürlich auch Vorlieben eine Rolle spielen).

Der Tiny2313 hat übrigens einen großen Bruder (was den Flash betrifft): den ATtiny4313

Wenn jetzt auf einen anderen Controller gewechselt werden soll, muß der NEC-Teil nochmal durchgegangen werden.

Zum Senden auf den K-Bus:
Im Prinzip läuft das ähnlich ab, wie das Empfangen - nur andersrum (also Telegramm mit Senderbyte, Längenbyte, Empfängerbyte, Datenbytes und der Checksumme zusammenstellen, und dann alles nacheinander ins UDR schieben, dabei hilft der TXC-IRQ).
Hier kommt jetzt aber ins Spiel, daß erstens gewartet werden muß bis der Bus frei ist, und zweitens überprüft werden muß, ob der Bus nicht anderweitig übernommen wurde.
Fragen an Hemi:
-soweit korrekt?
-wie ist das mit erstens, wie melde ich Interesse am Bus an? Wie belege ich ihn?
-zweitens verstehe ich so, daß ich Controllerseitig den SEN/STA tristate lasse, und den PIN auslese - solange der low ist ist alles i.o. (ggf also einen IRQ im Controller, wenn der hi geht)
-Wann muß ich, wenn der SEN/STA so hi geht das Senden abbrechen? sofort, oder nach dem laufenden Byte?
 
klar, hab die schaltung aber schon soweit fertig ;/

kann auch aufs senden verzichten, es sollte ja urspruenglich nur ein IBUS / NEC umsetzer werden :D
 
Nunja, so ein Tiny hat ja auch so seine Vorteile:
-teilweise geringerer Preis
-gibts meist als SOIC (wenn man TQFP oder anspruchsvoller nicht verlöten will)
-ggf geringere Göße

Wenn er also ausreicht - warum nicht...

Normalerweise faßt man doch erst zusammen, was man so alles will, und sucht sich dann (mit mehr oder weniger Reserven) einen geeigneten Controller raus (wobei natürlich auch Vorlieben eine Rolle spielen).

Der Tiny2313 hat übrigens einen großen Bruder (was den Flash betrifft): den ATtiny4313

Wenn jetzt auf einen anderen Controller gewechselt werden soll, muß der NEC-Teil nochmal durchgegangen werden.

Naja, prinzipiell haste Recht. Aber es ist ein Hobby, da muss man nicht auf jeden Cent schauen, finde ich.

Zum Senden auf den K-Bus:
Im Prinzip läuft das ähnlich ab, wie das Empfangen - nur andersrum (also Telegramm mit Senderbyte, Längenbyte, Empfängerbyte, Datenbytes und der Checksumme zusammenstellen, und dann alles nacheinander ins UDR schieben, dabei hilft der TXC-IRQ).
Hier kommt jetzt aber ins Spiel, daß erstens gewartet werden muß bis der Bus frei ist, und zweitens überprüft werden muß, ob der Bus nicht anderweitig übernommen wurde.
Fragen an Hemi:
-soweit korrekt?

Ja, ist richtig.

-wie ist das mit erstens, wie melde ich Interesse am Bus an? Wie belege ich ihn?

Gar nicht, Du sendest einfach. IBus ist multi-master-fähig, das bedeutet jeder schickt sein Zeug, wie er lustig ist, aber unter Einhaltung der Prios.

-zweitens verstehe ich so, daß ich Controllerseitig den SEN/STA tristate lasse, und den PIN auslese - solange der low ist ist alles i.o. (ggf also einen IRQ im Controller, wenn der hi geht)

Ist SEN/STA low: man darf senden
Ist SEN/STA high: man darf nicht senden

Wenn man den Pin an der MCU aus Ausgang konfiguriert, kann man das Senden abbrechen und den Bus für sich "gewinnen", in dem man den SEN/STA kurz auf low zieht.

-Wann muß ich, wenn der SEN/STA so hi geht das Senden abbrechen? sofort, oder nach dem laufenden Byte?

Das weiß ich leider nicht.
 
wenn ich mich recht entsinne, bin grade unterwegs, dann hat der NEC senden code ca 30% de flashs und 1 Timer verschlungen,.

wenn ich jetzt nur empfangen bzw horchen will, dann haette man doch noch reserve
prinzipiell brauch ich ja nur:

- unterscheidung ob alte oder neue nachricht (1 timer, if ), kann man nicht auch mit SEN/STA high: prüfen ?
- empfang der bytes (schleife)
- auswertung des empfangenen (if/select case consctruct)

vl bekomm ichs ja noch rein .. ;D
 
@Hemi:
klar, der Preis ist da das schwächste Argument. Ich arbeite lieber mit SMT als mit THT, und da sind mir die 1.27mm-SOICs eben etwas angenehmer, als die 0.8mm-TQFPs...
Außerdem hat man da (als ASMler) mit weniger Datenblatt zu kämpfen - wollte ja die Megas nicht schlecht machen - man muß halt entscheiden, welcher wo Sinn macht. Natürlich entwickelt man irgendwelche Vorlieben...
Egal.

@Topic:
Das mit dem Senden würde ich (erstmal) außen vor lassen - ob man das später noch mit reinkriegt weiß ich nicht, aber wenn die Schaltung so schon mal da ist, sollte als erstes auch die ursprüngliche Aufgabe angegangen werden.
In welcher Package-Variante hast Du den 2313 verbaut? DIP oder SOIC? Wenn DIP, dann direkt verlötet, oder gesockelt? (Meiner Meinung nach ist der 4313 nämlich bis auf den größeren Flash identisch/austauschbar)
Dent TxD des 2313 hast du sicher (leider) direkt mit dem THC verbunden - oder kann man den "unterbrechen", und ihn zum debuggen über einen Pegelwandler) auf einen PC legen? (Ich sehe dafür meist bei Prototypen eine Lötbrücke/Jumper vor. Kann man bei Bedarf trennen, und wenn nötig auf ein Terminal-Programm umlegen).

Den wesentlichen Ablauf hab ich mMn in #25 und #27 (Telegramm-Abbruch-Erkennung etc) skizziert. Der RxC-Interrupt filtert Dir so die reinkommenden Bytes, und packt daraus einen String (jedes neue Telegramm überschreibt den schon mit dem ersten Byte - Dein HP hat also die 1,7ms, um das alte Telegramm zu retten). Der String hat die Struktur QuellID|ZielID|DataByte(s).
Hmm... wenn man das über Strings machen will, muß sichergestellt werden, daß dabei kein Null-Byte (0x00) enthalten sein darf (weil das das String-ende symbolisiert. Kann ich davon ausgehen (insbesondere bei den Datenbytes) - wohl eher nicht...
Von einer Festen Telegramm-Länge können wir auch nicht ausgehen, also doch ein "Array" of Byte(?) und die Länge mitspeichern?
Das mit den Timings sehe ich mir später an...
 
hab, beim uart nen abzweig gemacht zum prüfen :)
es gibt wohl empfangsroutinen in c, welche einen ringpuffer nutzen, denke, wenn dann ein byte empfangen wird, wird das ganze empfangene 1 verschoben und dann das neue drangesetzt,.
 
Eigentlich müßte man auch die bestehende Verbindung zum TH3122 trennen, damit der das nicht empfängt (und auf den Bus legt). Andererseits sollte der such ja querstellen wenn man SEN/STA auf logisch high zwingt.

@Empfangsroutinen: richtig, gibts ja auch in Bascom. Input füllt so die ankommenden Bytes (also quasi die Chars hinter den Bytes) in einen nullterminierten String. Ich bin mir aber nicht sicher, ob das über einen Interrupt geht, oder einfach auf das Ende gewartet wird. Wir hatten ja da oben zu stehen, daß die Übertragung eines Bytes ca. 1,2ms dauert - da wartet der Controller (je nacht Takt) unter Umständen über tausend Takte lang drauf (anstelle irgendwas sinnvolles zu tun)
Außerdem kannst Du die Checksumme hier gleich prüfen, und mußt die dann nicht mitabspeichern. Das wesentliche Problem ist aber, daß Deine Telefgramme möglicherweise auch ASCII-Null-Bytes enthalten könnten. Wenn wir jetzt also einen String draus machen, ist der mit dieser null zu Ende. (Strings hättest Du mit Bascom halt einfach vergleichen können).
Wenn wir unser (eventuell gekürztes) Telegramm also nicht als String, sondern als Byte-"Kette" übergeben wollen, müssen wir das Ende anders erkennen - eben doch über das Längenbyte. Unsere Empfangsroutine sollte uns also aus den empfangenen Bytes eine Kette in folgender Form zusammensetzen:
Länge|Quelle|Ziel|Daten. Im Worst Case müssen wir im SRAM dafür also 35Bytes vorhalten. Für den Empfangsstatus hatten wir ja den Bytezähler. Die Vergleichs-Bytefolgen würde ich im Eeprom lagern - mir fällt ber grad keine Elegante Strukturierung dazu ein. am Ehesten genau so, nur mit dem jeweiligen NEC dahinter. Also Länge|Quelle|Ziel|Daten|NEC. Bei 2 Datenbytes also 6 Bytes - würden 21 Stück in den eeprom passen.
Der Vergleich mit der empfangenen Kette könnte dann in etwa(!) so ablaufen:
Ein Pointer fürs Eeprom zeigt erstmal auf Adresse 0.
Lade Eeprom(Pointer) in ein Register, und vergleiche mit erstem Byte der Kette (Längenbyte). Stimmen die überein, werden die weiteren Stellen nacheinander verglichenbis entweder die Restlänge 0 wird (dann haben wir den passenden Eintrag gefunden, und können das folgende Byte an sendnec übergeben (welcher es im Hintergrund sendet), oder es zu einer Unstimmigkeit kommt, dann sagt uns die Restlänge, um wieviel wir den Eeprom-Pointer erhöhen müssen, um das Längenbyte des nächsten Eintrages zu finden. Als End-erkennung der "Daten" könnte man einfach das Längenbyte 0 ablegen - dann war es ein zu ignorierendes Telegramm.
Bliebe noch zu klären, ob man das alles in eine ms gepackt bekommt, oder ob man das Telegramm erstmal puffern muß, weil der Empfang ggf die nächsten Bytes empfängt, und alles überschreibt. Dann hätten wir im worst case ca 6ms für die Auswertung, da dann das nächste Telegramm da sein könnte.
Alle Deine relevanten Telegramme verfügten über 2 Datenbytes, oder? Könnten alle 7ms gültige Telegramme zu verarbeiten sein - wie lange dauerte das senden eines(!) NEC-Telegrammes nochmal? das war doch das Zehnfache, oder? selbst mit Puffer kommt man da uU nicht weit...
 
hab hier auf die schnelle mal was gemacht, meinste ich bin auffem richtigen weg ?
Code:
$crystal = 8000000
$regfile = "ATtiny2313.dat"
$hwstack = 20                                               ' default use 32 for the hardware stack
$swstack = 10                                               'default use 10 for the SW stack
$framesize = 40                                             'default use 40 for the frame space
$baud = 9600
$sim

'Dim I_message As Byte                                       'nachrichtenlaenge
'Dim I_total As Byte
Dim Timer0_ms As Byte

'Dim Stoptime As Byte
Dim Delta_timer0ms As Byte
Dim Serial_flag As Byte
Dim Empfangszaehler As Byte

Dim Recieved As String * 36                                 'empfangende daten
Dim Startadress As Byte At Recieved + 1 Overlay
Dim Messagelength As Byte At Recieved + 2 Overlay
Dim Zieladress As Byte At Recieved + 3 Overlay
Dim Data_1 As Byte At Recieved + 4 Overlay
Dim Data_2 As Byte At Recieved + 5 Overlay
Dim Xorcheck As Byte                                        'At Recieved + 6 Overlay

Empfangszaehler = 36

Config Timer0 = Timer , Prescale = 256
Enable Timer0
Stop Timer0
Timer0 = 131
On Timer0 Timer0_isr
On Urxc Uart_isr                                            ' Keine automatische Register-Rettung
Enable Urxc                                                 ' Interrupt (Byte über USART erhalten) enabled

Enable Interrupts


Do
   If Ischarwaiting() = 1 Then                              'wenn zeichen im puffer wartet
     If Delta_timer0ms <= 17 Then                           'gehoert noch zu dieser nachricht
        Decr Empfangszaehler                                'zaehler um 1 erniedrigen
        Startadress = Inkey()                               'Recieved +                        'zeichen abholen
        Serial_flag = 0                                     'serial_flag zuruecksetzen
      Print Startadress
      End If
   End If

Loop
End

Uart_isr:
   Serial_flag = 1
   If Timer0 <> 131 Then                                    'falls timer schon läuft, dann zeit stoppen
      Stop Timer0
      Delta_timer0ms = Timer0_ms
      Timer0 = 131
   Else
      Start Timer0
   End If

      'If Empfangszaehler = 36 Then
   '      Start Timer1
   '      Decr Empfangszaehler
   '   Else
   '      Decr Empfangszaehler
   '   End If
Return

Timer0_isr:                                                 
   Incr Timer0_ms
   If Timer0_ms > 17 Then
      Timer0_ms = 0
   End If
Return
 
Hmm...
Ne, irgendwie isses das nicht...
Der Empfangspuffer kann kein (nullterminierter) String sein, da wir eine ASCII-Null als reguläres Element empfangen können wollen - ich empfehle einfach ein Byte-Array. Welche Größe? Nun, Was soll denn drin abgelegt werden? Quell und Ziel-ID, und die beiden Datenbytes, klar. Sobald auch andere Längen verarbeitet werden können sollen (max 32 Datenbytes), wir also hinterher nicht wissen, wie lang er jetzt ist, kommt zusätzlich noch das Längenbyte dazu. Eben um uns zu sagen, wieviele Bytes im Puffer das Telegramm bilden. Also 35 Bytes. (Struktur: Länge|Quelle|Ziel|[Daten] (0-32 Datenbytes)).

Jedesmal, wenn ein komplettes Byte durch den HW-UART empfangen wurde, wird die RXC-ISR ausgeführt. In dieser würde ich das empfangene Byte "abholen" (nicht erst im HP), und nach Auswertung des Bytezählers in das Pufferarray einbauen. Der Bytezähler gibt außerdem Aufschluß darüber, wann der Puffer ein komplett Telegramm enthält, und (ggf) ob das Byte im Puffer durch das HP verarbeitet/abgeholt wurde.

Und was ist jetzt mit abgebrochenen/abgewürgten Telegrammen? Also wenn zwischen 2 empfangegen Bytes mehr als 1,7ms (nicht 17) liegen? Nicht so kompliziert denken - das aktuelle Telegramm soll verworfen werden, und wir müssen wieder von vorn anfangen. Es ist also lediglich der Bytezähler wieder auf 255 (für das Byte, also die QuellID) zu setzen. Und wo?
Man kann den Timer0 so einstellen, daß er nach 1,7ms überläuft, und der entsprechenden ISR dann den Bytezähler umsetzen.
Timer0 ist dann beim Empfang eines jeden Bytes (in der RXC-ISR) wieder auf 0 zu setzen, quasi wie beim ... Watchdog ... äh ... kann man den nicht auf 1,7ms einstellen, und ihn den Bytezähler anbellen lassen (ohne Reset) -> Datenblatt such
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)