Forum: Mikrocontroller und Digitale Elektronik Problem: AT90CAN zu AT90CAN digitales CAN Signal


von Max M. (centech)


Lesenswert?

Hallo,

ich versuche seit Wochen eine CAN Kommunikation zwischen 2 AT90CAN MC 
herzustellen. Dazu habe ich schon diverse Codebeispiele (auch hier aus 
diesem Forum) ausprobiert und Datenblätter gewälzt. Mein Problem bisher:

Scheinbar sendet ein MC ein Signal, bekommt aber kein ACK, bzw erkennt 
der Empfänger das CAN Package nicht.

Ich bin gerade am überlegen ob es ein Hardware (Denk-) Fehler sein kann, 
ich habe einfach die CAN TX Leitung des einen AT90 mit der CAN RX 
Leitung verbunden und umgekehrt (GND natürlich auch). Ist mir hier schon 
ein Fehler unterlaufen? Ich bin davon ausgegangen, dass man das Digitale 
Signal nicht terminieren muss.

Anbei auch mein Code, ich würde mich über Hilfe sehr freuen! Vielen 
Dank.


main.c
1
/*
2
 * Main Modul
3
 * Author: Max
4
 */ 
5
6
//#define F_CPU 1600000UL
7
#include <avr/io.h>
8
#include <avr/delay.h>
9
10
#include "uart.h"
11
#include "can.h"
12
#include <avr/interrupt.h>
13
#include <avr/pgmspace.h>
14
15
//#define Sender
16
//#define FakeCan 
17
18
19
20
int main(void)
21
{
22
  
23
  cli();
24
  // initialisieren des at90can
25
  #ifndef FakeCan
26
    can_init();
27
    struct MOb mymsg;     
28
    mymsg.id=1;
29
    mymsg.data[0]="H";
30
    mymsg.data[1]="a";
31
    mymsg.data[2]="l";
32
    mymsg.data[3]="l";
33
    mymsg.data[4]="o";
34
    mymsg.data[5]="!";
35
    mymsg.data[6]="!";
36
    mymsg.data[7]="!";
37
  #else
38
  //FakeCan
39
  DDRD |= 1 << PD5; // Can Output
40
  PORTD |= ( 1 << PD5 );
41
  #endif
42
  // enable interrupts
43
  sei();
44
    
45
  
46
  DDRE |= 1 << PE5; // LED Output
47
  PORTE |= 1 << PE5; // LED start an
48
  
49
  DDRE |= 1 << PE6; // LED Output
50
  
51
  uart_init();
52
  uart_print("======================\n");
53
  uart_print("Programm Start\n");
54
  #ifdef Sender
55
  uart_print("Ich bin Sender\n");
56
  PORTE &=~ 1 << PE6; // LED start aus
57
  _delay_ms(2000*16);
58
  #else // empfänger
59
  uart_print("Ich bin Empfaenger\n");
60
  PORTE |= 1 << PE6; // LED start an
61
  PORTE &=~ 1 << PE5; // LED start aus
62
  _delay_ms(1000*16);
63
  #endif
64
  #ifdef FakeCan
65
  uart_print("!!!!! FAKE CAN ACTIVATED!!!!!\n");
66
  #endif
67
  uart_print("======================\n\n");
68
69
70
  uart_print("Schleifeneingang\n");
71
    while(1)
72
    {
73
  #ifdef FakeCan
74
  _delay_us(10*16);
75
  PORTD ^= ( 1 << PD5 ); // toggle CAN Signal  
76
  #else  
77
    #ifdef Sender
78
    _delay_ms(1000*16);
79
    PORTE ^= ( 1 << PE5 );
80
    can_tx(mymsg);
81
    uart_print("Sende!!\n");
82
    #else // empfänger
83
    // Check if a new message was received (via can interrupt)
84
    #endif
85
  #endif // fakecan ende  
86
    
87
     
88
    }
89
}

can.h
1
#ifndef CAN_H
2
#define CAN_H
3
4
#include <avr/io.h>
5
#include <avr/signal.h>
6
#include <avr/interrupt.h>
7
#include <stdio.h>
8
#include <string.h>
9
10
struct MOb
11
{
12
  unsigned long id;
13
  unsigned char data [8];
14
};
15
16
void can_init (void);
17
void can_tx (struct MOb msg);
18
19
#endif

