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
ok lag wohl daran das ich die def 2313def.dat geladen hatte anstatt attiny2313.dat
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
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
#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;
}
}
}
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...
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.
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;
}
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();
}
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?
$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