搜索
bottom↓
回复: 36

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

[复制链接]

出0入0汤圆

发表于 2009-3-27 15:06:37 | 显示全部楼层 |阅读模式
点击此处下载 ourdev_429047.pdf(文件大小:1.31M) (原文件名:iCAN协议(1.0).pdf)

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

 楼主| 发表于 2009-3-27 15:10:52 | 显示全部楼层
点击此处下载 ourdev_429048.rar(文件大小:3K) (原文件名:ican.rar)

出0入0汤圆

 楼主| 发表于 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                异常响应                从站不能正确处理接收到的命令帧时,发送异常响应帧
//////////////////////////////////////////////////////////////////////////////////

出0入0汤圆

 楼主| 发表于 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[order][0];                                                //  取出当前从站的《开关量输入总数》
                if (readorwrite)                                                                //        写资源请求吗?
                        return 1;                                                                        //        返回失败
        }
//-----------------------------------------------------
//检测要读写的资源是否落在DO区域(0x20~0x3F)
//-----------------------------------------------------
        else if (sourceid < 0x40)                                                        //        DO区域
        {
                i= SourceType[order][1] ;                                                //  取出当前从站的《开关量输出总数》
                sourceid -= 0x20;//????????????
                if (readorwrite == 0)                                                        //        读资源请求吗?
                        return 1;                                                                        //        返回失败
        }
//-----------------------------------------------------
//检测要读写的资源是否落在AI区域(0x40~0x5F)
//-----------------------------------------------------
        else if (sourceid < 0x60)                                                        //        AI区域
        {
                i= SourceType[order][2] ;                                                //  取出当前从站的《模拟量输入总数》
                sourceid -= 0x40;//???????????
                if (readorwrite)                                                                //        写资源请求吗?
                        return 1;                                                                        //        返回失败
        }
//-----------------------------------------------------
//检测要读写的资源是否落在AI区域(0x60~0x7F)
//-----------------------------------------------------
        else if (sourceid < 0x80)                                                        //        AO区域
        {
                i= SourceType[order][3];                                                //  取出当前从站的《模拟量输出总数》
                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);
}

出0入0汤圆

 楼主| 发表于 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)
//-----------------------------------------------------------------------------
        else  if ((segflag & 0x40) == 0x40)                                        //        启始段,批量数据的第一个分段
        {
        *RxCtr = 0x00;                                                                        //        接收数据指针指向零
        ucTemp = 0x01;                                                                        //        1=第一分段
    }
//-----------------------------------------------------------------------------
//中间分段标识(SegPolo=10)
//-----------------------------------------------------------------------------
        else                                                                                                //        中间数据段
        {
        ucTemp = segflag & 0x3f;                                                //        返回中间分段号
        *RxCtr = (segflag&0x3f)*7;                                                //        接收数据指针
    }
    return (ucTemp);                                                                        //        生成标识符                       
}


//*********************************************************************************************************
//定义iCAN帧ID码节点结构体
// ********************************************************************************************************
//typestruct {                                //        帧ID码
//          
//          uint32  SrcMACID;
//          uint32  DestMACID;
//          uint32  ACK;
//          uint32  FUNCID;
//          uint32  SourceID;
//} ICAN_OBJ;

//typestruct {                                //        ICAN读写缓冲
//          
//          uint32 ulID;                        //        发送的ID代码
//    uint  ucDataLenth;        //        数据场长度
//          uint  ucDataCtr;                //        读数据指针
//          uchar ucXID;                        //  0 标准帧;1 扩展帧
//          uchar        TrBegin;
//          uchar        ucDataBuff[8];        //        数据缓冲(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[order].SourceID;        //        资源节点编号
    ICAN_ObjIDTmp.FUNCID = 0x0F;                                                                //        功能码
    ICAN_ObjIDTmp.ACK = 1;                                                                                //        应答标志
    ICAN_ObjIDTmp.DestMACID = ICANSlav_ObjID[order].SrcMACID;        //        目标节点编号
    ICAN_ObjIDTmp.SrcMACID = ICANSlav_ObjID[order].DestMACID;        //        源节点编号
   
        ICAN_TrBuff[order].ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp);        //        生成ICAN报文ID
    ICAN_TrBuff[order].ucXID = 1;                                                                //  0 标准帧;1 扩展帧
    ICAN_TrBuff[order].ucDataBuff[0] = ErrID;                                        //  返回对应的错误代码
    ICAN_TrBuff[order].ucDataLenth = 2;                                                        //  数据场长度1字节
    ICAN_TrBuff[order].ucDataCtr = 0;                                                        //  读数据指针指0字节
    ICAN_TrBuff[order].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[8];                                        //        报文数据场
} 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  DOLen  AILen  AOLen
//
//★★★异常响应帧格式
//                                                                                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[order].Area[MasterMACID]!=pCANFrame->ucDataBuff[1])
        {
                ICAN_ErrorIDACK(order,ErrID_NotCommand);//错误代码返回报文(命令不技持,主站ID不对);
        }
