ba_wang_mao 发表于 2009-3-27 15:06:37

CANBUS高层协议-周立功公司推出的iCAN协议学习笔记

点击此处下载 ourdev_429047.pdf(文件大小:1.31M) (原文件名:iCAN协议(1.0).pdf)

ba_wang_mao 发表于 2009-3-27 15:10:52

点击此处下载 ourdev_429048.rar(文件大小:3K) (原文件名:ican.rar)

ba_wang_mao 发表于 2009-3-27 15:11:45

//////////////////////////////////////////////////////////////////////////////////
//FuncID                功能                                                描述
//0x00                Reserve                        保留功能码
//0x01                连续写端口                用于对单个或者多个资源节点的数据写入
//0x02                连续读端口                用于读取单个或者多个资源节点的数据
//0x03                事件触发传送        用于从站主动向已建立连接的主站传送数据
//0x04                建立连接                用于和iCAN从站建立通讯连接
//0x05                删除连接                用于删除与iCAN从站的通讯连接
//0x06                设备复位                用于复位iCAN从站
//0x07                MACID检测                用于检测网络上是指定MACID从站是否存在
//0x08-0x0e        Reserve                        保留功能码
//0x0f                异常响应                从站不能正确处理接收到的命令帧时,发送异常响应帧
//////////////////////////////////////////////////////////////////////////////////

ba_wang_mao 发表于 2009-3-27 15:14:46

///////////////////////////////////////////////////////////////////////////////////////////
//函数名称:=ICAN_SourceTest
//功能描述:资源检测
///////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
//                        order=
//                        sourceid=资源节点地址
//                        sourcelenth=资源节点数量
//                        readorwrite=
//                                                0:读资源标志
//                                                1:写资源标志
//返回参数:
//                        1=失败
//                        0=成功       
////////////////////////////////////////////////////////////////////////////////
uchar ICAN_SourceTest(uchar order,uchar sourceid,uchar sourcelenth,uchar readorwrite)
{
        uchar data i;
       
//-----------------------------------------------------
//检测要读写的资源是否落在DI区域(0x00~0x1F)
//-----------------------------------------------------
        if (sourceid < 0x20)                                                                //        DI区域
        {
                i = SourceType;                                                //取出当前从站的《开关量输入总数》
                if (readorwrite)                                                                //        写资源请求吗?
                        return 1;                                                                        //        返回失败
        }
//-----------------------------------------------------
//检测要读写的资源是否落在DO区域(0x20~0x3F)
//-----------------------------------------------------
        else if (sourceid < 0x40)                                                        //        DO区域
        {
                i= SourceType ;                                                //取出当前从站的《开关量输出总数》
                sourceid -= 0x20;//????????????
                if (readorwrite == 0)                                                        //        读资源请求吗?
                        return 1;                                                                        //        返回失败
        }
//-----------------------------------------------------
//检测要读写的资源是否落在AI区域(0x40~0x5F)
//-----------------------------------------------------
        else if (sourceid < 0x60)                                                        //        AI区域
        {
                i= SourceType ;                                                //取出当前从站的《模拟量输入总数》
                sourceid -= 0x40;//???????????
                if (readorwrite)                                                                //        写资源请求吗?
                        return 1;                                                                        //        返回失败
        }
//-----------------------------------------------------
//检测要读写的资源是否落在AI区域(0x60~0x7F)
//-----------------------------------------------------
        else if (sourceid < 0x80)                                                        //        AO区域
        {
                i= SourceType;                                                //取出当前从站的《模拟量输出总数》
                sourceid -= 0x60;//?????????????????????
                if (readorwrite == 0)                                                        //        读资源请求吗?
                        return 1;                                                                        //        返回失败
        }
//-----------------------------------------------------
//其他区域为可读写了
//-----------------------------------------------------
        else
        {
                return 0;                                                                                //        可读写区域(此处为什么不检查资源节点数量是否超出区域呢?)
        }        
        if (i==0)                                                                                        //        如果当前从站的资源类型数量(DI/DO/AI/AO)=0
                return 1;                                                                                //        返回失败
        if (sourcelenth + sourceid > i)                                                //        如果读取资源节点地址+资源节点数量>从站的资源类型数量(DI/DO/AI/AO)
                return 1;                                                                                //        返回失败
        return 0;                                                                                        //        返回成功
}


///////////////////////////////////////////////////////////////////////////////////////////
//函数名称:=ICAN_ObjIDManage
//功能描述:ICAN报文标识码生成
//                        本子程序的目的是将结构体指针ICAN_ObjID中保存的上述信息,
//                        合并到一个long型变量ulObjId中。
///////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
//                        ICAN_ObjID=指向iCAN报文标识码的结构体指针
//返回参数:
//                        ulObjId=合成后的iCAN报文标识码
//说明:iCAN协议的报文格式如下:
//                (1)、ID28-ID21=SrcMACID (源节点地址))
//                (2)、ID20-ID13=DestMACID((目标节点地址)
//                (3)、ID12=ACK
//                (4)、ID11-ID8=FuncID(功能码)
//                (5)、ID7-ID0=Source ID(资源节点地址)
///////////////////////////////////////////////////////////////////////////////////////////
uint32 ICAN_ObjIDManage(ICAN_OBJ* ICAN_ObjID)
{
    uint32 xdata ulObjId;

        ulObjId = 0;
    ulObjId =        (ICAN_ObjID->SrcMACID << 21) +                        //        源节点编号
                                (ICAN_ObjID->DestMACID << 13) +                        //        目标节点编号
                                (ICAN_ObjID->ACK << 12) +                                //        应答标志
                                (ICAN_ObjID->FUNCID << 8) +                                //        功能码
                                (ICAN_ObjID->SourceID);                                        //        资源节点编号
    return (ulObjId);
}

ba_wang_mao 发表于 2009-3-27 15:16:59

///////////////////////////////////////////////////////////////////////////////////////////
//函数名称:=ICAN_ObjIDRestore
//功能描述:ICAN报文标识码还原
//                        将long型变量Receive_ObjID中保存的iCAN报文标识码分离到结构体指针*ICAN_ObjID。
///////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
//                        Receive_ObjID=ICAN报文标识码
//出口参数:
//                        * ICAN_ObjID=结构体指针
///////////////////////////////////////////////////////////////////////////////////////////
void ICAN_ObjIDRestore(ICAN_OBJ *ICAN_ObjID, uint32 Receive_ObjID)
{   
    ICAN_ObjID->SrcMACID = (Receive_ObjID >> 21) & 0x000000FF;        //        源节点编号(ID28-ID21)
        ICAN_ObjID->DestMACID = (Receive_ObjID >> 13) & 0x000000FF;        //        目标节点编号(ID20-ID13)
    ICAN_ObjID->ACK = (Receive_ObjID >> 12) & 0x00000001;                //        应答标志(ID12)
    ICAN_ObjID->FUNCID = (Receive_ObjID >> 8) & 0x000000F;                //        功能码(ID11-ID8)
        ICAN_ObjID->SourceID = (Receive_ObjID) & 0x000000FF;                //        资源节点编号(ID7-ID0)
}


///////////////////////////////////////////////////////////////////////////////////////////
//函数名称:=ICAN_ObjByte0Manage
//功能描述:生成iCAN报文数据段0字节BYTE0(SegFlag,多帧传输及单帧传输)
///////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
//                TxCtr=读数据指针????????????????????????????????????
//                Lenth=报文长度(数据场长度)
//出口参数:
//                CAN报文数据段0字节(BYTE0)=SegFlag
///////////////////////////////////////////////////////////////////////////////////////////
uchar ICAN_ObjByte0Manage(uint TxCtr, uint Lenth)
{   
        uchar ucTemp;

//--------------------------------------------------------------------------       
//小于8字节,本次数据传输没有分段,分段标志SegFlag=0(iCAN报文一次最多只能传输7个字节)
//--------------------------------------------------------------------------       
        if (Lenth < 8)
        {
      ucTemp = 0;                                                                                //        BYTE0=0x00       
    }
        else
        {
//--------------------------------------------------------------------------       
//批量数据的第一个分段(SegPolo=01=0x40《bit7,bit6》,批量数据传输的第1个分段;此时,SegNum=0x00值)
//--------------------------------------------------------------------------       
                if (TxCtr == 0)                                                                        //        如果读数据指针=0                       
                {
                        ucTemp = 0x40;                                                                //        BYTE0=0x40       
      }
//--------------------------------------------------------------------------       
//批量数据的最后一个分段(SegPolo=11=0xC0《bit7,bit6》,最后分段)
//--------------------------------------------------------------------------       
                else if (TxCtr + 7 >= Lenth)                                        //        如果读数据指针+7>=报文长度
                {
            ucTemp = 0xC0;                                                                //        BYTE0=0xC0       
      }
                else
                {            
            if (TxCtr > 448)                                                        //        发送数据超过448字节
                        {
                return (0xFF);
            }
//--------------------------------------------------------------------------       
//中间数据段(中间分段SegPolo=10。SegNum值从0x01起,每次加1,以区分段数)
//--------------------------------------------------------------------------       
            ucTemp = TxCtr / 7 + 0x80;                                        //        计数对应的段数,并标识为中间段
      }                                                                                                //        BYTE0=0x80+分段编号(读数据指针/7)       
    }
    return (ucTemp);                                                                        //        生成标识符                       
}


