文章目录
一.概要
CAN全称是(Controller Area Network),控制器局域网络,是ISO国际标准化的串行通信协议,CAN是国际上应用最广泛的现场总线之一。
CAN通信只有两根信号线,分别是CAN_High和CAN_Low,CAN 控制器根据这两根线上的电位差来判断总线电平。总线申平分为显性电平和隐性申平,二者必居其一。发送方通过使总线电平发生变化,将消息发送给接收方。
CAN总线在车上应用非常广泛:
本文介绍了STM32单片机CAN口的基本概念,内部结构,波特率配置,接收滤波配置以及用CAN口进行数据通讯的例程。
二.CAN网络基本组成
一个典型的CAN网络由多个节点组成,每个节点至少包含一个CAN控制器和一个CAN收发器。此外,网络还需要适当的物理介质,如电缆和连接器来连接各个节点。
STM32G474RET6单片机是自带CAN控制器,只要外面挂一个CAN收发器(TJA1050/TJA1042等)就能组成一个CAN节点,实现跟其他节点CAN通讯。
三.STM32G474单片机CAN结构与特点
1.STM32G474单片机CAN基本结构图

CAN core
是CAN控制器的核心,包含协议控制器和接收/发送移位寄存器。它处理所有ISO 11898-1:2015协议功能,并支持11位和29位标识符。
Tx Handler
是用于发送报文,控制从消息RAM到CAN核心的消息传输。有三个Tx缓冲区可用于传输,Tx缓冲区可以用作Tx FIFO或Tx队列。
Rx Handler
是用于控制从CAN核心接收到的消息向外部消息的传输RAM。Rx处理程序支持两个接收FIFO,用于存储所有已接收的消息通过了验收过滤。对于11位ID,可以定义28个过滤器;对于29位ID,最多可以定义8个过滤器。
Message RAM interface
通过RAM将FDCAN访问连接到外部1K字节的消息RAM控制器/仲裁器。
2.STM32G474单片机FDCAN基本特点
STM32G474RET6单片机的FDCAN(Flexible Data-Rate CAN)具有以下主要特点:
- 协议兼容性
支持CAN 2.0标准协议(包括Part A、Part B)和ISO 11898-1:2015标准,同时兼容CAN-FD协议(含速率切换功能)。
支持AUTOSAR和J1939协议,适用于汽车和工业自动化领域。 - 高性能通信
最高支持2Mbps的通信速率(数据阶段),仲裁阶段速率与传统CAN一致(≤1Mbps)。支持64字节的大数据包传输,显著提升带宽利用率。 - 多模式操作
提供多种工作模式,包括正常模式(Normal)、环回模式(Internal/External Loopback)、总线监控模式(Bus Monitoring)等,适用于调试和不同应用场景。支持自动重传(AutoRetransmission)功能,确保数据传输可靠性。 - 硬件增强功能
内置硬件时戳,为每条接收报文附带时间信息,适用于高精度时序要求的应用。
支持多FIFO(接收/发送队列)和128条标准ID+128条扩展ID的报文过滤机制,提升数据处理效率。 - 外设集成
与STM32G474的丰富外设(如高分辨率定时器、ADC、USB等)协同工作,适用于复杂系统设计。
这些特性使STM32G474RET6的FDCAN适用于汽车电子(如BMS)、工业控制、数据采集等高实时性、高带宽需求的场合。
四.CAN协议帧格式
数据帧是使用最多的帧,结构上由7段组成,其中根据仲裁段ID码长度的不同,分为标准帧(CAN2.0A)和扩展帧(CAN2.0B),标识符(ID)长度不同:标准格式为11位,扩展格式为29位。

