Приборная панель с цифровой Led индикацией и сбором данных по CAN шине автомобиля

wixa
Offline
Зарегистрирован: 05.02.2012

Вообщем, даже не знаю с чего начать.

Немного о себе.

Arduino mega 2560 обладаю около недели. До этого практики програмирования и схемотехники не имел. Работаю инженером-строителем.

Предистория.

Автомобильная практика, и практика по Led подсветке началась, с приобретения Таврии 1100. Была сделана и установлена самостоятельно подсветка подрулевого пространства из dip led на макетных платах. Половина  Led не горела, как говорится первый блин комом, но и той половины которая работала, было вполне достаточно для поставленых перед ней целей. Таврия была успешно продана с подсветкой.

Второй опыт был уже на Mitsubishi Colt IV 1994 г.в., который был приобретен после Таврии. На данное авто былы изготовленна и установленна самостоятельно RGB подсветка (на лентах) подножного пространства, бардачка, багажника, и подножного уличного пространства при открывании двери. Преключение цветов осуществлялось с помощью регулятора на 6 положений (используются в старых уселителях). Подсветка имела 2 режима:

Режим 1: Срабатывание подсветки при только открывании дверей.

Режим 2: Постоянное горение. 

Авто с подсветкой, было передано Брату.

И вот пока я коплю денежку на очередное авто (Nissan Note), я решил подготовится, и перейти на новый уровень подсветки.

Планируется:

1. Подсветка внутренего пространства автомобиля, RGB с всевозможной регулеровкой цвета и яркости свечения

2. Наружное освещение необходимое, для конфортного пользования автомобилем в ночное время суток: Подсветка, пространства вокруг автомобиля, подсветка наружных ручек

3. Переделка и подсветка панели приборов на led индикацию со  сбором нужной информации по CAN шине.

Почему то я решил начать с самого сложного :)

Технический аспект:

1. Управление всем необходимым при помощи Atmega 328 с минимальной обвязкой Arduino ( не целесообразно использовать преобретёную Arduino mega 2560 для этой задачи.

2. Изготовление  печатной платы (подложки приборной панели) с Atmega 328 с минимальной обвязкой + CANbus декодера (будет принимать данные по CAN шине и пересылать их на Arduino) и led индикаторами основных показателей (тахометр, спидометр, топливо, температура двигателя). ( Всё SMD)

3. Изготовление накладки на подложку, из прозрачного ПВХ и поклейка на неё плёнок для четкой индикации + тонировка с верху ( что то похожее на Оптитрон)

Начал я с того что хотел получать сначала от датчиков информацию, но по документации выяснилось, что у Nissan Note нет датчика скорости, скорость считывается с датчиков ABS и передаётся от блока ABS по CAN шине бортовому компьютеру.

А если нельзя реализовать всё сразу, то незачем даже начинать :)

Так и возникло желание и необходимость получать нужную информацию по CAN шине, что очень и очень хорошо, меньше проблем с установкой, меньше проводов, зачем чтото считывать отдельно, если датчики автомобиля сделали это уже до тебя, нужно просто спросить их об этом :)

Вообщем начал я рыть, искать статьи, аналоги и тому подобное. К сожалению на Пост Советском пространстве Интернета, информации не много, и примеров почти нет.

А вот Буржуи давно уже сделали устройство и устройства которые обмениваются по CAN шине с автомобилем информацией. Одно, и самое удачное для меня www.youtube.com/watch

www.skpang.co.uk/catalog/arduino-canbus-shield-with-usd-card-holder-p-706.html

Вот страничка с опписанием, demo программой и билииотеками.

Вы спросите почему не купить эту плату и использовать.

Есть ряд причин по которым я не хочу это делать:

1.Высокая цена

2.Ненужная функциональнасть, почти вся

3.Нужно всё поместить в приборную панель

Вообщем нужно переделать этот проэкт, под выполнение своих функций.

Скачал я все файлы, и начал по ним рыться, искать, что же такое шлёт Arduino, что бы в ответ получать Скорость, число оборотов, температуру, и угол открытия дросельной заслонки.... 

Но так и не нашел.

Я очень надеюсь, что добрые форумчане с этого форума помогут мне с моим проэктом :)

Немного позже выкину наброски, как это всё должно выглядеть.

Всем откликнувшимя заранее благодарность.

 

Извините за растянутость :)

wixa
Offline
Зарегистрирован: 05.02.2012

Неужели не у кого никаких идей нет и наработок по CAN ? 

vworld
vworld аватар
Offline
Зарегистрирован: 26.09.2011

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

wixa
Offline
Зарегистрирован: 05.02.2012

Дело в том что я начал уже :) С самого начала, пока нет не подопытного, и нет спаяного CAN адаптера (а точнее двух адаптеров, для имитации CAN шины в домашних условиях), я решил сделать код, который в зависимости от переменного значения будет зажигать определёное количество светодиодов. Для экономии портов Atmega 328 блыо решено делать это с помощью сдвиговых регистров (8 битных), для задания переменого числа, я использовал потенциометр, код был успешно написан и с помощью форумчан (за что им большое СПАСИБО) сведён в маленькую фунцию код : 