///////////////////////////////////////////////////////////////////////////////////////////
//函数名称:=CAN_ObjByte0Restore
//功能描述:iCAN报文数据段0字节生成(获取分段标识)
//                        应用于连续写端口命令。根据接收报文中的第一个字节(分段码)来区分多帧数据中到底是
//                        哪一帧。(参见iCAN协议)
///////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
//                *RxCtr=接收缓冲区数据接收指针
//                segflag=接收报文第一字节=分段码
//出口参数:
//                *RxCtr=数据接收指针
//                ucTemp:
//                                0=接收的报文中没有分段
//                                1=当前是接收报文的第一分段
//                                segflag & 0x3f=当前是接收报文的中间分段(因为SegPolo占用bit7,bit6,分段号占用bit5,bit4,bit3,bit2,bit1,bit0,因此用0x3F分离出分段号)
//                                65=当前是接收报文的最后一个分段
//-----------------------------------------------------------------------------
uchar ICAN_ObjByte0Restore(uint * RxCtr, uchar segflag)
{   
        uchar ucTemp;
   
//-----------------------------------------------------------------------------
//无分段标识(SegPolo=00)
//-----------------------------------------------------------------------------
        if (segflag == 0)                                                                        //        没有分段
        {
      *RxCtr = 0x00;                                                                        //        接收数据指针指向零
      ucTemp = 0x00;                                                                        //        0=没有分段
    }
//-----------------------------------------------------------------------------
//最后分段标识(SegPolo=11)
//-----------------------------------------------------------------------------
        else if ((segflag & 0xC0) == 0xC0)                                        //        批量数据的最后一个分段
        {
      ucTemp = 65;                                                                        //        65=最后一个分段
    }
//-----------------------------------------------------------------------------
//第一分段标识(SegPolo=01)
//-----------------------------------------------------------------------------
        elseif ((segflag & 0x40) == 0x40)                                        //        启始段,批量数据的第一个分段
        {
      *RxCtr = 0x00;                                                                        //        接收数据指针指向零
      ucTemp = 0x01;                                                                        //        1=第一分段
    }
//-----------------------------------------------------------------------------
//中间分段标识(SegPolo=10)
//-----------------------------------------------------------------------------
        else                                                                                                //        中间数据段
        {
      ucTemp = segflag & 0x3f;                                                //        返回中间分段号
      *RxCtr = (segflag&0x3f)*7;                                                //        接收数据指针
    }
    return (ucTemp);                                                                        //        生成标识符                       
}


//*********************************************************************************************************
//定义iCAN帧ID码节点结构体
// ********************************************************************************************************
//typestruct {                                //        帧ID码
//          
//          uint32SrcMACID;
//          uint32DestMACID;
//          uint32ACK;
//          uint32FUNCID;
//          uint32SourceID;
//} ICAN_OBJ;

//typestruct {                                //        ICAN读写缓冲
//          
//          uint32 ulID;                        //        发送的ID代码
//    uintucDataLenth;        //        数据场长度
//          uintucDataCtr;                //        读数据指针
//          uchar ucXID;                        //0 标准帧;1 扩展帧
//          uchar        TrBegin;
//          uchar        ucDataBuff;        //        数据缓冲(32)字节
//} tICAN_TRBUFF;

///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=ICAN_ErrIDACK(uchar order)
//功能描述=填写错误报文
//-----------------------------------------------------------------------------------------
//                        1、从iCAN帧头结构体(ICANSlav_ObjID)取出“资源节点编号”-------
//                                                                                                       “源节点编号”                        |------>填写到结构体ICAN_ObjIDTmp
//                                                                                                      “目标节点编号”-------
//
//                                                                                                       “应答”=1       -------       
//                                                                                                                                                        |------>填写到结构体ICAN_ObjIDTmp
//                                                                                                       “功能码”=0x0F-------
//                                其中结构体ICAN_ObjIDTmp保存iCAN帧头信息,包括如下:
//                                        源节点编号、目标节点编号、应答位、功能码、资源节点编号
//                        2、填写iCAN读写缓冲结构体
//                                        (1)、填写发送的ID代码=(源节点编号、目标节点编号、应答位、功能码、资源节点编号)
//                                        (2)、填写扩展帧
//                                        (3)、填写数据缓冲区=错误代码(只填写一个字节)
//                                        (4)、填写发送报文长度=2字节(一个字节用来标识单帧/多帧,另一个字节=错误码)
//                                        (5)、填写读数据指针=0
//                                        (6)、填写发送开始标志
//-----------------------------------------------------------------------------------------
//入口参数:
//                order=
//                ErrID=错误号
///////////////////////////////////////////////////////////////////////////////////////////
void ICAN_ErrorIDACK(uchar order,uchar ErrID)
{
        ICAN_OBJ xdata ICAN_ObjIDTmp;

    ICAN_ObjIDTmp.SourceID = ICANSlav_ObjID.SourceID;        //        资源节点编号
    ICAN_ObjIDTmp.FUNCID = 0x0F;                                                                //        功能码
    ICAN_ObjIDTmp.ACK = 1;                                                                                //        应答标志
    ICAN_ObjIDTmp.DestMACID = ICANSlav_ObjID.SrcMACID;        //        目标节点编号
    ICAN_ObjIDTmp.SrcMACID = ICANSlav_ObjID.DestMACID;        //        源节点编号
   
        ICAN_TrBuff.ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp);        //        生成ICAN报文ID
    ICAN_TrBuff.ucXID = 1;                                                                //0 标准帧;1 扩展帧
    ICAN_TrBuff.ucDataBuff = ErrID;                                        //返回对应的错误代码
    ICAN_TrBuff.ucDataLenth = 2;                                                        //数据场长度1字节
    ICAN_TrBuff.ucDataCtr = 0;                                                        //读数据指针指0字节
    ICAN_TrBuff.TrBegin = 1;                                                                //        发送开始标志置位       
}



uchar function = 0;

//*********************************************************************************************************
//定义CAN报文结构体                               
// ********************************************************************************************************
//typestruct _tCANFrame {
//          uchar ucXID;                                                        //        0 标准帧(CAN2.0A);1 扩展帧(CAN2.0B)
//          uchar ucDLC;                                                        //        数据场长度(DLC)
//          uint32 ulID;                                                        //        CAN报文ID(iCAN帧标识符)
//          uchar ucDataBuff;                                        //        报文数据场
} tCANFrame;

///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_ConnectACK(uchar order, tCANFrame *pCANFrame)
//功能描述=建立连接命令(功能码=0x04,用于和iCAN从站建立通讯连接)
//★★★命令帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=0 功能码=0x04 资源节点=0xF7  |        分段码=0x00  MasterMACID  CyclicMaster
//
//★★★正常响应帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=1 功能码=0x04 资源节点=0xF7  |        分段码=0x00  DILen  DOLenAILenAOLen
//
//★★★异常响应帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=1 功能码=0x0F 资源节点=0xF7  |        分段码=0x00  ERRID
//说明:
//(1)、
//        在“建立连接”命令帧中源节点地址为主站 MACID,报文数据长度为 3 个字节。报文数据部分第一个字节表示分段码
//        (固定为 0x00) ;报文数据第二个字节表示主站 MACID;报文数据的第三个字节表示主站定时循环参数(CyclicMaster)
//(2)、CyclicMaster的单位为 10ms,当 CyclicMaster > 0时, (CyclicMaster*4)时间为从站判断主站发送通讯报文
//        的是否超时的时间间隔,在通讯过程中,如果从站在(CyclicMaster*4)时间内未收到主站的命令报文,将自动删除连接,
//        退出通讯。当CyclicMaster为 0 时,从站不检测通讯超时,直到收到正确的“删除连接”命令帧时,才删除与主站的连接。
//----------------------------------------------------------------------------------------------------------------
//入口参数:
//                        order=
//                        *pCANFrame=CAN报文结构体指针(保存DLC、iCAN帧头、iCAN报文)                                                       
//出口参数:
//                        无
//-----------------------------------------------------------------------------
void iCAN_ConnectACK(uchar order, tCANFrame *pCANFrame)
{
    ICAN_OBJ xdata ICAN_ObjIDTmp;                                                //        iCAN帧头结构体

//----------------------------------------------------------------------------
//检测之前是否已经建立连接成功
//----------------------------------------------------------------------------
        if (function >= 1)                                                                        //        如果之前已经建立过连接,两次建立连接则报错
        {
          ICAN_ErrorIDACK(order,ErrID_NotCommand);       
        }
//----------------------------------------------------------------------------
//检测功能码=0x04
//----------------------------------------------------------------------------
        else if (pCANFrame->ulID&0x00000400!=0x00000400)
        {
                ICAN_ErrorIDACK(order,ErrID_NotFunctionID);                //        功能码不对;
        }                                                                               
/*         else if(ICAN_Source.Area!=pCANFrame->ucDataBuff)
        {
                ICAN_ErrorIDACK(order,ErrID_NotCommand);//错误代码返回报文(命令不技持,主站ID不对);
        }
*/
//----------------------------------------------------------------------------
//检测分段码=0(主站请求报文的第一个字节必须=0,即分段码=0)
//----------------------------------------------------------------------------
        else if ((pCANFrame->ucDataBuff!=0))
        {
                ICAN_ErrorIDACK(order,ErrID_ParameterError);        //        错误代码返回报文(参数非法)
        }
//----------------------------------------------------------------------------
//填写应答报文给主站分三步骤:
//(1)、从报文中读取主站节点的MACID和通信节拍数
//(2)、填写iCAN报文帧头结构体ICAN_ObjIDTmp
//                        SrcMACID=源结点编号
//                        DestMACID=目标结点编号
//                        ACK=1
//                        FUNCID=0x04=功能码
//                        SourceID=0xF7=资源节点编号       
//(3)、填写iCAN读写缓冲区结构体ICAN_TrBuff
//                        ulID=iCAN帧头格式合成(ID28-ID0)
//                        ucXID = 1(扩展帧),iCAN只支持扩展帧
//                        ucDataLenth=5,发送报文长度(DLC=5);分段码占用一字节,DIlen占用一字节,DOlen占用一字节,AIlen占用一字节,AOlen占用一字节(共计5字节)
//                        ucDataBuff=报文数据场2字节(DI资源数量)
//                        ucDataBuff=报文数据场3字节(DO资源数量)
//                        ucDataBuff=报文数据场4字节(AI资源数量)
//                        ucDataBuff=报文数据场5字节(AO资源数量)
//                        TrBegin=发送报文标志
//----------------------------------------------------------------------------
        else
        {
                ICAN_Source.Area = pCANFrame->ucDataBuff;        //        读取主站节点的MACID
                ICAN_Source.Area = pCANFrame->ucDataBuff;        //        读取主站节点定时通信节拍数

                //----------------------------------
                //填写iCAN帧头结构体信息
                //----------------------------------
                ICAN_ObjIDTmp.SourceID = 0xF7;                                                                                //        资源节点编号
                ICAN_ObjIDTmp.FUNCID = 0x04;                                                                                //        功能码
                ICAN_ObjIDTmp.ACK = 1;                                                                                                //        应答标志(从站返回应答报文)
                ICAN_ObjIDTmp.DestMACID = ICAN_Source.Area;                //        目标节点编号
                ICAN_ObjIDTmp.SrcMACID = ICAN_Source.Area;                        //        源节点编号

                //------------------------------------
                //填写iCAN读写缓冲区结构体
                //------------------------------------
                ICAN_TrBuff.ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp);                        //        生成ICAN报文ID
                ICAN_TrBuff.ucXID = 1;                                                                                //0 标准帧;1 扩展帧
                ICAN_TrBuff.ucDataLenth = 5;                                                                        //数据场长度5字节
                ICAN_TrBuff.ucDataCtr = 0;                                                                        //读数据指针指0字节
                ICAN_TrBuff.ucDataBuff = SourceType;                        //报文数据场2字节(DI资源数量)
                ICAN_TrBuff.ucDataBuff = SourceType;                        //报文数据场3字节(DO资源数量)
                ICAN_TrBuff.ucDataBuff = SourceType;                        //报文数据场4字节(AI资源数量)
                ICAN_TrBuff.ucDataBuff = SourceType;                        //报文数据场5字节(AO资源数量)
                ICAN_TrBuff.TrBegin = 1;                                                                                //        发送开始标志置位       
        }