数据帧格式:
1.起始域
SOF=帧开始
2.仲裁域
ID=标识符
RTR=远程请求位,区分数据帧和遥控帧
3.控制域
IDE=扩展标志位,区分标准格式和扩展格式
r0=保留位,为后续协议升级留下空间
DLC=数据长度
4.数据域
0~8字节的长度
5.CRC域
CRC=循环几余校验码
6.ACK域
ACK=响应位
7.结束域
EOF=帧结束
CAN通信标准帧还是扩展帧,选择使用哪种帧类型取决于具体的应用需求。如果需要传输较小数据量且标识符长度不超过11位,可以选择CAN标准帧。而对于需要传输更大数据量和更长标识符的应用,则应选用CAN扩展帧,一般CAN通信双方之间会先约定好采用标准帧还是扩展帧协议。
五.STM32G474RET6的CAN通讯波特率
由于CAN属于异步通讯,没有时钟信号线,连接在同一个总线网络中的各个节点会像串口异步通讯那样,节点间使用约定好的波特率进行通讯。
同时,CAN还使用"位同步"的方式来抗干扰、吸收误差,实现对总线电平信号进行正确的采样,确保通讯正常。
如下所述把名义上的每位时间分为3段:
● 同步段(SYNC_SEG):通常期望位的变化发生在该时间段内。其值固定为1个时间单元(1 x tCAN)。
● 时间段1(BS1):定义采样点的位置。它包含CAN标准里的PROP_SEG和PHASE_SEG1。
其值可以编程为1到16个时间单元,但也可以被自动延长,以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。
● 时间段2(BS2):定义发送点的位置。它代表CAN标准里的PHASE_SEG2。其值可以编程为1到8个时间单元,但也可以被自动缩短以补偿相位的负向漂移。