can.c
1
#include "can.h"
2
3
4
/*******************************************************************
5
CAN initialization:
6
Mailbox 0: Receive  --> interrupt
7
Mailbox 1: Transmit --> polling
8
*******************************************************************/
9
void can_init (void)
10
{
11
  CANGCON |= (1<<SWRES);            //reset CAN interface
12
  
13
  //reset all MObs
14
  for (unsigned char i=0; i<15; i++)
15
  {
16
    CANPAGE = (i<<4);            //select MOb
17
    CANCDMOB = 0;              //disable MOb
18
    CANSTMOB = 0;              //clear status
19
    CANIDT1 = 0;              //clear ID
20
    CANIDT2 = 0;
21
    CANIDT3 = 0;
22
    CANIDT4 = 0;
23
    CANIDM1 = 0;              //clear mask
24
    CANIDM2 = 0;
25
    CANIDM3 = 0;
26
    CANIDM4 = 0;
27
    for (unsigned char j=0; j<8; j++)
28
      CANMSG = 0;              //clear data
29
  }
30
31
  //bit timing -> datasheet page 260 (check table)
32
  CANBT1 = 0xC6; //500kBits/s  // 0x12;    //  100 kBit/s  0xC6;    //  10 kBit/s
33
  CANBT2 = 0x0C;//0x04;
34
  CANBT3 = 0x37;//0x13;
35
  
36
37
  
38
  CANGCON = (1<<ENASTB);            //start CAN interface
39
  
40
  //configure MOb0
41
  CANPAGE = (0<<4);
42
  CANIDT1 = 0;                //ID
43
  CANIDT2 = 0;
44
  CANIDT3 = 0;
45
  CANIDT4 = 0;
46
  CANIDM1 = 0;                //get all messages
47
  CANIDM2 = 0;                //1 = check bit
48
  CANIDM3 = 0;                //0 = ignore bit
49
  CANIDM4 = (1<<IDEMSK);
50
  CANCDMOB = (1<<CONMOB1) | (1<<IDE);    //reception, ext. ID
51
  
52
  //interrupts
53
  CANGIE = (1<<ENIT) | (1<<ENRX) | (1<<ENERR) | (1<<ENERG); //enable receive interrupt  //(1<<ENERR) | (1<<ENERG);    //enable error interrupt
54
  CANIE1 = 0;
55
  CANIE2 = (1<<IEMOB0); //Set MOB for which Interrupts are enabled
56
  CANSIT1 = 0;
57
  CANSIT2 = 0;
58
  
59
  while (!(CANGSTA & (1<<ENFG)));      //wait until module ready
60
}
61
62
/*******************************************************************
63
CAN transmission via mailbox 1 (polling)
64
*******************************************************************/
65
void can_tx (struct MOb msg)
66
{  
67
  //enable MOb1, auto increment index, start with index = 0
68
  CANPAGE = (1<<4);
69
  
70
  CANCDMOB = (1<<IDE) | (8<<DLC0);      //set IDE bit, length = 8
71
  
72
  msg.id <<= 3;                //write 29 Bit identifier
73
  CANIDT4 = (unsigned char) (msg.id&0xF8);
74
  CANIDT3 = (unsigned char) (msg.id>>8);
75
  CANIDT2 = (unsigned char) (msg.id>>16);
76
  CANIDT1 = (unsigned char) (msg.id>>24);
77
  
78
  for (unsigned char i=0; i<8; i++)    //put data in mailbox
79
    CANMSG = msg.data [i];
80
  
81
  CANCDMOB |= (1<<CONMOB0);          //enable transmission
82
  uart_print("wait for TXOK...!\n");
83
  while (!(CANSTMOB & (1<<TXOK)));      //wait until complete
84
  uart_print("...got it!\n");
85
  CANSTMOB &= ~(1<<TXOK);          //reset flag
86
}
87
88
/*******************************************************************
89
CAN receive interrupt service routine (mailbox 0)
90
*******************************************************************/
91
SIGNAL (SIG_CAN_INTERRUPT1)            //receive interrupt
92
{
93
  
94
  PORTE |= 1 << PE6; // LED start an
95
  PORTE |= 1 << PE5; // LED start an
96
  uart_print("\n\nCAN INTERRUPT!\n");
97
  unsigned char temp = CANPAGE;        //save CANPAGE
98
  struct MOb msg;
99
  
100
  CANPAGE = 0x00;                //select MOb0
101
  CANSTMOB &= ~(1<<RXOK);          //clear interrupt flag
102
  
103
  for (unsigned char i=0; i<8; i++)    //get data
104
    msg.data [i] = CANMSG;
105
  
106
  msg.id = 0;
107
  msg.id |= ((unsigned long) CANIDT1<<24);  //get identifier
108
  msg.id |= ((unsigned long) CANIDT2<<16);
109
  msg.id |= ((unsigned long) CANIDT3<<8);
110
  msg.id |= (CANIDT4&0xF8);
111
  msg.id >>= 3;
112
  
113
  uart_print("id: "+msg.id);
114
  uart_print("\n");
115
  uart_print("data: "+msg.data[0]+msg.data[1]+msg.data[2]+msg.data[3]+msg.data[4]+msg.data[5]+msg.data[6]+msg.data[7]);
116
  uart_print("\n");
117
//   printf ("ID: 0x%04X%04X\r\n", (unsigned int) (msg.id>>16), (unsigned int) (msg.id&0xFFFF));
118
//   
119
//   printf ("Data: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\r\n",
120
//       msg.data [0], msg.data [1], msg.data [2], msg.data [3],
121
//       msg.data [4], msg.data [5], msg.data [6], msg.data [7]);
122
  
123
  CANCDMOB = (1<<CONMOB1) | (1<<IDE);    //reconfig mailbox
124
  
125
  CANPAGE = temp;                //restore CANPAGE
126
}