//----------------------------------------------------------------------------
//设置建立连接成功
//----------------------------------------------------------------------------
    function++;
}





///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_MACIDTest(uchar order, uchar ack)
//功能描述=MACID检测命令(从站上电发送MACID检测命令),功能码=0x07
//                        “MAC ID检测”命令帧用于检测网络中是否存在指定“节点地址”的从站。在 iCAN
//                        网络中,具有该“节点地址”的从站在接收到“MAC ID检测”命令帧后给出响应,告
//                        知命令发送节点,该“节点地址”已经存在。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//★★★命令帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=0 功能码=0x07 资源节点=随机数  |        分段码=0x00  MAC ID  序列号(4字节)
//
//★★★响应帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=1 功能码=0x07 资源节点=随机数  |        分段码=0x00  MAC ID  序列号(4字节)
//说明:
//(1)、在“MAC ID检测”命令帧中资源节点为随机数。报文数据长度为 6 个字节,报文数据第一个字节表示分段码(固定为 0) ;
//                第二个字节表示要检测的“节点地址” ;第三至六字节为发送命令节点的设备序列号。
//(2)、从站在收到格式正确的“MACID检测”命令帧后,如果命令帧中的 MAC ID与自身的“节点地址”相同,从站发送“MAC ID
//                检测”响应帧。对格式不正确的“MACID检测” 命令帧或命令帧中的 MAC ID与自身的 “节点地址”不同,从站忽略该 “MAC
//                ID检测”命令帧,不产生任何响应报文。
//(3)、“MAC ID检测”响应帧数据部分的“MAC ID”表示发送响应报文节点的“节点地址” ,4 字节的“产品序列号”为发送
//                响应的节点的设备序列号。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
//        order=
//        ack=
//                0:
//                1:
//出口参数:
//        无                                               
//-----------------------------------------------------------------------------
void iCAN_MACIDTest(uchar order, uchar ack)
{
   
    ICAN_OBJ xdata ICAN_ObjIDTmp;                                                                                                //        iCAN帧头结构体

    ICAN_ObjIDTmp.SourceID = 0xEE;                                                                                                //        资源节点编号(随机)
    ICAN_ObjIDTmp.FUNCID = 0x07;                                                                                                //        功能码
    ICAN_ObjIDTmp.ACK = ack;                                                                                                        //        应答标志
//------------------------------------------------------------------------------------------------
//为了探测网络上是否有相同的节点编号,故源节点编号=目标节点编号,都从0xEE中获取
//------------------------------------------------------------------------------------------------
        ICAN_ObjIDTmp.DestMACID = ICAN_Source.Area;                                        //        目标节点编号
    ICAN_ObjIDTmp.SrcMACID = ICAN_Source.Area;                                        //        源节点编号
   
        ICAN_TrBuff.ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp);                                        //        生成ICAN报文ID
    ICAN_TrBuff.ucXID = 1;                                                                                                //0 标准帧;1 扩展帧
    ICAN_TrBuff.ucDataLenth = 6;                                                                                        //数据场长度6字节
    ICAN_TrBuff.ucDataCtr = 0;                                                                                        //读数据指针指0字节
    ICAN_TrBuff.ucDataBuff = ICAN_Source.Area;                        //报文数据场2字节(MACID)
    ICAN_TrBuff.ucDataBuff = ICAN_Source.Area;        //报文数据场3字节(SN第1字节)
    ICAN_TrBuff.ucDataBuff = ICAN_Source.Area; //报文数据场4字节(SN第2字节)
    ICAN_TrBuff.ucDataBuff = ICAN_Source.Area; //报文数据场5字节(SN第3字节)
    ICAN_TrBuff.ucDataBuff = ICAN_Source.Area; //报文数据场5字节(SN第4字节)
    ICAN_TrBuff.TrBegin = 1;                                                                                                //        发送开始标志置位       
}



///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_UnConnectACK(uchar order, tCANFrame *pCANFrame)
//功能描述=删除连接命令(功能码=0x05)
//                        “删除连接”命令帧用于主站撤销与从站建立的通讯。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//★★★命令帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=0 功能码=0x05 资源节点=0xF7  |        分段码=0x00  Master MACID
//
//★★★正常响应帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=1 功能码=0x05 资源节点=0xF7  |        分段码=0x00

//★★★异常响应帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=1 功能码=0x0F 资源节点=0xF7  |        分段码=0x00        ERRID
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
//        order=
//        *pCANFrame=CAN报文结构体(保存iCAN帧头、DLC、报文数据场数据)
//出口参数:
//        无
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void iCAN_UnConnectACK(uchar order, tCANFrame *pCANFrame)
{
   
        ICAN_OBJ xdata ICAN_ObjIDTmp;

//----------------------------------------------------------------------------------------------------------------
//检测之前是否未建立连接成功,若是,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
        if (function ==0 )
        {
                ICAN_ErrorIDACK(order, ErrID_NotConnect) ;                //        错误代码返回报文连接不存在
        }
//----------------------------------------------------------------------------------------------------------------
//检测命令帧报文第二字节的Master MACID是否和从站保存的Master MACID相同,若不相同,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
        else if (pCANFrame->ucDataBuff != ICAN_Source.Area)
        {
                ICAN_ErrorIDACK(order, ErrID_NotConnect) ;                //        错误代码返回报文连接不存在
                return;
    }
//----------------------------------------------------------------------------------------------------------------
//检测命令帧报文第一字节的分段码=0,若不等于0,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
        else if ((pCANFrame->ucDataBuff!=0))
        {
                ICAN_ErrorIDACK(order,ErrID_ParameterError);        //        错误代码返回报文(参数非法)
        }
//----------------------------------------------------------------------------------------------------------------
//取消建立连接,发送正常响应帧报文给主站
//----------------------------------------------------------------------------------------------------------------
    else
        {
                function=0;                                                                                //        取消建立连接
            ICAN_ObjIDTmp.SourceID = 0xF7;                                                                                //        资源节点编号
            ICAN_ObjIDTmp.FUNCID = 0x05;                                                                                //        功能码
            ICAN_ObjIDTmp.ACK = 1;                                                                                                //        应答标志
            ICAN_ObjIDTmp.DestMACID = ICAN_Source.Area;                //        目标节点编号
            ICAN_ObjIDTmp.SrcMACID = ICAN_Source.Area;                        //        源节点编号

            ICAN_Source.Area = NOMASTER;                                        //        清除目标主站节点的MACID
            ICAN_Source.Area = 0;                                                        //        清除目标主站节点定时通信节拍数

            ICAN_TrBuff.ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp);                        //        生成ICAN报文ID
            ICAN_TrBuff.ucXID = 1;                                                                                //0 标准帧;1 扩展帧
            ICAN_TrBuff.ucDataLenth = 1;                                                                        //数据场长度1字节
            ICAN_TrBuff.ucDataCtr = 0;                                                                        //读数据指针指0字节
            ICAN_TrBuff.TrBegin = 1;                                                                                //        发送开始标志置位       
        }
}




///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_ResetACK(uchar order, tCANFrame *pCANFrame)
//功能描述=设备复位命令(功能码=0x06)
//                        “设备复位”命令帧用于复位从站设备。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//★★★命令帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=0 功能码=0x06 资源节点=随机数  |        分段码=0x00  Master MACID
//
//★★★正常响应帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=1 功能码=0x06 资源节点=随机数  |        分段码=0x00