#include <SPI.h> 

int led = 0;       // переменная для вывода на led
int val = 0;       // переменная для хранения значения входного напряжения
int potPin = 2;    // потенциометр подключается к 2-му порту
//Порт подключенный к ST_CP 74HC595 SS
int latchPin = 22;
//Порт подключенный к SH_CP  74HC595 SCK
int clockPin = 32;
//Порт подключенный к DS 74HC595 mosi
int dataPin = 33;
 
void setup() {
  //устанавливаем режим порта выхода
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
 
void STI ()
{  //устанавливаем LOW на latchPin пока не окончена передача байта
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, LSBFIRST, highByte(led)); //ввыводим старший байт
    shiftOut(dataPin, clockPin, LSBFIRST, lowByte(led));   // выводи младший байт
    //устанавливаем HIGH на latchPin, чтобы проинформировать регистр, что передача окончена.
    digitalWrite(latchPin, HIGH);
     
}
   
   
void loop() {
  val = analogRead(potPin);    // считываем значение с потенциометра
  val = val/4;  // конвертируем из 0-1023 к 0-255
  val=val/16;   //конвертируем из 0-255 в 0-16
  led=(1<<(val+1))-1;
STI();
}

 

wixa
Offline
Зарегистрирован: 05.02.2012

Фактически это основной код который будет использоватся для управления индикацией, правда к нему надо еще добавить кусочек кода который будет укравлять RGB  подсветкой стрелок приборов опять же в зависимость от переменого числа.

Но вот не задача, число то я задаю вручную, а мне надо его получить от бортового компьютера автомобиля, в моём случае по Can Шине.

Кстати может кто подскажет ответ на такой вопрос :

CAN шина, как я понимаю это способ передачи данных (т.е. порядок пересылки информации по заданому числу каналов (зависит от количество прободов CAN High и CAN Low)) если передожить на язык обычных людей то CAN (Судя по всему-это "слова", "предложения", "абзаци" и т.д, А вот сами данные это протокол OBD2 (что представляет собой "Алфавит" т.е набор символов и з которых в зависимости от протокола формируются и прересылаются пакеты данных)....

Я правильно понимаю структуру? 

wixa
Offline
Зарегистрирован: 05.02.2012

Так вот. Для решения, данной задачи, а именно задачи обмена информацией между Arduino и блоком ESM надо написать код. Так как я в програмировании полный "ZERO" (как любил говорить мой любимый и увадаемый куратор Дипломного проэкта Легостаев Анатолий Дмитревич), и из личного опыта работы инженером проэктировщиком, в моём случае лучше взять готовый проэкт и переделать его под свои нужды. Найденый мною пример выполняет почти все функции которые мне нужны, а также масса функций которые мне не нужны, поэтому надо его переделать и убрать всё не нужное, но для начала надо разабратся, а как именно он выполняет, нужные мне функции, что бы не наудалять лишнего :).

И я полез в пример :

/* Welcome to the ECU Reader project. This sketch uses the Canbus library.
It requires the CAN-bus shield for the Arduino. This shield contains the MCP2515 CAN controller and the MCP2551 CAN-bus driver.
A connector for an EM406 GPS receiver and an uSDcard holder with 3v level convertor for use in data logging applications.
The output data can be displayed on a serial LCD.

The SD test functions requires a FAT16 formated card with a text file of WRITE00.TXT in the card.


SK Pang Electronics www.skpang.co.uk

v3.0 21-02-11  Use library from Adafruit for sd card instead.

*/

#include <SdFat.h>        /* Library from Adafruit.com */
#include <SdFatUtil.h>
#include <NewSoftSerial.h>
#include <Canbus.h>


Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

NewSoftSerial sLCD =  NewSoftSerial(3, 6); /* Serial LCD is connected on pin 14 (Analog input 0) */
#define COMMAND 0xFE
#define CLEAR   0x01
#define LINE0   0x80
#define LINE1   0xC0


/* Define Joystick connection */
#define UP     A1
#define RIGHT  A2
#define DOWN   A3
#define CLICK  A4
#define LEFT   A5

  
char buffer[512];  //Data will be temporarily stored to this buffer before being written to the file
char tempbuf[15];
char lat_str[14];
char lon_str[14];

int read_size=0;   //Used as an indicator for how many characters are read from the file
int count=0;       //Miscellaneous variable

int D10 = 10;

int LED2 = 8;
int LED3 = 7;

// store error strings in flash to save RAM
#define error(s) error_P(PSTR(s))

void error_P(const char* str) {
  PgmPrint("error: ");
  SerialPrintln_P(str);
  
  clear_lcd();
  sLCD.print("SD error");
  
  if (card.errorCode()) {
    PgmPrint("SD error: ");
    Serial.print(card.errorCode(), HEX);
    
    Serial.print(',');
    Serial.println(card.errorData(), HEX);
   
  }
  while(1);
}

NewSoftSerial mySerial =  NewSoftSerial(4, 5);

