Подключение контроллера шины CAN MCP2515 к Arduino: схема и программа

Подключение контроллера шины CAN MCP2515 к Arduino: схема и программа ОБД2

Can scanner на arduino

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

Именно с ним я и начал все эксперименты. Собрал простую схему с этим шилдом и жидкокристаллическим двухстрочным экраном. Цель была — вывести на экран хоть какие-то данные. Перебирал различные библиотеки для работы с CAN шиной на Arduino (сразу скажу, что правильная и рабочая библиотека называется CAN-BUS Shield by Seeed Studio с заголовочным файлом mcp_can.h), поменял кварцевый резонатор на шилде на 16 МГц (изначально стоял 8 МГц) — данных не было.

На шилде установлены две микросхемы: контроллер CAN шины MCP2515 и драйвер CAN шины TJA1050. Почитав документацию и различные форумы, решил поменять TJA1050 на более каноничный драйвер MCP2551 и данные появились. Возможно TJA1050 была изначально неисправна, так как с её подключением двумя проводками ошибиться было очень сложно, к тому же я использовал OBD и DB9 разъёмы для подключения.

За пару часов был написан простой CAN scanner, который выводил на жидкокристаллический дисплей номер захваченного пакета, его ID и до 8 байтов данных этого пакета.

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

Начало было положено, надо переходить к более интересной реализации.

Can sniffer на arduino


Задача стояла достаточно простая:

С первыми двумя задачами я вообще не видел никаких проблем. Библиотека предоставляла прерывание при приёме очередного пакета данных и удобные функции для получения данных. А вот отправку данных в сторону компьютера решил сделать через библиотеку CyberLib, которая устраняет некоторые накладные расходы всей платформы Arduino, за счёт чего можно немного разгрузить процессор для обработки данных. Позже от этой библиотеки пришлось отказаться.

Для того, чтобы отправляемые данные корректно обрабатывались на стороне компьютера, перед каждой очередной порцией данных в поток вставляется префикс из четырёх байтов 0xAA55AA55 (почему-то вспомнились эти байты по последним двум байтам загрузочного сектора DOS, только они там были в другом порядке). Логика такая:

На этом программная часть в Arduino, на тот момент, была завершена. Позже она была значительно переделана, но общая концепция не поменялась.

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

Примерно в это же время прибыли более миниатюрные компоненты Arduino Nano и Mini CAN shield.

Я спроектировал небольшой корпус, распечатал его и разместил внутри все компоненты.

Снаружи с одной стороны OBD разъём, с другой — Mini USB. Внутри имеется переключатель для терминирующего резистора.

Can sniffer на pc с использованием wxwidgets

Набросал простую заготовку программы на C#, которая выводит в Grid получаемые данные. И пошёл проверять в автомобиль. Только пошёл не со своим ноутбуком, так как у него батарея давно приказала долго жить и использовался он как стационарный компьютер, а взял нетбук с очень слабым процессором.

То что я увидел… Я ничего не увидел. Оба ядра загружены на 100%, интерфейс приложения не реагирует. Но на моём компьютере, который всё-таки значительно шустрее нетбука, с генератором случайных пакетов приложение нормально работало и отображало данные.

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


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

Архитектурно программа состоит из двух потоков: интерфейсный и поток работы с последовательным портом. Никаких невероятно интересных алгоритмов не применялось. Код обильно снабжён комментариями и должен быть довольно понятен. Ссылка на исходники будет в конце статьи.

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

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

Далее мне захотелось всё-таки проверить, справляется ли последовательный порт с потоком данных. Для этого я на стороне Arduino добавил счётчики количества принятых пакетов и счетчик байтов в пакете. Эти счётчики отправляются на компьютер в пакете с идентификатором 0x000.

Программа при получении этих данных не выводит их в таблицу, а отображает в отдельных информационных полях сверху. Полученные результаты даже весьма понравились. В среднем принимается до 750 пакетов/с со скоростью до 9,5 кБ/с, а это где в районе до 80 кбит/с, что вполне по силам последовательному порту. Но всё равно, обмен данными настроен по умолчанию на 500 кбит/с, пусть лучше будет запас.

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

Код ошибки:  Что такое OBD2 разъем и как пользоваться адаптером системы диагностики автомобилей - полезные статьи на Автодромо