*/
//----------------------------------------------------------------------------
//检测分段码=0(主站请求报文的第一个字节必须=0,即分段码=0)
//----------------------------------------------------------------------------
        else if ((pCANFrame->ucDataBuff[0]!=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[0]=报文数据场2字节(DI资源数量)
//                        ucDataBuff[1]=报文数据场3字节(DO资源数量)
//                        ucDataBuff[2]=报文数据场4字节(AI资源数量)
//                        ucDataBuff[3]=报文数据场5字节(AO资源数量)
//                        TrBegin=发送报文标志
//----------------------------------------------------------------------------
        else
        {
                ICAN_Source[order].Area[MasterMACID] = pCANFrame->ucDataBuff[1];        //        读取主站节点的MACID
                ICAN_Source[order].Area[CyclicMaster] = pCANFrame->ucDataBuff[2];        //        读取主站节点定时通信节拍数

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

                //------------------------------------
                //填写iCAN读写缓冲区结构体
                //------------------------------------
                ICAN_TrBuff[order].ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp);                        //        生成ICAN报文ID
                ICAN_TrBuff[order].ucXID = 1;                                                                                //  0 标准帧;1 扩展帧
                ICAN_TrBuff[order].ucDataLenth = 5;                                                                        //  数据场长度5字节
                ICAN_TrBuff[order].ucDataCtr = 0;                                                                        //  读数据指针指0字节
                ICAN_TrBuff[order].ucDataBuff[0] = SourceType[order][0];                        //  报文数据场2字节(DI资源数量)
                ICAN_TrBuff[order].ucDataBuff[1] = SourceType[order][1];                        //  报文数据场3字节(DO资源数量)
                ICAN_TrBuff[order].ucDataBuff[2] = SourceType[order][2];                        //  报文数据场4字节(AI资源数量)
                ICAN_TrBuff[order].ucDataBuff[3] = SourceType[order][3];                        //  报文数据场5字节(AO资源数量)
                ICAN_TrBuff[order].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[order].Area[MACID];                                        //        目标节点编号
    ICAN_ObjIDTmp.SrcMACID = ICAN_Source[order].Area[MACID];                                        //        源节点编号
   
        ICAN_TrBuff[order].ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp);                                        //        生成ICAN报文ID
    ICAN_TrBuff[order].ucXID = 1;                                                                                                //  0 标准帧;1 扩展帧
    ICAN_TrBuff[order].ucDataLenth = 6;                                                                                        //  数据场长度6字节
    ICAN_TrBuff[order].ucDataCtr = 0;                                                                                        //  读数据指针指0字节
    ICAN_TrBuff[order].ucDataBuff[0] = ICAN_Source[order].Area[MACID];                        //  报文数据场2字节(MACID)
    ICAN_TrBuff[order].ucDataBuff[1] = ICAN_Source[order].Area[SerialNumber];        //  报文数据场3字节(SN第1字节)
    ICAN_TrBuff[order].ucDataBuff[2] = ICAN_Source[order].Area[SerialNumber+1]; //  报文数据场4字节(SN第2字节)
    ICAN_TrBuff[order].ucDataBuff[3] = ICAN_Source[order].Area[SerialNumber+2]; //  报文数据场5字节(SN第3字节)
    ICAN_TrBuff[order].ucDataBuff[4] = ICAN_Source[order].Area[SerialNumber+3]; //  报文数据场5字节(SN第4字节)
    ICAN_TrBuff[order].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[1] != ICAN_Source[order].Area[MasterMACID])
        {
                ICAN_ErrorIDACK(order, ErrID_NotConnect) ;                //        错误代码返回报文连接不存在
                return;
    }
