一、CAN的基本知识
1. 物理层
- 差分信号
- ISO11898标准:高速、短距离“闭环网络”,它的总线最大长度为40m,通信速度最高为1Mbps,总线的两端各要求有一个“120欧”的电阻。
- ISO11519-2标准:低速、远距离“开环网络”它的最大传输距离为1km,最高通讯速率为125kbps,两根总线是独立的、不形成闭环,要求每根总线上各串联有一个“2.2千欧”的电阻。
- 逻辑1时(隐性电平):CAN_High和CAN_Low线上的电压均为2.5v,即它们的电压差VH-VL=0V;
- 逻辑0时(显性电平):CAN_High的电平为3.5V,CAN_Low线的电平为1.5V,即它们的电压差为VH-VL=2V。
假如有两个CAN通讯节点,在同一时间,一个输出隐性电平,另一个输出显性电平,类似I2C总线的“线与”特性将使它处于显性电平状态,显性电平的名字就是这样来的。
2. 协议层
① 数据位格式
- CAN时钟的最小周期称为最小时间单元Time Quantum(Tq)
- 同步段(SS)、传播时间段(PTS)、相位缓冲段1(PBS1)和相位缓冲段2(PBS2)。每个段都占有数量不同的Tq,一个完整的bit,由8~25个Tq组成,除了SS段是固定的1Tq之外,其他的段占有Tq的数量都是可调的。
- 通过确定一个数据位的总Tq,可以计算波特率:
例如:而每个数据位由19个Tq组成,波特率可得
1 x 1 0 6 / 19 = 52631.6 ( b p s ) 1x10^6/19 = 52631.6 (bps) 1x106/19=52631.6(bps)
② STM32数据位格式
STM32的CAN外设,数据位格式与标准的略有不同,分为三段:
在STM32CubemX中波特率的计算,
Time Quanta in Bit Segment 1是位段1
Time Quanta in Bit Segment 2是位段2
按上图的配置计算波特率:
CAN总线在时钟树的APB1总线上,当前的总线频率为30MHz
经过10分频后,CAN的1Tq为大概为333.33ns
BS1段设置为1Tq,BS2段设置为4Tq,可得1bit的总时间为
SYNC(1)+ BS1(1) + BS2(4) = 6Tq
波特率为:
B
a
u
d
r
a
t
e
=
1
/
6
T
q
=
1
/
(
333.33
∗
6
)
=
1
/
(
1999
)
≈
499.99
K
b
i
t
/
s
Baudrate = 1/6Tq = 1/(333.33*6) = 1/(1999)≈499.99K bit/s
Baudrate=1/6Tq=1/(333.33∗6)=1/(1999)≈499.99Kbit/s
3. CAN 通信帧
- 帧种类
帧格式 | 含义 |
---|---|
数据帧 | 用于节点向外传送数据 |
遥控帧 | 用于向远端节点请求数据 |
错误帧 | 用于向远端节点通知校验错误,请求重新发送上一个数据 |
过载帧 | 用于通知远端节点:本节点尚未做好接收准备 |
帧间隔 | 用于将数据帧及遥控帧与前面的帧分离开来 |
- 数据帧格式为:帧起始(SOF段一个显性位(逻辑0))、 仲裁段、控制段、数据段、CRC段、ACK段和帧结束(EOF段以7个连续的隐性位(逻辑1)结束)
3. 仲裁段: 内容为数据帧的CAN ID(标识符),数据帧具有标准格式和扩展格式两种
标准格式的CAN的ID为11位、扩展帧格式为29位。
当两个节点同时发送报文时,若首先出现隐性电平,则会失去对总线的占有权,进入接收状态,在CAN通信中0是显性电平,所以CAN的ID越小,其优先级越高。
二、STM的CAN使用
1. CAN 过滤器
参考链接:https://blog.csdn.net/qq_35480173/article/details/98878309
①两种过滤模式
模式 | 优点 | 缺点 |
---|---|---|
列表模式 | 能精确地过滤每个指定的CAN ID | 有数量限制 |
掩码模式 | 取决于屏蔽码,有时无法完全精确到每一个CAN ID,部分不期望的CAN ID有时也会收到 | 数量取决于屏蔽码,最多无上限 |
②过滤寄存器
- CAN_FM1R寄存器中的FBMx位:”0”表示掩码模式,”1”表示列表模式。
下图的每一个位对应地表示这28个过滤器的工作模式
- CAN_FS1R寄存器表示CAN ID的位宽:0:16位宽 1:32位宽
- CAN_FxR1和CAN_FxR2 两个寄存器
列表模式-16位宽模式下: 写入4个标准CAN ID
列表模式-32位宽模式下: 写入2个CAN ID
掩码模式-16位宽模式: 2对验证码+屏蔽码组合来用,但它只能对标准CAN ID进行过滤
掩码模式-32位宽模式: CAN_FxR1用做32位宽的验证码,而CAN_FxR2则用作32位宽的屏蔽码
注意:下面STID表示标准ID有11位,EXID为扩展ID有18位(扩展帧ID总共29位).
然后是RTR,表示是否为远程帧(遥控帧)。IDE,表示扩展帧标识。
2. CAN 初始化和配置
下面以常用的32位掩码模式为例解释CAN的初始化配置和过滤器配置
1. CAN初始化
/* CAN1 init function */
void MX_CAN1_Init(void)
{
/* USER CODE BEGIN CAN1_Init 0 */
/* USER CODE END CAN1_Init 0 */
/* USER CODE BEGIN CAN1_Init 1 */
/* USER CODE END CAN1_Init 1 */
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 14;
hcan1.Init.Mode = CAN_MODE_NORMAL; //正常模式
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_4TQ; //BS1时间段
hcan1.Init.TimeSeg2 = CAN_BS2_1TQ; //BS2时间段
hcan1.Init.TimeTriggeredMode = DISABLE;
hcan1.Init.AutoBusOff = ENABLE;
hcan1.Init.AutoWakeUp = DISABLE;
hcan1.Init.AutoRetransmission = DISABLE; //自动重发
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = ENABLE; //发送使用FIFO
if (HAL_CAN_Init(&hcan1) != HAL_OK)
{
Error_Handler();
}
// 过滤只接收0x000018xx的CAN ID
uint32_t mask = 0xffffff00;
mask <<= 3;
mask |= 0x02; //设置只接受数据帧
/* USER CODE BEGIN CAN1_Init 2 */
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //掩码模式
sFilterConfig.FilterIdHigh = ((0x00001871 << 3) >> 16) & 0xffff; //配置ID
sFilterConfig.FilterIdLow = ((0x00001871 << 3) & 0xffff) | CAN_ID_EXT; //配置扩展帧
sFilterConfig.FilterMaskIdHigh = (mask >> 16) & 0xffff;
sFilterConfig.FilterMaskIdLow = (mask & 0xffff); //配置掩码
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //32位宽度
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; //FIFO0
sFilterConfig.FilterBank = 0; //过滤器0
sFilterConfig.SlaveStartFilterBank = 14; //从属CAN2实例的起始过滤器库,单CAN没有用,
//过滤器Min_Data = 0 和最大值 Max_Data = 27
sFilterConfig.FilterActivation = ENABLE;
if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
//使能FIFO接收中断
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
Error_Handler();
}
/* USER CODE END CAN1_Init 2 */
}
void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(canHandle->Instance==CAN1)
{
/* USER CODE BEGIN CAN1_MspInit 0 */
/* USER CODE END CAN1_MspInit 0 */
/* CAN1 clock enable */
__HAL_RCC_CAN1_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**CAN1 GPIO Configuration
PB8 ------> CAN1_RX
PB9 ------> CAN1_TX
*/
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* CAN1 interrupt Init */
HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
/* USER CODE BEGIN CAN1_MspInit 1 */
/* USER CODE END CAN1_MspInit 1 */
}
}
2. CAN接收和发送
//CAN 接收回调函数
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
if(hcan->Instance == CAN1)
{
HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rxHeader, rxdata);
}
}
//CAN 发送函数
HAL_StatusTypeDef UserCan_Transmit(uint32_t Id, uint32_t IDE, uint32_t RTR, uint32_t DLC, uint8_t *data)
{
CAN_TxHeaderTypeDef txHeader;
txHeader.StdId = Id;
txHeader.ExtId = Id;
txHeader.IDE = IDE;//CAN_ID_STD;
txHeader.RTR = RTR;//CAN_RTR_DATA;
txHeader.DLC = DLC;//8;
txHeader.TransmitGlobalTime = DISABLE;
return HAL_CAN_AddTxMessage(&hcan1, &txHeader, data, &TxMailboxNumber);
}
标签:HAL,简单,hcan1,STM32,Init,CAN1,GPIO,ID
From: https://blog.csdn.net/TANG3223/article/details/144006863