Files
Hero-C-Board-Legacy/云台/云台-old/System/CAN.c

281 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "stm32f4xx.h" // Device header
#include "stm32f4xx_conf.h"
#include "CAN.h"
#include "M3508.h"
#include "GM6020.h"
#include "M2006.h"
#include "LinkCheck.h"
#include "Warming.h"
#include "CToC.h"
#include "RefereeSystem.h"
uint8_t CAN_CAN1DeviceNumber=4;//CAN1总线上设备数量
uint8_t CAN_CAN2DeviceNumber=2;//CAN2总线上设备数量
uint8_t CAN_DeviceNumber=6;//CAN总线上设备数量
uint32_t CAN_CAN1IDList[10][2]={{CAN_GM6020,GM6020_2},{CAN_M2006,M2006_7},{CAN_M3508,M3508_1},{CAN_M3508,M3508_2},0};//CAN1总线上设备ID列表
uint32_t CAN_CAN2IDList[10][2]={{CAN_GM6020,GM6020_1},{CAN_RoboMasterC,CToC_MasterID1},0};//CAN2总线上设备ID列表
int8_t CAN_IDSelect=0;//CAN总线上ID列表选择位
/*
*函数简介:CAN总线初始化
*参数说明:无
*返回类型:无
*备注:默认使用CAN1(CAN1-Tx为PD1,CAN1-Rx为PD0),CAN2(CAN2-Tx为PB6,CAN2-Rx为PB5)
*备注:CAN波特率1M,默认1Tq=1/14us≈0.07us
*备注:使用CAN2需要在打开CAN2时钟之前打开CAN1时钟,且CAN2筛选器编号为15~27
*/
void CAN_CANInit(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);//开启时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//复用推挽
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//默认上拉
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
GPIO_Init(GPIOD,&GPIO_InitStructure);//配置PD0(CAN1-Rx)和PD1(CAN1-Tx)
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5 | GPIO_Pin_6;
GPIO_Init(GPIOB,&GPIO_InitStructure);//配置PB5(CAN2-Rx)和PB6(CAN2-Tx)
GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_CAN1);//开启PD0的CAN1复用模式
GPIO_PinAFConfig(GPIOD,GPIO_PinSource1,GPIO_AF_CAN1);//开启PD1的CAN1复用模式
GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_CAN2);//开启PB5的CAN2复用模式
GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_CAN2);//开启PB6的CAN2复用模式
CAN_InitTypeDef CAN_InitStructure;
CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;//正常模式
CAN_InitStructure.CAN_Prescaler=3;//时钟分频,1Tq=Prescaler/T_PCLK=Prescaler/42M
CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;//SJW极限值
CAN_InitStructure.CAN_BS1=CAN_BS1_10tq;//PBS1段长度
CAN_InitStructure.CAN_BS2=CAN_BS2_3tq;//PBS2段长度,1/Baudrate=T_1bit=(1+BS1+BS2)Tq
CAN_InitStructure.CAN_TTCM=DISABLE;//关闭时间触发功能
CAN_InitStructure.CAN_ABOM=ENABLE;//开启自动离线管理功能
CAN_InitStructure.CAN_AWUM=ENABLE;//开启自动唤醒功能
CAN_InitStructure.CAN_NART=ENABLE;//禁止自动重传功能
CAN_InitStructure.CAN_RFLM=DISABLE;//关闭锁定FIFO功能
CAN_InitStructure.CAN_TXFP=DISABLE;//配置报文优先级判定为标识符决定
CAN_Init(CAN1,&CAN_InitStructure);
CAN_Init(CAN2,&CAN_InitStructure);
CAN_FilterInitTypeDef CAN_FilterInitStructure;
CAN_FilterInitStructure.CAN_FilterNumber=0;//筛选器编号0(编号0~14属于CAN1,编号15~27属于CAN2)
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//存入FIFO0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//掩码模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_16bit;//筛选器尺度为16bits
CAN_FilterInitStructure.CAN_FilterIdHigh=(CAN_CAN1IDList[0][1]<<5);//标识符=STID[15:5]+RTR[4:4](0)+IDE[3:3](0)+EXID[2:0](000)
CAN_FilterInitStructure.CAN_FilterIdLow=(CAN_CAN1IDList[0][1]<<5);//筛选器尺度为16bits,故没有高低位之分
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0xFFE3;//掩码(1111 1111 0000 0011),1对应位必须匹配,0对应位无需匹配
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xFFE3;//筛选器尺度为16bits,故没有高低位之分
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;//使能筛选器
CAN_FilterInit(&CAN_FilterInitStructure);
CAN_FilterInitStructure.CAN_FilterNumber=15;//筛选器编号15(编号0~14属于CAN1,编号15~27属于CAN2)
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO1;//存入FIFO1
CAN_FilterInitStructure.CAN_FilterIdHigh=(0x000<<5);//标识符=STID[15:5](189/0001 1000 1001)+RTR[4:4](0)+IDE[3:3](0)+EXID[2:0](000)
CAN_FilterInitStructure.CAN_FilterIdLow=(0x000<<5);//CAN2先给0,默认从CAN1开始串行接收
CAN_FilterInit(&CAN_FilterInitStructure);
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//打通CAN1_FIFO0到NVIC的通道
CAN_ITConfig(CAN2,CAN_IT_FMP1,ENABLE);//打通CAN2_FIFO1到NVIC的通道
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//选择NVIC分组2(2位抢占优先级2位响应优先级)
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=CAN1_RX0_IRQn;//选择CAN1_FIFO0接收中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级为1
NVIC_Init(&NVIC_InitStructure);//初始化CAN1_FIFO0的NVIC
NVIC_InitStructure.NVIC_IRQChannel=CAN2_RX1_IRQn;//选择CAN2_FIFO1接收中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级为1
NVIC_Init(&NVIC_InitStructure);//初始化CAN2_FIFO1的NVIC
}
/*
*函数简介:CAN1总线接收报文
*参数说明:报文存储数组
*返回类型:报文ID
*备注:默认8字节标准数据帧
*备注:没有接收到数据,直接退出,返回0
*/
uint32_t CAN_CAN1Receive(uint8_t *Data)
{
CanRxMsg RxMessage;
if(CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0;//没有接收到数据,直接退出
CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);//读取数据
for(uint32_t i=0;i<8;i++)
Data[i]=RxMessage.Data[i];//储存数据
return RxMessage.StdId;//返回ID
}
/*
*函数简介:CAN2总线接收报文
*参数说明:报文存储数组
*返回类型:报文ID
*备注:默认8字节数据
*备注:没有接收到数据,直接退出,返回0
*/
uint32_t CAN_CAN2Receive(uint8_t *Data)
{
CanRxMsg RxMessage;
if(CAN_MessagePending(CAN2,CAN_FIFO1)==0)return 0;//没有接收到数据,直接退出
CAN_Receive(CAN2,CAN_FIFO1,&RxMessage);//读取数据
for(uint32_t i=0;i<8;i++)
Data[i]=RxMessage.Data[i];
return RxMessage.StdId;
}
/*
*函数简介:CAN1总线更改接收ID
*参数说明:接收ID
*返回类型:无
*备注:无
*/
void CAN_CAN1ChangeID(uint32_t ID)
{
CAN1->FMR |= 0x00000001;//配置CAN_FMR寄存器FINIT位进入初始化模式
CAN1->sFilterRegister[0].FR1 = ((uint32_t)0xFFE3<<16) | (ID<<5);//配置CAN_F0R1寄存器更改ID低位
CAN1->sFilterRegister[0].FR2 = ((uint32_t)0xFFE3<<16) | (ID<<5);//配置CAN_F0R2寄存器更改ID高位(16bits尺度下无高低位区别)
CAN1->FMR &= ~(0x00000001);//配置CAN_FMR寄存器FINIT位回到工作模式
}
/*
*函数简介:CAN2总线更改接收ID
*参数说明:接收ID
*返回类型:无
*备注:无
*/
void CAN_CAN2ChangeID(uint32_t ID)
{
CAN1->FMR |= 0x00000001;
CAN1->sFilterRegister[15].FR1 = ((uint32_t)0xFFE3<<16) | (ID<<5);
CAN1->sFilterRegister[15].FR2 = ((uint32_t)0xFFE3<<16) | (ID<<5);
CAN1->FMR &= ~(0x00000001);
}
/*
*函数简介:CAN接收ID列表复位
*参数说明:无
*返回类型:无
*备注:复位CAN_IDSelect,重新从CAN1的1号设备开始接收
*/
void CAN_CANIDReset(void)
{
CAN_IDSelect=0;
CAN_CAN1ChangeID(CAN_CAN1IDList[0][1]);
CAN_CAN2ChangeID(0x000);
}
/*
*函数简介:CAN接收获取裁判系统状态
*参数说明:无
*返回类型:无
*备注:跳转到接收底盘C板的回传数据,主要用于发射机构掉电时的CAN设备隔离
*/
void CAN_CAN_GetRefereeSystemData(void)
{
CAN_IDSelect=5;
CAN_CAN1ChangeID(0x000);
CAN_CAN2ChangeID(CAN_CAN2IDList[1][1]);
}
/*
*函数简介:CAN1_FIFO0接收中断函数
*参数说明:无
*返回类型:无
*备注:进入中断时关闭连接检测计时,离开中断时重新打开连接检测计时
*备注:某一设备掉线时,CAN_IDSelect会停留在当前设备在ID列表的索引
*备注:从掉线到重新连接时会重启遥控器
*/
void CAN1_RX0_IRQHandler(void)
{
if(CAN_GetITStatus(CAN1,CAN_IT_FMP0)==SET)//查询接收中断标志位
{
uint8_t Data[8];//接收数据
uint32_t ID=CAN_CAN1Receive(Data);//接收数据帧的ID
LinkCheck_OFF();//关闭连接检测定时
if(LinkCheck_ErrorID>=0 && LinkCheck_ErrorID<CAN_CAN1DeviceNumber)//接收的是掉线设备的数据
if(ID==CAN_CAN1IDList[LinkCheck_ErrorID][1])
{
LinkCheck_ErrorID=-1;//清除掉线设备
LinkCheck_Error=0;//回到正常连接状态
Warming_BuzzerClean();//清除蜂鸣器报警
}
if(CAN_CAN1IDList[CAN_IDSelect][0]==CAN_M3508)M3508_CANDataProcess(ID,Data);//处理M3508的数据
else if(CAN_CAN1IDList[CAN_IDSelect][0]==CAN_M2006)M2006_CANDataProcess(ID,Data);//处理M2006的数据
else GM6020_CANDataProcess(ID,Data);//处理GM6020的数据
CAN_IDSelect=(CAN_IDSelect+1)%CAN_DeviceNumber;//更换CAN总线ID切换选择位
if(CAN_IDSelect>=0 && CAN_IDSelect<CAN_CAN1DeviceNumber){CAN_CAN1ChangeID(CAN_CAN1IDList[CAN_IDSelect][1]);CAN_CAN2ChangeID(0x000);}//CAN1、CAN2更换接收ID
else{CAN_CAN1ChangeID(0x000);CAN_CAN2ChangeID(CAN_CAN2IDList[CAN_IDSelect-CAN_CAN1DeviceNumber][1]);}//设置接收ID为0规定为关闭接收
if(RefereeSystem_ShooterOpenFlag==1)//检测到发射机构上电添加CAN设备
{
RefereeSystem_ShooterOpenCounter++;
if(RefereeSystem_ShooterOpenCounter>=5000)//计次5000下等待发射机构设备启动
{
RefereeSystem_ShooterOpenCounter=0;
RefereeSystem_ShooterOpenFlag=0;//发射机构离开上电期间
CAN_CAN1DeviceNumber=4;//添加CAN设备
CAN_DeviceNumber=6;
}
}
LinkCheck_ON();//连接检测重新计时
CAN_ClearITPendingBit(CAN1,CAN_IT_FMP0);//清除CAN1的FIFO0接收中断标志位
}
}
/*
*函数简介:CAN2_FIFO1接收中断函数
*参数说明:无
*返回类型:无
*备注:进入中断时关闭连接检测计时,离开中断时重新打开连接检测计时
*备注:某一设备掉线时,CAN_IDSelect会停留在当前设备在ID列表的索引
*/
void CAN2_RX1_IRQHandler(void)
{
if(CAN_GetITStatus(CAN2,CAN_IT_FMP1)==SET)//查询接收中断标志位
{
uint8_t Data[8];//接收数据
uint32_t ID=CAN_CAN2Receive(Data);//接收数据帧的ID
LinkCheck_OFF();//关闭连接检测定时
if(LinkCheck_ErrorID>=CAN_CAN1DeviceNumber && LinkCheck_ErrorID<CAN_DeviceNumber)//接收的是掉线设备的数据
if(ID==CAN_CAN2IDList[LinkCheck_ErrorID-CAN_CAN1DeviceNumber][1])
{
LinkCheck_ErrorID=-1;//清除掉线设备
LinkCheck_Error=0;//回到正常连接状态
Warming_BuzzerClean();//清除蜂鸣器报警
}
if(CAN_CAN2IDList[CAN_IDSelect-CAN_CAN1DeviceNumber][0]==CAN_GM6020)GM6020_CANDataProcess(ID,Data);//处理6020的数据
else if(CAN_CAN2IDList[CAN_IDSelect-CAN_CAN1DeviceNumber][0]==CAN_RoboMasterC)CToC_CANDataProcess(ID,Data);//处理板间通讯
CAN_IDSelect=(CAN_IDSelect+1)%CAN_DeviceNumber;//更换CAN总线ID切换选择位
if(CAN_IDSelect>=0 && CAN_IDSelect<CAN_CAN1DeviceNumber){CAN_CAN1ChangeID(CAN_CAN1IDList[CAN_IDSelect][1]);CAN_CAN2ChangeID(0x000);}//CAN1、CAN2更换接收ID
else{CAN_CAN1ChangeID(0x000);CAN_CAN2ChangeID(CAN_CAN2IDList[CAN_IDSelect-CAN_CAN1DeviceNumber][1]);}//设置接收ID为0规定为关闭接收
if(RefereeSystem_ShooterOpenFlag==1)//检测到发射机构上电添加CAN设备
{
RefereeSystem_ShooterOpenCounter++;
if(RefereeSystem_ShooterOpenCounter>=5000)//计次5000下等待发射机构设备启动
{
RefereeSystem_ShooterOpenCounter=0;
RefereeSystem_ShooterOpenFlag=0;//发射机构离开上电期间
CAN_CAN1DeviceNumber=4;//添加CAN设备
CAN_DeviceNumber=6;
}
}
LinkCheck_ON();//连接检测重新计时
CAN_ClearITPendingBit(CAN2,CAN_IT_FMP1);//清除CAN2的FIFO1接收中断标志位
}
}