//----------------------------------------------------------------------------------------------------------------
//检测命令帧报文第一字节的分段码=0,若不等于0,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
          else if ((pCANFrame->ucDataBuff[0]!=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[order].Area[MasterMACID];                //        目标节点编号
            ICAN_ObjIDTmp.SrcMACID = ICAN_Source[order].Area[MACID];                        //        源节点编号

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

            ICAN_TrBuff[order].ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp);                        //        生成ICAN报文ID
            ICAN_TrBuff[order].ucXID = 1;                                                                                //  0 标准帧;1 扩展帧  
            ICAN_TrBuff[order].ucDataLenth = 1;                                                                        //  数据场长度1字节
            ICAN_TrBuff[order].ucDataCtr = 0;                                                                        //  读数据指针指0字节
            ICAN_TrBuff[order].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[order].Area[MasterMACID]!= ICANSlav_ObjID[order].SrcMACID)
        {
                ICAN_ErrorIDACK(order, ErrID_NotConnect) ;                                                //        错误代码返回报文连接不存在
                return;
        }
//----------------------------------------------------------------------------------------------------------------
//检测命令帧报文第二字节的Master MACID是否和从站保存的Master MACID相同,若不相同,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
        if ((pCANFrame->ucDataBuff[1] != ICAN_Source[order].Area[MACID]))
        {
                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[order].Area[MasterMACID];                //        目标节点编号
    ICAN_ObjIDTmp.SrcMACID = ICAN_Source[order].Area[MACID];                        //        源节点编号

    ICAN_TrBuff[order].ulID = ICAN_ObjIDManage(&ICAN_ObjIDTmp);                        //        生成ICAN报文ID
    ICAN_TrBuff[order].ucXID = 1;                                                                                //  0 标准帧;1 扩展帧  
    ICAN_TrBuff[order].ucDataLenth = 1;                                                                        //  数据场长度1字节
    ICAN_TrBuff[order].ucDataCtr = 0;                                                                        //  读数据指针指0字节
    ICAN_TrBuff[order].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  SubIndex  Length
//
//说明:
//(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[order].Area[MasterMACID]!= ICANSlav_ObjID[order].SrcMACID)        //        连接不存在 错误码命令处理
        {
               
                ICAN_ErrorIDACK(order, ErrID_NotConnect) ;                //        错误代码返回报文连接不存在
                return;
        }
//----------------------------------------------------------------------------------------------------------------
//检测之前是否未建立连接成功,若是,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
        if (function==0)                                                                        //        连接不存在 错误码命令处理
        {
                       
                ICAN_ErrorIDACK(order, ErrID_NotConnect) ;                //        错误代码返回报文连接不存在
                return;
        }
//---------------------------------------------------------------------------------------------------------       
//资源检测,返回1=资源非法,返回0=资源合法
//sourceID=资源节点编号
//pCANFrame->ucDataBuff[1]=iCAN命令帧第二字节(=访问资源节点Length)
//0=连续读端口标志
//---------------------------------------------------------------------------------------------------------       
        if (ICAN_SourceTest(order,sourceID,pCANFrame->ucDataBuff[1],0))        //        资源检测
        {
                ICAN_ErrorIDACK(order, ErrID_NotSourceID) ;                //        错误代码返回报文资源不存在
                return;
        }

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

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

//------------------------------------------------------------------------------------------
//根据接收报文的帧头中的资源节点地址来判断当前是“连续读资源节点”还是“连续读资源子节点”
//------------------------------------------------------------------------------------------
    if (i >= 0xF9)
        {
                k = pCANFrame->ucDataBuff[1];                                                                //        读取资源节点的子地址(SubIndex)
                j = pCANFrame->ucDataBuff[2];                                                                //        读取资源长度(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[order].ucDataBuff[l] = SourceType[order][k]; //读取指定单元的地址       
                                }
                        }
                        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[order].ucDataBuff[l] = ICAN_IOconfig[order][k]; //读取指定单元的地址       
                                }
                        }
                        else
                        {
                                ICAN_ErrorIDACK(order, ErrID_NotSourceID);                        //        错误代码返回报文,参数非法
                                return;
                        }
                }
