STM32(HAL)——CAN通信

8. CAN

8.1 基本概念

全称Controller Area Network,是一种半双工,异步通讯。没有主从的说法,每个设备都可以发送和接收。

8.1.1 物理层

两条信号线,CAN_High和CAN_Low两条差分信号线,以差分形式通讯

两种网络形式:

闭环:允许总线最长40m,最高速1Mbps

在这里插入图片描述

∘ \circ 规定总线两端各有一个120Ω电阻。

∘ \circ CAN控制器是各个连接到总线上的设备的控制器,一般需要配备一个CAN收发器(比如咱们战队码盘上的CAN收发器用的是TJA1050),用于将CAN控制器的二进制码流转换为CAN总线的差分电平,在两条有差分电压的总线电缆上传输数据

开环:最大传输距离1Km,最高速125Kbps
在这里插入图片描述

∘ \circ 规定每根线串联一个2.2kΩ的电阻

CAN协议差分信号

在这里插入图片描述

∘ \circ 显性电平对应“0”,隐性电平对应“1”。隐性电平(1)两条线电压都是2.5V,即压差为0;显性电平(0)CAN_High和CAN_Low分别为3.5V和1.5V,压差为2V。

∘ \circ 总线上,只要有一个节点输出显性,则总线上为显性电平;只有所有节点都是隐性电平,总线才为隐性电平

∘ \circ 由于CAN是半双工的,收发分开进行,且是总线通讯,所以一个时刻只能有一个节点发送,其他节点在此时只能接收

8.1.2 协议层

位时序

意义:为了实现正确的总线电平采样,确保通讯正常。最小单位是Tq(Time Quantum),一个完整位由8~25个Tq组成

组成:SS段、PTS 段、PBS1段、PBS2段

段名 意义 作用
SS(1Tq) 同步段 使总线各节点同步
PTS(1~8Tq) 传播时间段 补偿物理延时,是传播时间、收发器延时之和的两倍
PBS1(1~8Tq) 相位缓冲段1 补偿变压阶段误差
PBS2(2~8Tq) 相位缓冲段2 补偿边沿阶段误差
SJW(1~4Tq) 再同步补偿宽度 补偿时钟频率偏差、传输延迟等

例如

在这里插入图片描述

通讯波特率的计算:CAN使用的时钟线是APB1 peripheral clocks(假设是APC),即一般是SYSCLK的四分频。而CAN通讯还要对此进行预分频(假设是Prescaler),则一个Tq为 Prescaler / APC(单位s)。而一个数据位占(SS+PTS+PBS1+PBS2+SJW)个Tq。则一秒可以传输的位数就是 1 T q ∗ 一 个 位 得 T q 数 \frac{1}{Tq*一个位得Tq数} TqTq1

### STM32 F407 HALCAN通信教程 #### 初始化CAN模块 为了使能CAN外设并配置基本参数,需调用`HAL_CAN_Init()`函数。此函数接受指向`CAN_HandleTypeDef`结构体的指针作为参数,该结构体包含了所有必要的初始化设置[^3]。 ```c // 定义CAN句柄 CAN_HandleTypeDef hcan; void MX_CAN1_Init(void) { hcan.Instance = CAN1; // 配置CAN定时器 hcan.Init.Prescaler = 9; hcan.Init.Mode = CAN_MODE_NORMAL; hcan.Init.SyncJumpWidth = CAN_SJW_1TQ; hcan.Init.TimeSeg1 = CAN_BS1_13TQ; hcan.Init.TimeSeg2 = CAN_BS2_2TQ; hcan.Init.TimeTriggeredMode = DISABLE; hcan.Init.AutoBusOff = DISABLE; hcan.Init.AutoWakeUp = DISABLE; hcan.Init.AutoRetransmission = ENABLE; hcan.Init.ReceiveFifoLocked = DISABLE; hcan.Init.TransmitFifoPriority = DISABLE; if (HAL_CAN_Init(&hcan) != HAL_OK) { Error_Handler(); } } ``` #### 发送数据到CAN总线 发送消息至CAN网络涉及创建一个包含待传输信息的消息对象,并将其传递给`HAL_CAN_AddTxMessage()`方法。这会尝试立即将消息放入发送队列中等待处理。 ```c uint8_t data[] = {0x01, 0x02, 0x03}; CanTxMsgTypeDef TxMessage; TxMessage.StdId = 0x123; // 设置标准ID TxMessage.ExtId = 0x00; // 扩展ID不适用 TxMessage.RTR = CAN_RTR_DATA; // 数据帧而非远程请求帧 TxMessage.IDE = CAN_ID_STD; // 使用标准ID格式 TxMessage.DLC = sizeof(data); // 数据长度码 memcpy(TxMessage.Data, data, sizeof(data)); if(HAL_CAN_AddTxMessage(&hcan, &TxMessage, NULL, NULL)!= HAL_OK){ /* 错误处理 */ } ``` #### 接收来自CAN总线的数据 有两种方式可以用来读取接收到的信息——轮询(查询模式)和中断驱动的方式(接收模式)。对于简单的应用场景来说,采用轮询机制可能就足够了;而对于更复杂的应用,则推荐使用基于事件触发的方法来提高响应速度和效率。 ##### 查询模式下的接收操作 在这种情况下,程序不断检查是否有新的报文到达缓冲区直到发现为止: ```c CanRxMsgTypeDef RxMessage; while(1){ if(HAL_CAN_GetRxFifoFillLevel(&hcan,CAN_RX_FIFO0)>0){ // 检查RX FIFO是否为空 if(HAL_CAN_GetRxMessage(&hcan,CAN_RX_FIFO0,&RxMessage,RxData)==HAL_OK){ // 处理接收到的数据... } } } ``` ##### 中断模式下接收操作 当新消息被成功存入接收FIFO时会产生相应的硬件中断信号通知CPU去获取这些数据包: ```c extern void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef *hcan){ CanRxMsgTypeDef RxMessage; uint8_t RxData[8]; if(hcan->Instance==CAN1 && HAL_CAN_GetRxMessage(hcan,CAN_RX_FIFO0,&RxMessage,RxData)==HAL_OK){ // 对接收到的数据做进一步解析或反应... } } /* 在主循环或其他地方注册回调函数 */ __weak void HAL_CAN_MspInit(CAN_HandleTypeDef* hcan){ ... __HAL_LINKDMA(hcan,hdmarx,hdma_can_rx); ... } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值