//★★★异常响应帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=1 功能码=0x0F 资源节点=随机数  |        分段码=0x00        ERRID
//
//说明:
//(1)、在“设备复位”命令帧中资源节点可以为任意地址,报文数据长度为 2 个字节,报文数据第一个字节表示分段码,
//                报文数据第二个字节表示目标节点 MAC ID。
//(2)、从站收到正确的“设备复位”命令后,如果从站支持命令复位功能,返回正常响应,随后设备重启。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
//        order=
//        *pCANFrame=CAN报文结构体(保存iCAN帧头、DLC、报文数据场数据)
//出口参数:
//        无
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void iCAN_ResetACK(uchar order, tCANFrame *pCANFrame)
{
        ICAN_OBJ xdata ICAN_ObjIDTmp;
   
//----------------------------------------------------------------------------------------------------------------
//检测之前是否未建立连接成功,若是,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
        if (function==0)
        {
                ICAN_ErrorIDACK(order, ErrID_NotConnect) ;                                                //        错误代码返回报文连接不存在
                return;               
        }
//----------------------------------------------------------------------------------------------------------------
//ICANSlav_ObjID=iCAN帧头的结构体(包含:源节点、目的节点、功能码、ACK、资源节点地址)
//如果iCAN帧头结构体中包含的源结点编号≠从站保存的Master MACID        ,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
//这段指令的含义是判断连接是否存在,因为删除连接时,会将从站保存的Master MACID设置为不可能的节点编号(120)
//因此可能通过检测从站内部保存的Master MACID和iCAN帧头中的源节点编号是否相同来检测连接是否已经建立。
//----------------------------------------------------------------------------------------------------------------
        if (ICAN_Source.Area!= ICANSlav_ObjID.SrcMACID)
        {
                ICAN_ErrorIDACK(order, ErrID_NotConnect) ;                                                //        错误代码返回报文连接不存在
                return;
        }
//----------------------------------------------------------------------------------------------------------------
//检测命令帧报文第二字节的Master MACID是否和从站保存的Master MACID相同,若不相同,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
        if ((pCANFrame->ucDataBuff != ICAN_Source.Area))
        {
                ICAN_ErrorIDACK(order, ErrID_ParameterError) ;                                        //        错误代码返回报文参数非法(参数非法 错误码命令处理)
      return;
    }
//----------------------------------------------------------------------------------------------------------------
//如果不支持复位命令,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
        if (FlagSystemResetEn)
        {
                ICAN_ErrorIDACK(order, ErrID_NotCommand) ;                                                //        错误代码返回不支持复位命令
      return;
    }
    ICAN_ObjIDTmp.SourceID = 0xF7;                                                                                //        资源节点编号
    ICAN_ObjIDTmp.FUNCID = 0x06;                                                                                //        功能码
    ICAN_ObjIDTmp.ACK = 1;                                                                                                //        应答标志
    ICAN_ObjIDTmp.DestMACID = ICAN_Source.Area;                //        目标节点编号
    ICAN_ObjIDTmp.SrcMACID = ICAN_Source.Area;                        //        源节点编号

    ICAN_TrBuff.ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp);                        //        生成ICAN报文ID
    ICAN_TrBuff.ucXID = 1;                                                                                //0 标准帧;1 扩展帧
    ICAN_TrBuff.ucDataLenth = 1;                                                                        //数据场长度1字节
    ICAN_TrBuff.ucDataCtr = 0;                                                                        //读数据指针指0字节
    ICAN_TrBuff.TrBegin = 1;                                                                                //        发送开始标志置位       
        //复位的节点是本节点
        //SystemReset();//系统复位标志
}




///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_ReadACK(uchar order, uchar sourceID, tCANFrame *pCANFrame)
//功能描述=连续读端口命令(功能码=0x02)
//                        “连续读端口”命令帧用于读取指定资源节点中的数据。在命令帧中指定了所要读取的资源
//                        节点首地址和读取的数据长度。从站接收到“连续读端口”命令后,如果判断命令帧有效,
//                        就会将资源中的数据返回给主站。。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//★★★访问资源节点命令帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=0 功能码=0x02 资源节点  |        分段码=0x00  Length
//
//说明:
//(1)、访问资源节点的“连续读端口”命令用于访问资源节点 0x00~0xF8。
//(2)、在访问资源节点的“连续读端口”命令帧中,报文数据部分第一个字节表示分段码(固定为 0x00) ,
//               第二个字节为所要读出的数据长度(Length<=32) 。使用“连续读端口”命令访问资源节点时,最
//               多允许读出 32个资源节点的数据。如果所读的字节数据超过 7 个字节,则从站使用分帧响应。
//
//★★★访问资源子节点命令帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=0 功能码=0x02 资源节点  |        分段码=0x00  SubIndexLength
//
//说明:
//(1)、访问资源子节点的“连续读端口”命令用于访问资源节点 0xF9~0xFF处的资源子节点。
//(2)、在访问资源子节点的“连续读端口”命令帧中,报文数据部分第一个字节表示分段码(固定为 0x00) ;
//               第二个字节为所要读的资源子节点;第三个字节为所要读出的数据长度(Length<=32) 。使用“连续
//               读端口”命令访问资源子节点时,最多允许读出 32个资源子节点的数据。如果所读的字节数据超过7个
//               字节,则从站使用分帧响应。
//
//★★★正常响应帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=1 功能码=0x02 资源节点  |        分段码 1-7个字节
//
//说明:
//(1)、如果“连续读端口”命令帧中指定的资源段范围在从站中有效,从站使用正常响应返回主站读取的数据;
//               当主站请求的数据超过7个字节时,从站使用分段传输。“连续读端口”命令最多允许读出 32个资源节
//                点的数据。
//
//★★★异常响应帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=1 功能码=0x0F 资源节点  |        分段码=0x00        ERRID
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
//        order=
//        *pCANFrame=CAN报文结构体(保存iCAN帧头、DLC、报文数据场数据)
//出口参数:
//        无
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void iCAN_ReadACK(uchar order, uchar sourceID, tCANFrame *pCANFrame)
{
   
    ICAN_OBJ xdata ICAN_ObjIDTmp;                                                //        iCAN帧头的结构体
    uchar i, j, k, l;

//----------------------------------------------------------------------------------------------------------------
//ICANSlav_ObjID=iCAN帧头的结构体(包含:源节点、目的节点、功能码、ACK、资源节点地址)
//如果iCAN帧头结构体中包含的源结点编号≠从站保存的Master MACID        ,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
//这段指令的含义是判断连接是否存在,因为删除连接时,会将从站保存的Master MACID设置为不可能的节点编号(120)
//因此可能通过检测从站内部保存的Master MACID和iCAN帧头中的源节点编号是否相同来检测连接是否已经建立。
//----------------------------------------------------------------------------------------------------------------
        if (ICAN_Source.Area!= ICANSlav_ObjID.SrcMACID)        //        连接不存在 错误码命令处理
        {
               
                ICAN_ErrorIDACK(order, ErrID_NotConnect) ;                //        错误代码返回报文连接不存在
                return;
        }
//----------------------------------------------------------------------------------------------------------------
//检测之前是否未建立连接成功,若是,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
        if (function==0)                                                                        //        连接不存在 错误码命令处理
        {
                       
                ICAN_ErrorIDACK(order, ErrID_NotConnect) ;                //        错误代码返回报文连接不存在
                return;
        }
//---------------------------------------------------------------------------------------------------------       
//资源检测,返回1=资源非法,返回0=资源合法
//sourceID=资源节点编号
//pCANFrame->ucDataBuff=iCAN命令帧第二字节(=访问资源节点Length)
//0=连续读端口标志
//---------------------------------------------------------------------------------------------------------       
        if (ICAN_SourceTest(order,sourceID,pCANFrame->ucDataBuff,0))        //        资源检测
        {
                ICAN_ErrorIDACK(order, ErrID_NotSourceID) ;                //        错误代码返回报文资源不存在
                return;
        }

//-----------------------------------------------------------------------------------
//填写iCAN帧头结构体相关信息
//-----------------------------------------------------------------------------------
        ICAN_ObjIDTmp.SourceID = ICANSlav_ObjID.SourceID;                //        资源节点编号
    ICAN_ObjIDTmp.FUNCID = 0x02;                                                                        //        读功能码
    ICAN_ObjIDTmp.ACK = 1;                                                                                        //        应答标志
    ICAN_ObjIDTmp.DestMACID = ICAN_Source.Area; //        目标节点编号???????????????
    ICAN_ObjIDTmp.SrcMACID = ICAN_Source.Area;                //        源节点编号?????????????????

//-----------------------------------------------------------------------------------
//填写iCAN读写缓存结构体
//-----------------------------------------------------------------------------------
    ICAN_TrBuffR.ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp);        //        生成ICAN报文ID(iCAN帧头合成)
    ICAN_TrBuffR.ucXID = 1;                                                                        //0 标准帧;1 扩展帧       
    i = sourceID;                                                                                                        //        获取资源节点的地址