//---------------------------------------------------------------------------------------------
//读资源子节点的保留数据
//---------------------------------------------------------------------------------------------
                else
                {

                }
        }
//---------------------------------------------------------------------------------------------
//读取正常数据
//---------------------------------------------------------------------------------------------
        else
        {
                j = pCANFrame->ucDataBuff[1];                                                                //        读取资源节点长度
                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[order].ucDataBuff[l] = ICAN_Source[order].Area; //读取指定单元的地址       
        }
    }
    ICAN_TrBuffR[order].ucDataLenth = j + 1;                                                //  数据场长度k字节
    ICAN_TrBuffR[order].ucDataCtr = 0;                                                                //  读数据指针指0字节
    ICAN_TrBuffR[order].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[order].Area[MasterMACID]!= ICANSlav_ObjID[order].SrcMACID)                        //        连接不存在,错误码命令处理
        {
                ICAN_ErrorIDACK(order, ErrID_NotConnect) ;                                                                                //        错误代码返回报文连接不存在
                return;
        }
//----------------------------------------------------------------------------------------------------------------
//检测之前是否未建立连接成功,若是,则返回错误报文
//----------------------------------------------------------------------------------------------------------------
        if (function == 0)                                                                                                                                        //        还没有建立连接, 错误码命令处理
        {
                ICAN_ErrorIDACK(order, ErrID_NotConnect);                                                                                //        错误代码返回报文连接不存在
                return;
        }
//----------------------------------------------------------------------------------------------------------------
//获取分段标识子程序,入口参数如下:
//ICAN_ReBuff[order].ucDataCtr=接收缓冲区结构体读数据指针
//pCANFrame->ucDataBuff[0]=CAN报文结构体第一字节(存储分段码)
//返回:0=无分段
//           65=最后分段
//                1=第一分段
//         其它=中间分段
//----------------------------------------------------------------------------------------------------------------
        i = ICAN_ObjByte0Restore(&ICAN_ReBuff[order].ucDataCtr, pCANFrame->ucDataBuff[0]);        //        获取分段标识

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

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

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




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


//----------------------------------------------------------------------------------------------------------------
//结构体CANFrame中保存的iCAN帧头合成信息--->结构体指针ICANSlav_ObjID
//----------------------------------------------------------------------------------------------------------------
                                ICAN_ObjIDRestore(&ICANSlav_ObjID[order], CANFrame.ulID);                                        //        ICAN报文标识码还原                       
                                switch (ICANSlav_ObjID[order].FUNCID)
                                {
                                        case 0x01:                                                                                                                                //        用于对单个或者多个资源节点的数据写入
                                                iCAN_WriteACK(order, ICANSlav_ObjID[order].SourceID, &CANFrame);        //        写数据命令命令
                                                break;
                                        case 0x02:                                                                                                                                //        用于对单个或者多个资源节点的数据读取
                                                iCAN_ReadACK(order, ICANSlav_ObjID[order].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[order].ACK == 0)                                                                        //        ACK == 0(接收到检测命令)
                                                {                                                                                                                                        //        用于响应网络上是否有相同MACID节点的检测
                                                        iCAN_MACIDTest(order,1);                                                                                //        接收到MACID检测命令并返回响应命令
                                                }
                                                else                                                                                                                                //        ACK == 1(接收到响应命令)
                                                {
                                                        MACIDTemp = ICAN_Source[order].Area[MACID];                                                //        记录当前的MACID
                                                        ICAN_ControlInfo[order].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[order]->ulChNr, ulICANRxMsgNbrTbl, &MsgObjectBuf, 1); //读取邮箱数据
                if (pReceFrameBuff[order]->ucBufFull != 0) {
                    //接收缓冲区未满
                    CANFrame.ucXID = 1; //扩展ID
                    CANFrame.ulID = (MsgObjectBuf.ulMsgID & 0x1FFFFFFF); //读取ID内容
                    CANFrame.ucDLC = MsgObjectBuf.ulMsgLen; //获取数据长度
                    CAN_ucWriteBuffer(pReceFrameBuff[order], &CANFrame);//  把接收的数据写入指定的接收缓存
                    
                }
                ICAN_ControlInfo[order].ReDataCtr++;
            }
        }
         */
        /*
         *  中断发送数据
         
        for (i = 0; i < 4; i++) {
            //对4个发送邮箱进行读数据处理
            if ((ulMsgObjID & (0x00000001 << (pCAN_Node_Info[order]->ulTxMsgObjNr - 1)))) {//有中断生产
                ClearIntFlag(pCAN_Node_Info[order], pCAN_Node_Info[order]->ulTxMsgObjNr);//清除发送中断标志
//                if ((SendBuffToBus((void*)pCAN_Node_Info[order])) == 0) {
//                    //总线不忙
                    ICAN_ControlInfo[order].Idle = 0;
//                }
            }
        }
    }
} */




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

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

