Підключення та опанування CAN-шини, за допомогою MCP2515 до STM32, ARDUINO, ESP 32
Сьогодні робототехніка в Україні перестала бути просто інженерним захопленням чи комерційним напрямком. Це питання нашої технологічної переваги та, без перебільшення, питання виживання. Створюючи сучасні роботизовані системи, ми неминуче стикаємося з необхідністю об’єднати десятки датчиків, приводів та контролерів у єдиний організм. І тут на допомогу приходить CAN (Controller Area Network) — надійний «хребет» промислових та оборонних систем.
Але тут криється підступна пастка для початківців. Часто CAN сприймають як готове рішення «під ключ», забуваючи, що це лише транспортний протокол.
Шина CAN відповідає за те, щоб пакет даних фізично дійшов від точки А до точки Б, не загубившись у шумі та завадах. Але те, що саме всередині цього пакету — це вже питання «словника». Саме тут починаються відмінності: чи це CANopen, чи J1939, чи специфічний кастомний протокол виробника вашого сервоприводу. Кожен пристрій на шині може говорити «різними діалектами», і саме вмінню налаштувати «перекладача» між Мікроконтролером та периферією буду присвячувати багато статей на нашому сайті.
В цій статті я хочу сугубо описати підключення модуля на базі мікросхеми MCP2515 до мікроконтролера, для приклада взята STM32U585Cx Core Board без вбудованого апаратного CAN. Бо тема CAN це дуже велика і неможливе все охопити в одній статті.
Модуль MCP2515 спілкується з мікроконтролером через інтерфейс SPI (Serial Peripheral Interface
Варіант підключення
| Пін MCP2515 | Пін STM32 | Опис |
|---|---|---|
| VCC | 5V | Живлення модуля (5 вольт) |
| GND | G (GND) | "Земля" (спільний мінус) |
| CS | PA4 | Chip Select (активація модуля) |
| SO | PA6 | MISO (Master In Slave Out) |
| SI | PA7 | MOSI (Master Out Slave In) |
| SCK | PA5 | Serial Clock (тактовий сигнал) |
| INT | PB0 | Interrupt (переривання) |

Як працює "перекладач" (Схема передачі даних)
- STM32 (Майстер) "спілкується" з MCP2515 (Контролером) виключно через інтерфейс SPI. Мікроконтролер відправляє сюди "сирі" дані, які хоче надіслати в CAN-шину, а також команди налаштування.
- MCP2515 — це "мозок" модуля. Він бере дані з SPI, самостійно "запаковує" їх у стандартний CAN-фрейм (додає ID повідомлення, контрольні суми, біти підтвердження), стежить за таймінгами та чергою.
- CAN-трансивер (друга маленька мікросхема на платі, наприклад, TJA1050) отримує від MCP2515 логічні сигнали й перетворює їх на фізичну різницю напруг для дротів CAN-High та CAN-Low.
Що таке SPI?
SPI (Serial Peripheral Interface) — це послідовний синхронний протокол передачі даних.
Його часто називають "стандартом швидкості", оскільки він дозволяє мікроконтролеру спілкуватися з периферією набагато швидше, ніж, наприклад, через інтерфейс I2C чи UART.
Ключові особливості:
- Синхронність: Передача даних відбувається під диригуванням тактового сигналу (Clock). Це означає, що STM32 і MCP2515 завжди знають, в який момент часу "ловити" біт даних.
- Full-Duplex (Повнодуплекс): Пристрій може одночасно відправляти та приймати дані. Це як розмова, де ви можете одночасно і говорити, і слухати.
4 основні лінії зв'язку
Щоб зрозуміти SPI, достатньо запам'ятати 4 дроти, які з'єднують ваш STM32 та MCP2515:
- SCK (Serial Clock): "Серцебиття" системи. Його генерує Майстер (STM32). Він каже: "Зараз передаємо біт номер один... тепер номер два...". Без нього передача неможлива.
- MOSI (Master Out, Slave In): "Дорога в один бік". По цьому дроту STM32 надсилає команди та дані в MCP2515.
- MISO (Master In, Slave Out): "Дорога назад". По цьому дроту модуль MCP2515 відправляє відповіді та зчитані з CAN-шини повідомлення назад до STM32.
- CS (Chip Select) / SS (Slave Select): "Пін уваги". Оскільки на одній лінії SPI можуть висіти декілька пристроїв, цей пін каже модулю: "Гей, MCP2515, слухай мене, я зараз буду з тобою працювати". Коли рівень напруги на цьому піні падає (активний низький рівень), модуль "прокидається" і починає слухати SPI.
Приклад коду: Базова взаємодія STM32 з MCP2515 через SPI
Щоб надіслати дані, ми повинні зробити три речі: вибрати модуль (CS LOW), відправити дані по SPI, і відпустити модуль (CS HIGH).
Приклад коду
/* * Функція для відправки даних до MCP2515
* Використовуємо PA4 як Chip Select (CS) згідно з нашою схемою.
*/
void MCP2515_Transmit(uint8_t *data, uint16_t size) {
// 1. Опускаємо CS в 0, щоб активувати модуль MCP2515
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
// 2. Відправляємо дані через апаратний SPI
// hspi1 - це дескриптор вашого SPI, налаштований у CubeIDE
HAL_SPI_Transmit(&hspi1, data, size, 100);
// 3. Піднімаємо CS в 1, щоб завершити передачу
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
}
Chip Select (CS): Ми вручну керуємо піном PA4, тому що протокол SPI вимагає "окремого запрошення" до кожного пристрою. Поки пін PA4 знаходиться у стані RESET (низький рівень), модуль MCP2515 "слухає" наші команди.
- HAL_SPI_Transmit: Це стандартна функція HAL, яка автоматично керує тактовим сигналом (SCK) та лінією даних (MOSI), щоб відправити байт у модуль.
- Важливо: Оскільки STM32U585 не має апаратного CAN-контролера, цей код — це "фундамент". Для повноцінної роботи з шиною CAN (з протоколами CANopen або J1939) я рекомендую використовувати готову бібліотеку-драйвер для MCP2515 (наприклад, порти для STM32), яка вже містить функції
MCP2515_Init()таMCP2515_SendMessage().
Рівень вище: Використання бібліотеки
Тепер, коли ми розуміємо, як працює SPI, давайте подивимось, як виглядає реальна відправка повідомлення в CAN-шину. Щоб не винаходити велосипед, ми використовуємо бібліотеку (наприклад, портовану MCP2515 для STM32). Вона бере на себе всю "магію" налаштування швидкості шини (Bitrate), фільтрів та черги повідомлень.
Приклад коду відправки повідомлення
#include "mcp2515.h" // Підключаємо заголовний файл бібліотеки
#include "spi.h" // Ваші налаштування SPI (HAL)
// Структура повідомлення CAN
struct can_frame canMsg;
void CAN_Send_Example(void) {
// 1. Налаштування ідентифікатора (ID) повідомлення
// Це адреса "отримувача" або тип повідомлення в шині
canMsg.can_id = 0x123;
// 2. Налаштування довжини даних (DLC - Data Length Code)
// CAN шина передає від 0 до 8 байт даних
canMsg.can_dlc = 8;
// 3. Заповнення масиву даних (наприклад, показання сенсора)
canMsg.data[0] = 0xDE;
canMsg.data[1] = 0xAD;
canMsg.data[2] = 0xBE;
canMsg.data[3] = 0xEF;
canMsg.data[4] = 0x00;
canMsg.data[5] = 0x00;
canMsg.data[6] = 0x00;
canMsg.data[7] = 0x01; // Наприклад, стан реле
// 4. Відправка повідомлення в шину
if (MCP2515_SendMessage(&canMsg) == MCP2515_OK) {
// Повідомлення успішно поставлено в чергу на відправку
} else {
// Помилка відправки (можливо, шина переповнена)
}
}
Поясню три критичні елементи структури can_frame:
can_id(Ідентифікатор): Це найважливіша частина. В CAN-шині немає "адрес" у звичному розумінні (як в I2C). Тут є пріоритети. Чим менше число ID, тим вищий пріоритет у повідомлення. Якщо два пристрої почнуть говорити одночасно, шина віддасть перевагу тому, у кого менший ID.can_dlc: Стандарт CAN жорстко обмежує розмір даних — максимум 8 байт на одне повідомлення. Якщо вам треба передати більше (наприклад, великий масив), вам доведеться розбивати дані на кілька повідомлень або використовувати протоколи вищого рівня (як CANopen).MCP2515_SendMessage: Це функція, яка ховає всередині себе складний алгоритм SPI-обміну. Вона сама "смикає" пін CS, передає команду запису в буфер модуля, і чекає підтвердження від контролера.
Дякую що звернули увагу на мою статтю якщо вам подобається такий контент, буду вдячний за репости моїх статей у ваші соціальні ресурси. Також прошу залишати коменти під нашими статтями.
Коментарі (0)
Наразі немає коментарів. Будьте першим!
Залишити коментар