//------------------------------------------------------------------------------------------
//根据接收报文的帧头中的资源节点地址来判断当前是“连续读资源节点”还是“连续读资源子节点”
//------------------------------------------------------------------------------------------
    if (i >= 0xF9)
        {
                k = pCANFrame->ucDataBuff;                                                                //        读取资源节点的子地址(SubIndex)
                j = pCANFrame->ucDataBuff;                                                                //        读取资源长度(Length)
          if (j >= 32)                                                                                                //        一次最多能读32单元超过则为无效,参数非法
                {
                        ICAN_ErrorIDACK(order, ErrID_ParameterError);                        //        错误代码返回报文
                        return;
          }
                if ((i+j) > 0xFF)                                                                                        //        要读取的资源节点数量超过255,参数非法
                {
                        ICAN_ErrorIDACK(order, ErrID_NotSourceID) ;                                //        错误代码返回报文
                        return;
          }
//---------------------------------------------------------------------------------------------
//#define IOParameter           0xF8                                                                        //        输入/输出通道参数
//---------------------------------------------------------------------------------------------
                   if (i==IOParameter)                                                                                        //        IO参数
                {
                           if (j < 4)                                                                                                //        读取资源长度(Length)<4吗?
                        {                                                                                                                //        因为输入/输出通道参数只包含DILen,DOLen,AILen,AOLen=4
                                for (l = 0,k=0; l < j; l++, k++)
                                {
                                        //将数据送入接收缓冲
                                        ICAN_TrBuffR.ucDataBuff = SourceType; //读取指定单元的地址       
                                }
                        }
                        else
                        {
                               
                                ICAN_ErrorIDACK(order, ErrID_NotSourceID);                        //        错误代码返回报文,参数非法
                                return;
                        }
//---------------------------------------------------------------------------------------------
//#define IOConfigure         0xF9                                                                                //        输入/输出配置参数
//---------------------------------------------------------------------------------------------
//“配置资源” 用于设备标识、 通讯参数以及 I/O单元的配置, 占用资源节点 0xE0~0xFF。“配置资源”
//包括设备标识、通讯参数、I/O 属性和 I/O 配置,通过配置资源节点可以获取iCAN 从站设备的各种信息。
//---------------------------------------------------------------------------------------------
                }
                else if (i == IOConfigure)                                                                        //        IO配置
                {
                           if (j < 32)
                        {
                                for (l = 0; l < j; l++, k++)
                                {
                                        //将数据送入接收缓冲
                                        ICAN_TrBuffR.ucDataBuff = ICAN_IOconfig; //读取指定单元的地址       
                                }
                        }
                        else
                        {
                                ICAN_ErrorIDACK(order, ErrID_NotSourceID);                        //        错误代码返回报文,参数非法
                                return;
                        }
                }
//---------------------------------------------------------------------------------------------
//读资源子节点的保留数据
//---------------------------------------------------------------------------------------------
                else
                {

                }
        }
//---------------------------------------------------------------------------------------------
//读取正常数据
//---------------------------------------------------------------------------------------------
        else
        {
                j = pCANFrame->ucDataBuff;                                                                //        读取资源节点长度
                if (j >= 32)                                                                                                //        一次最多能读32单元超过则为无效,参数非法
                {
                        ICAN_ErrorIDACK(order, ErrID_ParameterError);                        //        错误代码返回报文,参数非法
                        return;
          }
          if ((i+j) >0xFF)                                                                                        //        资源节点超过255,参数非法
                {
                        ICAN_ErrorIDACK(order, ErrID_NotSourceID) ;                                //        错误代码返回报文,参数非法
                        return;
          }
                for (l = 0; l < j; l++, i++)                                                                //        将数据送入接收缓冲       
                {   
            ICAN_TrBuffR.ucDataBuff = ICAN_Source.Area; //读取指定单元的地址       
      }
    }
    ICAN_TrBuffR.ucDataLenth = j + 1;                                                //数据场长度k字节
    ICAN_TrBuffR.ucDataCtr = 0;                                                                //读数据指针指0字节
    ICAN_TrBuffR.TrBegin = 1;                                                                //        发送开始标志置位       
}




///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_WriteACK(uchar order, uchar sourceID, tCANFrame *pCANFrame)
//功能描述=连续写端口命令(功能码=0x01)
//                        “连续写端口”命令帧用于修改指定资源节点中的数据。在命令帧中指定了所要进行操
//                        作的资源的首地址以及数据。从站接收到“连续写端口”命令后,如果判断命令帧有效,
//                        就会保存命令中的数据到相应的资源节点位置。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//★★★访问资源节点命令帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=0 功能码=0x01 资源节点  |        分段码  1~7个字节
//
//说明:
//(1)、访问资源节点的“连续写端口”命令用于访问资源节点 0x00~0xF8。
//(2)、在访问资源节点的“连续写端口”命令帧中,报文数据部分第一个字节为分段码,第二个字节
//                开始为所要写入的数据,当所要写入的数据超过 7 个字节时,则要使用分段传输。使用连续写
//                端口命令访问资源节点时,最多允许修改 32 个资源节点的数据。
//
//★★★访问资源子节点命令帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=0 功能码=0x01 资源节点  |        分段码  资源子节点1~6个字节
//
//说明:
//(1)、访问资源子节点的“连续写端口”命令用于访问资源节点 0xF9~0xFF处的资源子节点。
//(2)、在访问资源子节点的“连续写端口”命令帧中,报文数据部分第一个字节为分段码,第二个字节为
//               要访问的资源子节点,第三个字节开始为所要写入的数据。当所要写入的数据超过 6个字节时,则
//               要使用分段传输,使用分段传输时,只有第一段命令帧的数据部分包含资源子节点,中间和结尾段
//               的命令帧的数据部分只包含分段码和传输的数据。使用连续写端口命令访问资源子节点时,最多允
//               许修改 32个资源子节点的数据。
//
//★★★正常响应帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=1 功能码=0x01 资源节点  |        分段码=0x00
//
//说明:
//(1)、        如果“连续写端口”命令帧中指定的资源段范围在从站中有效,从站在正确处理接收到的数据后
//                        返回正常响应。使用多段传输时,从站只有在接收完最后一段命令帧后才作出响应。
//
//★★★异常响应帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=1 功能码=0x0F 资源节点  |        分段码=0x00        ERRID
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
//        order=
//        *pCANFrame=CAN报文结构体(保存iCAN帧头、DLC、报文数据场数据)
//出口参数:
//        无
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void iCAN_WriteACK(uchar order, uchar sourceID, tCANFrame *pCANFrame)
{
    static uchar WriteTest=0;                                                                                                                        //        全局变量,记录多帧传输前一分段编号
    ICAN_OBJ xdata ICAN_ObjIDTmp;                                                                                                                //        iCAN帧头结构体
    uchar i, j, l;
       
//----------------------------------------------------------------------------------------------------------------
//ICANSlav_ObjID=iCAN帧头的结构体(包含:源节点、目的节点、功能码、ACK、资源节点地址)
//如果iCAN帧头结构体中包含的源结点编号≠从站保存的Master MACID        ,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
//这段指令的含义是判断连接是否存在,因为删除连接时,会将从站保存的Master MACID设置为不可能的节点编号(120)
//因此可能通过检测从站内部保存的Master MACID和iCAN帧头中的源节点编号是否相同来检测连接是否已经建立。
//----------------------------------------------------------------------------------------------------------------
        if (ICAN_Source.Area!= ICANSlav_ObjID.SrcMACID)                        //        连接不存在,错误码命令处理
        {
                ICAN_ErrorIDACK(order, ErrID_NotConnect) ;                                                                                //        错误代码返回报文连接不存在
                return;
        }
//----------------------------------------------------------------------------------------------------------------
//检测之前是否未建立连接成功,若是,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
        if (function == 0)                                                                                                                                        //        还没有建立连接, 错误码命令处理
        {
                ICAN_ErrorIDACK(order, ErrID_NotConnect);                                                                                //        错误代码返回报文连接不存在
                return;
        }
//----------------------------------------------------------------------------------------------------------------
//获取分段标识子程序,入口参数如下:
//ICAN_ReBuff.ucDataCtr=接收缓冲区结构体读数据指针
//pCANFrame->ucDataBuff=CAN报文结构体第一字节(存储分段码)
//返回:0=无分段
//           65=最后分段
//                1=第一分段
//       其它=中间分段
//----------------------------------------------------------------------------------------------------------------
        i = ICAN_ObjByte0Restore(&ICAN_ReBuff.ucDataCtr, pCANFrame->ucDataBuff);        //        获取分段标识

//----------------------------------------------------------------------------------------------------------------
//数据接收完毕或者没有分段报文
//----------------------------------------------------------------------------------------------------------------
   if (i == 65 || i == 0)
        {
      for (l = 1; l < pCANFrame->ucDLC; l++)                                                                                        //        将最后一帧或唯一的数据送入接收缓冲
                {
            ICAN_ReBuff.ucDataBuff.ucDataCtr++] =pCANFrame->ucDataBuff; //        读取CAN结构体中的数据到接收缓冲区       
      }
          if (ICAN_ReBuff.ucDataCtr >= 32)                                                                                        //一次最多能读32单元超过则为无效,资源节点超过255也是非法
                {
                        ICAN_ErrorIDACK(order, ErrID_ParameterError);                                                                //        错误代码返回报文,参数非法
                        return;
          }
                if (ICAN_SourceTest(order,ICANSlav_ObjID.SourceID,ICAN_ReBuff.ucDataCtr,1))       
                {                                                                                                                                                                //        写端口时,资源检测
                        ICAN_ErrorIDACK(order, ErrID_NotSourceID);                                                                        //        错误代码返回报文资源不存在
                        return;
                }
      if (ICANSlav_ObjID.SourceID >= 0xF9)                                                                                //        写资源字节点地址
                {
                        l = ICAN_ReBuff.ucDataBuff;//资源地址的子地址
                        if (i == IOParameter)
                        {//IO参数
                                   if (ICAN_ReBuff.ucDataCtr < 5)
                                {//资源配置数量为4字节
                                  for (j=1;j<ICAN_ReBuff.ucDataCtr;j++,l++){
                                                //将接收缓冲数据送入目标资源
                                                SourceType = ICAN_TrBuff.ucDataBuff; //读取指定单元的地址       
                                        }
                                }else{
                                        //参数非法
                                        ICAN_ErrorIDACK(order, ErrID_ParameterError) ;//错误代码返回报文//参数非法
                                        return;
                                }
                        }else if(i==IOConfigure){//IO配置
                                   if(ICAN_ReBuff.ucDataCtr<32){//资源配置数量为4字节
                                  for(j=1;j<ICAN_ReBuff.ucDataCtr;j++,l++){
                                                //将接收缓冲数据送入目标资源
                                                ICAN_IOconfig = ICAN_TrBuff.ucDataBuff; //读取指定单元的地址       
                                        }
                                }else{
                                        //参数非法
                                        ICAN_ErrorIDACK(order, ErrID_ParameterError) ;//错误代码返回报文//参数非法
                                        return;
                                }
                        }else{//其他资源子地址无效
                                        //参数非法
                                        ICAN_ErrorIDACK(order, ErrID_NotSourceID) ;//错误代码返回报文//参数非法
                                        return;
                        }
                }else{//写普通资源节点
                  i = sourceID; //获取资源节点的地址
                  if((i<0x20)||((i>=40)&&(i<60))){//只读区进行写
                                        ICAN_ErrorIDACK(order, ErrID_OprationInvalid) ;//错误代码返回报文//操作无效
                                        return;
                        }
                        for(j=0;j<ICAN_ReBuff.ucDataCtr;j++,i++){
                                ICAN_Source.Area=ICAN_ReBuff.ucDataBuff;//将数据写入对应的资源区
                        }
                }
          ICAN_ObjIDTmp.SourceID = ICANSlav_ObjID.SourceID; //资源节点编号
          ICAN_ObjIDTmp.FUNCID = 0x01; //写功能码
          ICAN_ObjIDTmp.ACK = 1; //应答标志
          ICAN_ObjIDTmp.DestMACID = ICAN_Source.Area; //目标节点编号
          ICAN_ObjIDTmp.SrcMACID = ICAN_Source.Area; //源节点编号
          ICAN_TrBuff.ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp); //生成ICAN报文ID
          ICAN_TrBuff.ucXID = 1; //0 标准帧;1 扩展帧//
          ICAN_TrBuff.ucDataLenth = 1; //数据场长度1字节//
          ICAN_TrBuff.ucDataCtr = 0; //读数据指针指0字节//
          ICAN_TrBuff.TrBegin = 1; //发送开始标志置位       
                WriteTest=0;//保护标志无效
        }
