1. CAN控制器初始化与位定时配置

CAN控制器初始化与位定时配置 学习卡片

任务目标

完成CAN控制器的基础初始化配置,包括:使能CAN外设时钟、配置位时序(波特率)、设置工作模式(正常模式/环回模式),并通过读取寄存器验证配置是否生效。本案例以STM32F407的bxCAN外设为例,使用标准外设库(SPL)实现。

环境依赖

  • 硬件:STM32F407开发板(板载CAN收发器TJA1050)
  • 软件:Keil MDK-ARM 5.x + STM32F4xx标准外设库
  • 连接:CAN_H/CAN_L接入CAN分析仪或双板互联

关键完整代码


#include "stm32f4xx.h"
#include "stm32f4xx_can.h"

// 引脚配置:PB8=RX, PB9=TX(复用功能AF9)
static void CAN_GPIO_Config(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_CAN1);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_CAN1);
}

// CAN初始化:波特率500kbps,正常模式
void CAN_Init_Config(void) {
    CAN_InitTypeDef CAN_InitStructure;
    CAN_FilterInitTypeDef CAN_FilterInitStructure;
    
    // 1. 使能CAN1时钟(APB1总线,时钟42MHz)
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
    CAN_GPIO_Config();
    
    // 2. CAN寄存器初始化
    CAN_DeInit(CAN1);
    CAN_StructInit(&CAN_InitStructure);
    
    // 3. 位时序配置:APB1=42MHz,500kbps
    //    BS1=9tq, BS2=6tq, Prescaler=3 → 42MHz/(3*(1+9+6))=500kHz
    CAN_InitStructure.CAN_TTCM = DISABLE;      // 时间触发关闭
    CAN_InitStructure.CAN_ABOM = ENABLE;       // 自动离线管理
    CAN_InitStructure.CAN_AWUM = ENABLE;       // 自动唤醒
    CAN_InitStructure.CAN_NART = DISABLE;      // 非自动重传
    CAN_InitStructure.CAN_RFLM = DISABLE;      // 接收FIFO非锁定
    CAN_InitStructure.CAN_TXFP = DISABLE;      // 发送优先级由标识符决定
    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;  // 正常模式
    CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;   // 同步跳转1tq
    CAN_InitStructure.CAN_BS1 = CAN_BS1_9tq;   // 时间段1 = 9tq
    CAN_InitStructure.CAN_BS2 = CAN_BS2_6tq;   // 时间段2 = 6tq
    CAN_InitStructure.CAN_Prescaler = 3;       // 预分频3
    CAN_Init(CAN1, &CAN_InitStructure);
    
    // 4. 滤波器配置:接收所有ID(屏蔽模式)
    CAN_FilterInitStructure.CAN_FilterNumber = 0;
    CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
    CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
    CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000;
    CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FIFO0;
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
    CAN_FilterInit(&CAN_FilterInitStructure);
}

// 验证函数:读取寄存器并返回配置状态
uint8_t CAN_Verify_Config(void) {
    uint8_t status = 0;
    
    // 检查CAN1是否已退出初始化模式(进入正常模式)
    if ((CAN1->MCR & CAN_MCR_INRQ) == 0) {
        status |= 0x01;  // Bit0: 初始化模式已退出
    }
    
    // 验证波特率寄存器:BS1=9, BS2=6, Prescaler=3
    uint32_t btr = CAN1->BTR;
    if (((btr & CAN_BTR_TS1) >> 16) == 8) {   // TS1[3:0]+1=9
        status |= 0x02;  // Bit1: BS1配置正确
    }
    if (((btr & CAN_BTR_TS2) >> 20) == 5) {   // TS2[2:0]+1=6
        status |= 0x04;  // Bit2: BS2配置正确
    }
    if ((btr & CAN_BTR_BRP) == 2) {            // BRP[9:0]+1=3
        status |= 0x08;  // Bit3: 预分频配置正确
    }
    
    // 验证工作模式(正常模式:SILM=0, LBKM=0)
    if ((CAN1->BTR & (CAN_BTR_SILM | CAN_BTR_LBKM)) == 0) {
        status |= 0x10;  // Bit4: 正常模式
    }
    
    return status;
}

// 主函数调用示例
int main(void) {
    uint8_t verify_result;
    
    CAN_Init_Config();
    verify_result = CAN_Verify_Config();
    
    // 若verify_result == 0x1F,则所有配置项均正确
    while (1) {
        // 主循环(可在此添加发送/接收测试)
    }
}

运行与验证

  1. 将代码编译下载至STM32F407开发板,确保PB8/PB9已连接CAN收发器。
  2. 在main()中调用CAN_Init_Config()完成初始化。
  3. 调用CAN_Verify_Config(),通过调试器观察返回值:
返回值含义
0x1F所有配置项正确(初始化模式退出、BS1=9、BS2=6、预分频=3、正常模式)
其他值对应位为0表示该项配置失败,需检查时钟或寄存器写入

通过条件:verify_result == 0x1F,且CAN1的MCR寄存器INRQ位为0(已退出初始化模式)。若使用CAN分析仪连接总线,可观察到总线空闲电平(隐性位2.5V)。

常见问题

  • 初始化失败(INRQ始终为1):检查CAN1时钟是否已使能,以及GPIO复用配置是否正确。
  • 波特率偏差:确认APB1时钟频率为42MHz(若系统时钟不同需重新计算预分频值)。
  • 无法退出初始化模式:在设置CAN_MCR_INRQ=0后需等待硬件确认,标准外设库的CAN_Init()已包含等待机制。