Записав всё это в журнал, можно потом спокойно сесть и посмотреть передаваемые данные. Для этого в журнал могут записываться даже ASCII текстовые данные. Так же можно выбирать тип файла, символ разделитель и настроить фильтр пакетов кликом в таблице по указанному идентификатору пакета и нажатию кнопки «Добавить ID в фильтр» (по умолчанию записываются все данные), если запись всех данных избыточна.

Именно тогда пришло осознание, что все приложения для телефона, которые производят всякую «диагностику» через связку ELM327 и телефон не общаются напрямую с CAN шиной автомобиля. Они всего лишь используют функционал диагностики OBD через CAN шину посредством обращения к CAN ID 0x7E0.

Обычно это адрес контроллера мотора (ЭБУ), ответ же от него приходит в пакете с идентификатором 0x7E8. А вот все остальные пакеты данных — это так называемый Vendor Specific и ни один производитель так просто их не раскроет (хотя есть пример: Ford выпустил SDK для своих автомобилей).

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

Звучит не очень понятно, но вот в связи с чем это делалось: обороты мотора приходят в пакете CAN ID 0x180, в первых двух байтах. Эти два байта дают некое слово, которое пропорционально оборотам. Если значение этого слова разделить на 8, то получатся текущие обороты.

Поэтому указывается множитель 0,125, как обратная величина от 8. Далее это слово визуализируется в графике с динамической подстройкой по амплитуде. В принципе, множитель можно искать в обратной последовательности: нашёл ячейки, которые по графику очень похожи на обороты мотора или ещё что-то искомое, после чего подгоняется множитель для получения действительных значений.

Ну а двоичное представление позволяет искать различные битовые индикаторы. Например поиск индикаторов указателей поворота сводится к тому, чтобы включить их и наблюдать какая ячейка начинает изменяться, в примере ниже это CAN ID 0x481 байт 2. После чего клик по ячейке приводит к отображению её двоичного значения в соответствующем поле, где уже видны переключающиеся младшие два бита (левый, правый и если вместе — аварийная сигнализация).

И напоследок мне понадобилось сделать отправку некоторых управляющих данных в CAN шину и посмотреть реакцию на эти команды. В программу на Arduino был добавлен код, который принимает данные со стороны компьютера и передаёт в CAN шину. Именно на этом этапе пришлось отказаться от CyberLib, так как у неё не было поддержки прерывания поступления данных в буфер последовательного порта.

В программе на компьютере добавил несколько текстовых полей, в которые можно ввести различные параметры и таблицу для просмотра ответа исполнительного устройства. В примере ниже показаны команды управления включить/отключить первую скорость вентилятора охлаждения (0x0A) и включить/отключить муфту кондиционера (0x0B).

Can модуль (контроллер шины can) mcp2515

Модуль MCP2515 включает в себя CAN контроллер MCP2515, который представляет собой высокоскоростной CAN приемопередатчик. Соединение модуля MCP2515 с микроконтроллером осуществляется с помощью интерфейса SPI, поэтому его легко подключить ко всем микроконтроллерам с данным интерфейсом.

Начинающим изучение CAN-шины целесообразно начинать именно с этого модуля ввиду его простоты и легкости подключения к большинству современных микроконтроллеров.

Основные технические характеристики модуля MCP2515:

  • включает в себя высокоскоростной CAN приемопередатчик TJA1050;
  • размеры модуля: 40×28mm;
  • управление по интерфейсу SPI с возможностью подключения к CAN-шине нескольких устройств;
  • кварцевый генератор на 8 МГц;
  • сопротивление на концах 120 Ом;
  • включает независимый ключ, светодиодный индикатор, индикатор мощности;
  • поддерживает скорости передачи данных до 1 Мбит/с;
  • низкий потребляемый ток в режиме ожидания;
  • возможность подключения до 112 устройств (узлов).

Назначение контактов (распиновка) CAN модуля MCP2515 представлено в следующей таблице.

Наименование контактаНазначение контакта
VCCконтакт питания 5 В
GNDобщий провод (земля)
CSSPI SLAVE select pin (Active low) (выбор ведомого)
SOSPI master input slave output lead
SISPI master output slave input lead
SCLKконтакт синхронизации SPI
INTконтакт прерывания MCP2515

В данном проекте мы будем передавать данные, считываемые с датчика температуры и влажности DHT11 платой Arduino Nano, плате Arduino Uno с помощью CAN модуля MCP2515.

Can шина

Описывать технические подробности CAN шины в деталях — удел документации. В данной статье достаточно знать, что она:

