Делаем звуки поворотников с помощью Arduino

Имеется автомобиль Ravon R4, он же Chevrolet Cobalt в детстве. И чтобы жизнь мёдом не казалась от владения столь прекрасным пепелацем, подкинули нам искусственную сложность: при замене штатной магнитолы исчезают звуки поворотников. В статье по ссылке подобрано разобрана суть проблемы, а здесь мы будем её решать несколько костыльным путём.

Требования

  • Автомобиль Chevrolet Cobalt в комплектации LTZ или Ravon R4 любой комплектации;
  • Любой программируемый микроконтроллер, я использую Arduino UNO;
  • MCP2515 - CAN-контроллер с интерфейсом SPI;
  • DFPlayer Mini - аппаратный проигрыватель MP3 файлов с последовательным интерфейсом управления;
  • Любой динамик для воспроизведения звуков.

Стоимость такого удовольствия следующая: Arduino (250 руб.), MCP2515 (130 руб.), DFPlayer (60 руб.), динамик (50 руб.). Итого 490 рублей.

Подключение

Схема подключения Arduino и MCP2515 для автомобиля Chevrolet Cobalt и Ravon R4
Итоговая схема подключения

Начнем с CAN-декодера. Прежде чем начать с ним работать, я по советам других пользователей сразу перепаял кварцевый резонатор c 8мГц на 16мГц. У платы MCP2515 в сторону шины два вывода: CAN High и CAN Low. Работать мы будем с шиной SWCAN, которая по своей природе является однопроводной. Значит, CAN High подключаем к шине, CAN Low на землю. Тут уже присутствуют варианты:

  • Взять SWCAN с диагностической колодки, пин №5. Там же кинуть землю;
  • Взять SWCAN с разъема для магнитолы, в нем он находится под номером №14, а земля №38:
Разъем подключения магнитолы Chevrolet Cobalt LTZ и Ravon R4

Другой стороной MCP2515 подключаем к нашему микроконтроллеру - Arduino UNO. Делаем это как показано на схеме:

Подключение MCP2515 к Arduino UNO
  • INT => D2;
  • SCK => D13;
  • SI - D11;
  • SO - D12;
  • CS - D10;
  • GND - GND;
  • VCC - 5V.

MP3 проигрыватель управляется по последовательному порту через пины RX и TX. По факту RX не используется, управление одностороннее. В случае с Arduino можно использовать как физический интерфейс, размещенный на пинах D0 (RX) и D1 (TX) Ардуины, так и воспользовавшись библиотекой SoftwareSerial поднять программный интерфейс на любом цифровом пине. Я выбрал второй вариант и использовал для него пин D6. При первом подключении я столкнулся с помехами на динамик, решением оказалось TX пин подключить через 1кОм резистор. Подключаем проигрыватель так:

  • VCC - 5V;
  • GND - GND;
  • TX - D6;
  • SPK_1 и SPK_2 - на динамик.

На этом подключение заканчивается и мы переходим к теории о шине SWCAN.

SWCAN шина и используемые в ней коды

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

В интернете мне удалось найти два кода соответствующих включению и выключению звука поворотников, но для меня так же критичны звуки незакрытых дверей и непристегнутого ремня. Потому пришлось прибегнуть к самостоятельному "отлову" необходимых кодов. Для этого я использовал программу Can Hacker и залитый соответствующий скетч в ардуино.

Перехват кодов SWCAN с помощью CAN Hacker на Ravon R4
Интерфейс программы CAN Hacker во время перехвата кодов SWCAN Ravon R4

Проехавшись буквально пять минут, создавая ситуация для воспроизведения нужных мне звуков я вывел искомые значения. С радостью делюсь ими с вами (если вдруг, вы найдете еще какие-нибудь интересные значения, не поленитесь поделиться ими с нами :) ):

Поворотник (включить):Extended ID: 0x10400060 DLC: 5 Data: 0x82 0x08 0x01 0xFF 0xD4
Поворотник (выключить):Extended ID: 0x10400060 DLC: 5 Data: 0x81 0x08 0x01 0xFF 0xD5
Открытая водительская дверь на зажигании (включить):Extended ID: 0x10400040 DLC: 5 Data: 0x86 0x3C 0xFF 0xFF 0x58
Открытая водительская дверь на зажигании (выключить):Extended ID: 0x10400040 DLC: 5 Data: 0x86 0x3C 0x00 0xFF 0x58
Сброс одометра (единократный щелчок):Extended ID: 0x10400060 DLC: 5 Data: 0x85 0x1E 0x01 0x33 0x38
Непристегнутый ремень на скорости выше 20км/ч (включить):Extended ID: 0x10400058 DLC: 5 Data: 0x87 0x65 0x64 0xFF 0x05
Непристегнутый ремень на скорости выше 20км/ч (выключить):Extended ID: 0x10400058 DLC: 5 Data: 0x87 0x65 0x00 0xFF 0x05
Тройной писк при открытой двери в движении (единократно):Extended ID: 0x10400060 DLC: 5 Data: 0x86 0x28 0x04 0xFF 0x88
Движение на стояночном тормозе (включить):Extended ID: 0x10400060 DLC: 5 Data: 0x86 0x1E 0xFF 0xFF 0x78
Движение на стояночном тормозе (выключить):Extended ID: 0x10400060 DLC: 5 Data: 0x86 0x1E 0x00 0xFF 0x78