//----------------------------------------------------------------------------------------------------------------
//接收到第一个段
//----------------------------------------------------------------------------------------------------------------
        else if (i == 1)
        {
                if (WriteTest!=0)                                                                                                                                //        接收过程被重刷新
                {
                        ICAN_ErrorIDACK(order, ErrID_WriteError) ;                                                                        //错误代码返回报文,参数非法
                        return;
                }
                for (l = 1; l < 8; l++)                                                                                                                                                       
                {
                        ICAN_ReBuff.ucDataBuff.ucDataCtr++] =pCANFrame->ucDataBuff; //读取缓冲区中的数据       
                }
                WriteTest = 2;                                                                                                                                        //        下一段为02段
        }
//----------------------------------------------------------------------------------------------------------------
//数据接收中间段
//----------------------------------------------------------------------------------------------------------------
        else
        {
                if (WriteTest != i)                                                                                                                                //        接收过程帧格式不正确
                {
                        ICAN_ErrorIDACK(order, ErrID_ParameterError);                                                                //        错误代码返回报文//参数非法
                        return;
                }
                WriteTest++;                                                                                                                                        //        指向下一个帧
      for (l = 1; l < 8; l++)                                                                                                                        //        将数据送入接收缓冲
                {
            ICAN_ReBuff.ucDataBuff.ucDataCtr++] =pCANFrame->ucDataBuff; //读取缓冲区中的数据       
      }
          if (ICAN_ReBuff.ucDataCtr >= 32)                                                                                        //        一次最多能读32单元超过则为无效,资源节点超过255也是非法       
                {
                        ICAN_ErrorIDACK(order, ErrID_ParameterError);                                                                //        错误代码返回报文,参数非法
                        return;
          }
        }
}




///////////////////////////////////////////////////////////////////////////////////////////
//函数名称=iCAN_CyclicACK(uchar order)
//功能描述=事件触发传送命令(功能码=0x03)
//                        事件触发传送”命令用于 iCAN 从站主动向已建立连接的主站发送数据。iCAN 从站的
//                        “定时循环传送”和“事件触发传送”都使用该命令帧格式。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//★★★命令帧格式
//                                                                                CAN帧ID                                                                                CAN帧数据部分
//----------------------------------------------------------------------------------------------------------------
//                        源节点目标节点 ACK=1 功能码=0x03 资源节点  |        分段码  输入端口数据
//
//说明:
//(1)、iCAN 从站根据输入端口的数据长度,决定是否采用分段传输。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//入口参数:
//        order=
//出口参数:
//        无
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void iCAN_CyclicACK(uchar order)
{
    ICAN_OBJ xdata ICAN_ObjIDTmp;
    uchar i, j, l;

//----------------------------------------------------------------------------------------------------------------
//这段指令的含义是判断连接是否存在,因为删除连接时,会将从站保存的Master MACID设置为不可能的节点编号(120)
//因此可能通过检测从站内部保存的Master MACID和iCAN帧头中的源节点编号是否相同来检测连接是否已经建立。
//----------------------------------------------------------------------------------------------------------------
        if (ICAN_Source.Area == NOMASTER )
        {
                ICAN_ErrorIDACK(order, ErrID_NotConnect);                                                //        错误代码返回报文连接不存在
                return;
        }
//i=0x00;                                                                                                                                //        (DI区)
//        j = SourceType;                                                                                        //        获取资源节点的地址(DI区)

        i=0x40;                                                                                                                                //        (AI区)
    j = SourceType;                                                                                        //        获取资源节点的地址(AI区)
        ICAN_ObjIDTmp.SourceID =i;                                                                                        //        资源节点编号(AI区)
    ICAN_ObjIDTmp.FUNCID = 0x03;                                                                                //        事件触发传送命令功能码
    ICAN_ObjIDTmp.ACK = 1;                                                                                                //        应答标志
    ICAN_ObjIDTmp.DestMACID = ICAN_Source.Area;                //        目标节点编号
    ICAN_ObjIDTmp.SrcMACID = ICAN_Source.Area;                        //        源节点编号

    ICAN_TrBuffC.ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp);                //        生成ICAN报文ID
    ICAN_TrBuffC.ucXID = 1;                                                                                //0 标准帧;1 扩展帧      
        for (l = 0; l < j; l++, i++)                                                                                //        读取正常数据,最多读取32字节,将数据送入接收缓冲               
        {       
                ICAN_TrBuffC.ucDataBuff = ICAN_Source.Area; //        读取指定单元的地址       
        }
    ICAN_TrBuffC.ucDataLenth = j + 1;                                                        //数据场长度k字节
    ICAN_TrBuffC.ucDataCtr = 0;                                                                        //读数据指针指0字节
    ICAN_TrBuffC.TrBegin = 1;                                                                        //        发送开始标志置位       
}




