Arduino 开发ESP32的CAN波特率1Mbps

5 篇文章 0 订阅
2 篇文章 0 订阅

CAN通信

CAN简介

CAN 是一种异步半双工的通讯方式,是由CAN_High和CAN_Low两条信号线,这两条线共同构成一组差分信号线,以差分信号的形式通讯,CAN的物理层特性主要分为闭环总线和开环总线网络两种,前者适用高速通讯,后者适用远距离传输。
在这里插入图片描述CAN_High - CAN_Low <0.5V时候为隐性的,逻辑信号表示为“逻辑1”(高电平)
CAN_High - CAN_Low >0.9V时候为显性的,逻辑信号表示为“逻辑0”(低电平)

下面看代码:

#include <CAN.h>

void setup() 
{
  Serial.begin(9600);
  while (!Serial);

  Serial.println("CAN Sender");

  // start the CAN bus at 1 Mbps
  if (!CAN.begin(1000E3)) 
  {
    Serial.println("Starting CAN failed!");
  }
}

void loop() 
{
  // send packet: id is 11 bits, packet can contain up to 8 bytes of data
  Serial.print("Sending packet ... ");

  CAN.beginPacket(0x12);
  CAN.write('h');
  CAN.write('e');
  CAN.write('l');
  CAN.write('l');
  CAN.write('o');
  CAN.endPacket();

  Serial.println("done");

  delay(1000);

  // send extended packet: id is 29 bits, packet can contain up to 8 bytes of data
  Serial.print("Sending extended packet ... ");

  CAN.beginExtendedPacket(0xabcdef);
  CAN.write('w');
  CAN.write('o');
  CAN.write('r');
  CAN.write('l');
  CAN.write('d');
  CAN.endPacket();

  Serial.println("done");

  delay(1000);
}

使用的时候会发现一个问题,实际波特率只有配置的一半,即配置500Kbps,实际CAN的速率只有250Kbps,配置1M的bps,实际速率只有500kbps。

但是现在需要1MCAN速率,怎么办呢?
有办法,因为实际速率是配置速率的一半,所以如果要让实际速率是1Mbps,只需要配置2M的波特率不就行了吗?
答案是否定的,因为配置速率超过1M。CAN的配置就失败了。那怎么办呢?
有办法,造成这个问题的情况有两种,一种就是ESP32的CAN控制器最高只能到500bps,所以才会有实际速率是配置的一半。但是手册上写的最高能到1M,所以应该不是CAN控制器的问题。那么就是底层代码的问题,还好是开源代码,所以我们之间去修改底层代码

int ESP32SJA1000Class::begin(long baudRate)
{
  CANControllerClass::begin(baudRate);

  _loopback = false;

  DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_CAN_RST);
  DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_CAN_CLK_EN);

  // RX pin
  gpio_set_direction(_rxPin, GPIO_MODE_INPUT);
  gpio_matrix_in(_rxPin, CAN_RX_IDX, 0);
  gpio_pad_select_gpio(_rxPin);

  // TX pin
  gpio_set_direction(_txPin, GPIO_MODE_OUTPUT);
  gpio_matrix_out(_txPin, CAN_TX_IDX, 0, 0);
  gpio_pad_select_gpio(_txPin);

  modifyRegister(REG_CDR, 0x80, 0x80); // pelican mode
  modifyRegister(REG_BTR0, 0xc0, 0x40); // SJW = 1
  modifyRegister(REG_BTR1, 0x70, 0x10); // TSEG2 = 1

  switch (baudRate) {
    case (long)1000E3:
      modifyRegister(REG_BTR1, 0x0f, 0x04);
      modifyRegister(REG_BTR0, 0x3f, 4);
      break;

    case (long)500E3:
      modifyRegister(REG_BTR1, 0x0f, 0x0c);
      modifyRegister(REG_BTR0, 0x3f, 4);
      break;

    case (long)250E3:
      modifyRegister(REG_BTR1, 0x0f, 0x0c);
      modifyRegister(REG_BTR0, 0x3f, 9);
      break;

    case (long)200E3:
      modifyRegister(REG_BTR1, 0x0f, 0x0c);
      modifyRegister(REG_BTR0, 0x3f, 12);
      break;

    case (long)125E3:
      modifyRegister(REG_BTR1, 0x0f, 0x0c);
      modifyRegister(REG_BTR0, 0x3f, 19);
      break;

    case (long)100E3:
      modifyRegister(REG_BTR1, 0x0f, 0x0c);
      modifyRegister(REG_BTR0, 0x3f, 24);
      break;

    case (long)80E3:
      modifyRegister(REG_BTR1, 0x0f, 0x0c);
      modifyRegister(REG_BTR0, 0x3f, 30);
      break;

    case (long)50E3:
      modifyRegister(REG_BTR1, 0x0f, 0x0c);
      modifyRegister(REG_BTR0, 0x3f, 49);
      break;

    case (long)40E3:
      modifyRegister(REG_BTR1, 0x0f, 0x0c);
      modifyRegister(REG_BTR0, 0x3f, 62);
      break;

    case (long)20E3:
      modifyRegister(REG_BTR1, 0x0f, 0x0c);
      modifyRegister(REG_BTR0, 0x3f, 124);
      break;

    case (long)10E3:
      modifyRegister(REG_BTR1, 0x0f, 0x0c);
      modifyRegister(REG_BTR0, 0x3f, 249);
      break;

    default:
      return 0;
      break;
  }

  modifyRegister(REG_BTR1, 0x80, 0x80); // SAM = 1
  writeRegister(REG_IER, 0xff); // enable all interrupts

  // set filter to allow anything
  writeRegister(REG_ACRn(0), 0x00);
  writeRegister(REG_ACRn(1), 0x00);
  writeRegister(REG_ACRn(2), 0x00);
  writeRegister(REG_ACRn(3), 0x00);
  writeRegister(REG_AMRn(0), 0xff);
  writeRegister(REG_AMRn(1), 0xff);
  writeRegister(REG_AMRn(2), 0xff);
  writeRegister(REG_AMRn(3), 0xff);


  modifyRegister(REG_OCR, 0x03, 0x02); // normal output mode
  // reset error counters
  writeRegister(REG_TXERR, 0x00);
  writeRegister(REG_RXERR, 0x00);

  // clear errors and interrupts
  readRegister(REG_ECC);
  readRegister(REG_IR);

  // normal mode
  modifyRegister(REG_MOD, 0x08, 0x08);
  modifyRegister(REG_MOD, 0x17, 0x00);

  return 1;
}

即修改寄存器的值就可以实现波特率为1M的CAN。

要如何修改寄存器,则需要看手册

在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述
首先可以得出 TQ = 2*(BPR寄存器的值+1) / Fosc
TQ :时间量子
BPR寄存器:CAN预分频寄存器
Fosc:ESP32的APB时钟,通常为80MHz

CAN_baud = (SJW + PBS1 + PBS2 + SS + 1) * 2TQ
SS衡为1,无法通过寄存器修改

这个公式手册里面没有,是我一个寄存器值一个寄存器值去试然后推出了的,亲测没有问题。
这过程中遇到最大的问题就是,如果配置的波特率不是整数或者无限循环小数,则无效,所以当初找规律没找到,因为大部分值配出来都是无效波特率。后面根据333.3333…和666.666…可以正常使用,去根据寄存器的值反推才得到公式。

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值