#define COMMAND 0xFE
//#define powerpin 4

#define GPSRATE 4800
//#define GPSRATE 38400


// GPS parser for 406a
#define BUFFSIZ 90 // plenty big
//char buffer[BUFFSIZ];
char *parseptr;
char buffidx;
uint8_t hour, minute, second, year, month, date;
uint32_t latitude, longitude;
uint8_t groundspeed, trackangle;
char latdir, longdir;
char status;
uint32_t waypoint = 0;
 
void setup() {
  Serial.begin(GPSRATE);
  mySerial.begin(GPSRATE);
  pinMode(LED2, OUTPUT); 
  pinMode(LED3, OUTPUT); 
 
  digitalWrite(LED2, LOW);
  pinMode(UP,INPUT);
  pinMode(DOWN,INPUT);
  pinMode(LEFT,INPUT);
  pinMode(RIGHT,INPUT);
  pinMode(CLICK,INPUT);

  digitalWrite(UP, HIGH);       /* Enable internal pull-ups */
  digitalWrite(DOWN, HIGH);
  digitalWrite(LEFT, HIGH);
  digitalWrite(RIGHT, HIGH);
  digitalWrite(CLICK, HIGH);
  
  
  Serial.begin(9600);
  Serial.println("ECU Reader");  /* For debug use */
  
  sLCD.begin(9600);              /* Setup serial LCD and clear the screen */
  clear_lcd();
 
  sLCD.print("D:CAN  U:GPS");
  sLCD.print(COMMAND,BYTE);
  sLCD.print(LINE1,BYTE); 
  sLCD.print("L:SD   R:LOG");
  
  while(1)
  {
    
    if (digitalRead(UP) == 0){
      Serial.println("gps");
      sLCD.print("GPS");
      gps_test();
    }
    
    if (digitalRead(DOWN) == 0) {
      sLCD.print("CAN");
      Serial.println("CAN");
      break;
    }
    
    if (digitalRead(LEFT) == 0) {
    
      Serial.println("SD test");
      sd_test();
    }
    
    if (digitalRead(RIGHT) == 0) {
    
      Serial.println("Logging");
      logging();
    }
    
  }
  
  clear_lcd();
  
  if(Canbus.init(CANSPEED_500))  /* Initialise MCP2515 CAN controller at the specified speed */
  {
    sLCD.print("CAN Init ok");
  } else
  {
    sLCD.print("Can't init CAN");
  } 
   
  delay(1000); 

}
 

void loop() {
 
  if(Canbus.ecu_req(ENGINE_RPM,buffer) == 1)          /* Request for engine RPM */
  {
    sLCD.print(COMMAND,BYTE);                   /* Move LCD cursor to line 0 */
    sLCD.print(LINE0,BYTE);
    sLCD.print(buffer);                         /* Display data on LCD */
   
    
  } 
  digitalWrite(LED3, HIGH);
   
  if(Canbus.ecu_req(VEHICLE_SPEED,buffer) == 1)
  {
    sLCD.print(COMMAND,BYTE);
    sLCD.print(LINE0 + 9,BYTE);
    sLCD.print(buffer);
   
  }
  
  if(Canbus.ecu_req(ENGINE_COOLANT_TEMP,buffer) == 1)
  {
    sLCD.print(COMMAND,BYTE);
    sLCD.print(LINE1,BYTE);                     /* Move LCD cursor to line 1 */
    sLCD.print(buffer);
   
   
  }
  
  if(Canbus.ecu_req(THROTTLE,buffer) == 1)
  {
    sLCD.print(COMMAND,BYTE);
    sLCD.print(LINE1 + 9,BYTE);
    sLCD.print(buffer);
     file.print(buffer);
  }  
//  Canbus.ecu_req(O2_VOLTAGE,buffer);
     
   
   digitalWrite(LED3, LOW); 
   delay(100); 
   
   

}