///////////////////////////////////////////////////////////////////////////////////////////
//ICAN模块从机通信接收子程序(Explain=解释, 说明)
///////////////////////////////////////////////////////////////////////////////////////////
void ICANRxMsgObjExplain(uchar order)
{
        tCANFrame xdata CANFrame;                                                                                        //        CAN报文结构体(存储CAN报文信息:DLC、DATA-DATA,扩展帧=1,iCAN报文帧头合成)
   
//----------------------------------------------------------------------------------------------------------------
//有数据处理,需要处理数据
//----------------------------------------------------------------------------------------------------------------
        if (ICAN_ControlInfo.ReDataCtr)
        {
                ICAN_ControlInfo.ReDataCtr--;
//----------------------------------------------------------------------------------------------------------------
//需要加入你的代码======
//----------------------------------------------------------------------------------------------------------------
//                ?????需要加入你的代码
//                ?????需要加入你的代码
//                ?????需要加入你的代码
      if (CAN_ucReadBuffer(pReceFrameBuff,&CANFrame) != EMPTY)                //
                {
//                        if (1)
                        {//如果到数据
//需要加入你的代码===================================================================
                                //如果数据不为空则处理


//----------------------------------------------------------------------------------------------------------------
//结构体CANFrame中保存的iCAN帧头合成信息--->结构体指针ICANSlav_ObjID
//----------------------------------------------------------------------------------------------------------------
                                ICAN_ObjIDRestore(&ICANSlav_ObjID, CANFrame.ulID);                                        //        ICAN报文标识码还原                       
                                switch (ICANSlav_ObjID.FUNCID)
                                {
                                        case 0x01:                                                                                                                                //        用于对单个或者多个资源节点的数据写入
                                                iCAN_WriteACK(order, ICANSlav_ObjID.SourceID, &CANFrame);        //        写数据命令命令
                                                break;
                                        case 0x02:                                                                                                                                //        用于对单个或者多个资源节点的数据读取
                                                iCAN_ReadACK(order, ICANSlav_ObjID.SourceID, &CANFrame);                //        读数据命令命令
                                                break;
                                        case 0x03:                                                                                                                                //        返回0X0F出错响应
                                                ICAN_ErrorIDACK(order, ErrID_NotFunctionID);                                                //        错误代码返回报文
                                                //iCAN_CyclicACK(order);
                                                break;
                                        case 0x04:                                                                                                                                //        用于和iCAN节点建立连接
                                                iCAN_ConnectACK(order, &CANFrame);                                                                        //        建立连接命令
                                                break;
                                        case 0x05:                                                                                                                                //        用于删除与iCAN节点建立的连接
                                                iCAN_UnConnectACK(order, &CANFrame);                                                                //        建立连接命令
                                                break;
                                        case 0x06:                                                                                                                                //        用于复位iCAN节点       
                                                iCAN_ResetACK(order, &CANFrame);                                                                        //        复位设备命令
                                                break;
                                        case 0x07:                                                                                                                                //        MACID检测命令
                                                if (ICANSlav_ObjID.ACK == 0)                                                                        //        ACK == 0(接收到检测命令)
                                                {                                                                                                                                        //        用于响应网络上是否有相同MACID节点的检测
                                                        iCAN_MACIDTest(order,1);                                                                                //        接收到MACID检测命令并返回响应命令
                                                }
                                                else                                                                                                                                //        ACK == 1(接收到响应命令)
                                                {
                                                        MACIDTemp = ICAN_Source.Area;                                                //        记录当前的MACID
                                                        ICAN_ControlInfo.MACIDTestStep = 9;                                                //        检测到相同的MACID节点
                                                }
                                                break;
                                        default:
                                                ICAN_ErrorIDACK(order, ErrID_NotFunctionID) ;                                                //        错误代码返回报文
                                                break;
                                }
      }
    }
}



//-----------------------------------------------------------------------------
//                                        ICAN模块从机通信处理程序
//-----------------------------------------------------------------------------
/*
void ICANSlaveISR(uchar order, unsigned long ulMsgObjID)
{
   
    tCANFrame xdata CANFrame;
    if (ulMsgObjID) {
      //有中断产生   
      
         // 中断接收数据
      for (i = 0; i < 4; i++) {
            //对4个接收邮箱进行读数据处理
            if (ulMsgObjID & (0x00000001 << (ulICANRxMsgNbrTbl - 1))) {
                //只要有一个邮箱接收数据则进行处理
                MsgObjectBuf.pucMsgData = CANFrame.ucDataBuff; //获取数据指针
                CANMessageGet(pCAN_Node_Info->ulChNr, ulICANRxMsgNbrTbl, &MsgObjectBuf, 1); //读取邮箱数据
                if (pReceFrameBuff->ucBufFull != 0) {
                  //接收缓冲区未满
                  CANFrame.ucXID = 1; //扩展ID
                  CANFrame.ulID = (MsgObjectBuf.ulMsgID & 0x1FFFFFFF); //读取ID内容
                  CANFrame.ucDLC = MsgObjectBuf.ulMsgLen; //获取数据长度
                  CAN_ucWriteBuffer(pReceFrameBuff, &CANFrame);//把接收的数据写入指定的接收缓存
                  
                }
                ICAN_ControlInfo.ReDataCtr++;
            }
      }
         */
      /*
         *中断发送数据
         
      for (i = 0; i < 4; i++) {
            //对4个发送邮箱进行读数据处理
            if ((ulMsgObjID & (0x00000001 << (pCAN_Node_Info->ulTxMsgObjNr - 1)))) {//有中断生产
                ClearIntFlag(pCAN_Node_Info, pCAN_Node_Info->ulTxMsgObjNr);//清除发送中断标志
//                if ((SendBuffToBus((void*)pCAN_Node_Info)) == 0) {
//                  //总线不忙
                  ICAN_ControlInfo.Idle = 0;
//                }
            }
      }
    }
} */




////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//ICAN模块从机通信发送子程序(单帧发送报文)
//-----------------------------------------------------------------------------------------------------------------
//(1)、ICAN_TrBuff=通用报文发送缓冲区
//(2)、ICAN_TrBuffR=读应答报文发送缓冲区(专门应用于连续读端口命令,功能码=0x02)
//(3)、ICAN_TrBuffC=循环应答报文发送(专门应用于事件触发传送命令,功能码=0x03)
//(4)、ICAN_ControlInfo.Idle = 0(发送模块空闲)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ICANTxMsgObjSend(uchar order)
{
   
    tCANFrame xdata CANFrame;                                                        //        定义CAN报文结构体
        tICAN_RWBUFF *pICAN_TrBuff;                                                        //        定义一个从机ICAN节点资源读缓冲
        uchar i;

        if ((ICAN_TrBuff.TrBegin || ICAN_TrBuffR.TrBegin || ICAN_TrBuffC.TrBegin) && (ICAN_ControlInfo.Idle == 0))       
        {
//-----------------------------------------------------------------------------------------------------------------
//通用报文发送
//-----------------------------------------------------------------------------------------------------------------
                if (ICAN_TrBuff.TrBegin)
                {
                        pICAN_TrBuff = (tICAN_RWBUFF *)(&ICAN_TrBuff);
                }
//-----------------------------------------------------------------------------------------------------------------
//读应答报文发送
//-----------------------------------------------------------------------------------------------------------------
                else if(ICAN_TrBuffR.TrBegin)
                {
                        pICAN_TrBuff = &ICAN_TrBuffR;
                }
//-----------------------------------------------------------------------------------------------------------------
//循环应答报文发送
//-----------------------------------------------------------------------------------------------------------------
                else
                {
                        pICAN_TrBuff = &ICAN_TrBuffC;
                }       
               

//-----------------------------------------------------------------------------------------------------------------
//下面开始将
//-----------------------------------------------------------------------------------------------------------------
                //发送标志有效并且总组空闲
                CANFrame.ulID = pICAN_TrBuff->ulID;                                //        生成ICAN报文ID(iCAN报文帧头)
      CANFrame.ucXID = pICAN_TrBuff->ucXID;                        //0 标准帧;1 扩展帧
      CANFrame.ucDataBuff = ICAN_ObjByte0Manage(pICAN_TrBuff->ucDataCtr, pICAN_TrBuff->ucDataLenth);        //        生成分段码                                                                       
      if ((CANFrame.ulID & 0x00000F00) != 0x00000F00)        //        如果当前不是发送《异常响应帧》
                {
                        ICAN_ControlInfo.ConnectTOTimer = 0; //        连接超时定时清零(为正常功能码时,定时清0;为异常功能码时,不清0)
                }
                for (i = 1; i < 8; i++)
                {
                        CANFrame.ucDataBuff = pICAN_TrBuff->ucDataBuff;                //        获取8个字节(读取报文数据场1字节)
            pICAN_TrBuff->ucDataCtr++;                                        //        数据指针加1
            if (pICAN_TrBuff->ucDataCtr >= pICAN_TrBuff->ucDataLenth)
                        {
                //发送缓冲的数据没读取完毕
                pICAN_TrBuff->TrBegin = 0;                                //        数据发送完毕
                break; //退出
            }
      }
      CANFrame.ucDLC = i;                                                                //写入数据场长度
//===================================================================================================================
//加入你的发送缓冲代码
//===================================================================================================================
                CAN_ucWriteBuffer(pSendFrameBuff, &CANFrame);        //        将数据帧写入发送缓冲                                                                                                       
                if (SendBuffToBus((void*)pSendFrameBuff))
                {//数据发送
                        ICAN_ControlInfo.CyclicTimer = 0;        //        此句为自己添加的,
                        //循环传送定时器清零,如果是循环发送数据的话,将从发送完应答信息之后开始;
            ICAN_ControlInfo.Idle = 0;                        //        发送成功总线忙
                  SFRPAGE = CONFIG_PAGE;
              P7MDOUT=0x03;       
                led0 =~led0;                                                                //        通信时,灯(P7.0)闪烁;
      }
                else
                {//没有发送成功则继续
            ICAN_ControlInfo.Idle = 2;
                }
//===================================================================================================================
//===================================================================================================================
    }
        if (ICAN_ControlInfo.Idle == 2)
        {//没有发送成功继续发送
                if (SendBuffToBus((void*)pCAN_Node_Info))
                {//数据发送
                        ICAN_ControlInfo.Idle = 0;                        //        发送成功总线忙
                        SFRPAGE = CONFIG_PAGE;
              P7MDOUT=0x03;       
                led0 =~led0;//通信时,灯(P7.0)闪烁;
      }
        }
}




uchar ICANTime1ms;                                                                                                //        处理通信延时计数器
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                        定时器处理程序
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ICAN_DlyCtr(uchar order)
{   
    ICANTime1ms++;                                                                                                //        毫秒计数器加1
    if (ICANTime1ms >= 10)
        {
      //累积到10MS(ICAN时间片单位)
                ICANTime1ms -= 10;                                                                                //        毫秒计数器减10
                //ICANTime1ms = 0;
//----------------------------------------------------------------------------------------------------------------
//ICAN_ControlInfo.MACIDTestStep = 10,表示:MACID检测完成,正常通信
//----------------------------------------------------------------------------------------------------------------
                if (ICAN_ControlInfo.MACIDTestStep == 10)
                {
//----------------------------------------------------------------------------------------------------------------
//CyclicMaster的单位为 10ms,当 CyclicMaster > 0时, (CyclicMaster*4)时间为从站判断主站发送通讯报文的是否超时的时
//间间隔,在通讯过程中,如果从站在(CyclicMaster*4)时间内未收到主站的命令报文,将自动删除连接,退出通讯。当
//CyclicMaster为 0 时,从站不检测通讯超时,直到收到正确的“删除连接”命令帧时,才删除与主站的连接。
//----------------------------------------------------------------------------------------------------------------
                        if (ICAN_Source.Area)                        //        IF CyclicMaster > 0(如果不为0,则有连接超时)
                        {
                if ((ICAN_ControlInfo.ConnectTOTimer >> 2) > ICAN_Source.Area)
                                {
                  //超过连接超时时间//连接定时器
                  ICAN_ControlInfo.ConnectTOFlag = 1;        //        连接超时标志置位
                }
                                else
                                {//连接未超时
                  ICAN_ControlInfo.ConnectTOFlag = 0;        //        连接超时标志清零
                        ICAN_ControlInfo.ConnectTOTimer++;        //        连接定时器+1
                                }
            }
                        else                                                                                                //        没有连接超时       
                        {               
                ICAN_ControlInfo.ConnectTOFlag = 0;                //        连接超时标志清零
                ICAN_ControlInfo.ConnectTOTimer = 0;                //        连接超时定时器清零
            }
//----------------------------------------------------------------------------------------------------------------
// CyclicParameter:定时循环参数, 当 CyclicParameter>0 时,按照 CyclicParameter设定定时参数,循环传送 I/O数据值;
// CyclicMaster:主站通讯定时参数,当 CyclicMaster>0 时, (CyclicMaster*4)时间为从站判断主站发送通讯报文的是否超时的时间间隔;
//----------------------------------------------------------------------------------------------------------------
            if (ICAN_Source.Area)
                        {
                //基于时间触发的通信//循环传送定时器
                ICAN_ControlInfo.CyclicTimer++;                        //        循环传送定时器+1
                if (ICAN_ControlInfo.CyclicTimer > ICAN_Source.Area)
                                {
                  //循环传送时间//循环传送定时器
                  ICAN_ControlInfo.CyclicParameterFlag = 1;//        循环传送标志置位
                  ICAN_ControlInfo.CyclicTimer = 0;        //        循环传送定时器清零
               }
            }
                        else
                        {
                //不存在基于时间触发的通信
                ICAN_ControlInfo.CyclicParameterFlag = 0;//        循环传送标志清零
                ICAN_ControlInfo.CyclicTimer = 0;                //        循环传送定时器清零
            }
      }
                else if (ICAN_ControlInfo.MACIDTestStep < 10)
                {
            //检测MACID两次
            if (ICAN_ControlInfo.MACIDTestTimer < 101)
                        {
                //MACID检测定时器小于1S
                ICAN_ControlInfo.MACIDTestTimer++;                //        MACID检测定时器+1
            }
      }
    }
}



////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                ican通信调度程序
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ICAN_Schedul(uchar order)
{
//----------------------------------------------------------------------------------------
//ICAN_ControlInfo.MACIDTestStep = 10(进入正常通信)
//----------------------------------------------------------------------------------------
        if (ICAN_ControlInfo.MACIDTestStep == 10)
        {
                if (ICAN_ControlInfo.CyclicParameterFlag)        //        循环传送标志置位(定时传送时间到)
                {
                        iCAN_CyclicACK(order);                                                        //        输入端口定时循环或者状态改变传送命令
            ICAN_ControlInfo.CyclicParameterFlag = 0;       
          }
                ICANRxMsgObjExplain(order);                                                        //        ICAN模块从机通信接收子程序
          ICANTxMsgObjSend(order);                                                        //        ICAN模块从机通信发送子程序
    }
//----------------------------------------------------------------------------------------
//ICAN_ControlInfo.MACIDTestStep = 0(第一次正在生成MACID检测报文)
//----------------------------------------------------------------------------------------
        else if (ICAN_ControlInfo.MACIDTestStep == 0)        //        目的=检测有没有与自己相同的MACID
        {
                iCAN_MACIDTest(order,0);                                                        //        第一次生成MACID检测报文(发送方)
                ICANTxMsgObjSend(order);                                                        //        ICAN模块从机通信发送子程序
               if (ICAN_ControlInfo.Idle == 0)                                //        如果发送成功
                {
                        ICAN_ControlInfo.MACIDTestTimer=0;                //        MACID定时器清零
                        ICAN_ControlInfo.MACIDTestStep = 1;                //        第一次等待超时
                }
           }
//----------------------------------------------------------------------------------------
//ICAN_ControlInfo.MACIDTestStep = 1(第一次正在等等接收MACID应答报文过程)
//----------------------------------------------------------------------------------------
        else if (ICAN_ControlInfo.MACIDTestStep == 1)
        {
                if (ICAN_ControlInfo.MACIDTestTimer > 100)        //        超时时间到没有检测到响应报文
                {
                        ICAN_ControlInfo.MACIDTestStep = 2;                //        再检测一次
                }
        }
//----------------------------------------------------------------------------------------
//ICAN_ControlInfo.MACIDTestStep = 2(第二次正在生成MACID检测报文)
//----------------------------------------------------------------------------------------
        else if (ICAN_ControlInfo.MACIDTestStep == 2)
        {
                iCAN_MACIDTest(order,0);                                                        //        第二次生成MACID检测报文(发送方)
                ICANTxMsgObjSend(order);                                                        //        ICAN模块从机通信发送子程序
               if (ICAN_ControlInfo.Idle == 0)                                //        如果发送成功
                {
                        ICAN_ControlInfo.MACIDTestTimer=0;                //        MACID定时器清零
                        ICAN_ControlInfo.MACIDTestStep = 3;                //        第二次等待超时
                }
    }
//----------------------------------------------------------------------------------------
//ICAN_ControlInfo.MACIDTestStep = 3(第二次正在等等接收MACID应答报文过程)
//----------------------------------------------------------------------------------------
        else if (ICAN_ControlInfo.MACIDTestStep == 3)
        {
            if (ICAN_ControlInfo.MACIDTestTimer > 100)        //        超时时间到没有检测到响应报文
                {
                        ICAN_ControlInfo.MACIDTestStep = 10;                //        进入正常通信
                }
        }
//----------------------------------------------------------------------------------------
//其他情况(预操作状态)????????????????????????????????????????????????????????????????????
//----------------------------------------------------------------------------------------
        else
        {
                if (MACIDTemp != ICAN_Source.Area)        //        等待MACID的改变
                {
                        ICAN_ControlInfo.MACIDTestStep = 0;                //        继续检测是否相同的MACID
                }
        }
}

lqs0501 发表于 2009-4-3 10:52:22

兄弟,怎么你学的和我学的都一样啊?能不能交流一下?

ba_wang_mao 发表于 2009-4-3 12:03:29

呵呵,我正在弄一个总线系统,中层协议是PROFIBUS总线,下层协议是CANBUS协议。
  由于CANBUS协议不太熟悉,因此下层协议先用MODBUS协议开发出来。(即PROFIBUS协议+MODBUS协议)
  

lnskngdc 发表于 2009-4-3 12:51:33

楼上的是在远方论坛的霸王猫?
你用profibus转can,用的是dpv0周期性报文吧?

ba_wang_mao 发表于 2009-4-3 15:54:14

是的。
 目前:AT90CAN128已经调试通过。PROFIBUS协议转换芯片用的是北京一家公司的。CAN高层协议准备用iCAN。

http://cache.amobbs.com/bbs_upload782111/files_13/ourdev_432469.JPG
(原文件名:未命名.JPG)

lnskngdc 发表于 2009-4-3 16:06:23

好大的项目啊,个人感觉有点复杂了,协议层太多
象楼主这样全能的人少啊,又做can,又做profibus,还有tcp/ip
profibus的程序是自己开发还是用开发包?

ba_wang_mao 发表于 2009-4-3 17:10:57

呵呵。
 目前只做CANBUS协议。PROFIBUS和TCP/IP是现成的。
 不过TCP/IP和PROFIBUS(从站)应该不太复杂。
 尤其是TCP/IP网上到处都是源代码。
PROFIBUS(从站)也是,就是操作SCP3芯片。网上也到处是相关的文章。

lnskngdc 发表于 2009-4-4 10:32:48

恩,是啊,我用的是vpc3+,移植的他们的demo程序,还算好用

nenggx 发表于 2009-4-4 11:23:26

先记下,以后学习!

iiset 发表于 2009-4-29 22:53:13

mark

ebug 发表于 2009-6-4 10:33:47

不错不错哦

lbfree 发表于 2009-6-5 10:23:22

有一点不理解。为什么ican要做成主从方式,CAN最大的特点就是能实现多主,以提高总线利用率,若用主从方式,比RS485除了能够实现故障封闭和错误恢复,就没什么明显优势了。不知我的理解对不对?

mikecn 发表于 2009-7-25 22:50:23

先做个记号

haeha 发表于 2009-7-26 01:25:15

记号,过段时间正准备用profibus

jchqxl 发表于 2009-7-26 01:55:27

嗯,学习了,谢谢。

hiberhe 发表于 2009-7-26 08:26:44

我觉得如果CAN只是做数据转发之类,没有必要用iCAN,自定义协议更简单,效率也更高。像iCAN,CANOpen,DeviceNet这类协议有其应用背景,在有些数据传输中反而觉得臃肿,它们的优点就是规范,所以重在互操作性好

pchust 发表于 2009-10-8 23:38:26

lz 这个貌似是ican从站的 关于主站的 你那里的资料或者源码有吗 可以给我发一份 pcrulovehust@foxmail.com 谢谢啦

ba_wang_mao 发表于 2009-10-10 10:53:10

下载链接,见1楼。

oldtom 发表于 2009-10-10 11:07:36

谢谢楼主共享。呵呵。等待有空时好好研究下。ZLG的ican貌似比can open精简很多,在工控上值得一用。

xk2yx 发表于 2009-10-20 22:04:09

谢谢。

YourARM 发表于 2009-10-20 22:13:25

楼主门路广

wswh2o 发表于 2009-12-23 13:59:00

这是他自己搞出来的,用的估计不多。
不过比canopen好理解多了。符合中国人的思维习惯呀。

armok 发表于 2010-2-14 21:16:52

waking 发表于 2010-4-27 13:40:52

mark

longsky1985 发表于 2010-9-17 10:23:48

MARK

xuejianhua1986 发表于 2010-9-24 18:48:30

mark

ljt8015 发表于 2010-9-25 18:54:55

mark!~

bulaimeimrz 发表于 2011-1-14 11:03:23

支持,MARK

ljt8015 发表于 2011-1-14 14:10:56

CAN数据帧最长只有8字节吧?

wanglikui 发表于 2011-3-15 11:07:09

mark

zzz123456 发表于 2013-9-4 09:06:21

记号,收藏

maxiang1985 发表于 2013-9-12 16:16:08

好牛xx啊                                                                                                                                                                                                                                             

gloryglory 发表于 2021-7-2 19:40:58

不错,学习学习,周公还是提供了很多好东西的
页: [1]
查看完整版本: CANBUS高层协议-周立功公司推出的iCAN协议学习笔记