Полученных данных достаточно, а значит мы переходим к программированию микроконтроллера.

Скетч для Arduino

В Arduino IDE устанавливаем необходимые для работы библиотеки:

Подготавливаем MicroSD флеш-карту для проигрывателя: форматируем в FAT32 и копируем в её корень файлы звуков строго под названием 0001.mp3, 0002.mp3, ..., 000n.mp3. Для начала можете воспользоваться звуками, которые подготовил я:

Скачать “Скетч декодера SWCAN-шины Chevrolet Cobalt и Ravon R4 вместе со звуками.”

CANBus_decoder_cobalt_r4.zip – Загружено 1216 раз – 1,27 МБ

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

Флешку вставляем в DFPlayer Mini и заливаем предложенный мною скетч для Arduino:

#include <mcp_can.h>
#include <SPI.h>

#include <SoftwareSerial.h>
#include <DFMiniMp3.h>

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128];

#define CAN0_INT 2                              // Set INT to pin 2
MCP_CAN CAN0(10);                               // Set CS to pin 10

class Mp3Notify
{
public:
  static void OnError(uint16_t errorCode)
  {
    Serial.println();
    Serial.print("Com Error ");
    Serial.println(errorCode);
  }

  static void OnPlayFinished(uint16_t globalTrack)
  {
    Serial.println();
    Serial.print("Play finished for #");
    Serial.println(globalTrack);   
  }

  static void OnCardOnline(uint16_t code)
  {
    Serial.println();
    Serial.print("Card online ");
    Serial.println(code);     
  }

  static void OnCardInserted(uint16_t code)
  {
    Serial.println();
    Serial.print("Card inserted ");
    Serial.println(code); 
  }

  static void OnCardRemoved(uint16_t code)
  {
    Serial.println();
    Serial.print("Card removed ");
    Serial.println(code);  
  }
};

SoftwareSerial secondarySerial(5, 6); // RX, TX
DFMiniMp3<SoftwareSerial, Mp3Notify> mp3(secondarySerial);

void setup()
{
  Serial.begin(115200);

  mp3.begin();
  mp3.setVolume(30);
  
  if(CAN0.begin(MCP_ANY, CAN_33K3BPS, MCP_16MHZ) == CAN_OK)
    Serial.println("MCP2515 Initialized Successfully!");
  else
    Serial.println("Error Initializing MCP2515...");
  
  CAN0.setMode(MCP_NORMAL);                     // Set operation mode to normal so the MCP2515 sends acks to received data.
  pinMode(CAN0_INT, INPUT);                            // Configuring pin for /INT input
  Serial.println("Start detect codes for Cobalt/R4...");
}