Полистав странички одного известного интернет магазина из поднебесной, я заказал несколько различных вариантов шилдов и пошёл изучать особенности электрических сигналов в автомобиле. Подопытным автомобилем выступил LADA Kalina Cross с 127-ым мотором и электронным блоком управления ИТЭЛМА М74.5 CAN.

Подключаюсь в диагностический разъём OBD (контакты 6 и 14) и смотрю осциллографом, что там имеется. После поворота ключа зажигания начинают бегать пакеты с амплитудой до 2,5 В. Ставлю паузу на осциллографе и смотрю на пакет.

Заметны стартовые и стоповые биты, какие-то данные в пакете. На тот момент я уже знал, что скорость передачи данных ожидается 500 кбит/с, как наиболее частая для моторной CAN шины. Длительность пакета получается около 230 мкс и перед пакетом наблюдается довольно большая пауза в передаче данных. Масштабирую время и вижу три пакета и паузы между ними.

Если сложить длительность передачи данных и паузу между пакетам получается, что передача одной порции данных занимает около 1 мс.

К чему я это всё вывожу? А вопрос чисто практический: хватит ли скорости последовательного порта для передачи всех данных? И исходя из увиденного, можно сделать вывод, что скорость 500 кбит/с развивается внутри пакета, который занимает примерно четверть времени на передачу.

Значит средняя скорость передачи будет вчетверо меньшей. На тот момент я ещё не располагал тестами скорости последовательного интерфейса Arduino и забегая вперёд скажу, что даже с самым распространённым преобразователем Serial to USB CH340 стабильно работает скорость в 2 Мбит/с.

Github – krufft/can-sniffer: can bus sniffer (arduino side)

CAN bus sniffer (Arduino side)

Видео, демонстрирующее работу проекта

8 509 просмотров

Инициализация can модуля mcp2515

Для установления соединения платы Arduino с модулем MCP2515 выполните следующую последовательность шагов. Но перед этим убедитесь в том, что указанная выше библиотека CAN MCP2515 установлена в вашу Arduino IDE.

Код ошибки:  Коды ошибок камаз 65115 евро 4

Шаг 1. Установите номер контакта, к которому подключена линия CS интерфейса SPI (10 по умолчанию).

Шаг 2. Установите скорость передачи и частоту кварцевого генератора.

Доступные скорости передачи:CAN_5KBPS, CAN_10KBPS, CAN_20KBPS, CAN_31K25BPS, CAN_33KBPS, CAN_40KBPS, CAN_50KBPS, CAN_80KBPS, CAN_83K3BPS, CAN_95KBPS, CAN_100KBPS, CAN_125KBPS, CAN_200KBPS, CAN_250KBPS, CAN_500KBPS, CAN_1000KBPS.

Доступные частоты кварцевого генератора:MCP_20MHZ, MCP_16MHZ, MCP_8MHZ

Шаг 3. Установите режимы.

Использование протокола can в arduino

Поскольку платы Arduino не имеют в своем составе встроенного CAN порта, то для реализации связи между ними по данному протоколу мы будем использовать внешние CAN модули MCP2515. Эти модули подключаются к плате Arduino по интерфейсу SPI.

Код программы для приемной части (arduino uno)

Краткие сведения о протоколе can

CAN (Controller Area Network – сеть контролеров) представляет собой протокол (стандарт) последовательной связи, разработанный для промышленных и автомобильных приложений. Это ориентированный на обмен сообщениями протокол, используемый для связи между множеством (несколькими) устройств.

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

CAN-сеть состоит из двух проводников (CAN High и CAN Low) и обеспечивает двунаправленную передачу данных. На практике под CAN-сетью обычно подразумевается сеть топологии “шина” с физическим уровнем в виде дифференциальной пары. Передача ведется кадрами, которые могут принимать все узлы сети. Для доступа к такой шине выпускаются специализированные микросхемы (модули) – драйверы CAN-шины.

Обычно скорость передачи по CAN-шине варьируется от 50 Кбит/с до 1 Мбит/с, а дальность связи лежит в диапазоне от 40 метров (на скорости 1 Мбит/с) до 1000 метров (на скорости 50 Кбит/с).

