CAN не передает данные о температуре

Я работаю над проектом шины 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 коллекторного узла на цифровом осциллографе. Это ничего не показало. Он не передает никаких данных. Почему он не передает данные?

Есть ли проблема с моим кодом? Должен ли я удалить условие запроса в узле передачи и просто записать данные во второй узел и отключить фильтр?

Если вам нужна помощь, хорошим способом начать было бы опубликовать код так, как вы его написали.enter code here unsigned char temperature,i[8];
У вас есть функция с именем interrupt(), но нет никаких указаний на то, что она связана с каким-либо реальным аппаратным прерыванием. Если эта функция никогда не выполняется, то flagона никогда не устанавливается и ничего не передается.

Ответы (3)

Я реализовал схему на двух макетных платах с использованием CAN-шины из витых пар.

Вам все еще нужно связать земли обоих микроконтроллеров вместе. CAN терпим к некоторым синфазным изменениям шинных линий, но они не могут быть произвольно плавающими. Другими словами, вам нужно соединить два узла тремя проводами, витой парой для линий CANH и CANL и проводом заземления.

Сэр, моя схема в порядке. Я имею в виду, что я подключил узел витыми парами. И оба узла заземлены в соответствии со схемой. ЖК-дисплей показывает приветственное сообщение, но не показывает температуру. Я думаю, что проблема с кодом. Вывод tx первого узла не показывает напряжения на цифровом осциллографе.
@Ammar Если вы не используете выделенную сигнальную землю, то в качестве опорной будет использоваться земля питания. Если между системами большая разница потенциалов, очевидно, что это не сработает. Но даже если его нет, вы уловите все виды электромагнитных помех от земли питания.
Сэр, я тестировал этот же код для передачи символов. Он работал, но не показывает температуру. Я не знаю, зачем здесь нужна выделенная земля? Схема построена на двух макетных платах, соединенных вместе. И длина шины меньше 300 см. Не думаю, что будет эми на такое расстояние
Работает ли встроенная функция ADC в этом проекте?

Этот код не имеет никакого смысла:

    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, и компилятор может неправильно его оптимизировать. Видеть это:

http://www.embedded.com/electronics-blogs/cole-bin/4418638/When-to-use---and-not-use---the-volatile-keyword

Да, я тоже думал, что DT не используется в коде. Какова его цель? Вы правы насчет цикла while. Я уже вносил в него изменения. Вы говорили о ключевом слове volatile. Мой компилятор mikroc не дал любая ошибка. Разве я не должен просто удалить ее?
@Ammar Примечание о volatile применяется только в том случае, если переменная используется ISR. Если опубликованный код является полным кодом, то это здесь не применяется. Но, тем не менее, вам нужно знать, как работает volatile при написании встроенного программного обеспечения любой формы.
Сэр, я не знаю, используется ли он в ISR. Но DT не используется. Так почему бы не заменить его другой переменной?
@Ammar Здесь явно используется: dt = CANRead(.... Просто петля неправильная.
Сэр, температура не отображается с использованием этого кода. Как вы думаете, в чем проблема? Могут ли данные о температуре отправляться в формате float или char?

Я предполагаю, что одно из этих сообщений получено неправильно. Здесь важна фильтрация сообщений: вы настроили фильтр получения так, чтобы оба сообщения, которые вы отправляете, были расширенного типа (29-битный идентификатор). Можете ли вы убедиться, что вы отправляете сообщения в виде расширенных кадров, а модули CAN инициализированы с включенными расширенными кадрами? Ваш код не совсем говорит об этом.

Стандартные и расширенные сообщения в CAN-шине совершенно разные. Если вы отправляете стандартное сообщение с идентификатором 5 и настроили фильтр получения на получение расширенных сообщений с идентификатором 5, вы ничего не получите.

Я ошибаюсь или вы инициализируете модуль CAN дисплея с неинициализированным init_flag и отправляете сообщения с неинициализированными аргументами send_flag ? Вы объявляете переменные Can_Init_Flags и Can_Send_Flags , которые не определены. Здесь может быть проблема.
Сэр, я передал символьную переменную, например, «B» с тем же кодом. Это сработало, но данные о температуре не отображаются на ЖК-дисплее.
Это означает, что фильтры настроены правильно.
Как узнать, включены ли фильтры в стандартных и расширенных фреймах?
это init_flags, а не CAN_init_flags. Это ошибка. Ошибка в узле отображения. Но проблема остается.
Итак, вы успешно передали и получили хотя бы одно сообщение? В этом случае проблема может заключаться в настройках скорости передачи данных. Шина CAN имеет немного хитрый механизм обработки ошибок, который отключает узел, обнаруживший слишком много ошибок в шине. вот статья об обработке ошибок CAN. Дело в том, что если Phase_Seg1 и Phase_Seg2 установлены так, что у узлов возникают трудности с приемом или передачей сообщений, их счетчики ошибок увеличиваются и в итоге они переходят в режим отключения шины.
Шину можно проверить осциллографом. Если кажется, что на пускай какой-то. Сообщения отправляются, но затем узлы просто перестают отправлять, проблема может заключаться в обработке ошибок.
Так что же нужно сделать, чтобы ошибки не остановили автобус?
Во-первых, вы должны гарантировать, если это действительно проблема. Стеки протоколов CAN обычно реализуют функции для получения счетчиков состояния или ошибок.