加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
    • 1. STM32CubeMX配置
    • 2. MDK-ARM编程
    • 3. 下载测试
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

CAN总线学习笔记 | CAN盒测试STM32的CAN中断接收

2023/01/19
2174
阅读需 19 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

CAN基础知识介绍文中介绍了CAN协议相关的基础知识,以及STM32F4芯片的CAN控制器相关知识,下面将通过实例,利用STM32CubeMX图形化配置工具,并配合CAN盒,来实现CAN通讯的中断收发测试

1. STM32CubeMX配置

⏩ CAN是挂载在APB1总线上,设置PCLK1时钟频率到最大45MHz

⏩ 激活CAN1,配置位时序参数,其他基本参数以及工作模式(此处设置为Normal普通模式)

CAN波特率的计算公式:只需要知道BS1和BS2的设置,以及APB1的时钟频率,就可以方便的计算出波特率。比如设置TS1=8、TS2=6和BRP=6,在APB1频率为45Mhz的条件下,即可得到CAN通信的波特率=45000/6/(8+6+1)=500Kbps

⏩ 激活USART1作为调试串口,配置相关LED对应的GPIO引脚作为指示灯

2. MDK-ARM编程

2.1 几个重要的结构体

⏩ CAN 初始化结构体:此结构体内容,可由STM32CubeMX工具进行配置

typedef struct
{
  uint32_t Prescaler;       /* 配置 CAN 外设的时钟分频,可设置为 1-1024*/
  uint32_t Mode;            /* 配置 CAN 的工作模式,回环或正常模式 */
  uint32_t SyncJumpWidth;   /* 配置 SJW 极限值 */
  uint32_t TimeSeg1;        /* 配置 BS1 段长度 */
  uint32_t TimeSeg2;        /* 配置 BS2 段长度 */
  FunctionalState TimeTriggeredMode;    /* 是否使能 TTCM 时间触发功能 */
  FunctionalState AutoBusOff;           /* 是否使能 ABOM 自动离线管理功能 */
  FunctionalState AutoWakeUp;           /* 是否使能 AWUM 自动唤醒功能 */
  FunctionalState AutoRetransmission;   /* 是否使能 NART 自动重传功能 */
  FunctionalState ReceiveFifoLocked;    /* 是否使能 RFLM 锁定 FIFO 功能 */
  FunctionalState TransmitFifoPriority; /* 配置 TXFP 报文优先级的判定方法 */
} CAN_InitTypeDef;

⏩ 发送及接收头结构体:主要用于构造发送报文,以及接收报文。收发发文时,需要自定义头结构体变量

typedef struct
{
  uint32_t StdId;      /* 存储报文的标准标识符 11 位,0-0x7FF */
  uint32_t ExtId;      /* 存储报文的扩展标识符 29 位,0-0x1FFFFFFF */
  uint32_t IDE;        /* 存储 IDE 扩展标志 */
  uint32_t RTR;        /* 存储 RTR 远程帧标志 */
  uint32_t DLC;        /* 存储报文数据段的长度,0-8 */
  FunctionalState TransmitGlobalTime; 
} CAN_TxHeaderTypeDef;

typedef struct
{
  uint32_t StdId;      /* 存储报文的标准标识符 11 位,0-0x7FF. */
  uint32_t ExtId;      /* 存储报文的扩展标识符 29 位,0-0x1FFFFFFF */
  uint32_t IDE;        /* 存储 IDE 扩展标志 */
  uint32_t RTR;        /* 存储 RTR 远程帧标志 */
  uint32_t DLC;        /* 存储报文数据段的长度,0-8 */
  uint32_t Timestamp; 
  uint32_t FilterMatchIndex; 
} CAN_RxHeaderTypeDef;

过滤器结构体:STM32CubeMX不会初始化过滤器的相关内容,需要自己添加

typedef struct
{
  uint32_t FilterIdHigh;         /*CAN_FxR1 寄存器的高 16 位 */
  uint32_t FilterIdLow;          /*CAN_FxR1 寄存器的低 16 位 */
  uint32_t FilterMaskIdHigh;     /*CAN_FxR2 寄存器的高 16 位 */
  uint32_t FilterMaskIdLow;      /*CAN_FxR2 寄存器的低 16 位 */
  uint32_t FilterFIFOAssignment; /* 设置经过筛选后数据存储到哪个接收 FIFO */
  uint32_t FilterBank;           /* 筛选器编号,范围0-27,CAN1是0-13,CAN2是14-27 */
  uint32_t FilterMode;           /* 筛选器模式 */
  uint32_t FilterScale;          /* 设置筛选器的尺度 */
  uint32_t FilterActivation;     /* 是否使能本筛选器 */
  uint32_t SlaveStartFilterBank; /* CAN2起始过滤器组 */
} CAN_FilterTypeDef;

2.2 程序编写

⏩ 生成工程后,打开can.c文件,可见STM32CubeMX已经对位时序参数、其他基本参数以及工作模式进行了初始化。但是并没有初始化过滤器的相关内容,因此需要我们自己添加,并在CAN初始化时调用