Необходимые компоненты

  1. Плата Arduino Uno (купить на AliExpress).
  2. Плата Arduino Nano (купить на AliExpress).
  3. Датчик температуры и влажности DHT11 (купить на AliExpress).
  4. ЖК дисплей 16х2 (купить на AliExpress).
  5. MCP2515 CAN Module (контроллер шины CAN MCP2515) – 2 шт. (купить на AliExpress).
  6. Потенциометр 10 кОм (купить на AliExpress).
  7. Макетная плата.
  8. Соединительные провода.

Объяснение программы для передающей части (arduino nano)

В передающей части к плате Arduino Nano подключен CAN модуль MCP2515 по интерфейсу SPI, а данные температуры и влажности, считываемые с датчика DHT11, передаются далее по CAN-шине.

Первым делом в программе подключим необходимые библиотеки: библиотеку SPI для использования интерфейса SPI, библиотеку MCP2515 для использования связи с помощью протокола CAN и библиотеку DHT для работы с датчиком DHT11. Ранее на нашем сайте мы уже рассматривали подключение датчика DHT11 к плате Arduino.

Дадим название контакту, к которому подключен датчик DHT11 – это контакт A0 платы Arduino Nano.

Также определим DHTTYPE как DHT11.

Определим переменную canMsg типа данных структура для хранения сообщений CAN формата.

Установим номер контакта, к которому подключена линия CS интерфейса SPI (10 по умолчанию).

Также создадим объект dht класса DHT с параметрами DHT pin и DHTTYPE.

В функции void setup():

Инициализируем связь по протоколу SPI.

Начнем считывание данных температуры и влажности с датчика DHT11.

Сбросим в исходное состояние (RESET) модуль MCP2515 с помощью следующей команды:

Установим для модуля MCP2515 скорость передачи 500 кбит/с и частоту кварцевого генератора 8 МГц.

Установим модуль MCP2525 в обычный режим (normal mode).

В функции void loop():

Считаем значения температуры и влажности с датчика DHT11 и сохраним их в переменных целого типа h и t.

Далее установим идентификатору (CAN ID) значение 0x036 (на ваш выбор), DLC (длина поля данных) присвоим значение 8 (8 байт), запишем значения температуры и влажности в поля данных data[0]  и data[1], в остальные поля данных запишем значения 0.

Код ошибки:  Коды ошибок Toyota — Расшифровка. Симптомы. Причины.

После всего этого передадим сообщение по CAN-шине с помощью команды:

После выполнения этой команды значения температуры и влажности передадутся в виде сообщения по CAN-шине.

Объяснение программы для приемной части (arduino uno)

В приемной части нашего проекта к плате Arduino Uno подключены модуль MCP2515 и ЖК дисплей 16х2. Здесь плата Arduino Uno принимает значения температуры и влажности по CAN шине и отображает их на экране ЖК дисплея 16х2.

Первым делом в программе подключим используемые библиотеки: библиотеку SPI для использования интерфейса SPI, библиотеку MCP2515 для использования связи с помощью протокола CAN и библиотеку LiquidCrsytal для работы с ЖК дисплеем 16х2.

Далее сообщим плате Arduino, к каким ее контактам подключен ЖК дисплей 16х2.

Определим переменную canMsg типа данных структура для хранения сообщений CAN формата.

Установим номер контакта, к которому подключена линия CS интерфейса SPI (10 по умолчанию).

В функции void setup ():

Установим ЖК дисплей в режим работы 16×2 и отобразим на его экране приветственное сообщение.

Инициализируем связь по протоколу SPI.

Сбросим в исходное состояние (RESET) модуль MCP2515 с помощью следующей команды:

Установим для модуля MCP2515 скорость передачи 500 кбит/с и частоту кварцевого генератора 8 МГц.

Установим модуль MCP2525 в обычный режим (normal mode).

В функции void loop():

Следующая команда (с использованием оператора условия If) используется для приема сообщения из CAN-шины.

Если записанное условие if выполняется, данные принимаются и сохраняются в переменной canMsg, поле data [0] этой переменной будет содержать значение влажности, а поле data [1] – значение температуры. Мы будем сохранять эти значения в переменных целого типа (integer) x и y.

После успешного приема значений температуры и влажности мы выводим их на экран ЖК дисплея.

Применения can протокола

  1. В связи с чрезвычайно высокой надежностью и устойчивостью CAN протокола он широко применяется в автомобилях, промышленных механизмах, сельском хозяйстве, медицинском оборудовании и т.д.
  2. В связи с небольшим количеством используемых проводников CAN протокол исключительно удобен для применения в автомобилях.
  3. Устройства на основе CAN протокола отличаются низкой стоимостью.
  4. В CAN-сеть (шину) легко добавлять и удалять новые устройства.