void logging(void)
{
  clear_lcd();
  
  if(Canbus.init(CANSPEED_500))  /* Initialise MCP2515 CAN controller at the specified speed */
  {
    sLCD.print("CAN Init ok");
  } else
  {
    sLCD.print("Can't init CAN");
  } 
   
  delay(500);
  clear_lcd(); 
  sLCD.print("Init SD card");  
  delay(500);
  clear_lcd(); 
  sLCD.print("Press J/S click");  
  sLCD.print(COMMAND,BYTE);
  sLCD.print(LINE1,BYTE);                     /* Move LCD cursor to line 1 */
   sLCD.print("to Stop"); 
  
  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  if (!card.init(SPI_HALF_SPEED,9)) error("card.init failed");
  
  // initialize a FAT volume
  if (!volume.init(&card)) error("volume.init failed");
  
  // open the root directory
  if (!root.openRoot(&volume)) error("openRoot failed");

  // create a new file
  char name[] = "WRITE00.TXT";
  for (uint8_t i = 0; i < 100; i++) {
    name[5] = i/10 + '0';
    name[6] = i%10 + '0';
    if (file.open(&root, name, O_CREAT | O_EXCL | O_WRITE)) break;
  }
  if (!file.isOpen()) error ("file.create");
  Serial.print("Writing to: ");
  Serial.println(name);
  // write header
  file.writeError = 0;
  file.print("READY....");
  file.println();  

  while(1)    /* Main logging loop */
  {
     read_gps();
     
     file.print(waypoint++);
     file.print(',');
     file.print(lat_str);
     file.print(',');
     file.print(lon_str);
     file.print(',');
      
    if(Canbus.ecu_req(ENGINE_RPM,buffer) == 1)          /* Request for engine RPM */
      {
        sLCD.print(COMMAND,BYTE);                   /* Move LCD cursor to line 0 */
        sLCD.print(LINE0,BYTE);
        sLCD.print(buffer);                         /* Display data on LCD */
        file.print(buffer);
         file.print(',');
    
      } 
      digitalWrite(LED3, HIGH);
   
      if(Canbus.ecu_req(VEHICLE_SPEED,buffer) == 1)
      {
        sLCD.print(COMMAND,BYTE);
        sLCD.print(LINE0 + 9,BYTE);
        sLCD.print(buffer);
        file.print(buffer);
        file.print(','); 
      }
      
      if(Canbus.ecu_req(ENGINE_COOLANT_TEMP,buffer) == 1)
      {
        sLCD.print(COMMAND,BYTE);
        sLCD.print(LINE1,BYTE);                     /* Move LCD cursor to line 1 */
        sLCD.print(buffer);
         file.print(buffer);
       
      }
      
      if(Canbus.ecu_req(THROTTLE,buffer) == 1)
      {
        sLCD.print(COMMAND,BYTE);
        sLCD.print(LINE1 + 9,BYTE);
        sLCD.print(buffer);
         file.print(buffer);
      }  
    //  Canbus.ecu_req(O2_VOLTAGE,buffer);
       file.println();  
  
       digitalWrite(LED3, LOW); 
 
       if (digitalRead(CLICK) == 0){  /* Check for Click button */
           file.close();
           Serial.println("Done");
           sLCD.print(COMMAND,BYTE);
           sLCD.print(CLEAR,BYTE);
     
           sLCD.print("DONE");
          while(1);
        }

  }
 
 
 
 
}
     

void sd_test(void)
{
 clear_lcd(); 
 sLCD.print("SD test"); 
 Serial.println("SD card test");
   
     // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  if (!card.init(SPI_HALF_SPEED,9)) error("card.init failed");
  
  // initialize a FAT volume
  if (!volume.init(&card)) error("volume.init failed");
  
  // open root directory
  if (!root.openRoot(&volume)) error("openRoot failed");
  // open a file
  if (file.open(&root, "LOGGER00.CSV", O_READ)) {
    Serial.println("Opened PRINT00.TXT");
  }
  else if (file.open(&root, "WRITE00.TXT", O_READ)) {
    Serial.println("Opened WRITE00.TXT");    
  }
  else{
    error("file.open failed");
  }
  Serial.println();
  
  // copy file to serial port
  int16_t n;
  uint8_t buf[7];// nothing special about 7, just a lucky number.
  while ((n = file.read(buf, sizeof(buf))) > 0) {
    for (uint8_t i = 0; i < n; i++) Serial.print(buf[i]);
  
  
  }
 clear_lcd();  
 sLCD.print("DONE"); 

  
 while(1);  /* Don't return */ 
    

}
void read_gps(void)
{
 uint32_t tmp;

  unsigned char i;
  unsigned char exit = 0;
  
  
  while( exit == 0)
  { 
    
   readline();
 
  // check if $GPRMC (global positioning fixed data)
   if (strncmp(buffer, "$GPRMC",6) == 0) {
     
        digitalWrite(LED2, HIGH);
        
        // hhmmss time data
        parseptr = buffer+7;
        tmp = parsedecimal(parseptr); 
        hour = tmp / 10000;
        minute = (tmp / 100) % 100;
        second = tmp % 100;
        
        parseptr = strchr(parseptr, ',') + 1;
        status = parseptr[0];
        parseptr += 2;
          
        for(i=0;i<11;i++)
        {
          lat_str[i] = parseptr[i];
        }
        lat_str[12] = 0;
      //  Serial.println(" ");
      //  Serial.println(lat_str);
       
        // grab latitude & long data
        latitude = parsedecimal(parseptr);
        if (latitude != 0) {
          latitude *= 10000;
          parseptr = strchr(parseptr, '.')+1;
          latitude += parsedecimal(parseptr);
        }
        parseptr = strchr(parseptr, ',') + 1;
        // read latitude N/S data
        if (parseptr[0] != ',') {
          
          latdir = parseptr[0];
        }
        
        // longitude
        parseptr = strchr(parseptr, ',')+1;
      
        for(i=0;i<12;i++)
        {
          lon_str[i] = parseptr[i];
        }
        lon_str[13] = 0;
        
        //Serial.println(lon_str);
   
        longitude = parsedecimal(parseptr);
        if (longitude != 0) {
          longitude *= 10000;
          parseptr = strchr(parseptr, '.')+1;
          longitude += parsedecimal(parseptr);
        }
        parseptr = strchr(parseptr, ',')+1;
        // read longitude E/W data
        if (parseptr[0] != ',') {
          longdir = parseptr[0];
        }
        
    
        // groundspeed
        parseptr = strchr(parseptr, ',')+1;
        groundspeed = parsedecimal(parseptr);
    
        // track angle
        parseptr = strchr(parseptr, ',')+1;
        trackangle = parsedecimal(parseptr);
    
        // date
        parseptr = strchr(parseptr, ',')+1;
        tmp = parsedecimal(parseptr); 
        date = tmp / 10000;
        month = (tmp / 100) % 100;
        year = tmp % 100;
        
       
        digitalWrite(LED2, LOW);
        exit = 1;
       }
       
  }   

}

      
      