我们以STM32G474RET6为例,CAN时钟是挂在APB1上,APB1时钟是170Mhz,
NBRP[8:0]: 波特率分频器 (Baud rate prescaler) ,这个寄存器我们配置成9。
SEG1[7:0]: 时间段1 (Time segment 1) ,这个寄存器我们配置成46。
SEG2[6:0]: 时间段2 (Time segment 2) ,这个寄存器我们配置成19。
根据波特率公式:
tBS1 = tq * (SEG1[7:0] + 1)。
tBS2 = tq * (SEG2[6:0] + 1)。
tq = (NBRP[8:0]+ 1) x tPCLK。
tPCLK=1/170000000。
波特率=1/(tq + tBS1+tBS2)
=1/tq*(1+(SEG1[7:0] + 1)+(SEG2[6:0] + 1))
=170000000/((NBRP[8:0] + 1)*(1+(SEG1[7:0] + 1)+(SEG2[6:0] + 1)))
波特率计算结果就是
170000000/((9+1)*(1+(46+1)+(19+1)))=250000bps。
一般CAN波特率都是250k,500k,1M,125k,我们只要参照250K波特率的配置,改下波特率分频器就很方便能改大改小,都是倍数关系。
六.STM32G474RET6的CAN接收过滤器配置
CAN的过滤器的配置是对CAN接收到的报文进行过滤的配置,在STM32芯片中,可以对CAN的报文进行过滤,从而省略MCU的处理过程,通过配置ID范围、掩码或双ID模式,硬件自动过滤无关报文,减少进入中断的无效数据量。在CAN协议里,报文的标识符不代表节点的地址,而是跟报文的优先级相关的。发送者以广播的形式把报文发送给所有的接收者。节点在接收报文时,根据标识符的值决定是否需要该报文,如果需要,就拷贝到SRAM里,如果不需要,报文就被丢弃且无需软件的干预。
STM32G474RET6的FDCAN模块支持多种ID过滤器配置模式:
范围过滤(FDCAN_FILTER_RANGE) :接受FilterID1到FilterID2之间的所有报文(含边界值)。
双ID过滤(FDCAN_FILTER_DUAL) :仅接受完全匹配FilterID1或FilterID2的报文。
掩码过滤(FDCAN_FILTER_MASK) :FilterID1为匹配值,FilterID2为掩码(1表示必须匹配,0表示不关心)。
无EIDM范围过滤(FDCAN_FILTER_RANGE_NO_EIDM):类似范围过滤但忽略扩展ID掩码位。
我们着重介绍下掩码过滤(FDCAN_FILTER_MASK) ,掩码过滤旨在通过掩蔽单个位来过滤消息ID组接收到的消息ID。在传统的位掩码过滤中,使用SF1ID/EF1ID作为消息ID滤波器,而SF2ID/EF2ID用作滤波器掩码。过滤掩码中的0位将屏蔽配置ID的对应位位置过滤器,例如,该位位置上接收到的消息ID的值与此无关接收过滤。仅接受接收到的消息ID中对应部分掩码位(mask bits)与接受过滤(acceptance filtering)相关。如果所有掩码位都为1,则只有当接收到的消息ID与(某个值/条件)相匹配时,才会发生匹配消息ID过滤器是相同的。如果所有掩码位均为0,则所有消息ID均匹配。
比如EF1ID为0x321,EF2ID为0x3ff,这样CAN只接收ID为0x321的报文。
比如EF1ID为0x321,EF2ID为0,这样CAN可以接收任意ID的报文,因为所有掩码位均为0,则所有消息ID均匹配。
比如EF1ID为0x321,EF2ID为0x3f0,这样CAN可以接收0x320~0x32f范围内的报文,因为低4位都为0,所以低4位的报文就不需要匹配。
七.CubeMX配置一个CAN数据收发例程
1. 硬件准备
STLINK接STM32G474RET6开发板,STLINK接电脑USB口,TTL转CAN小模块插在板子上,CAN盒插电脑,CAN总线通过杜邦线相连,板子需要5V USB线供电。
2.创建CubeMX工程
如下图所示,打开STM32CubeMX软件,新建工程。
如下图所示,Part Number处输入STM32G474RE,再双击就创建新的工程。
如下图所示,配置下载口引脚,PA13为SWD的SWDIO脚,PA14为SWD的SWCLK脚。
如下图所示,配置FDCAN2,PB12,PB13为CAN通讯引脚,波特率250kbps。
如下图所示,配置外部8M晶振。
如下图所示,配置系统主频170Mhz,使用外部8MHZ晶振。
配置工程文件名,保存路径,KEIL5工程输出方式,生成工程。
如下图所示,增加代码,配置CAN的发送与接收寄存器。
如下图所示,增加代码,实现CAN发送与接收。
主要代码如下
c
FDCAN_RxHeaderTypeDef RxHeader;//接收头
uint8_t RxData[8];//接收数组
FDCAN_TxHeaderTypeDef TxHeader;//发送头
uint8_t TxData[8];//发送数组
//配置标准帧
static void FDCAN_Config(void)
{
FDCAN_FilterTypeDef sFilterConfig;
/* Configure Rx filter */
sFilterConfig.IdType = FDCAN_STANDARD_ID;
sFilterConfig.FilterIndex = 0;
sFilterConfig.FilterType = FDCAN_FILTER_MASK;
sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
sFilterConfig.FilterID1 = 0x321;
sFilterConfig.FilterID2 = 0x7FF;
if (HAL_FDCAN_ConfigFilter(&hfdcan2, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
/* Configure global filter:Filter all remote frames with STD and EXT ID Reject non matching frames with STD ID and EXT ID */
if (HAL_FDCAN_ConfigGlobalFilter(&hfdcan2, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE) != HAL_OK)
{
Error_Handler();
}
/* Start the FDCAN module */
if (HAL_FDCAN_Start(&hfdcan2) != HAL_OK)
{
Error_Handler();
}
if (HAL_FDCAN_ActivateNotification(&hfdcan2, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
{
Error_Handler();
}
/* Prepare Tx Header */
TxHeader.Identifier = 0x321;
TxHeader.IdType = FDCAN_STANDARD_ID;
TxHeader.TxFrameType = FDCAN_DATA_FRAME;
TxHeader.DataLength = FDCAN_DLC_BYTES_2;
TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
TxHeader.MessageMarker = 0;
}
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();//8M外部晶振,170M系统主频
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_FDCAN2_Init();//配置CAN,波特率250k,170000/10/(47+20+1), PB12:FDCAN2_RX,PB13:FDCAN2_TX
/* USER CODE BEGIN 2 */
FDCAN_Config();//配置发送帧,接收帧为0x321
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
TxData[0] = 0x00;
TxData[1] = 0xAD;//发送数组内容定义
/* Start the Transmission process */
if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan2, &TxHeader, TxData) != HAL_OK)//发送CAN帧
{
/* Transmission request Error */
Error_Handler();
}
HAL_Delay(100);//等待100ms
if (HAL_FDCAN_GetRxFifoFillLevel(&hfdcan2, FDCAN_RX_FIFO0) >= 1)//查询FIFO0是否有CAN帧
{
/* Retrieve Rx message from RX FIFO0 */
if (HAL_FDCAN_GetRxMessage(&hfdcan2, FDCAN_RX_FIFO0, &RxHeader, RxData) != HAL_OK)//读取CAN报文,数据内容存储到RxData
{
Error_Handler();
}
}
}
/* USER CODE END 3 */
}
3.实验效果
打开电脑上位机,通过电脑CAN上位机,250kbps,就能收到板子发出来的报文,ID是0x321,内容是0x00,0xAD。
通过CAN上位机发送ID为0X321,内容为0x1234的标准帧数据,在Keil5调试界面的Watch界面查看RxData变量,能显示板子收到的数据。
八.小结
CAN协议因其高性能、可靠性和灵活性而逐渐被广泛应用于工业控制、汽车、航空航天、船舶、医疗设备、智能家居等领域。