Проводники, используемые в can

CAN протокол работает по двум проводникам, именуемыми CAN_H и CAN_L, для передачи и приема информации. Оба проводника работают как дифференциальная линия, что означает что CAN сигнал (0 или 1) представляет собой разность потенциалов между CAN_L и CAN_H.

Обычно в протоколе CAN используется кабель с витыми жилами. Как показано на выше приведенном рисунке, на обоих концах CAN-сети включается 120-омный резистор для обеспечения баланса в линии.

Сравнение can с spi и i2c

На нашем сайте мы ранее уже рассматривали использование в платах Arduino протоколов SPI и I2C, поэтому давайте сравним данные протоколы с протоколом CAN.

ПараметрSPII2CCAN
Скорость3-10 Мбит/сстандарт: 100 Кбит/с;

быстрый: 400 Кбит/с;

быстрый: 3,4 Мбит/с;

10 Кбит/с – 1 Мбит/с (зависит от длины используемых проводов)
Типсинхронныйсинхронныйасинхронный
Число проводов3 (MISO, MOSI, SCK, SS1, SS2…SS(n))
Дуплексполный дуплексполудуплексполудуплекс

По скорости стандарт CAN не в лидерах, но его главным “козырем” является высокая надежность связи.

Схема проекта

Схема проекта для связи между двумя платами Arduino с помощью протокола CAN и модулей MCP2515 представлена на следующем рисунке.

Соединения на передающей стороне:

Компонент – контактArduino Nano
MPC2515 – VCC 5V
MPC2515 – GNDGND
MPC2515 – CSD10 (SPI_SS)
MPC2515 – SOD12 (SPI_MISO)
MPC2515 – S ID11 (SPI_MOSI)
MPC2515­ – SCKD13 (SPI_SCK)
MPC2515 – INTD2
DHT11 – VCC 5V
DHT11 – GNDGND
DHT11­ – OUTA0

Соединения на приемной стороне:

Компонент – контактArduino Uno
MPC2515 – VCC 5V
MPC2515 – GNDGND
MPC2515 – CS10 (SPI_SS)
MPC2515 – SO12 (SPI_MISO)
MPC2515 – SI11 (SPI_MOSI)
MPC2515 – SCK13 (SPI_SCK)
MPC2515 – INT2
LCD (ЖК дисплей) – VSSGND
LCD – VDD 5V
LCD – V0к среднему контакту потенциометра 10 кОм
LCD – RS3
LCD – RWGND
LCD – E4
LCD – D45
LCD – D56
LCD – D67
LCD – D78
LCD – A 5V
LCD – KGND

Соединения между двумя CAN модулями MCP2515:

H – CAN HighL – CAN Low

MCP2515 (Arduino Nano)MCP2515 (Arduino UNO)
HH
LL

После сборки всей схемы на макетных платах у нас получилась следующая конструкция.

Тестирование работы проекта

После того, как аппаратная часть проекта будет готова, загрузите коды программы в платы Arduino в передающей и приемной частях проекта. После этого при подаче питания на схемы вы должны увидеть, как значения температуры и влажности, считанные одной платой Arduino с датчика DHT11, передаются по CAN-шине другой плате Arduino, которая выводит эти принятые значения на экран ЖК дисплея.

Формат can сообщений

В CAN-сети данные передаются в виде сообщений определенного формата. Этот формат состоит из большого числа сегментов, но двумя основными сегментами является идентификатор (identifier) и данные (data), которые и позволяют передавать и принимать сообщения по CAN-шине.

Идентификатор (Identifier) – также известен под именами CAN ID и PGN (Parameter Group Number). Он используется для идентификации CAN устройств в CAN-сети. Длина идентификатора составляет 11 или 29 бит в зависимости от того какой тип протокола CAN используется:

  • Standard (стандартный) CAN: 0-2047 (11-bit);
  • Extended (расширенный) CAN: 0-229-1 (29-bit).

Data – это данные, которые необходимо передать от одного устройства другому. Длина данных может составлять от 0 до 8 байт.

Data Length Code (DLC) (длина поля данных): может принимать значения от 0 до 8 в зависимости от количества байт для передачи.

Оцените статью
OBD
Добавить комментарий

Adblock
detector