void gps_test(void){
  uint32_t tmp;
  uint32_t lat;
  unsigned char i;
  
  while(1){
  
   readline();
  
  // check if $GPRMC (global positioning fixed data)
  if (strncmp(buffer, "$GPRMC",6) == 0) {
    
    // hhmmss time data
    parseptr = buffer+7;
    tmp = parsedecimal(parseptr); 
    hour = tmp / 10000;
    minute = (tmp / 100) % 100;
    second = tmp % 100;
    
    parseptr = strchr(parseptr, ',') + 1;
    status = parseptr[0];
    parseptr += 2;
      
    for(i=0;i<11;i++)
    {
      lat_str[i] = parseptr[i];
    }
    lat_str[12] = 0;
     Serial.println("\nlat_str ");
     Serial.println(lat_str);
   
  
    // grab latitude & long data
    // latitude
    latitude = parsedecimal(parseptr);
    if (latitude != 0) {
      latitude *= 10000;
      parseptr = strchr(parseptr, '.')+1;
      latitude += parsedecimal(parseptr);
    }
    parseptr = strchr(parseptr, ',') + 1;
    // read latitude N/S data
    if (parseptr[0] != ',') {
      
      latdir = parseptr[0];
    }
    
    //Serial.println(latdir);
    
    // longitude
    parseptr = strchr(parseptr, ',')+1;
  
    for(i=0;i<12;i++)
    {
      lon_str[i] = parseptr[i];
    }
    lon_str[13] = 0;
    
    Serial.println(lon_str);
   
  
    longitude = parsedecimal(parseptr);
    if (longitude != 0) {
      longitude *= 10000;
      parseptr = strchr(parseptr, '.')+1;
      longitude += parsedecimal(parseptr);
    }
    parseptr = strchr(parseptr, ',')+1;
    // read longitude E/W data
    if (parseptr[0] != ',') {
      longdir = parseptr[0];
    }
    

    // groundspeed
    parseptr = strchr(parseptr, ',')+1;
    groundspeed = parsedecimal(parseptr);

    // track angle
    parseptr = strchr(parseptr, ',')+1;
    trackangle = parsedecimal(parseptr);

    // date
    parseptr = strchr(parseptr, ',')+1;
    tmp = parsedecimal(parseptr); 
    date = tmp / 10000;
    month = (tmp / 100) % 100;
    year = tmp % 100;
    
    Serial.print("\nTime: ");
    Serial.print(hour, DEC); Serial.print(':');
    Serial.print(minute, DEC); Serial.print(':');
    Serial.print(second, DEC); Serial.print(' ');
    Serial.print("Date: ");
    Serial.print(month, DEC); Serial.print('/');
    Serial.print(date, DEC); Serial.print('/');
    Serial.println(year, DEC);
    
    sLCD.print(COMMAND,BYTE);
    sLCD.print(0x80,BYTE);
    sLCD.print("La");
   
    Serial.print("Lat"); 
    if (latdir == 'N')
    {
       Serial.print('+');
       sLCD.print("+");
    }
    else if (latdir == 'S')
    {  
       Serial.print('-');
       sLCD.print("-");
    }
     
    Serial.print(latitude/1000000, DEC); Serial.print('\┬░', BYTE); Serial.print(' ');
    Serial.print((latitude/10000)%100, DEC); Serial.print('\''); Serial.print(' ');
    Serial.print((latitude%10000)*6/1000, DEC); Serial.print('.');
    Serial.print(((latitude%10000)*6/10)%100, DEC); Serial.println('"');
    
    
    
    sLCD.print(latitude/1000000, DEC); sLCD.print(0xDF, BYTE); sLCD.print(' ');
    sLCD.print((latitude/10000)%100, DEC); sLCD.print('\''); //sLCD.print(' ');
    sLCD.print((latitude%10000)*6/1000, DEC); sLCD.print('.');
    sLCD.print(((latitude%10000)*6/10)%100, DEC); sLCD.print('"');
    
    sLCD.print(COMMAND,BYTE);
    sLCD.print(0xC0,BYTE);
    sLCD.print("Ln");
   
      
    Serial.print("Long: ");
    if (longdir == 'E')
    {
       Serial.print('+');
       sLCD.print('+');
    }
    else if (longdir == 'W')
    { 
       Serial.print('-');
       sLCD.print('-');
    }
    Serial.print(longitude/1000000, DEC); Serial.print('\┬░', BYTE); Serial.print(' ');
    Serial.print((longitude/10000)%100, DEC); Serial.print('\''); Serial.print(' ');
    Serial.print((longitude%10000)*6/1000, DEC); Serial.print('.');
    Serial.print(((longitude%10000)*6/10)%100, DEC); Serial.println('"');
    
    sLCD.print(longitude/1000000, DEC); sLCD.print(0xDF, BYTE); sLCD.print(' ');
    sLCD.print((longitude/10000)%100, DEC); sLCD.print('\''); //sLCD.print(' ');
    sLCD.print((longitude%10000)*6/1000, DEC); sLCD.print('.');
    sLCD.print(((longitude%10000)*6/10)%100, DEC); sLCD.print('"');
     
  }
  
 //   Serial.println("Lat: ");
 //   Serial.println(latitude);
  
 //   Serial.println("Lon: ");
 //   Serial.println(longitude);
  }



}