//-----------------------------------------------------------------------------------------------------------------
//下面开始将
//-----------------------------------------------------------------------------------------------------------------
                //发送标志有效并且总组空闲
                CANFrame.ulID = pICAN_TrBuff->ulID;                                //        生成ICAN报文ID(iCAN报文帧头)
        CANFrame.ucXID = pICAN_TrBuff->ucXID;                        //  0 标准帧;1 扩展帧
        CANFrame.ucDataBuff[0] = ICAN_ObjByte0Manage(pICAN_TrBuff->ucDataCtr, pICAN_TrBuff->ucDataLenth);        //        生成分段码                                                                       
        if ((CANFrame.ulID & 0x00000F00) != 0x00000F00)        //        如果当前不是发送《异常响应帧》
                {
                        ICAN_ControlInfo[order].ConnectTOTimer = 0; //        连接超时定时清零(为正常功能码时,定时清0;为异常功能码时,不清0)
                }
                for (i = 1; i < 8; i++)
                {
                        CANFrame.ucDataBuff = pICAN_TrBuff->ucDataBuff[pICAN_TrBuff->ucDataCtr];                //        获取8个字节(读取报文数据场1字节)
            pICAN_TrBuff->ucDataCtr++;                                        //        数据指针加1
            if (pICAN_TrBuff->ucDataCtr >= pICAN_TrBuff->ucDataLenth)
                        {
                //发送缓冲的数据没读取完毕
                pICAN_TrBuff->TrBegin = 0;                                //        数据发送完毕
                break; //退出
            }
        }
        CANFrame.ucDLC = i;                                                                //  写入数据场长度
//===================================================================================================================
//加入你的发送缓冲代码
//===================================================================================================================
                CAN_ucWriteBuffer(pSendFrameBuff[order], &CANFrame);        //        将数据帧写入发送缓冲                                                                                                         
                if (SendBuffToBus((void*)pSendFrameBuff[order]))
                {//数据发送
                        ICAN_ControlInfo[order].CyclicTimer = 0;        //        此句为自己添加的,
                        //循环传送定时器清零,如果是循环发送数据的话,将从发送完应答信息之后开始;
            ICAN_ControlInfo[order].Idle = 0;                        //        发送成功总线忙
                    SFRPAGE = CONFIG_PAGE;
                P7MDOUT=0x03;       
                led0 =~led0;                                                                //        通信时,灯(P7.0)闪烁;
        }
                else
                {//没有发送成功则继续
            ICAN_ControlInfo[order].Idle = 2;
                }
