CAN初始化

CAN的模式

  1. CAN主要有三种:初始化模式、正常模式和睡眠模式

CAN的初始化步骤

CAN基本外设初始化

CAN外设初始化主要是CAN通信中的配置,比如波特率、采样点等

当硬件处于初始化模式时,可以进行软件初始化。为进入该模式,软件将 CAN_MCR 寄存器的 INRQ 位置 1,并等待硬件通过将 CAN_MCR 寄存器的 INAK 位置 1 来确认请求。在初始化模式下,所有从 CAN 总线传入和传出的消息都将停止,并且 CAN 总线输出 CANTX的状态为隐性(高)。为初始化 CAN 控制器,软件必须设置位定时 (CAN_BTR) 和 CAN 选项 (CAN_MCR) 寄存器

CAN筛选器初筛化

筛选器主要是通过CAN报文的ID获取自己需要的报文

软件必须将 FINIT 位 (CAN_FMR) 置 1,才可以初始化筛选器相关寄存器。筛选器的初始化也可以在初始化模式之外进行(即使 CAN 正在正常通信,也可以重新配置筛选器筛选器必须处于激活状态,无法重新配置)。
注意:
FINIT=1 时, CAN 接收停用。筛选器值也可通过停用( CAN_FA1R 寄存器的)相关筛选器激活位来修改。如果某个筛选器组未使用,建议将其保持未激活状态(将相应 FACT 位保持清零)

CAN切换为正常模式

进入正常模式的请求可通过将 CAN_MCR 寄存器的 INRQ 位清零来发出。但是,CAN不是立即进入正常模式的,必须等待一个由 11 个连续隐性位(总线空闲状态)组成的序列,才可以进入正常模式。硬件通过将 CAN_MSR 寄存器的 INAK 位清零,来确认切换到正常模式。

示例代码

  1. 检查参数传入是否正确
  2. 使能CAN引脚、配置复用通道、使能CAN时钟

     CAN_RX_GPIO_CLK_ENABLE();   /* CAN_RX脚时钟使能 */
     CAN_TX_GPIO_CLK_ENABLE();   /* CAN_TX脚时钟使能 */
     sys_gpio_set(CAN_TX_GPIO_PORT, CAN_TX_GPIO_PIN,
                  SYS_GPIO_MODE_AF, SYS_GPIO_OTYPE_PP, SYS_GPIO_SPEED_HIGH, SYS_GPIO_PUPD_PU); 
     sys_gpio_set(CAN_RX_GPIO_PORT, CAN_RX_GPIO_PIN,
                  SYS_GPIO_MODE_AF, SYS_GPIO_OTYPE_PP, SYS_GPIO_SPEED_HIGH, SYS_GPIO_PUPD_PU);   
     sys_gpio_af_set(CAN_TX_GPIO_PORT, CAN_TX_GPIO_PIN, CAN_TX_GPIO_AF); 
     sys_gpio_af_set(CAN_RX_GPIO_PORT, CAN_RX_GPIO_PIN, CAN_RX_GPIO_AF); 
     RCC->APB1ENR |= 1 << 25;    /* 使能CAN时钟 CAN使用的是APB1的时钟(max: 42M) */
  3. 退出休眠,进行CAN初始化配置
    如果软件通过将 INRQ 位置 1 来请求进入初始化模式,则必须同时将 SLEEP 位清零。

     CAN1->MCR = 0x0000;         /* 退出睡眠模式(同时设置所有位为0) */
     CAN1->MCR |= 1 << 0;        /* 请求CAN进入初始化模式 */
     while ((CAN1->MSR & 1 << 0) == 0)   /* 等待进入初始化模式成功 */
     {
         i++;
    
         if (i > 100)            /* 进入初始化模式失败 */
         {
             return 2;
         }
     }
    
     CAN1->MCR |= 0 << 7;        /* 非时间触发通信模式 */
     CAN1->MCR |= 0 << 6;        /* 软件自动离线管理 */
     CAN1->MCR |= 0 << 5;        /* 睡眠模式通过软件唤醒(清除CAN1->MCR的SLEEP位) */
     CAN1->MCR |= 1 << 4;        /* 禁止报文自动传送 */
     CAN1->MCR |= 0 << 3;        /* 报文不锁定,新的覆盖旧的 */
     CAN1->MCR |= 0 << 2;        /* 优先级由报文标识符决定 */
     CAN1->BTR = 0;              /* 清除原来的设置. */
     CAN1->BTR |= mode << 30;    /* LBKM = mode, 模式设置  0, 普通模式; 1, 回环模式; */
     CAN1->BTR |= tsjw << 24;    /* SJW[1:0] = tsjw, 重新同步跳跃宽度(Tsjw)为 tsjw + 1 个时间单位 */
     CAN1->BTR |= tbs2 << 20;    /* TS2[2:0] = tbs2, Tbs2 = tbs2 + 1 个时间单位 */
     CAN1->BTR |= tbs1 << 16;    /* TS1[2:0] = tbs1, Tbs1 = tbs1 + 1 个时间单位 */
     CAN1->BTR |= brp << 0;      /* BRP[9:0] = brp, Fdiv = brp + 1 */
     
     /* 波特率: Fpclk1 / ((Tbs1 + Tbs2 + 1) * Fdiv) */
     CAN1->MCR &= ~(1 << 0);     /* 请求CAN退出初始化模式 */
    
     while ((CAN1->MSR & 1 << 0) == 1)
     {
         i++;
    
         if (i > 0XFFF0)
         {
             return 3;           /* 退出初始化模式失败 */
         }
     }
  4. 初始化筛选器

     /* 过滤器初始化, 这里只用到了过滤器0, 且不过滤任何ID */
     CAN1->FMR |= 1 << 0;        /* 过滤器组工作在初始化模式 */
     CAN1->FA1R &= ~(1 << 0);    /* 过滤器0不激活 */
     CAN1->FS1R |= 1 << 0;       /* 过滤器位宽为32位. */
     CAN1->FM1R |= 0 << 0;       /* 过滤器0工作在标识符屏蔽位模式 */
     CAN1->FFA1R |= 0 << 0;      /* 过滤器0关联到FIFO0 */
     CAN1->sFilterRegister[0].FR1 = 0X00000000;  /* 32位ID */
     CAN1->sFilterRegister[0].FR2 = 0X00000000;  /* 32位MASK */
     CAN1->FA1R |= 1 << 0;       /* 激活过滤器0 */
  5. 切换到正常模式

     CAN1->FMR &= 0 << 0;        /* 过滤器组进入正常模式 */
最后修改:2026 年 01 月 17 日
如果觉得我的文章对你有用,请随意赞赏