void readline(void) {
  char c;
  
  buffidx = 0; // start at begninning
  while (1) {
      c=mySerial.read();
      if (c == -1)
        continue;
  //    Serial.print(c);
      if (c == '\n')
        continue;
      if ((buffidx == BUFFSIZ-1) || (c == '\r')) {
        buffer[buffidx] = 0;
        return;
      }
      buffer[buffidx++]= c;
  }
}
uint32_t parsedecimal(char *str) {
  uint32_t d = 0;
  
  while (str[0] != 0) {
   if ((str[0] > '9') || (str[0] < '0'))
     return d;
   d *= 10;
   d += str[0] - '0';
   str++;
  }
  return d;
}

void clear_lcd(void)
{
  sLCD.print(COMMAND,BYTE);
  sLCD.print(CLEAR,BYTE);
}   

(КОД ВЗЯТ ИЗ ФАЙЛА ECU_reader_loger.PDE, который находится в архиве Canbus_v3.zip скаченого от сюда code.google.com/p/skpang/downloads/detail) (это я на всякий случай, а то  не очень разбираюсь в раззрешениях на использование информации)

wixa
Offline
Зарегистрирован: 05.02.2012

И начал искать всё что касается оборотов двигателя (RPM), нахожу 2 упоминания  :

Первое :

171 void loop() {
172
173 if(Canbus.ecu_req(ENGINE_RPM,buffer) == 1) /* Request for engine RPM */

174 {
175 sLCD.print(COMMAND,BYTE); /* Move LCD cursor to line 0 */
176 sLCD.print(LINE0,BYTE);
177 sLCD.print(buffer); /* Display data on LCD */
178
179
180 }

 

И Второе:

276 if(Canbus.ecu_req(ENGINE_RPM,buffer) == 1) /* Request for engine RPM */
277 {
278 sLCD.print(COMMAND,BYTE); /* Move LCD cursor to line 0 */
279 sLCD.print(LINE0,BYTE);
280 sLCD.print(buffer); /* Display data on LCD */
281 file.print(buffer);
282 file.print(',');
283
284 }

 

Я не програмист, но понимаю что в обоих случаях стоит проверка буфера ENGINE_RPM, на то есть ли в нём что-то, и если есть то это выводится на экран. Судя по этой части строчки Canbus.ecu_req , надо лезть в файл под названием Canbus.cpp в том же архиве.
 

Изходя из того что в архиве находятся 2 файла Canbus, одно с разширением cpp, а другое h , могу предположить что это библиотека.

Библиотека - (в моём понимании) это набор функций, которые лежат в одном файле, и из которой можно дтянуть нужную тебе не засоряя ненужными код твоей программы.

открываю его (файл с расширением cpp) и ищу опять же всё что связано с RPM : 

/**
 * 
 *
 * Copyright (c) 2008-2009  All rights reserved.
 */
#include "WConstants.h"
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "pins_arduino.h"
#include <inttypes.h>
#include "global.h"
#include "mcp2515.h"
#include "defaults.h"
#include "Canbus.h"




/* C++ wrapper */
CanbusClass::CanbusClass() {

 
}
char CanbusClass::message_rx(unsigned char *buffer) {
		tCAN message;
	
		if (mcp2515_check_message()) {
		
			
			// Lese die Nachricht aus dem Puffern des MCP2515
			if (mcp2515_get_message(&message)) {
			//	print_can_message(&message);
			//	PRINT("\n");
				buffer[0] = message.data[0];
				buffer[1] = message.data[1];
				buffer[2] = message.data[2];
				buffer[3] = message.data[3];
				buffer[4] = message.data[4];
				buffer[5] = message.data[5];
				buffer[6] = message.data[6];
				buffer[7] = message.data[7];								
//				buffer[] = message[];
//				buffer[] = message[];
//				buffer[] = message[];
//				buffer[] = message[];																												
			}
			else {
			//	PRINT("Kann die Nachricht nicht auslesen\n\n");
			}
		}

}

char CanbusClass::message_tx(void) {
	tCAN message;


	// einige Testwerte
	message.id = 0x7DF;
	message.header.rtr = 0;
	message.header.length = 8;
	message.data[0] = 0x02;
	message.data[1] = 0x01;
	message.data[2] = 0x05;
	message.data[3] = 0x00;
	message.data[4] = 0x00;
	message.data[5] = 0x00;
	message.data[6] = 0x00;
	message.data[7] = 0x00;						
	
	
	
	
//	mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), (1<<REQOP1));	
		mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), 0);
		
	if (mcp2515_send_message(&message)) {
		//	SET(LED2_HIGH);
		return 1;
	
	}
	else {
	//	PRINT("Fehler: konnte die Nachricht nicht auslesen\n\n");
	return 0;
	}