void loop()
{
  if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
  {
    CAN0.readMsgBuf(&rxId, &len, rxBuf);      // Read data: len = data length, buf = data byte(s)
    if((rxId & 0x80000000) == 0x80000000) {     // Determine if ID is standard (11 bits) or extended (29 bits)
      if ((rxId & 0x1FFFFFFF) == 272629856) {
        // Поворотники
        if (rxBuf[0] == 0x82) {
          mp3.stop();
          mp3.playMp3FolderTrack(4);
        }
        if (rxBuf[0] == 0x81) {
          mp3.stop();
          mp3.playMp3FolderTrack(5);
        }
        // Одометр
        if (rxBuf[0] == 0x85) {
          mp3.stop();
          mp3.playMp3FolderTrack(7);
        }
        // Открытая дверь на драйве
        if (rxBuf[0] == 0x86 && rxBuf[1] == 0x28) {
          mp3.stop();
          mp3.playMp3FolderTrack(9);
        }
        // Движение на ручнике
        if (rxBuf[0] == 0x86 && rxBuf[1] == 0x1E && rxBuf[2] == 0xFF) {
          mp3.stop();
          mp3.playMp3FolderTrack(1);
        }
        if (rxBuf[0] == 0x86 && rxBuf[1] == 0x1E && rxBuf[2] == 0x00) {
          mp3.stop();
        }
      }
      if ((rxId & 0x1FFFFFFF) == 272629824) {
        // Открытая водительская дверь на зажигании
        if (rxBuf[0] == 0x86 && rxBuf[2] == 0xFF) {
          mp3.stop();
          mp3.playMp3FolderTrack(6);
        }
        if (rxBuf[0] == 0x86 && rxBuf[2] == 0x00) {
          mp3.stop();
        }
      }
      if ((rxId & 0x1FFFFFFF) == 272629848) {
        // Ремень на скорости выше 20кмч
        if (rxBuf[0] == 0x87 && rxBuf[2] == 0x64) {
          mp3.stop();
          mp3.playMp3FolderTrack(8);
        }
        if (rxBuf[0] == 0x87 && rxBuf[2] == 0x00) {
          mp3.stop();
        }
      }
    } else
      sprintf(msgString, "Standard ID: 0x%.3lX       DLC: %1d  Data:", rxId, len);
    
    if((rxId & 0x40000000) == 0x40000000){    // Determine if message is a remote request frame.
      sprintf(msgString, " REMOTE REQUEST FRAME");
    } else {
      for(byte i = 0; i<len; i++){
        sprintf(msgString, " 0x%.2X", rxBuf[i]);
      }
    }
  }
}

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