//===================================================================================================================
//===================================================================================================================
    }
        if (ICAN_ControlInfo[order].Idle == 2)
        {//没有发送成功继续发送
                if (SendBuffToBus((void*)pCAN_Node_Info[order]))
                {//数据发送
                        ICAN_ControlInfo[order].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[order].MACIDTestStep = 10,表示:MACID检测完成,正常通信
//----------------------------------------------------------------------------------------------------------------
                if (ICAN_ControlInfo[order].MACIDTestStep == 10)
                {
//----------------------------------------------------------------------------------------------------------------
//CyclicMaster的单位为 10ms,当 CyclicMaster > 0时, (CyclicMaster*4)时间为从站判断主站发送通讯报文的是否超时的时
//间间隔,在通讯过程中,如果从站在(CyclicMaster*4)时间内未收到主站的命令报文,将自动删除连接,退出通讯。当
//CyclicMaster为 0 时,从站不检测通讯超时,直到收到正确的“删除连接”命令帧时,才删除与主站的连接。
//----------------------------------------------------------------------------------------------------------------
                        if (ICAN_Source[order].Area[CyclicMaster])                        //        IF CyclicMaster > 0(如果不为0,则有连接超时)
                        {
                if ((ICAN_ControlInfo[order].ConnectTOTimer >> 2) > ICAN_Source[order].Area[CyclicMaster])
                                {
                    //超过连接超时时间//连接定时器
                    ICAN_ControlInfo[order].ConnectTOFlag = 1;        //        连接超时标志置位
                }
                                else
                                {//连接未超时
                    ICAN_ControlInfo[order].ConnectTOFlag = 0;        //        连接超时标志清零
                        ICAN_ControlInfo[order].ConnectTOTimer++;        //        连接定时器+1
                                }
            }
                        else                                                                                                //        没有连接超时       
                        {               
                ICAN_ControlInfo[order].ConnectTOFlag = 0;                //        连接超时标志清零
                ICAN_ControlInfo[order].ConnectTOTimer = 0;                //        连接超时定时器清零
            }
//----------------------------------------------------------------------------------------------------------------
// CyclicParameter:定时循环参数, 当 CyclicParameter>0 时,按照 CyclicParameter设定定时参数,循环传送 I/O数据值;
// CyclicMaster:主站通讯定时参数,当 CyclicMaster>0 时, (CyclicMaster*4)时间为从站判断主站发送通讯报文的是否超时的时间间隔;
//----------------------------------------------------------------------------------------------------------------
            if (ICAN_Source[order].Area[CyclicParameter])
                        {
                //基于时间触发的通信//循环传送定时器
                ICAN_ControlInfo[order].CyclicTimer++;                        //        循环传送定时器+1
                if (ICAN_ControlInfo[order].CyclicTimer > ICAN_Source[order].Area[CyclicParameter])
                                {
                    //循环传送时间//循环传送定时器
                    ICAN_ControlInfo[order].CyclicParameterFlag = 1;//        循环传送标志置位
                    ICAN_ControlInfo[order].CyclicTimer = 0;        //        循环传送定时器清零
               }
            }
                        else
                        {
                //不存在基于时间触发的通信
                ICAN_ControlInfo[order].CyclicParameterFlag = 0;//        循环传送标志清零
                ICAN_ControlInfo[order].CyclicTimer = 0;                //        循环传送定时器清零
            }
        }
                else if (ICAN_ControlInfo[order].MACIDTestStep < 10)
                {
            //检测MACID两次
            if (ICAN_ControlInfo[order].MACIDTestTimer < 101)
                        {
                //MACID检测定时器小于1S
                ICAN_ControlInfo[order].MACIDTestTimer++;                //        MACID检测定时器+1
            }
        }
    }
}



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

出0入0汤圆

发表于 2009-4-3 10:52:22 | 显示全部楼层
兄弟,怎么你学的和我学的都一样啊?能不能交流一下?

出0入0汤圆

 楼主| 发表于 2009-4-3 12:03:29 | 显示全部楼层
呵呵,我正在弄一个总线系统,中层协议是PROFIBUS总线,下层协议是CANBUS协议。
  由于CANBUS协议不太熟悉,因此下层协议先用MODBUS协议开发出来。(即PROFIBUS协议+MODBUS协议)
  

出0入0汤圆

发表于 2009-4-3 12:51:33 | 显示全部楼层
楼上的是在远方论坛的霸王猫?
你用profibus转can,用的是dpv0周期性报文吧?

出0入0汤圆

 楼主| 发表于 2009-4-3 15:54:14 | 显示全部楼层