return 1;
 
}

char CanbusClass::ecu_req(unsigned char pid,  char *buffer) 
{
	tCAN message;
	float engine_data;
	int timeout = 0;
	char message_ok = 0;
	// Prepair message
	message.id = PID_REQUEST;
	message.header.rtr = 0;
	message.header.length = 8;
	message.data[0] = 0x02;
	message.data[1] = 0x01;
	message.data[2] = pid;
	message.data[3] = 0x00;
	message.data[4] = 0x00;
	message.data[5] = 0x00;
	message.data[6] = 0x00;
	message.data[7] = 0x00;						
	

	mcp2515_bit_modify(CANCTRL, (1<<REQOP2)|(1<<REQOP1)|(1<<REQOP0), 0);
//		SET(LED2_HIGH);	
	if (mcp2515_send_message(&message)) {
	}
	
	while(timeout < 4000)
	{
		timeout++;
				if (mcp2515_check_message()) 
				{

					if (mcp2515_get_message(&message)) 
					{
							if((message.id == PID_REPLY) && (message.data[2] == pid))	// Check message is the reply and its the right PID
							{
								switch(message.data[2])
								{   /* Details from http://en.wikipedia.org/wiki/OBD-II_PIDs */
									case ENGINE_RPM:  			//   ((A*256)+B)/4    [RPM]
									engine_data =  ((message.data[3]*256) + message.data[4])/4;
									sprintf(buffer,"%d rpm ",(int) engine_data);
									break;
							
									case ENGINE_COOLANT_TEMP: 	// 	A-40			  [degree C]
									engine_data =  message.data[3] - 40;
									sprintf(buffer,"%d degC",(int) engine_data);
							
									break;
							
									case VEHICLE_SPEED: 		// A				  [km]
									engine_data =  message.data[3];
									sprintf(buffer,"%d km ",(int) engine_data);
							
									break;

									case MAF_SENSOR:   			// ((256*A)+B) / 100  [g/s]
									engine_data =  ((message.data[3]*256) + message.data[4])/100;
									sprintf(buffer,"%d g/s",(int) engine_data);
							
									break;

									case O2_VOLTAGE:    		// A * 0.005   (B-128) * 100/128 (if B==0xFF, sensor is not used in trim calc)
									engine_data = message.data[3]*0.005;
									sprintf(buffer,"%d v",(int) engine_data);
							
									case THROTTLE:				// Throttle Position
									engine_data = (message.data[3]*100)/255;
									sprintf(buffer,"%d %% ",(int) engine_data);
									break;
							
								}
								message_ok = 1;
							}

					}
				}
				if(message_ok == 1) return 1;
	}


 	return 0;
}






char CanbusClass::init(unsigned char speed) {

  return mcp2515_init(speed);
 
}

CanbusClass Canbus; 

 

wixa
Offline
Зарегистрирован: 05.02.2012

Нахожу первое :

129 case ENGINE_RPM: // ((A*256)+B)/4 [RPM]
130 engine_data = ((message.data[3]*256) + message.data[4])/4;
131 sprintf(buffer,"%d rpm ",(int) engine_data);
132 break;

Тут я и стопорюсь......

Помогите разобратся, куда дальше идти. как вообще понять что отсылает (либо Arduino либо контролер MCP2515 ) чтобы получить данные, и кто именно из них делает запрос???

Запросы идут автоматом от контролера CAN (MCP 2515) и Arduino просто принимает данные от него???

Или Arduino что то посылает контролеру, а тот соответственно бортовому компьютеру, и получает в замен данные.....

Понял только одно ,что  ((A*256)+B)/4 [RPM] это формула которая есть на Wiki en.wikipedia.org/wiki/OBD-II_PIDs используется для вычисления числа оборотов двигателя за минуту .

Заранее благодарен, всем откликнушившимся. 

Извините, если заставил подумать что делать ничего не собираюсь, а только жду чтоб форумчане это сделали за меня.

MarioM
Offline
Зарегистрирован: 18.04.2011

нет ничего хуже рыться в чужом коде.