12 ответов к «Делаем звуки поворотников с помощью Arduino»

  1. Добрый день,
    Решил осуществить данный проект на своем авто. Приобрел все необходимое, но компиляция скетча не проходит. Помогите решить проблему, может на связь с вами выйти хоть по переписке.

  2. Здравствуйте. Не совсем понимаю строки:
    if((rxId & 0x80000000) == 0x80000000) { // Determine if ID is standard (11 bits) or extended (29 bits)
    if ((rxId & 0x1FFFFFFF) == 272629856)
    Откуда цифры 272629856?
    Делаю подобный проект, только вот собираюсь ловить сигнал с кнопок руля и управлять кнопками на Блютуз модуле. Не подскажите в таком случае, у меня сигнал 3С4(ID) 2(DLC) 00 08 00(DATA), как написать этот кусок кода под мой сигнал? Спасибо.
    ПС: автомобиль другой.

  3. Уважаемый автор! Сохранился ли у Вас can dump с низко скоростной шины? Пытаюсь вкорячить в авто магнитолу с блютуз и CAN шиной. Блокировку снял, но магнитола отключается через 10 минут работы. Пытаюсь сделать CAN sender. Поделитесь если есть записанная трасса CAN сообщений. Нужно подать сигнал АСС в шину. Спасибо.

  4. Подскажите как выставить в программе CanHacker 2.00.01 скорость 33.3kbps.
    В ней есть настройка "User Def" но значение не могу вычесть калькулятором.

  5. Скетч не рабочий ну совсем
    Как починить?

    In file included from E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:9:0:
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h: In instantiation of 'DFMiniMp3::reply_t DFMiniMp3::retryCommand(uint8_t, uint8_t, uint16_t, bool) [with T_SERIAL_METHOD = SoftwareSerial; T_NOTIFICATION_METHOD = Mp3Notify; T_CHIP_VARIANT = Mp3ChipOriginal; uint8_t = unsigned char; uint16_t = unsigned int]':
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:571:21: required from 'void DFMiniMp3::setCommand(uint8_t, uint16_t) [with T_SERIAL_METHOD = SoftwareSerial; T_NOTIFICATION_METHOD = Mp3Notify; T_CHIP_VARIANT = Mp3ChipOriginal; uint8_t = unsigned char; uint16_t = unsigned int]'
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:170:19: required from 'void DFMiniMp3::setVolume(uint8_t) [with T_SERIAL_METHOD = SoftwareSerial; T_NOTIFICATION_METHOD = Mp3Notify; T_CHIP_VARIANT = Mp3ChipOriginal; uint8_t = unsigned char]'
    E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:66:19: required from here
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:557:43: error: no matching function for call to 'Mp3Notify::OnError(DFMiniMp3&, uint16_t&)'
    T_NOTIFICATION_METHOD::OnError(*this, reply.arg);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
    E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:22:15: note: candidate: static void Mp3Notify::OnError(uint16_t)
    E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:22:15: note: candidate expects 1 argument, 2 provided
    In file included from E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:9:0:
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h: In instantiation of 'void DFMiniMp3::callNotification(DFMiniMp3::reply_t) [with T_SERIAL_METHOD = SoftwareSerial; T_NOTIFICATION_METHOD = Mp3Notify; T_CHIP_VARIANT = Mp3ChipOriginal]':
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:395:29: required from 'bool DFMiniMp3::abateNotification() [with T_SERIAL_METHOD = SoftwareSerial; T_NOTIFICATION_METHOD = Mp3Notify; T_CHIP_VARIANT = Mp3ChipOriginal]'
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:71:33: required from 'void DFMiniMp3::loop() [with T_SERIAL_METHOD = SoftwareSerial; T_NOTIFICATION_METHOD = Mp3Notify; T_CHIP_VARIANT = Mp3ChipOriginal]'
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:445:13: required from 'void DFMiniMp3::drainResponses() [with T_SERIAL_METHOD = SoftwareSerial; T_NOTIFICATION_METHOD = Mp3Notify; T_CHIP_VARIANT = Mp3ChipOriginal]'
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:539:27: required from 'DFMiniMp3::reply_t DFMiniMp3::retryCommand(uint8_t, uint8_t, uint16_t, bool) [with T_SERIAL_METHOD = SoftwareSerial; T_NOTIFICATION_METHOD = Mp3Notify; T_CHIP_VARIANT = Mp3ChipOriginal; uint8_t = unsigned char; uint16_t = unsigned int]'
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:571:21: required from 'void DFMiniMp3::setCommand(uint8_t, uint16_t) [with T_SERIAL_METHOD = SoftwareSerial; T_NOTIFICATION_METHOD = Mp3Notify; T_CHIP_VARIANT = Mp3ChipOriginal; uint8_t = unsigned char; uint16_t = unsigned int]'
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:170:19: required from 'void DFMiniMp3::setVolume(uint8_t) [with T_SERIAL_METHOD = SoftwareSerial; T_NOTIFICATION_METHOD = Mp3Notify; T_CHIP_VARIANT = Mp3ChipOriginal; uint8_t = unsigned char]'
    E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:66:19: required from here
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:406:50: error: no matching function for call to 'Mp3Notify::OnPlayFinished(DFMiniMp3&, DfMp3_PlaySources, uint16_t&)'
    T_NOTIFICATION_METHOD::OnPlayFinished(*this, DfMp3_PlaySources_Usb, reply.arg);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:29:15: note: candidate: static void Mp3Notify::OnPlayFinished(uint16_t)
    E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:29:15: note: candidate expects 1 argument, 3 provided
    In file included from E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:9:0:
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:410:50: error: no matching function for call to 'Mp3Notify::OnPlayFinished(DFMiniMp3&, DfMp3_PlaySources, uint16_t&)'
    T_NOTIFICATION_METHOD::OnPlayFinished(*this, DfMp3_PlaySources_Sd, reply.arg);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:29:15: note: candidate: static void Mp3Notify::OnPlayFinished(uint16_t)
    E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:29:15: note: candidate expects 1 argument, 3 provided
    In file included from E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:9:0:
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:414:50: error: no matching function for call to 'Mp3Notify::OnPlayFinished(DFMiniMp3&, DfMp3_PlaySources, uint16_t&)'
    T_NOTIFICATION_METHOD::OnPlayFinished(*this, DfMp3_PlaySources_Flash, reply.arg);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:29:15: note: candidate: static void Mp3Notify::OnPlayFinished(uint16_t)
    E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:29:15: note: candidate expects 1 argument, 3 provided
    In file included from E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:9:0:
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:418:54: error: 'OnPlaySourceOnline' is not a member of 'Mp3Notify'
    T_NOTIFICATION_METHOD::OnPlaySourceOnline(*this, static_cast(reply.arg));
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:422:56: error: 'OnPlaySourceInserted' is not a member of 'Mp3Notify'
    T_NOTIFICATION_METHOD::OnPlaySourceInserted(*this, static_cast(reply.arg));
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:426:55: error: 'OnPlaySourceRemoved' is not a member of 'Mp3Notify'
    T_NOTIFICATION_METHOD::OnPlaySourceRemoved(*this, static_cast(reply.arg));
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    c:\Users\valer\OneDrive\���������\Arduino\libraries\DFPlayer_Mini_Mp3_by_Makuna\src/DFMiniMp3.h:430:43: error: no matching function for call to 'Mp3Notify::OnError(DFMiniMp3&, uint16_t&)'
    T_NOTIFICATION_METHOD::OnError(*this, reply.arg);
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~
    E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:22:15: note: candidate: static void Mp3Notify::OnError(uint16_t)
    E:\adruino\поворотники\CANbus_reciever_cobalt_r4\CANbus_reciever_cobalt_r4.ino:22:15: note: candidate expects 1 argument, 2 provided

    exit status 1

    Compilation error: exit status 1

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *