You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于CAN总线(MCP2515)的双Arduino按钮状态传输问题咨询

问题描述

我计划用两台通过CAN总线(MCP2515模块)连接的Arduino检测按钮输入变化。发射端按钮使用内部下拉电阻,引脚设为外部中断。目前发射端代码未给CAN数据帧canMsg1和canMsg2的data字段赋值,想知道接收端能否通过这类消息识别输入引脚的状态?


发射端代码(原代码含笔误,已标注修正点)

#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(decPin, INPUT_PULLUP); // 原代码写为decnPin,已修正

  // 原代码直接用引脚号,建议用digitalPinToInterrupt适配不同Arduino板型
  attachInterrupt(digitalPinToInterrupt(incPin), inc, FALLING); 
  attachInterrupt(digitalPinToInterrupt(decPin), dec, FALLING);              
}

void loop() {}

void inc() {
  current_time = millis();
  if (current_time - previous_time > 200) { // 200ms消抖
    mcp2515.sendMessage(&canMsg1);
  }
  previous_time = current_time;
}

void dec() {
  current_time = millis();
  if (current_time - previous_time > 200) { // 200ms消抖
    mcp2515.sendMessage(&canMsg2);
  }
  previous_time = current_time;
}

接收端代码(原代码优化版)

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

struct can_frame canMsg; // 无需定义两个帧,用一个变量接收所有消息

MCP2515 mcp2515(10);

int pos = 0;

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

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

void loop() {
  if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {
    switch(canMsg.can_id) {
      case 0xAA:
        pos++;
        Serial.print("当前pos值:");
        Serial.println(pos);
        break;
      case 0xBB:
        pos--;
        Serial.print("当前pos值:");
        Serial.println(pos);
        break;
      default:
        break;
    }
  }
}

解答

核心结论

当前代码无法让接收端可靠识别引脚状态,原因如下:

  1. 发射端未初始化canMsg1.data和canMsg2.data字段,发送的是内存随机值,接收端读取到的data[0]完全不确定,无法对应引脚的LOW/HIGH状态。
  2. 原接收端依赖data[0] == LOW触发逻辑,但随机值可能偶然满足条件导致误触发,也可能永远不满足导致功能失效。

修正方案

发射端修改:明确赋值数据帧

在发送消息前,给data字段赋予明确的状态值,比如直接发送按钮按下时的LOW状态:

void inc() {
  current_time = millis();
  if (current_time - previous_time > 200) {
    canMsg1.data[0] = LOW; // 明确标记按钮按下状态
    mcp2515.sendMessage(&canMsg1);
  }
  previous_time = current_time;
}

void dec() {
  current_time = millis();
  if (current_time - previous_time > 200) {
    canMsg2.data[0] = LOW;
    mcp2515.sendMessage(&canMsg2);
  }
  previous_time = current_time;
}

也可以读取实时引脚状态发送:canMsg1.data[0] = digitalRead(incPin);,不过因为是下降沿中断触发,此时引脚状态必然是LOW,直接赋值更高效。

接收端适配

如果保留原接收端的data[0]判断逻辑,只需确保接收逻辑与发送端的赋值对应即可;如果仅通过can_id区分按钮动作(比如0xAA对应加、0xBB对应减),则可以完全忽略data字段,如优化后的接收端代码所示,逻辑更简洁。


内容的提问来源于stack exchange,提问作者Ktray

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 06:05:23