/*************笔记****************
1、波特率计算:baud=(systime/(pre*(bs1+bs2+sjw)))
例如: 500khz=(36/(12*(3+2+1)))
2、CudeMX配置CAN:最重要的就是通讯配置要一致,且波特率也一致。
Bit Timings Parameters(位计时参数)
----Prescaler(for Time Quantum) 预分频器(用于时间量)
----Time Quantum (时间量)
----Time Quanta in Bit Segment 1 (位段1中的时间量)
----Time Quanta in Bit Segment 2 (位段2中的时间量)
----Time for one Bit (can总线BT时间确定-用于确定波特率)
----ReSynchronization Jump Width (重同步跳转宽度)
***********************************/
#include "MyCAN.h"
#include "can.h"
#include "FreeRTOS.h"
#include "cmsis_os.h"

/*********************************************
函数名:CAN_Config
功 能:过滤器配置
形 参:
hcan --CAN信息结构体 (hcan/hcan1/hcan2)
FIFO_Num --通道选择 (0=RX_FIFO0/1=RX_FIFO1)
返回值:
备 注:本函数需要放到main.c中进行初始化。 放在MX_CAN_Init();后面的用户区
CAN_Config(&hcan,0);//过滤器配置,启动通道0

笔 记:使用STM32F103CVET6芯片时发现,[PB8/PB9]只能使用FIFO0 [PA11/PA12]两个通道正常使用
**********************************************/
void CAN_Config(CAN_HandleTypeDef *phcan, uint8_t FIFO_Num)
{
/*配置过滤器,用于接收指定范围的ID帧*/
CAN_FilterTypeDef CAN_FilterType;
CAN_FilterType.FilterBank = 0; //筛选器组[0,13]
CAN_FilterType.SlaveStartFilterBank = 14; //启动从过滤器组[0,27]
CAN_FilterType.FilterIdHigh = 0x0000; //要过滤的ID高位[0x0000,0xFFFF]
CAN_FilterType.FilterIdLow = 0x0000; //要过滤的ID低位[0x0000,0xFFFF]
CAN_FilterType.FilterMaskIdHigh = 0x0000; //过滤器高16位每位无必须匹配
CAN_FilterType.FilterMaskIdLow = 0x0000; //过滤器低16位每位无必须匹配
CAN_FilterType.FilterFIFOAssignment = FIFO_Num; //过滤器被关联到(0=RX_FIFO0/1=RX_FIFO1)
CAN_FilterType.FilterMode = CAN_FILTERMODE_IDMASK; //工作在标识符屏蔽位模式
CAN_FilterType.FilterScale = CAN_FILTERSCALE_32BIT; //过滤器位宽为单个32位
CAN_FilterType.FilterActivation = ENABLE; //使能过滤器
if(HAL_CAN_ConfigFilter(phcan, &CAN_FilterType) != HAL_OK)
{
Error_Handler();
}
/*开启对应CAN通道的中断服务*/
if(FIFO_Num == 0)
{
if(HAL_CAN_ActivateNotification(phcan, CAN_IT_RX_FIFO0_MSG_PENDING ) != HAL_OK)
{
Error_Handler();
}
}
else
{
if(HAL_CAN_ActivateNotification(phcan, CAN_IT_RX_FIFO1_MSG_PENDING ) != HAL_OK)
{
Error_Handler();
}
}

/*启动CAN通讯*/
if(HAL_CAN_Start(phcan) != HAL_OK)
{
Error_Handler();
}
}

