【物联网】深入理解CAN通信:原理、应用和实现(超详细,万字警告)_can通讯 对话机制

CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.SlaveStartFilterBank = 0;

if (HAL\_CAN\_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK) {
    // 错误处理
}

  1. 启动CAN:
if (HAL\_CAN\_Start(&hcan) != HAL_OK) {
    // 错误处理
}

  1. 发送和接收数据:
if (HAL\_CAN\_AddTxMessage(&hcan, &TxHeader, TxData, &TxMailbox) != HAL_OK) {
    // 错误处理
}

if (HAL\_CAN\_GetRxMessage(&hcan, CAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK) {
    // 错误处理
}

6.3 实现的整体代码
// 包含所需的头文件
#include "stm32f4xx\_hal.h"

// CAN消息结构体
CAN_TxHeaderTypeDef TxHeader;
CAN_RxHeaderTypeDef RxHeader;
uint8\_t TxData[8];
uint8\_t RxData[8];

void CAN\_Configuration(void)
{
  // 初始化CAN控制器
  hcan.Instance = CAN1;
  hcan.Init.Prescaler = 10;
  hcan.Init.Mode = CAN_MODE_NORMAL;
  hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
  hcan.Init.TimeSeg1 = CAN_BS1_8TQ;
  hcan.Init.TimeSeg2 = CAN_BS2_7TQ;
  hcan.Init.TimeTriggeredMode = DISABLE;
  hcan.Init.AutoBusOff = ENABLE;
  hcan.Init.AutoWakeUp = DISABLE;
  hcan.Init.AutoRetransmission = ENABLE;
  hcan.Init.ReceiveFifoLocked = DISABLE;
  HAL\_CAN\_Init(&hcan);

  // 配置CAN过滤器
  CAN_FilterTypeDef sFilterConfig;
  sFilterConfig.FilterBank = 0;
  sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
  sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
  sFilterConfig.FilterIdHigh = 0x0000;
  sFilterConfig.FilterIdLow = 0x0000;
  sFilterConfig.FilterMaskIdHigh = 0x0000;
  sFilterConfig.FilterMaskIdLow = 0x0000;
  sFilterConfig.Filter
继续
MaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.SlaveStartFilterBank = 14;
HAL\_CAN\_ConfigFilter(&hcan, &sFilterConfig);

// 启动CAN通信
HAL\_CAN\_Start(&hcan);

// 配置CAN消息头
TxHeader.StdId = 0x123;
TxHeader.ExtId = 0x00;
TxHeader.RTR = CAN_RTR_DATA;
TxHeader.IDE = CAN_ID_STD;
TxHeader.DLC = 8;
TxHeader.TransmitGlobalTime = DISABLE;
}

void CAN\_SendData(uint8\_t\* data, uint32\_t length)
{
// 填充发送消息的数据
for (uint8\_t i = 0; i < length; i++) {
TxData[i] = data[i];
}

// 发送消息
if (HAL\_CAN\_AddTxMessage(&hcan, &TxHeader, TxData, &TxMailbox) == HAL_OK) {
HAL\_CAN\_Transmit(&hcan, 100);
}
}

void CAN\_ReceiveData(void)
{
// 接收消息
if (HAL\_CAN\_GetRxFifoFillLevel(&hcan, CAN_RX_FIFO0) > 0) {
if (HAL\_CAN\_GetRxMessage(&hcan, CAN_RX_FIFO0, &RxHeader, RxData) == HAL_OK) {
// 处理接收到的数据
// …
}
}
}

int main(void)
{
// 初始化HAL库和其他外设

// 配置CAN通信
CAN\_Configuration();

while (1) {
// 发送数据
uint8\_t sendData[] = {0x01, 0x02, 0x03};
CAN\_SendData(sendData, sizeof(sendData));

// 接收数据
CAN\_ReceiveData();
}
}

以上示例代码演示了一个简单的CAN发送和接收流程。首先,在CAN_Configuration函数中,配置CAN控制器和过滤器。然后,在主函数中,使用CAN_SendData函数发送数据,使用CAN_ReceiveData函数接收数据。

此外,为了调试和监测CAN通信,HAL库提供了一些有用的函数和工具。例如,可以使用HAL_CAN_GetState()函数获取CAN控制器的当前状态,包括初始化、准备就绪、发送中、传输完成等。还可以使用HAL_CAN_GetErrorCounter()函数获取错误计数器的值,以及使用HAL_CAN_GetRxMessage()函数获取接收到的CAN帧的相关信息。

7. 使用标准库实现CAN通信

除了HAL库,还可以使用标准库进行CAN通信的实现。标准库相对较底层,需要直接操作寄存器和位操作来配置和控制CAN控制器。

与HAL库类似,使用标准库进行CAN通信需要进行CAN总线的初始化、过滤器的配置、数据的发送和接收等操作。不同之处在于,需要直接操作寄存器来完成这些任务。

7.1 实现步骤
  • 配置GPIO端口和引脚,用于连接CAN总线。
  • 配置CAN控制器的工作模式、波特率、位定时参数等。
  • 配置CAN过滤器,设置过滤器的标识符、执行类型等。
  • 使用CAN发送函数将数据发送到总线上。
  • 使用CAN接收函数接收来自其他节点的数据。
7.2 步骤的代码实现

当使用标准库实现STM32的CAN通信时,需要按照以下步骤进行配置和操作:

  1. 配置CAN1时钟:
RCC\_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

  1. 初始化CAN1:
CAN_InitTypeDef CAN_InitStructure;
CAN_InitStructure.CAN_TTCM = DISABLE;
CAN_InitStructure.CAN_ABOM = DISABLE;
CAN_InitStructure.CAN_AWUM = DISABLE;
CAN_InitStructure.CAN_NART = DISABLE;
CAN_InitStructure.CAN_RFLM = DISABLE;
CAN_InitStructure.CAN_TXFP = DISABLE;
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq;
CAN_InitStructure.CAN_Prescaler = 10;
CAN\_Init(CAN1, &CAN_InitStructure);

  1. 配置CAN过滤器:
CAN_FilterInitTypeDef CAN_FilterInitStructure;
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);

  1. 使能CAN1接收中断:
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC\_Init(&NVIC_InitStructure);
CAN\_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);

  1. 实现CAN1接收中断处理函数:
void CAN1\_RX0\_IRQHandler(void) {
  if (CAN\_GetITStatus(CAN1, CAN_IT_FMP0) != RESET) {
    CAN\_Receive(CAN1, CAN_FIFO0, &RxMessage);
    // 处理接收到的消息
  }
}

  1. 编写CAN发送函数:
void CAN\_SendData(uint8\_t\* data, uint8\_t length) {
  // 填充发送消息的数据
  for (uint8\_t i = 0; i < length; i++) {
    TxMessage.Data[i] = data[i];
  }

  // 设置发送消息的参数
  TxMessage.StdId = 0x123;
  TxMessage.ExtId = 0x00;
  TxMessage.IDE = CAN_Id_Standard;
  TxMessage.RTR = CAN_RTR_DATA;
  TxMessage.DLC = length;

  // 发送消息
  uint8\_t mailbox;
  CAN\_Transmit(CAN1, &TxMessage);
}

  1. 在主函数中调用相关函数:
int main(void) {
  // 初始化CAN配置
  CAN\_Configuration();

  while ((CAN1->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) {
    // 等待CAN1退出初始化模式
  }

  while (1) {
    // 发送数据
    uint8\_t sendData[] = {0x01, 0x02, 0x03};
    CAN\_SendData(sendData, sizeof(sendData));

    // 延时一段时间
    for (volatile uint32\_t i = 0; i < 1000000; i++) {}
  }
}

7.3 实现的整体代码
#include "stm32f4xx.h"

// CAN消息结构体
CanTxMsgTypeDef TxMessage;
CanRxMsgTypeDef RxMessage;

void CAN\_Configuration(void) {
  // 使能CAN1时钟
  RCC\_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

  // CAN1初始化
  CAN_InitTypeDef CAN_InitStructure;
  CAN_InitStructure.CAN_TTCM = DISABLE;
  CAN_InitStructure.CAN_ABOM = DISABLE;
  CAN_InitStructure.CAN_AWUM = DISABLE;
  CAN_InitStructure.CAN_NART = DISABLE;
  CAN_InitStructure.CAN_RFLM = DISABLE;
  CAN_InitStructure.CAN_TXFP = DISABLE;
  CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
  CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
  CAN_InitStructure.CAN_BS1 = CAN_BS1_8tq;
  CAN_InitStructure.CAN_BS2 = CAN_BS2_7tq;
  CAN_InitStructure.CAN_Prescaler = 10;
  CAN\_Init(CAN1, &CAN_InitStructure);

  // CAN过滤器配置
  CAN_FilterInitTypeDef CAN_FilterInitStructure;
  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);

  // CAN接收中断使能
  CAN\_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);

  // 使能CAN1
  CAN\_Cmd(CAN1, ENABLE);

  // NVIC中断配置
  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC\_Init(&NVIC_InitStructure);
}

void CAN\_SendData(uint8\_t\* data, uint8\_t length) {
  // 填充发送消息的数据
  for (uint8\_t i = 0; i < length; i++) {
    TxMessage.Data[i] = data[i];
  }

  // 设置发送消息的参数
  TxMessage.StdId = 0x123;
  TxMessage.ExtId = 0x00;
  TxMessage.IDE = CAN_Id_Standard;
  TxMessage.RTR = CAN_RTR_DATA;
  TxMessage.DLC = length;

  // 发送消息
  uint8\_t transmissionMailbox = 0;
  CAN\_Transmit(CAN1, &TxMessage);
}

void CAN1\_RX0\_IRQHandler(void) {
  if (CAN\_GetITStatus(CAN1, CAN_IT_FMP0) != RESET) {
    // 接收到消息
    CAN\_Receive(CAN1, CAN_FIFO0, &RxMessage);

    // 处理接收到的消息
    // ...
  }
}

int main(void) {
  // 初始化CAN配置
  CAN\_Configuration();

  while ((CAN1->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) {
    // 等待CAN1退出初始化模式
  }

  while (1) {
    // 发送数据
    uint8\_t sendData[] = {0x01, 0x02, 0x03};
    CAN\_SendData(sendData, sizeof(sendData));

    // 延时一段时间
    for (volatile uint32\_t i = 0; i < 1000000; i++) {}
  }
}

8. CAN通信实际案例分析

在汽车电控系统中,CAN通信被广泛应用于各个控制单元之间的数据传输。例如,在引擎控制单元(ECU)中,通过CAN总线与刹车系统的控制单元、仪表盘的控制单元进行通信。引擎控制单元可以向刹车系统发送刹车指令,同时获取仪表盘上的车速和引擎转速等信息。

在工业控制系统中,CAN通信常用于连接不同的设备和传感器,以实现实时数据交换和协调工作。例如,在机器人系统中,通过CAN总线连接各个关节控制器和传感器,实现机器人的协调运动和数据传输。

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

29146897)]

[外链图片转存中…(img-8P9yCS0S-1715629146897)]

[外链图片转存中…(img-OKVKAkqu-1715629146898)]

[外链图片转存中…(img-fMhYAJov-1715629146898)]

[外链图片转存中…(img-zjy7ht76-1715629146899)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值