Ардуино именно посылает запросы на контроллер, структура запроса описана в структуре tCAN (ищи ее описание гдето в скачанных тобою модулях). Запрос отправляется на контроллер с пустыми переременными (строки кода 105-109), и возвращается с контроллера уже заполненными. из последнего кода видим /message.data[2] = pid;/ (строка 104), этот pid приходит в функцию извне и в твоем случае равен константе ENGINE_RPM, которая по моим догадкам описана в файле "WConstants.h". 

вотчто мне удалось понять по приведенным тобой примерам.

 

 

wixa
Offline
Зарегистрирован: 05.02.2012

ENGINE_RPM опписана в заголовочном файле к библиотеке CANBUS :

/**
 * CAN BUS
 *
 * Copyright (c) 2010 Sukkin Pang All rights reserved.
 */

#ifndef canbus__h
#define canbus__h

#define CANSPEED_125 	7		// CAN speed at 125 kbps
#define CANSPEED_250  	3		// CAN speed at 250 kbps
#define CANSPEED_500	1		// CAN speed at 500 kbps


#define ENGINE_COOLANT_TEMP 0x05
#define ENGINE_RPM          0x0C
#define VEHICLE_SPEED       0x0D
#define MAF_SENSOR          0x10
#define O2_VOLTAGE          0x14
#define THROTTLE			0x11

#define PID_REQUEST         0x7DF
#define PID_REPLY			0x7E8

class CanbusClass
{
  public:

	CanbusClass();
    char init(unsigned char);
	char message_tx(void);
	char message_rx(unsigned char *buffer);
	char ecu_req(unsigned char pid,  char *buffer);
private:
	
};
extern CanbusClass Canbus;
//extern tCAN message;

#endif 

 

wixa
Offline
Зарегистрирован: 05.02.2012

0x0C это PID кторый отвечает за обороты, но что означает предидущих 2 байта :

102 message.data[0] = 0x02;
103 message.data[1] = 0x01;

Я догадываюсь, что 0х01 - это режим "Show current data" кторый отражает информацию в реальном времени.

Но вот за что отвечает байт 102 message.data[0] = 0x02; ??? Это вопрос №1 ( опять же, догадываюсь, что это размер в байтах кторые будут возвращатся, т.е для исчисления всех показателей нужно максимом 2 байта, в некоторых один....

Но зачем отсылать пустых 5 байт а не 2 ? или надо полюбасу отсылать 8 ? Это вопрос №2 если утверждение правильно)

Не понятно, где искать опписание tCAN ??? вопрос №3

И те файлы которые написаны для MCP 2515, заливаются отдельно на контролер MCP2515 ??? тоже не понятно...

Вообщем вопросов уйма, и небольшая растеряность. :)

 

MarioM
Offline
Зарегистрирован: 18.04.2011

в ответе на вопрос номер три скрывается ответ на вопрос номер один, а описание структуры нужно искать в одном из подключенных header'ов в самом начале модуля.

по вопросу номер два - да, нужно отправлять сразу все.. протокол значит такой.

 

wixa
Offline
Зарегистрирован: 05.02.2012

Нашел. на Wiki :

Я был прав, этот байт для задания ответного количества байт, но вот интересно, что с 3го по 7-й байты не используются, и должны быть 0х55..... непонятно чего в примере 0х00 ?!

 

А вот кто мне ответит на вопрос:

МК MCP2515 шьется отдельно? или его не надо шить?

ВиталийАТ
Offline
Зарегистрирован: 14.12.2011

А как обходишь блок с индикацией заряда аккумулятора? Есть в современных авто (с 2000х примерно) такой прикол, что они без этого блока не посылают возбуждающий ток на ротор генератора. Этот блок анализирует заряд аккумулятора, посылает сигнал на лампу в панели и открывает ход тока к ротору. При этом если лампа перегорела, то в некоторых машинах надо менять лампу, а в некоторых - нормально, и так подаёт. Тем не менее, если ты решил выкинуть приборку и воткнуть туда экран, то должен как-то обойти эту заковырку. Обошёл? Как?

wixa
Offline
Зарегистрирован: 05.02.2012

Вопервых я приборку выкидывать не собираюсь..... она остаётся, просто на неё будет крепится новая разведеная плата, а поверх платы, пластиковые напкладки..... в местах, где стоят диоды индикации всего кроме спидометр тахометра, и топлива будут отверстия в моей плате, чтоб всё продолжало индицироватся..... примерно так 

LEVV2006
LEVV2006 аватар
Offline
Зарегистрирован: 15.04.2011

Здравствуйте! тема актуальна и для меня. Мне необходимо снимать показания скорости. Думаю подключиться к CAN шине.
«Вы спросите почему не купить эту плату и использовать.
Есть ряд причин по которым я не хочу это делать:
1.Высокая цена
2.Ненужная функциональнасть, почти вся
3.Нужно всё поместить в приборную панель
Вообщем нужно переделать этот проэкт, под выполнение своих функций.»

Полностью согласен. И по этому вопрос: Кто нибуть Строил подобный модуль?
 

wixa
Offline
Зарегистрирован: 05.02.2012

Человек, с другого форума.... говорил что будет пробовать..... напишите ему сюда