Отправка и чтение состояния кнопки по шине CAN с помощью Arduino

Я собираюсь прочитать изменение ввода кнопки, используя 2 отдельных Arduino, подключенных через шину CAN (MP2515). Передатчик подключается к кнопке с внутренним подтягивающим резистором, этот контакт будет действовать как внешнее прерывание. Моя ссылка исходит от здесь. Не присваивая какое-либо значение фрейму данных (canMsg1 и canMsg2 в приведенном ниже коде), достаточно ли этого для получателя, чтобы понять состояние входного контакта?

Исходный код, использующий digitalRead(pin) для чтения и последующей записи состояния кнопки одним Arduino.

передатчик CAN массажа

#include <SPI.h>
#include <mcp2515.h>

struct can_frame canMsg1;
struct can_frame canMsg2;

MCP2515 mcp2515(10);

int incPin(2);
int decPin(3);
unsigned long current_time = 0;
unsigned long previous_time = 0;

void setup() {
  Serial.begin(9600);
  SPI.begin();

  mcp2515.reset();
  mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ);
  mcp2515.setNormalMode();
  
  canMsg1.can_id = 0xAA;
  canMsg1.can_dlc = 1;
  canMsg2.can_id = 0xBB
  canMsg2.can_dlc = 1;

  pinMode(incPin, INPUT_PULLUP);
  pinMode(decnPin, INPUT_PULLUP);

  attachInterrupt(incpPin, inc, FALLING);
  attachInterrupt(decPin, dec, FALLING);              
}

void loop() {}

void inc() {
  current_time = millis();
  if (current_time - previous_time > 200) { //debouncing for 0.2s
    mcp2515.sendMessage(&canMsg1);
  }
  previous_time = current_time;
}

void dec() {
  current_time = millis();
  if (current_time - previous_time > 200) { //debouncing for 0.2s
    mcp2515.sendMessage(&canMsg2);
  }
  previous_time = current_time;
}

приемник/считыватель CAN-сообщений

#include <SPI.h>
#include <mcp2515.h>

struct can_frame canMsg1;
struct can_frame canMsg2;

MCP2515 mcp2515(10);

int pos = 0;
int up;
int down;

void setup() {
  Serial.begin(9600);
  SPI.begin();

  mcp2515.reset();
  mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ);
  mcp2515.setNormalMode();      
}

void loop() {
  if (mcp2515.readMessage(&canMsg1) == MCP2515::ERROR_OK) { //read CAN increment button message
    if (canMsg1.can_id==0xAA) {
      up = canMsg1.data[0];
      if (up == LOW) {
        pos++;
      } else {}
    }      
  }

  if (mcp2515.readMessage(&canMsg2) == MCP2515::ERROR_OK) { //read CAN decrement button message
    if (canMsg2.can_id==0xBB) {
      down = canMsg2.data[0];
      if (down == LOW) {
        pos--;
      } else {}
    }      
  }
}

Что касается части кнопки, это не рекомендуется. Устранение дребезга кнопки с помощью прерывания является более сложным, чем обычное устранение дребезга (если у вас нет внешних аппаратных фильтров).

Lundin 24.01.2023 10:17

Вместо настройки аппаратного обеспечения, могу ли я просто вместо этого вызвать другую функцию из прерывания для устранения дребезга и отправить canMsg? Я предполагаю, что ISR должны быть как можно короче (?)

Ktray 24.01.2023 10:32

Вы получите прерывание за отскок, что является проблемой. Вот пример того, как это можно сделать: stackoverflow.com/a/32647699/584518 . Но это излишне сложно и, следовательно, плохой дизайн. Профессиональные разработки используют периодические таймеры, которые считывают GPIO, например: stackoverflow.com/a/54900591/584518. Опционально с цифровыми фильтрами (медианные фильтры и т.д.).

Lundin 24.01.2023 10:38
5 дизайнов темных кнопок с использованием HTML и CSS
5 дизайнов темных кнопок с использованием HTML и CSS
Здесь представлены пять дизайнов темных кнопок с кодом с использованием HTML и CSS:
0
3
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы правы, ваши события CAN не требуют никаких данных. Но тогда почему вы устанавливаете can_dlc в 1? Нет данных 0 байт.

Вы можете попробовать это:

Избавляться от:

struct can_frame canMsg1;  // these only hog global memory for no practical use.
struct can_frame canMsg2;

Измените свои процедуры прерывания на:

void inc() {
  current_time = millis();
  if (current_time - previous_time > 200) { //debouncing for 0.2s
    mcp2515.beginPacket(0xAA);
    mcp2515.endPacket();
  }
  previous_time = current_time;
}

void dec() {
  current_time = millis();
  if (current_time - previous_time > 200) { //debouncing for 0.2s
    mcp2515.beginPacket(0xBB);
    mcp2515.endPacket();
  }
  previous_time = current_time;
}

Я не мог понять, что такое canMsg7 и canMsg8. И почему вам нужно несколько структур сообщений в глобальной памяти для получения одного сообщения CAN за раз ... Я действительно не думаю, что это необходимо. Поскольку в ваших пакетах нет данных, получение также упрощается:

int loop() {
    if (mcp2515.parsePacket() != 0) {  // != 0 => we have fully received a packet.
        switch (mcp2515.packetId()) {
           case 0xAA:
               // inc switch was pressed
               // ...
               break;

           case 0xBB:
               // dec switch was pressed
               // ...
               break;
        }
    }
}

Спасибо за указание на canMsg7 и canMsg8, это должно быть canMsg1/2, мой плохой лол. Кроме того, я немного потерялся здесь, особенно beginPacket и endPacked. Не могли бы вы обратиться к какой-нибудь ссылке об этом?

Ktray 24.01.2023 09:54

Документация по API находится здесь: github.com/sandeepmistry/arduino-CAN/blob/master/API.md. Это API, который я использовал. Он прост в использовании: beginPacket(id); write(); по мере необходимости, затем endPacket(); отправляет все это.

Michaël Roy 24.01.2023 11:29

Другие вопросы по теме