Hallo Community,
Zwar habe ich folgendes Problem.
Ich wollte für ein Projekt mithilfe des AT90CAN128 CAN Ids auslesen und
diese über ein Display ausgeben.
Leider bekomme ich es nicht genau hin. Habe auch schon die Forumssuche
benutzt, aber hier findet man meist nur Beispiele zum senden und
antworten.
Der Controller soll eigentlich "nur" Ids auslesen können.
Jetzt wollte ich hier Fragen ob jemand hierfür vielleicht einen Beispiel
Code oder eine Lib oder sonstiges hätte.
Schonmal danke im Vorraus.
Mit freundlichen Grüßen
Julian
Vielen Dank. Diesen Beitrag habe ich auch schon komplett durchgepaukt.
Da fehlt mir aber leider ein Beispiel zum ID empfangen.
Nehmen wir an ich will den Inhalt von dem unsigned int mit der ID
0x773[2]als Beispiel in eine Variable speichern, sodass ich die auf
einem Display ausgeben kann.
Der Codeschnipsel welcher dann in der Main stehen würde, den bekomme ich
einfach nicht hin.
Vielleicht weiß ja noch jemand was.
Schonmal danke im Vorraus.
Vielen Dank!
Wenn ich dass richtig sehe, kann ich dann dort meine IDs anpassen. Und
wenn noch mehr hinzukommen, da in dem Beispiel ja nur zwei sind. Einfach
eine weitere Canpage hinzufügen und dann kann ich auf die IDs zugreifen.
Jedoch verstehe ich nicht wie sie bei CANMSG auf 0x55 und 0xaa kommen,
da ihre Empfangs ID ja 0x333 ist.
Entschuldigen Sie für die vielleicht unnötigen Fragen, aber bin sehr neu
in diesem Gebiet.
Schonmal Danke im Vorraus.
Julian M. schrieb:> Wenn ich dass richtig sehe, kann ich dann dort meine IDs anpassen. Und> wenn noch mehr hinzukommen, da in dem Beispiel ja nur zwei sind. Einfach> eine weitere Canpage hinzufügen und dann kann ich auf die IDs zugreifen.
Im CANPAGE Register steht drin, auf welche Message-Box sich die aktuelle
Aktion gerade bezieht.
Das wird im Interrupt gesichert damit man nicht die Hauptschleife
durcheinander wirft.
Also im Grunde meinst Du wahrscheinlich das richtige, so formuliert
hätte ich das aber nicht.
Wenn man das mit dem Filter so benutzt das pro Message eine ID verwendet
wird, dann muss man für eine weitere ID eine neue Message-Box
konfigurieren.
> Jedoch verstehe ich nicht wie sie bei CANMSG auf 0x55 und 0xaa kommen,> da ihre Empfangs ID ja 0x333 ist.
0x55 0xaa ist der Botschafts-Inhalt, nur so als Beispiel.
Die bis acht Byte der Botschaft liegen ja nicht in acht Registern, der
Zugriff erfolgt über das eine CANMSG Register.
Ach ja, die Botschaft wird in dem Beispiel nicht mal gelesen, es wird ja
nur dessen Empfang festgestellt und ein Flag gesetzt.
Übrigens, die CANEN Zeilen in der Init sind überflüssig - stören aber
auch nicht.
Vielen Dank, dass du dir dafür so Zeit nimmst.
Habe dann nun auch alles soweit verstanden.
In dem Beispiel Programm wird getestet ob er eine Nachricht erhält und
wenn diese Erhalten wurde. Schickt er eine Neue Massage los mit dem
Message Inhalt 0x55 und 0xaa.
Dann muss ich mich jetzt nur noch Informieren wie man die Message dann
ausließt und in eine Variable speichern kann, welche ich dann auf dem
Display ausgeben kann.
Ist alles komplizierter als Gedacht, da man im Internet zum reinen
Auslesen nicht sonderlich viel findet. Sondern eher zum Senden.
Julian M. schrieb:> Dann muss ich mich jetzt nur noch Informieren wie man die Message dann> ausließt und in eine Variable speichern kann, welche ich dann auf dem> Display ausgeben kann.
Die Daten sind wie geschrieben im CANMSG Register.
Man muss die also nur noch auslesen:
1
if(CANSIT2&0x02)// MOB1
2
{
3
CANPAGE=(1<<4);// select MOB1
4
CANSTMOB&=~(1<<RXOK);// clear interrupt flag
5
CANCDMOB=(1<<CONMOB1)|(1<<DLC3);
6
7
var1=CANMSG;
8
var2=CANMSG;
9
var3=CANMSG;
10
var4=CANMSG;
11
var5=CANMSG;
12
var6=CANMSG;
13
var7=CANMSG;
14
var8=CANMSG;
15
16
can_received=42;
17
}
Oder mit ner Schleife in ein Array schieben, oder was auch immer. :-)
Im CANPAGE Register steht dazu noch ein Index und es gibt ein Auto-Index
Bit, die werden durch den Zugriff auf CANPAGE auf Null gesetzt und
fertig.
Und als einfaches Beispiel fängt das Null Fehler ab, zum Beispiel könnte
eine Botschaft mit weniger Byte eingehen als erwartet werden.
Vielen Dank für Ihre schnellen Antworten.
Die 0x02 oben wird dann die dementsprechende ID sein.
also bei mir z.B. 0x773[2].
dann versuch ich das mal, vielen Dank nochmal.
Julian M. schrieb:> Die 0x02 oben wird dann die dementsprechende ID sein.
Nein, im CANSIT2 Register findet man, welche Message-Box den Interrupt
ausgelöst hat.
Das ist total faul geschrieben. :-)
1
if((CANSIT2&(1<<SIT1))!=0)// IRQ von Message-Box 1?
In dem Beispiel ist Message-Box 1 auf den Empfang der ID 0x333
konfiguriert.
Vielen Dank für Alles habe nun mal mein Bestes gegeben und den C-Code
angehängt. Vielleicht könnten sie ja, wenn sie Zeit haben mal drüber
schauen.
Habe das Beispiel angepasst. Wollte fragen ob dies so stimmt und ich
dann in der While Schleife auch immer den Aktuellen Wert habe. Habe auch
noch eine zweite Id zum empfangen eingestellt.
Schonmal danke im Vorraus.
Den Block unter der Konfiguration für die jeweiligen Message-Boxen
braucht man nur einmal und wenn man ein Register wie CANIE2 ein zweites
Mal beschreibt dann besser mit einer Read-Modify-Write Operation. :-)
1
ISR(CAN_INT_vect)
2
{
3
uint8_tcanpage;
4
5
canpage=CANPAGE;// save canpage
6
7
if((CANSIT2&(1<<SIT1))!=0)// MOB1
8
{
9
CANPAGE=(1<<4);// select MOB1
10
CANSTMOB&=~(1<<RXOK);// clear interrupt flag
11
CANCDMOB=(1<<CONMOB1)|(1<<DLC3);
12
13
inti;
14
unsignedintmesswerte[8];
15
16
for(i=0;i<8;i++){
17
18
messwerte[i]=CANMSG;
19
20
}
21
22
can_received=42;
23
}
24
25
if((CANSIT2&(1<<SIT2))!=0)// MOB2
26
{
27
CANPAGE=(2<<4);// select MOB1
28
CANSTMOB&=~(1<<RXOK);// clear interrupt flag
29
CANCDMOB=(1<<CONMOB1)|(1<<DLC3);
30
31
inti;
32
unsignedinttemperatur[8];
33
34
for(i=0;i<8;i++){
35
36
temperatur[i]=CANMSG;
37
38
}
39
40
can_received=42;
41
}
42
43
CANPAGE=canpage;// restore canpage
44
}
Ähem, erstmal sind die Variablen lokal für die Funktion, das verlässt
den Interrupt doch nie.
Und dann ist es "(1<<SIT2)" für MOB2.
Und die 1980er klingeln gerade durch und wollen Ihre Variablen vom Typ
"int" und "unsigned int" wieder haben. ;-)
1
DDRB=0x00;// alle Pins auf Eingang
2
PORTB=0xff;// Pullups an
3
4
DDRC=(1<<PC2)|(1<<PC7)|(1<<PC6);
5
PORTC=0xff;// Pullups an / Ausgang auf High
6
7
DDRD=0x00;// alle Pins auf Eingang
8
PORTD=0xff;// Pullup-Widerstände an
9
10
DDRE=0x00;// alle Pins auf Eingang
11
PORTE=0xff;// Pullups an
Da fehlt noch einiges, der 90CANxx hat noch ein paar Ports mehr
und TXCAN auf PD5.
Das ist einfach nur Copy-Paste von meinem Mega16M1 Beispiel.
1
while(1)
2
{
3
// Hier kann ich dann einfach den Wert der Id ausgeben lassen?
4
// also in dem ich einfach in den Displaybefehl als ausgabewert messwerte[3] eingebe?
5
// und auch zum Beispiel temperatur[4]?
6
}
7
}
Ja, sobald die auch verfügbar sind. :-)
Also am einfachsten Global deklariert mit volatile wie die
"can_received" Variable und mit Default-Wert.
Vielen Dank!
Ich hoffe, ich habe nun die Sachen richtig verbessert.
Ich habe die zwei Can Ports des at90Can auf 1 gesetzt und sonst noch die
Ports auf Ausgang die ich brauche.
Und durch die Globale Deklaration kann ich nun auf die Variablen in der
Main zugreifen?
Schonmal danke im Vorraus.
Mach aus der "6" mal noch eine 15, der 90CAN hat ein paar Message-Boxen
mehr. :-)
1
volatileuint16_tmesswerte[8]={0};
2
volatileuint16_ttemperatur[8]={0};
Warum eigentlich 16 Bit wenn die Werte doch nur 8 Bit breit sind?
1
DDRD=(1<<PD5)|(1<<PD6);
2
DDRA=0xFF;// Hier sind LEDs angeschlossen
3
DDRC=0xFF;// Hier sind LEDs angeschlossen
Also kann ja jeder machen wie er will, aber normalerweise initalisiere
ich erstmal alle Ports komplett durch und schalte bei den unbenutzen
Pins die Pullup-Widerstände ein.
Und ja, in dem Context würde ein "PORTA = 0x00" nichts bewirken weil das
Register nach dem Reset sowieso auf Null steht, ich finde es aber
übersichtlicher explizit hinzuschreiben was man vorhat.
Vielen Dank, dank ihnen verstehe ich nun einigermaßen was ich mache :)
Habe nun noch meine letzte ID hinzugefügt.
Ist eine Multiplex ID, hoffe ich habe sie richtig realisiert.
Nun habe ich jedoch noch eine Frage, wird der Interrupt dann immer von
selbst ausgelößt oder muss ich den in der Main() auch irgendwo auslösen?
Dass ich immer die Aktuelle Zahlen habe und nicht nur die, die er beim
ersten Durchgang rausließt.
Schonmal danke im Vorraus
Julian M. schrieb:> Ist eine Multiplex ID, hoffe ich habe sie richtig realisiert.
Sieht gut aus, ist nur nicht ganz optimal.
1
for(i=0;i<8;i++){// Ist ein Multiplex mit 3 Row
2
// Welche Row dran ist wird im Bit 0 übertragen
3
if(i==0){
4
row=CANMSG;
5
}else{
6
temperatur[i][row]=CANMSG;
7
}
8
}
Das "if(i==0)" wird bei jedem Durchlauf mit überprüft.
1
row=CANMSG;
2
3
for(i=0;i<7;i++){
4
temperatur[i][row]=CANMSG;
5
}
Als Optimierung etwas witzlos, zugegeben, man sollte Interrupts aber
auch immer so kurz wie möglich halten.
> Nun habe ich jedoch noch eine Frage, wird der Interrupt dann immer von> selbst ausgelößt
Ja, es gibt automatisch einen IRQ wenn eine Botschaft mit der passenden
ID empfangen wurde.
> Dass ich immer die Aktuelle Zahlen habe und nicht nur die, die er beim> ersten Durchgang rausließt.
Das Flag "can_received" ist in meinem Beispiel dafür da der
Hauptschleife zu melden, dass was empfangen wurde.
Das könnte man dafür nutzen um ein Display nur bei Änderungen zu
aktualisieren.
1
if(can_received!=0)
2
{
3
can_received=0;
4
mach_was_mit_den_daten();
5
}
Wobei das auch drei Flags sein könnten, für jede Botschaft einzeln.
can_received_temperatur
can_received_gang
can_received_messwerte
Oder so ähnlich. :-)
Oder ganz weglassen geht auch. :-)
Vielen Dank.
Habe nun meinen Code soweit fertig, es kommen auch keine Error
Meldungen.
Kann ihn leider warscheinlcih erst Dienstag testen.
Jedoch kommen zwei Warnings einmal:
Warning 1 #warning "F_CPU not defined for <util/delay.h>" [-Wcpp]
Obwohl ich
#define F_CPU 16000000ULL
#include <util/delay.h>
geschrieben habe.
Die zweite Warning verstehe ich leider gar nicht und weis auch nicht,
nach was ich im Internet suchen sollte.
Warning 2 'CAN_INT_vect' appears to be a misspelled signal handler
[enabled by default]
Schonmal danke im Vorraus. :)
Julian M. schrieb:> Warning 1 #warning "F_CPU not defined for <util/delay.h>" [-Wcpp]> Obwohl ich> #define F_CPU 16000000ULL> #include <util/delay.h>> geschrieben habe.
Hmm, das bekomme ich garnicht.
Ich habe gerade ein neues Projekt aufgemacht mit dem 90CAN128, Deinen
Text rein kopiert, das GLCD Zeug auskommentiert und durchlaufen lassen.
Auch ein zusätzliches "_delay_ms(12);" führt zu keiner Warnung.
> Die zweite Warning verstehe ich leider gar nicht und weis auch nicht,> nach was ich im Internet suchen sollte.>> Warning 2 'CAN_INT_vect' appears to be a misspelled signal handler> [enabled by default]
Das kommt davon, wenn man das "trocken" macht. :-)
Das muss "ISR (CANIT_vect)" sein.
Aber ich bekomme noch zwei Warnung für das hier:
Also habe es heute geflasht, leider hatte ich heute keine möglichkeit
die Can übertragung zu testen, werde ich morgen machen.
Jetzt aber eine Frage muss ich dass ISR wieder umbennen wenn ein CAN
angeschlossen ist?
Und ist es normal, dass wenn kein CAN angeschlossen ist, auf dem Display
an den Postionen der Prints eine Art Verpixeltes Zeichen erscheint? Da
die Zahlen ja eigentlich mit 0 deklariert sind.
Schonmal danke im Vorraus.
Hier ist der Schaltplan.
Also Chip AT90CAN128, dann sind LEDs die angesteuert werden und das
Display3000.
Die CAN Daten kommen von einer BOSCH MS4 Box.
Spontan fällt mir auf, dass da erheblich zu wenig Kondensatoren an den
Versorgungs-Anschlüssen der ICs sind.
Und wieder mal die "typischen" 22pF Kondensatoren am Quarz - welcher
Quarz ist das genau?
Sind die Fuse-Bits im Controller richtig gesetzt so das der auch
wirklich auf den 16 MHz läuft?
Edit: Was zum Henker soll da drauf ein 3A Schaltregler?
Es ist ein 16 MHz Quartz.
Die Fuse-Bits müssten richtig gesetzt sein. Sie haben mir ja damals ein
Testprogramm geschickt und dort war ja auch auf 16 Mhz eingestellt und
sie meinten ja dass im CAN bereicht, sich der Chip nicht unterscheidet
zum AT90CAN128.
Julian M. schrieb:> Es ist ein 16 MHz Quartz.
Ja, schon, aber welcher genau?
> Die Fuse-Bits müssten richtig gesetzt sein.
Müssten oder sind? :-)
> Sie haben mir ja damals ein Testprogramm geschickt und dort war> ja auch auf 16 Mhz eingestellt
Das Programm ändert aber nichts an den Einstellungen, das Programm geht
von dieser Konfiguration aus.
> und sie meinten ja dass im CAN bereicht,> sich der Chip nicht unterscheidet zum AT90CAN128.
Das ist richtig, bis auf die Anzahl der Message-Objekte unterscheiden
sich die CAN-Einheiten nicht.
Oh wo sehe ich welcher Quartz dies genau ist. Wie schon gesagt ist mein
erstes Projekt und habe die Platine so bekommen.
Achso wenn das Programm nichts an den Einstellungen ändert wird dies
wohl der Fehler sein. Habe dann gar keine Einstellungen.
Julian M. schrieb:> Oh wo sehe ich welcher Quartz dies genau ist. Wie schon gesagt ist mein> erstes Projekt und habe die Platine so bekommen.
Dann kann man nur hoffen, dass derjenige der das gebaut hat wusste, was
er tut, am Schaltplan lässt sich das aber leider erstmal nicht wirklich
fest machen.
Hast Du auch das Layout? Wie sieht der Quarz denn aus?
Bei 500 kBit wird es aber so oder so hoffentlich nicht daran liegen.
> Achso wenn das Programm nichts an den Einstellungen ändert wird dies> wohl der Fehler sein. Habe dann gar keine Einstellungen.
Kommt darauf an ob der Controller auf dem Board noch ganz frisch war
oder ob damit schon jemand rumgespielt hat.
Mach im Programmier-Fenster mal die "Fuse" Einstellungen auf und mach
Screenshots davon.
Julian M. schrieb:> Daran wirds dann wohl liegen oder?
Yup, genau daran liegt es, der Controller läuft dann nur aus dem
internen RC-Oszillator mit 1 MHz.
Leider kann ich im Emulator den 90CAN128 nicht auswählen, ich habe aber
auch keinen Programmer hier.
Auf jeden Fall muss die CKDIV8 Fuse aus sein.
Und mach mal nen Screenshot von den Einstellung für den Takt, aus dem
Kopf heraus müsste das eine der Optionen ganz unten sein, stelle aber
besser nichts ein wenn Du nicht sicher bist.
Edit, habe mal nen Bild angehängt.
Das kommt von http://www.engbedded.com/fusecalc/
Das Layout ist auch an mehreren Stellen falsch, viel Erfahrung hatte der
Benedict damit nicht.
Aber ich gehe mal davon aus, dass das mal irgendwie funktioniert hat
wenn das in einem Formula-Student Racer verbaut war.
Die 22pF sind übrigens wirklich falsch für den Quarz, in der Bauform
haben die typisch ein CL von 30pF und bräuchten so je 56pF.
Nur sollte der dennoch anlaufen und der CAN müsste bei 500kBit gerade
noch so laufen.
Der CAN-Transceiver ist jedenfalls richtig verdrahtet, dem fehlt nur ein
Kondensator an der Versorgung.
Die Fuses passen jetzt?
Ist der Jumper am CAN gesteckt, oder ein externe 120 Ohm am Bus oder in
der "BOSCH MS4 Box" 120 Ohm verbaut/aktiviert?
Vielen Dank, habe gerade erfahren, dass es noch nie funktioniert hat.
Ein Jumper ist nicht gesteckt. Ich glaube in der box sind die 120ohm
aktiviert, denn wenn man Daten direkt ausließt von der ms4 also mit
einem converter anschließt und dann empfängt man zum Beispiel mit
busmaster die Botschaften.
Die Fuses müssten nun passen.
Vielen Dank für alles, ich halte euch auf dem laufenden ob es
funktioniert.
Julian M. schrieb:> Vielen Dank, habe gerade erfahren, dass es noch nie funktioniert hat.
Na, die Vögel sind ja lustig, Dir so ein Board anzudrehen. :-)
Was passiert denn wenn Du an das lauffähige System aus Bosch-Box und
USB-CAN-Adapter mit Busmaster die Platine auch noch als dritten
Teilnehmer anschliesst?
Ach ja, noch einen, hast Du jetzt eigentlich die Port Konfiguration noch
ergänzt? In Deinem letzten Test-Programm stand da ja quasi noch nichts
drin.
Habs die Ports für den can auf high gesetzt. Dann die Ports für die LEDs
als Ausgang gesetzt und dann halt noch das Display initialisiert.
Wenn ich die Platine als dritten Teilnehmer anschließe ist es so, dass
die eigentlich gar nicht reagiert. Also es verändern sich keine Werte
auf dem display oder so.
Sind wirklich alle Ports durchkofiguriert?
Und was sagt dann Busmaster? Keine Error-Frames? Die Botschaften liegen
auch wirklich auf dem Bus?
Und Du kannst doch mit einer von den 16 LEDs im CAN-Interrupt wackeln.
Nein keine error frames, also die ms4 sendet aufjedenfall die
Botschaften richtig. Das Problem ist, dass er nicht in das ISR reingeht
irgendwie.
Ob die Ports alle richtig sind kann ich leider nicht sagen. Dafür kenne
ich mich zuwenig aus, ist mein erstes Projekt. Habe halt im Internet
nach geschaut, welche Ports der at90can128 für die can Übertragung
braucht und die habe ich auf high gesetzt. Wahrscheinlich habe ich mich
mit diesem Projekt einfach übernommen. Und die Ports für das display
usw. Sind richtig gesetzt. Den ich habe das Programm mal so
umgeschrieben dass anstatt die can Daten. Festgelegte Werte genommen
werden die sich verändern. Dann funktioniert auch alles wunderbar.
DDRB=(1<<PB1)|(1<<PB2)|(1<<PB4)|(1<<PB5)|(1<<PB6);// LCD-Ports auf Ausgang setzen
7
PORTB=(1<<PB0)|(1<<PB7);// Pullups an ungenutzen Pins einschalten
8
9
DDRC=0xFF;// Hier sind LEDs angeschlossen
10
PORTC=0x00;
11
12
DDRD=(1<<PD5);
13
PORTD=(1<<PD0)|(1<<PD1)|(1<<PD2)|(1<<PD3)|(1<<PD4)|(1<<PD7);// Pullups an ungenutzen Pins einschalten
14
15
DDRE=(1<<PE1);
16
PORTE=(1<<PE2)|(1<<PE3)|(1<<PE4)|(1<<PE5)|(1<<PE6)|(1<<PE7);// Pullups an ungenutzen Pins einschalten
17
18
DDRF=0x00;// alle Pins auf Eingang
19
PORTF=0xff;// Pullup-Widerstände an
20
21
DDRG=0x00;// alle Pins auf Eingang
22
PORTG=0xff;// Pullup-Widerstände an
23
}
Beim PORTB für das LCD bin ich mir nicht sicher, die müssten irgendwo
anders noch initialisiert werden, dazu fehlt aber jeglicher Aufruf in
Deinem Programm.
Eine LED kann man wackeln lassen mit dem PIN-Register:
PINC = (1<<PC0); // Zustand von LED1 wechseln
Das geht nicht mit allen AVR, aber beim 90CAN funktioniert das so.