是的。
 目前:AT90CAN128已经调试通过。PROFIBUS协议转换芯片用的是北京一家公司的。CAN高层协议准备用iCAN。


(原文件名:未命名.JPG)

出0入0汤圆

发表于 2009-4-3 16:06:23 | 显示全部楼层
好大的项目啊,个人感觉有点复杂了,协议层太多
象楼主这样全能的人少啊,又做can,又做profibus,还有tcp/ip
profibus的程序是自己开发还是用开发包?

出0入0汤圆

 楼主| 发表于 2009-4-3 17:10:57 | 显示全部楼层
呵呵。
 目前只做CANBUS协议。PROFIBUS和TCP/IP是现成的。
 不过TCP/IP和PROFIBUS(从站)应该不太复杂。
 尤其是TCP/IP网上到处都是源代码。
  PROFIBUS(从站)也是,就是操作SCP3芯片。网上也到处是相关的文章。

出0入0汤圆

发表于 2009-4-4 10:32:48 | 显示全部楼层
恩,是啊,我用的是vpc3+,移植的他们的demo程序,还算好用

出0入0汤圆

发表于 2009-4-4 11:23:26 | 显示全部楼层
先记下,以后学习!

出0入0汤圆

发表于 2009-4-29 22:53:13 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-6-4 10:33:47 | 显示全部楼层
不错不错哦

出0入0汤圆

发表于 2009-6-5 10:23:22 | 显示全部楼层
有一点不理解。为什么ican要做成主从方式,CAN最大的特点就是能实现多主,以提高总线利用率,若用主从方式,比RS485除了能够实现故障封闭和错误恢复,就没什么明显优势了。不知我的理解对不对?

出0入0汤圆

发表于 2009-7-25 22:50:23 | 显示全部楼层
先做个记号

出0入0汤圆

发表于 2009-7-26 01:25:15 | 显示全部楼层
记号,过段时间正准备用profibus

出0入0汤圆

发表于 2009-7-26 01:55:27 | 显示全部楼层
嗯,学习了,谢谢。

出0入0汤圆

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

出0入0汤圆

发表于 2009-10-8 23:38:26 | 显示全部楼层
lz 这个貌似是ican从站的 关于主站的 你那里的资料或者源码有吗 可以给我发一份 pcrulovehust@foxmail.com 谢谢啦

出0入0汤圆

 楼主| 发表于 2009-10-10 10:53:10 | 显示全部楼层
下载链接,见1楼。

出0入0汤圆

发表于 2009-10-10 11:07:36 | 显示全部楼层
谢谢楼主共享。呵呵。等待有空时好好研究下。ZLG的ican貌似比can open精简很多,在工控上值得一用。

出0入0汤圆

发表于 2009-10-20 22:04:09 | 显示全部楼层
谢谢。

出0入0汤圆

发表于 2009-10-20 22:13:25 | 显示全部楼层
楼主门路广

出0入0汤圆

发表于 2009-12-23 13:59:00 | 显示全部楼层
这是他自己搞出来的,用的估计不多。
不过比canopen好理解多了。符合中国人的思维习惯呀。
头像被屏蔽

出0入0汤圆

发表于 2010-2-14 21:16:52 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

发表于 2010-4-27 13:40:52 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-17 10:23:48 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-9-24 18:48:30 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-25 18:54:55 | 显示全部楼层
mark!~

出0入0汤圆

发表于 2011-1-14 11:03:23 | 显示全部楼层
支持,MARK

出0入0汤圆

发表于 2011-1-14 14:10:56 | 显示全部楼层
CAN数据帧最长只有8字节吧?

出0入0汤圆

发表于 2011-3-15 11:07:09 | 显示全部楼层
mark

出0入0汤圆

发表于 2013-9-4 09:06:21 | 显示全部楼层
记号,收藏

出0入0汤圆

发表于 2013-9-12 16:16:08 | 显示全部楼层
好牛xx啊                                                                                                                                                                                                                                             

出0入0汤圆

发表于 2021-7-2 19:40:58 来自手机 | 显示全部楼层
不错,学习学习,周公还是提供了很多好东西的
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 08:02

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表