Я работаю над проектом шины CAN. Это проект из книги « Продвинутые проекты микроконтроллеров» Догана. Это проект шины CAN датчика температуры. Как вы знаете, проект не может быть смоделирован, потому что MCP2551 недоступен в Proteus, поэтому я реализовал его «железно» в соответствии со схемой в книге.
Я реализовал схему на двух макетных платах с использованием CAN-шины из витых пар. Я использовал PIC18F458 со встроенным модулем CAN. Длина автобуса менее 500 см. Когда я тестировал его, на ЖК-дисплее отображалось только приветственное сообщение. Я тестировал код для передачи символов. Он работал, но для температуры он не показывает данные.
Вот код узла коллектора.
//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
}
}
}
}
А вот код узла отображения
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
}
}
}
Температура вообще не отображается. Я пытался изменить код несколько раз, но проблема остается прежней. Я проверил вывод tx коллекторного узла на цифровом осциллографе. Это ничего не показало. Он не передает никаких данных. Почему он не передает данные?
Есть ли проблема с моим кодом? Должен ли я удалить условие запроса в узле передачи и просто записать данные во второй узел и отключить фильтр?
Я реализовал схему на двух макетных платах с использованием CAN-шины из витых пар.
Вам все еще нужно связать земли обоих микроконтроллеров вместе. CAN терпим к некоторым синфазным изменениям шинных линий, но они не могут быть произвольно плавающими. Другими словами, вам нужно соединить два узла тремя проводами, витой парой для линий CANH и CANL и проводом заземления.
Этот код не имеет никакого смысла:
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
}
}
Я полагаю, что вас обманули ваши собственные намерения. Последняя скобка выше относится к for(;;)
- потому что цикл while не имеет никаких фигурных скобок, он имеет только пустую ;
нулевую инструкцию и не имеет тела цикла.
Таким образом, линии dt = 0; while(!dt);
бесполезны, потому что в этой точке dt всегда равно нулю.
Вы наверное хотели написать
while(!dt)
{
dt = CANRead(&id, b, &len, &Can_Rcv_Flags);
}
Вот почему вы всегда должны использовать фигурные скобки после каждого оператора управления или цикла в своем коде и никогда не ставить точку с запятой в одной строке. Хорошие компиляторы предостерегают от таких точек с запятой.
В противном случае, если это было преднамеренно, несмотря на странный отступ, и dt
это переменная, совместно используемая с ISR, ваш код все еще неверен, потому что он dt
не был объявлен как as volatile
, и компилятор может неправильно его оптимизировать. Видеть это:
dt = CANRead(...
. Просто петля неправильная.Я предполагаю, что одно из этих сообщений получено неправильно. Здесь важна фильтрация сообщений: вы настроили фильтр получения так, чтобы оба сообщения, которые вы отправляете, были расширенного типа (29-битный идентификатор). Можете ли вы убедиться, что вы отправляете сообщения в виде расширенных кадров, а модули CAN инициализированы с включенными расширенными кадрами? Ваш код не совсем говорит об этом.
Стандартные и расширенные сообщения в CAN-шине совершенно разные. Если вы отправляете стандартное сообщение с идентификатором 5 и настроили фильтр получения на получение расширенных сообщений с идентификатором 5, вы ничего не получите.
МАНЬЯКК
enter code here unsigned char temperature,i[8];
Дэйв Твид
interrupt()
, но нет никаких указаний на то, что она связана с каким-либо реальным аппаратным прерыванием. Если эта функция никогда не выполняется, тоflag
она никогда не устанавливается и ничего не передается.