/*********************************************
函数名:Can_TxMessage
功 能:利用CAN发送一帧数据
形 参:
hcan --CAN信息结构体 (hcan/hcan1/hcan2)
ide --帧类型 (0,标准帧 1,扩展帧)
id --帧ID号 (标准帧[0,0x7FF] 扩展帧[0,0x1FFFFFFF])
len --数据长度 (指数组长度byte) 范围:0-8
pdata --数据内容 例如:"12345678"或数组地址 长度由上面参数决定
返回值:0:成功。1:失败
备 注:
**********************************************/
uint8_t Can_TxMessage(CAN_HandleTypeDef *phcan, uint8_t ide, uint32_t id, uint8_t len, uint8_t *pdata)
{
uint32_t TxMailbox; //得到发送成功的邮箱号
CAN_TxHeaderTypeDef TxHeader; //发送-头协议 信息结构体,用于填充参数
HAL_StatusTypeDef HAL_RetVal; //CAN返回值
uint16_t i = 0;
/*填充 发送 头协议*/
if(ide == 0)
{
TxHeader.IDE = CAN_ID_STD;
TxHeader.StdId = id;
}
else
{
TxHeader.IDE = CAN_ID_EXT;
TxHeader.ExtId = id;
}

TxHeader.RTR = CAN_RTR_DATA, //消息的帧类型 数据帧
TxHeader.DLC = len, //帧的长度 8
TxHeader.TransmitGlobalTime = DISABLE; //不捕获时间

/*询问CAN是否有空闲邮箱*/
while(HAL_CAN_GetTxMailboxesFreeLevel(phcan) == 0)
{
i++;
if(i > 0xfffe)//超时,发送失败
return 1;
}
osDelay(1);

/*发送帧*/
HAL_RetVal = HAL_CAN_AddTxMessage(phcan, &TxHeader, pdata, &TxMailbox); //发送一帧数据
//printf("TxMailbox %d\r\n",TxMailbox);
if(HAL_RetVal != HAL_OK)
return 1;
return 0;
}

/*********************************************
函数名:HAL_CAN_RxFifo0MsgPendingCallback
功 能:CAN 通道0 接收回调函数,当有完整帧到达,就会触发。
形 参:hcan --CAN信息结构体 (hcan/hcan1/hcan2)
返回值:
备 注:
**********************************************/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
uint8_t Rxbuff[8] = ""; //存放帧数据
CAN_RxHeaderTypeDef RxHeader; //存放帧头协议
HAL_StatusTypeDef HAL_RetVal; //CAN返回值

if(hcan->Instance == CAN1)
{

HAL_RetVal = HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxHeader, Rxbuff); //从通道0缓存区读取一帧
if(HAL_RetVal == HAL_OK)
{
/*用户自定义区*/
if(RxHeader.IDE == 0)
{
printf("FIFO0,ID:%d -- Rxbuff:%s\r\n", RxHeader.StdId, Rxbuff);
}
else
{
printf("FIFO0,ID:%d -- Rxbuff:%s\r\n", RxHeader.ExtId, Rxbuff);
}
}
}
//if(hcan->Instance == CAN2)//针对有两个CAN时,共享通道0
}
/*********************************************
函数名:HAL_CAN_RxFifo1MsgPendingCallback
功 能:CAN 通道1 接收回调函数,当有完整帧到达,就会触发。
形 参:hcan --CAN信息结构体 (hcan/hcan1/hcan2)
返回值:
备 注:
**********************************************/
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
uint8_t Rxbuff[8] = ""; //存放帧数据
CAN_RxHeaderTypeDef RxHeader; //存放帧头协议
HAL_StatusTypeDef HAL_RetVal; //CAN返回值

if(hcan->Instance == CAN1)
{
HAL_RetVal = HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO1, &RxHeader, Rxbuff); //从通道1缓存区读取一帧
if(HAL_RetVal == HAL_OK)
{
/*用户自定义区*/
if(RxHeader.IDE == 0)
{
printf("FIFO1,ID:%d -- Rxbuff:%s\r\n", RxHeader.StdId, Rxbuff);
}
else
{
printf("FIFO1,ID:%d -- Rxbuff:%s\r\n", RxHeader.ExtId, Rxbuff);
}
}
}
//if(hcan->Instance == CAN2)//针对有两个CAN时,共享通道1
}


/*用于回环测试*/
void Can_Dome(CAN_HandleTypeDef *hcan1)
{
uint8_t sta;
sta = Can_TxMessage(hcan1, 0, 8, 8, "789456");
if(sta != 0)
{
printf("err:%d\r\n", sta);
}
}
#ifndef _MYCAN_H
#define _MYCAN_H
#include "main.h"
void CAN_Config(CAN_HandleTypeDef *phcan, uint8_t FIFO_Num);

uint8_t Can_TxMessage(CAN_HandleTypeDef *phcan, uint8_t ide, uint32_t id, uint8_t len, uint8_t *pdata);

void Can_Dome(CAN_HandleTypeDef *hcan1);
#endif