//下面的设置只使能了FIFO0,并不过滤任何消息
void CAN_Filter_Config(){
  CAN_FilterTypeDef sFilterConfig;
 
  sFilterConfig.FilterBank = 0;      //筛选器编号, CAN1是0-13, CAN2是14-27
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //采用掩码模式
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //设置筛选器的尺度, 采用32位
  sFilterConfig.FilterIdHigh = 0X0000;    //过滤器ID高16位,即CAN_FxR1寄存器的高16位
  sFilterConfig.FilterIdLow = 0X0000;     //过滤器ID低16位,即CAN_FxR1寄存器的低16位
  sFilterConfig.FilterMaskIdHigh = 0X0000;   //过滤器掩码高16位,即CAN_FxR2寄存器的高16位
  sFilterConfig.FilterMaskIdLow = 0X0000;    //过滤器掩码低16位,即CAN_FxR2寄存器的低16位
  sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //设置经过筛选后数据存储到哪个接收FIFO
  sFilterConfig.FilterActivation = ENABLE;   //是否使能本筛选器
  sFilterConfig.SlaveStartFilterBank = 14;   //指定为CAN1分配多少个滤波器组
 
  if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
  {
    Error_Handler();
  }
}

⏩ 编写发送和接收数据函数:此处将格式固定为标准数据帧,ID为12

uint8_t CAN1_Send_Msg(uint8_t *msg, uint8_t len){
  uint16_t i = 0;
  uint32_t txMailBox;
  uint8_t send_buf[8];
 
  txHeader.StdId = 12;
  txHeader.ExtId = 12;
  txHeader.IDE = CAN_ID_STD;
  txHeader.RTR = CAN_RTR_DATA;
  txHeader.DLC = len;
 
  for(i = 0; i < len; i++)
    send_buf[i] = msg[i];
 
  if(HAL_CAN_AddTxMessage(&hcan1, &txHeader, send_buf, &txMailBox) != HAL_OK)
    return 1; 
  return 0;
}

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan){
  uint16_t i = 0;
  uint8_t buf[8] = {0};
 
  if(hcan->Instance == CAN1){
    printf("*******************************rn");
    printf("Recv via STM32F429 Interruptrn");
 
    HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &rxHeader, buf);
 
    if(rxHeader.IDE == CAN_ID_STD)
      printf("StdId ID: %dn", rxHeader.StdId);
    else
      printf("ExtId ID: %dn", rxHeader.ExtId);
    printf("rn");
    printf("CAN IDE: %dn", rxHeader.IDE);printf("rn");
    printf("CAN RTR: %dn", rxHeader.RTR);printf("rn");
    printf("CAN DLC: %dn", rxHeader.DLC);printf("rn");
    printf("Recv Data: ");
 
    for(i = 0; i < rxHeader.DLC; i++)
      printf("%c ",buf[i]);
 
    printf("rn");
    printf("*******************************rn");
  }
}

⏩ 默认Cubemx生成的代码并没有can start,没有调用HAL_CAN_Start(&hcan1) 来使能CAN,因此需要在CAN初始化代码中添加

void MX_CAN1_Init(void){
  ......
  /* USER CODE BEGIN CAN1_Init 2 */
  CAN_Filter_Config();
  HAL_CAN_Start(&hcan1); 
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  /* USER CODE END CAN1_Init 2 */
}

⏩ 主函数main.c中,代码如下

int main(void){
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_CAN1_Init();
  MX_USART1_UART_Init();
   /* USER CODE BEGIN 2 */
  uint8_t ret;
  printf("CAN Testing....!rn");
  uint8_t txdata[8] = {78, 79, 82, 77, 65, 76, 33, 32};
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_1);
    printf("Start Send data...rn");
  
    ret = CAN1_Send_Msg(txdata, 8);
    if(ret == 0)
      printf("STM32F429 CAN Send success!rn");
    else 
      printf("STM32F429 CAN Send failed!rn");
  
    HAL_Delay(3000);
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

3. 下载测试

将CAN盒与STM32的CAN接口连接起来,CAN盒连接电脑,使用CAN调试软件接收和发送数据,如下图示

STM32工程编译无误后,下载到开发板,可以看到系统运行时D1指示灯不断闪烁,串口不断的打印STM32发送CAN消息成功的信息。使用CAN调试软件,可以看到CAN盒接收到了STM32发出的数据。使用调试软件,发送CAN数据给STM32

串口调试助手中可以看到,STM32通过中断接收到了CAN盒发来的数据

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
SN65HVD233DR 1 Texas Instruments 3.3 V CAN Transceiver with Standby Mode, Loopback 8-SOIC -40 to 125

ECAD模型

下载ECAD模型
$2.73 查看
KSZ8567RTXI 1 Microchip Technology Inc IC ETHERNET SWITCH 7PORT 128TQFP

ECAD模型

下载ECAD模型
$10.98 查看
KSZ8995MA 1 Microchip Technology Inc DATACOM, LAN SWITCHING CIRCUIT, PQFP128

ECAD模型

下载ECAD模型
$7.2 查看

相关推荐

电子产业图谱

公众号:嵌入式攻城狮;专注于分享和记录嵌入式开发技术,主要包含C语言、STM32、STM32CubeMX、lwIP、FreeRTOS、Linux、Zigbee、WIFI、BLE、LoRa、NB-loT、PCB电路设计、QT等等。