CAN总线收发,中断方式接收
平台:战舰mini板,STM32F103RB STM32CUBEMX V5.3 TrueSTUDIO V9.3
配置CAN
CAN的波特率最大为1Mbps。 波特率计算方法:时钟主频 / 分频 / (tq1 + tq2 + swj) stm32f103的CAN的时钟主频是36M,分9频就是4M,在除以(5 + 2 + 1)得到500K的波特率。 注意:stm32cubemx生成的CAN代码是不带过滤器的,需要自己手动添加。
代码修改
CAN初始化
CAN_HandleTypeDef hcan1;
CAN_FilterTypeDef sFilterConfig;
void MX_CAN_Init(void)
{
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 9;
hcan1.Init.Mode = CAN_MODE_LOOPBACK;
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_5TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_2TQ;
hcan1.Init.TimeTriggeredMode = DISABLE;
hcan1.Init.AutoBusOff = DISABLE;
hcan1.Init.AutoWakeUp = DISABLE;
hcan1.Init.AutoRetransmission = DISABLE;
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = ENABLE;
if (HAL_CAN_Init(&hcan1) != HAL_OK)
{
Error_Handler();
}
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 = 14;
if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_CAN_Start(&hcan1) != HAL_OK)
{
Error_Handler();
}
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
Error_Handler();
}
}
覆写接收中断回调函数
(注意:上面的配置我们使用的式FIFO0,所以要覆写FIFO0的中断回调函数):
void can_msg_info(CAN_RxHeaderTypeDef* hdr, const void* data)
{
printf("IDE : %s\r\n",
hdr->IDE == CAN_ID_STD ? "CAN_ID_STD" : "CAN_ID_EXT");
printf("RTR : %s\r\n",
hdr->RTR == CAN_RTR_DATA ? "CAN_RTR_DATA" : "CAN_RTR_REMOTE");
printf("DLC : %ld\r\n", hdr->DLC);
printf("StdId : 0x%X\r\n", hdr->StdId);
printf("ExtId : 0x%X\r\n", hdr->ExtId);
printf("Data : %s\r\n", (char *) data);
}
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
if (hcan->Instance == hcan1.Instance)
{
uint8_t buf[8];
CAN_RxHeaderTypeDef CAN_RX_HDR;
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &CAN_RX_HDR, buf)
== HAL_OK)
{
can_msg_info(&CAN_RX_HDR, buf);
HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
}
}
}
CA发送函数:
uint8_t CAN_Transmit(const void* buf, uint32_t len)
{
uint32_t txmailbox = 0;
uint32_t offset = 0;
CAN_TxHeaderTypeDef hdr;
hdr.IDE = CAN_ID_STD;
hdr.RTR = CAN_RTR_DATA;
hdr.StdId = 0x12;
hdr.ExtId = 0x12;
hdr.TransmitGlobalTime = DISABLE;
while(len != 0)
{
hdr.DLC = len > 8 ? 8 : len;
if(HAL_CAN_AddTxMessage(&hcan1, &hdr, ((uint8_t *)buf) + offset, &txmailbox) != HAL_OK)
return 1;
offset += hdr.DLC;
len -= hdr.DLC;
}
return 0;
}
附注:stm32cubemx can配置参数详解:
配置参数
参数 | 意思 |
---|
Prescaler | 预分频,即位时序提到的APB1 peripheral clocks继续分一次频 | Time Quantum | 最小时间单位Tq,自动计算出来的,不需要填写 | Time Quanta in Bit Segment 1 | PBS1段长度 | Time Quanta in Bit Segment 2 | PBS2段长度 | ReSynchronization Jump Width | 重同步跳跃宽度,即位时序提到的SJW | Time Triggered Communication Mode | 是否使能时间触发 | Automatic Bus-Off Management | 是否使能自动离线管理 | Automatic Wake-Up Modet | 是否使能自动唤醒 | Qutomatic Retransmission | 是否使能自动重传 | Receive Fifo Locked Mode | 是否使能锁定FIFO | Transmit Fifo Priority | 配置报文优先级的判断方法 | Oprating Mode | 操作模式 |
- 这些参数也可以在can.c中自行修改
- 中断(NVIC)设置,根据需要设置,一般勾上CAN1 RX0 Interrupt
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数}Tq?一个位得Tq数1 例如:在时钟树查得APB1 peripheral clocks是45MHz,预分频为5,则一个Tq为 4 45 M H z = 111.1111 … ( n s ) \frac{4}{45MHz}=111.1111\dots(ns)45MHz4=111.1111…(ns) ,上图中有19个Tq,则此时波特率为1 19 ? 111.11 ? 1 0 ? 9 ≈ 473689 ( b p s ) \frac{1}{19111.11*10^{-9}}\approx473689(bps)19?111.11?10?91≈473689(bps)
|