项目场景:
CAN通讯相比较于USART,具有更高的抗干扰性能,并且能并挂多个负载,节约单片机资源
CubeMX关键配置:
代码修改
can.c文件添加发送函数:
/* USER CODE BEGIN 1 */
CAN_TxHeaderTypeDef TXHeader;
CAN_RxHeaderTypeDef RXHeader;
/*CAN发送数据,入口参数为要发送的数组指针,数据长度,返回0代表发送数据无异常,返回1代表传输异常*/
uint8_t CAN_Send_Msg(uint32_t CAN_TxExtId,uint8_t* msg,uint8_t len)
{
uint8_t i=0;
uint32_t TxMailbox;
uint8_t message[8];
TXHeader.ExtId=CAN_TxExtId; //扩展标识符(29位)
TXHeader.IDE=CAN_ID_EXT; //使用扩展帧
TXHeader.RTR=CAN_RTR_DATA; //数据帧
TXHeader.DLC=len;
for(i=0;i<len;i++)
{
message[i]=msg[i];
}
if(HAL_CAN_AddTxMessage(&hcan, &TXHeader, message, &TxMailbox) != HAL_OK)//发送
{
return 1;
}
while(HAL_CAN_GetTxMailboxesFreeLevel(&hcan) != 3) {}
return 0;
}
/* USER CODE END 1 */
任务函数间断发送:
/*******************************************CAN数据整理打包发送*****************************************************/
ContrlToB_Byte_Messagey[0]=(Laser_En_Flag<<2)|Spitfire_En_Flag<<1|Oil_En_Flag; //发送的是激光 喷火 喷油 (当然喷火的时候一定会喷油)
ContrlToB_Byte_Messagey[1]=Angle_Rand[1];
ContrlToB_Byte_Messagey[2]=Angle_Rand[2];
ContrlToB_Byte_Messagey[3]=0x00;
ContrlToB_Byte_Messagey[4]=0x00;
ContrlToB_Byte_Messagey[5]=0x00;
ContrlToB_Byte_Messagey[6]=0x00;
ContrlToB_Byte_Messagey[7]=ContrlToB_Byte_Messagey[0]+ContrlToB_Byte_Messagey[1]+ContrlToB_Byte_Messagey[2]+
ContrlToB_Byte_Messagey[3]+ContrlToB_Byte_Messagey[4]+ContrlToB_Byte_Messagey[5]+ContrlToB_Byte_Messagey[6];
Can_count1++;
if(Can_count1>=3) //90ms发送一次CAN信息给控制板B
{
CAN_Send_Msg(0x00004710,ContrlToB_Byte_Messagey,8);
}
写到这里还不够,会导致发送卡死
找到can的init函数,在usercode里添加:
/* USER CODE BEGIN CAN_Init 2 */
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterActivation = ENABLE;//打开过滤器
sFilterConfig.FilterBank = 0;//过滤器0 这里可设0-13
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;//采用掩码模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;//采用32位掩码模式
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;//采用FIFO0
sFilterConfig.FilterIdHigh = 0x0000; //设置过滤器ID高16位
sFilterConfig.FilterIdLow = 0x0000;//设置过滤器ID低16位
sFilterConfig.FilterMaskIdHigh = 0x0000;//设置过滤器掩码高16位
sFilterConfig.FilterMaskIdLow = 0x0000;//设置过滤器掩码低16位
if(HAL_CAN_ConfigFilter(&hcan,&sFilterConfig) != HAL_OK)//初始化过滤器
{
Error_Handler();
}
if(HAL_CAN_Start(&hcan) != HAL_OK)//打开can
{
Error_Handler();
}
if(HAL_CAN_ActivateNotification(&hcan,CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)//开启接受邮箱0挂起中断
{
Error_Handler();
}
/* USER CODE END CAN_Init 2 */
上位机验证
打开GCANTools软件,找到设备,配置CAN1,波特率选择1000K,观察接受CAN数据是否正常。
CAN中断接收部分:
需要在CubeMX里开启中断
程序部分
添加接受邮箱0挂起中断回调函数
uint8_t RXmessage[8];
uint32_t pTxMailbox = 0;
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)//接受邮箱0挂起中断回调函数
{
if(HAL_CAN_GetRxMessage(hcan,CAN_FILTER_FIFO0,&RXHeader,RXmessage)==HAL_OK)//获取数据
{
//接受来自主控制板A的数据
if (RXHeader.ExtId ==0x00004710)
{
if (RXmessage[7]!=RXmessage[0]+RXmessage[1]+RXmessage[2] +RXmessage[3] +RXmessage[4]+RXmessage[5] +RXmessage[6]) return; //校验
// printf("Can_Recive_Step1:DataCrc16 Passed\r\n");
Oil_En_Flag=(RXmessage[0]&0x01)>>0; //00000001
Spitfire_En_Flag=(RXmessage[0]&0x02)>>1; //00000010
Laser_En_Flag=(RXmessage[0]&0x04)>>2;
Vertical_Angle_Offset=RXmessage[1]; //俯仰角度偏移量 俯仰设置的最大角度是28.65 即0.5弧度
Horizontal_Angle_Offset=RXmessage[2]; //水平角度偏移量
if(RXmessage[0]==0x06) //调试判断返回帧
{
CAN_Send_Msg(0x00004712,TXmessage3,8);
}
//数值接受后处理
if(Oil_En_Flag==1)
{
htim3.Instance->CCR3=1850;
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,1);
}
else if(Oil_En_Flag==0)
{
htim3.Instance->CCR3=1100;
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,1);
}
if(Spitfire_En_Flag==1)
{
htim3.Instance->CCR3=1850;
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,1);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,1);
}
else if(Spitfire_En_Flag==0)
{
if(Oil_En_Flag==0) htim3.Instance->CCR3=1100;
else if(Oil_En_Flag==1) htim3.Instance->CCR3=1850;
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,0); //GPIO_PIN_14 管理点火
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,1);
}
if(Laser_En_Flag==1) HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,1);
else if(Laser_En_Flag==0) HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,0);
}
//接受来自CAN设备2的数据
else if (RXHeader.ExtId ==0x00002014)
{
if (RXmessage[7]!=RXmessage[0]+RXmessage[1]+RXmessage[2] +RXmessage[3] +RXmessage[4]+RXmessage[5] +RXmessage[6]) return; //校验
printf("Can_Recive_Step1:DataCrc16 Passed\r\n");
// Oil_En_Flag=(RXmessage[2]&0x01)>>0; //00000001
// Spitfire_En_Flag=(RXmessage[2]&0x02)>>1; //00000010
// Laser_En_Flag=(RXmessage[2]&0x04)>>2;
if(RXmessage[0]==0x01)
{
CAN_Send_Msg(0x00002015,TXmessage3,8);
}
}
}
}
判断 if (RXHeader.ExtId ==0x00004710)
这样就可以实现接受不同的扩展帧ID处理不同的数据啦!