Ich habe an einem CAN-Bus-Projekt gearbeitet. Es ist ein Projekt aus dem Buch Advanced Micro Controller Projects von Dogan. Es ist ein CAN-Bus-Projekt für Temperatursensoren. Wie Sie wissen, kann das Projekt nicht simuliert werden, da MCP2551 nicht in Proteus verfügbar ist, also habe ich es gemäß dem Schaltplan im Buch in Hardware implementiert.
Ich habe die Schaltung auf zwei Steckbrettern mit einem CAN-Bus aus Twisted Pairs implementiert. Ich habe PIC18F458 mit seinem eingebauten CAN-Modul verwendet. Die Länge des Busses beträgt weniger als 500 cm. Als ich es getestet habe, zeigte es nur die Willkommensnachricht auf dem LCD. Ich habe den Code für die Übertragung von Zeichen getestet. Es hat funktioniert, aber für die Temperatur werden keine Daten angezeigt.
Hier ist der Code des Kollektorknotens.
//unsigned char Can_Init_Flags, Can_Send_Flags,dt,len, Can_Rcv_Flags;
unsigned short init_flag, send_flag,len, read_flag;volatile int dt;
char SJW, BRP, Phase_Seg1, Phase_Seg2, Prop_Seg, txt[4];
long id, mask;
int bitvalue;
float vout, temperature; int flag;
#define d portb.b0
void adc_setting()
{
adcon0 = 0x00;
adcon1 = 0x80;
intcon = 0xc0;
pie1.adie = 1;
pir1.adif = 0;
}
void interrupt()
{
if (pir1.adif)
{
pir1.adif = 0;
adcon0.adon = 0;
flag = 1;
adcon0.adon = 1;
adcon0.go_done = 1;
}
}
void main()
{
//Portc=0x08;
TRISA = 0xFF; // PORTA are inputs
//TRISB = 0x08; // RB2 is output, RB3 is input
//
// Configure A/D converter
//
//ADC_Init();
adc_setting();
adcon0.adon = 1;
adcon0.go_done = 1;
//ADCON1 = 0x80;
//
// CAN BUS Timing Parameters
//
SJW = 1;
BRP = 1;
Phase_Seg1 = 6;
Phase_Seg2 = 7;
BRP = 1;
Prop_Seg = 6;
init_flag= _CAN_CONFIG_SAMPLE_THRICE &
_CAN_CONFIG_PHSEG2_PRG_ON &
_CAN_CONFIG_STD_MSG &
_CAN_CONFIG_DBL_BUFFER_ON &
_CAN_CONFIG_VALID_XTD_MSG &
_CAN_CONFIG_LINE_FILTER_OFF;
send_flag = _CAN_TX_PRIORITY_0 &
_CAN_TX_XTD_FRAME &
_CAN_TX_NO_RTR_FRAME;
read_flag=0;
//
// Initialise CAN module
//
CANInitialize(SJW, BRP, Phase_Seg1, Phase_Seg2, Prop_Seg,init_flag );
//
// Set CAN CONFIG mode
//
CANSetOperationMode(_CAN_MODE_CONFIG,0xFF);
mask = -1;
//
// Set all MASK1 bits to 1's
//
CANSetMask(_CAN_MASK_B1, mask, _CAN_CONFIG_XTD_MSG);
//
// Set all MASK2 bits to 1's
//
CANSetMask(_CAN_MASK_B2, mask, _CAN_CONFIG_XTD_MSG);
//
// Set id of filter B1_F1 to 500
//
CANSetFilter(_CAN_FILTER_B1_F1,500,_CAN_CONFIG_XTD_MSG);
//
// Set CAN module to NORMAL mode
//
CANSetOperationMode(_CAN_MODE_NORMAL, 0xFF);
// Program loop. Read the temperature from analog temperature sensor
while(1) // Endless loop
{
//
// Wait until a request is received
//
dt = 0;
while (!dt) dt = CANRead (&id, i, &len, read_flag);
if (id == 500 && i[0]=='T')
{
if (flag==1)
{
bitvalue = (adresh<<8)+adresl;
vout = bitvalue * 0.00488;
temperature = vout / 0.0100;
i[0] = temperature;
id = 3; // Identifier
CANWrite (id, i, 1, send_flag); // send temperature
}
}
}
}
Und hier ist der Code des Anzeigeknotens
float temperature; unsigned char i[8];
unsigned short init_flag, send_flag, dt, len, read_flag;
char SJW, BRP, Phase_Seg1, Phase_Seg2, Prop_Seg, txt[4];
long id, mask;
sbit LCD_RS at RC4_bit;
sbit LCD_EN at RC5_bit;
sbit LCD_D4 at RC0_bit;
sbit LCD_D5 at RC1_bit;
sbit LCD_D6 at RC2_bit;
sbit LCD_D7 at RC3_bit;
sbit LCD_RS_Direction at TRISC4_bit;
sbit LCD_EN_Direction at TRISC5_bit;
sbit LCD_D4_Direction at TRISC0_bit;
sbit LCD_D5_Direction at TRISC1_bit;
sbit LCD_D6_Direction at TRISC2_bit;
sbit LCD_D7_Direction at TRISC3_bit;
// End LCD module connections
void main()
{
TRISC = 0; // PORTC are outputs (LCD)
//TRISB = 0x08; // RB2 is output, RB3 is input
//
// CAN BUS Parameters
SJW = 1;
BRP = 1;
Phase_Seg1 = 6;
Phase_Seg2 = 7;
Prop_Seg = 6;
Init_Flags = _CAN_CONFIG_SAMPLE_THRICE &
_CAN_CONFIG_PHSEG2_PRG_ON &
_CAN_CONFIG_STD_MSG &
_CAN_CONFIG_DBL_BUFFER_ON &
_CAN_CONFIG_VALID_XTD_MSG &
_CAN_CONFIG_LINE_FILTER_OFF;
Send_Flags = _CAN_TX_PRIORITY_0 &
_CAN_TX_XTD_FRAME &
_CAN_TX_NO_RTR_FRAME;
Can_Rcv_Flags = 0;
//
//
// Initialize CAN module
//
//
CANInitialize(SJW, BRP, Phase_Seg1, Phase_Seg2, Prop_Seg, init_flag);
// Set CAN CONFIG mode
//
CANSetOperationMode(_CAN_MODE_CONFIG, 0xFF);
mask = -1;
// Set all MASK1 bits to 1's
CANSetMask(_CAN_MASK_B1, mask, _CAN_CONFIG_XTD_MSG);
// Set all MASK2 bits to 1's
//
CANSetMask(_CAN_MASK_B2, mask, _CAN_CONFIG_XTD_MSG);
//
// Set id of filter B2_F3 to 3
//
CANSetFilter(_CAN_FILTER_B2_F3, 3, _CAN_CONFIG_XTD_MSG);
//
// Set CAN module to NORMAL mode
//
CANSetOperationMode(_CAN_MODE_NORMAL, 0xFF);
// Configure LCD
Lcd_init(); // LCD is connected to PORTC
Lcd_Out(1,1,"CAN BUS"); // Display heading on LCD
Delay_ms(1000); // Wait for 2 seconds
//
// Program loop. Read the temperature from Node:COLLECTOR and display
// on the LCD continuously
//
while(1) // Endless loop
{
Lcd_Out(1,1,"Temp = "); // Display "Temp = "
//
// Send a message to Node:COLLECTOR and ask for data
//
i[0] = 'T'; // Data to be sent
id = 500; // Identifier
CANWrite(id, i, 1, send_flag); // Send 'T'
//
// Get temperature from node:COLLECT
//
dt = 0;
while(!dt)
dt = CANRead(&id, i, &len, &read_flag);
if(id == 3)
{
temperature = i[0];
ByteToStr(temperature,txt); // Convert to string
Lcd_Out(1, 8, txt); // Output to LCD
Delay_ms(1000); // Wait 1 second
}
}
}
Die Temperatur wird überhaupt nicht angezeigt. Ich habe versucht, den Code ein paar Mal zu ändern, aber das Problem bleibt das gleiche. Ich habe den TX-Pin des Kollektorknotens auf einem digitalen Oszilloskop überprüft. Es zeigte nichts. Es überträgt keine Daten. Warum werden keine Daten übertragen?
Gibt es ein Problem mit meinem Code? Soll ich die Anforderungsbedingung im Übertragungsknoten entfernen und nur Daten in den zweiten Knoten schreiben und den Filter deaktivieren?
Ich habe die Schaltung auf zwei Steckbrettern mit einem CAN-Bus aus Twisted Pairs implementiert.
Sie müssen noch die Masse beider Mikrocontroller miteinander verbinden. CAN toleriert einige Gleichtaktvariationen der Busleitungen, aber sie können nicht willkürlich erdfrei sein. Anders ausgedrückt, Sie müssen die beiden Knoten mit drei Drähten verbinden, dem verdrillten Paar für die CANH- und CANL-Leitungen und einem Erdungsdraht.
Dieser Code ergibt keinen Sinn:
dt = 0;
while(!dt);
dt = CANRead(&id, b, &len, &Can_Rcv_Flags);
if(id == 3)
{
temperature = b[0];
ByteToStr(temperature,txt); // Convert to string
Lcd_Out(1, 8, txt); // Output to LCD
Delay_ms(1000); // Wait 1 second
}
}
Ich glaube, Sie werden von Ihrer eigenen Einrückung getäuscht. Die letzte geschweifte Klammer oben gehört zu for(;;)
- da die while-Schleife keine geschweiften Klammern hat, hat sie nur eine leere ;
Nullanweisung und keinen Schleifenkörper.
Die Linien dt = 0; while(!dt);
sind also nutzlos, weil dt an dieser Stelle immer Null ist.
Du wolltest wahrscheinlich schreiben
while(!dt)
{
dt = CANRead(&id, b, &len, &Can_Rcv_Flags);
}
Aus diesem Grund sollten Sie immer geschweifte Klammern nach jeder Steuer- oder Schleifenanweisung in Ihrem Code verwenden und niemals Semikolons in derselben Zeile wie eins platzieren. Gute Compiler warnen vor solchen Semikolons.
Andernfalls, wenn dies trotz der seltsamen Einrückung beabsichtigt war und es sich um dt
eine Variable handelt, die mit einer ISR geteilt wird, ist Ihr Code immer noch falsch, da dt
er nicht als deklariert wurde volatile
und der Compiler ihn möglicherweise falsch optimiert. Sieh dir das an:
dt = CANRead(...
. Nur die Schleife ist falsch.Ich vermute, dass eine dieser Nachrichten nicht richtig empfangen wird. Die Nachrichtenfilterung ist hier wichtig: Sie haben den Empfangsfilter so konfiguriert, dass beide Nachrichten, die Sie senden, erweiterte Typen sind (29-Bit-ID). Können Sie überprüfen, ob Sie die Nachrichten als erweiterte Frames senden und die CAN-Module mit aktivierten erweiterten Frames initialisiert werden? Ihr Code ist diesbezüglich nicht ganz selbsterklärend.
Standard- und erweiterte Nachrichten im CAN-Bus sind völlig unterschiedlich. Wenn Sie eine Standardnachricht mit der ID 5 senden und den Empfangsfilter so konfiguriert haben, dass erweiterte Nachrichten mit der ID 5 empfangen werden, erhalten Sie nichts.
ManyYack
enter code here unsigned char temperature,i[8];
David Tweed
interrupt()
, aber es gibt keinen Hinweis darauf, dass sie mit einem tatsächlichen Hardware-Interrupt verbunden ist. Wenn diese Funktion nie ausgeführt wird,flag
wird sie nie gesetzt und es wird nichts übertragen.