von EMV (Gast)


Lesenswert?

Normalerweise braucht man dafür einen Transiver oder zumindest 
Pullup/Pulldown-Widerstände..
Ich bin nicht ganz sicher, aber einfach RX/TX verbringen funktioniert 
vermutlich nicht sauber. Stichwort "dominant" und "recessive" bits.

Ein Fehlendes ACK könnte auch ein Baudrate-Mismatch sein.

von Rudolph (Gast)


Lesenswert?

Die CAN-Transceiver bilden eine Schleife, das Signal das rausgeht kommt 
immer auch wieder rein.
Die beiden Controler direkt zu verbinden funktioniert doch nicht?

von Test (Gast)


Lesenswert?

Du brauchst die can transceiver, da can mit csma/ca arbeitet und jeder 
Controller sein eigenes Signal für die aribitrierung überwachen muss. Dh 
2 transceiver und ein oder 2 abschlusswiderstände

von ich (Gast)


Lesenswert?

Du mußt an die TX/RX-Pins des Controllers noch jeweils einen 
CAN-Transceiver anschließen. Schau dir mal den PCA82C251 an, der ist bei 
mir seit Jahren im Einsatz und hat sich bewährt. Gibt aber auch noch 
viele andere. Der Transceiver bringt dann deine eigentliche 
CAN-Schnittstelle mit CAN-High und CAN-Low. Direkt mit dem µC wird das 
nix.

von Max M. (centech)


Lesenswert?

Danke für eure schnelle Hilfe.

Das war mir so nicht bewusst, dachte die Transceiver machen einfach nur 
das digitale Signal zu einem differenziellen und umgekehrt.

Gut dann werde ich mir noch die Transceiver besorgen.


Danke!

von gggast (Gast)


Lesenswert?

Max M. schrieb:
> Danke für eure schnelle Hilfe.
>
> Das war mir so nicht bewusst, dachte die Transceiver machen einfach nur
> das digitale Signal zu einem differenziellen und umgekehrt.
>
> Gut dann werde ich mir noch die Transceiver besorgen.
>
> Danke!

machen sie auch... dadurch, dass die rückleitung zu deinem µC bei 
angeschossenem tranceiver immer mithochrechen kann was auf dem bus 
gerade abgeht funktioniert das csma cr verfahren. wenn du die signale 
einfach nur kreuzt sieht dein µC nur sein gegenüber und erkenn 
einenfehler, da es passieren kann, dass bei dominanten pegel 
einrezessiverauf rx gesehen wird... etc.
THEORETISCH,wenn du dafür sorgst, dass die beiden auf keien fall 
gleichzeitig senden, könnte es gehen wenn du zusätzlichzu deinen 
verbindungenen noch rx und tx von deinen controllern brückst. it zwar 
überhaupt nict sinn der sache, würde mich aber mal interessieren, ob das 
wirklch geht...

von CAN (Gast)


Angehängte Dateien:

Lesenswert?

Das könnte gehen wenn die TX Ausgänge OpenDrain wären. Ansonsten musst 
du einen Widerstand und 2 Dioden opfern.

von Max M. (centech)


Lesenswert?

Ja jetzt im Nachhinein habe ich sogar ne AP von Siemens dazu gefunden,
dort ist auch erklärt wie man das ganze ohne Transeiver machen kann.

http://www.mikrocontroller.net/attachment/28831/siemens_AP2921.pdf

ist mir aber zu "bastelig" werd mir den MAX3051 Transeiver 
besorgen.(http://www.farnell.com/datasheets/663306.pdf)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.