canfestival——从机发送PDO报文
1、PDO基本介绍
PDO(过程数据对象)用来传输实时数据,PDO分两种,一种是TPDO(发送的),一种是RPDO(接收的)。
触发模式:事件和定时器、远程请求、同步触发。
如下图所示,TPDO1在OD中索引为1800,此处写通讯参数。
TPDO 的通讯参数存放在 1800h to 19FFh ,映射参数存放在 1A00h to 1BFFh
网上下载一本电子书:canopen轻松入门(周立功)
2、PDO通讯参数
Transmission_Type:传输类型
Inhibit_Time:抑制时间,由于PDO的优先级较高,必要时需要抑制
Event_Timer:周期时间
SYNC_start_value:同步起始值
要修改的源程序位置如下:
/* index 0x1800 : Transmit PDO 1 Parameter. */
UNS8 EwtCanAnalysis_highestSubIndex_obj1800 = 6; /* number of subindex - 1*/
UNS32 EwtCanAnalysis_obj1800_COB_ID_used_by_PDO = 0x180; /* 384 */
UNS8 EwtCanAnalysis_obj1800_Transmission_Type = 0x0; /* 0 */
UNS16 EwtCanAnalysis_obj1800_Inhibit_Time = 0x0; /* 0 */
UNS8 EwtCanAnalysis_obj1800_Compatibility_Entry = 0x0; /* 0 */
UNS16 EwtCanAnalysis_obj1800_Event_Timer = 0x0; /* 0 */
UNS8 EwtCanAnalysis_obj1800_SYNC_start_value = 0x0; /* 0 */
ODCallback_t EwtCanAnalysis_Index1800_callbacks[] =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};
subindex EwtCanAnalysis_Index1800[] =
{
{ RO, uint8, sizeof (UNS8),
(void*)&EwtCanAnalysis_highestSubIndex_obj1800 },
{ RW, uint32, sizeof (UNS32),
(void*)&EwtCanAnalysis_obj1800_COB_ID_used_by_PDO },
{ RW, uint8, sizeof (UNS8),
(void*)&EwtCanAnalysis_obj1800_Transmission_Type },
{ RW, uint16, sizeof (UNS16),
(void*)&EwtCanAnalysis_obj1800_Inhibit_Time },
{ RW, uint8, sizeof (UNS8),
(void*)&EwtCanAnalysis_obj1800_Compatibility_Entry },
{ RW, uint16, sizeof (UNS16),
(void*)&EwtCanAnalysis_obj1800_Event_Timer },
{ RW, uint8, sizeof (UNS8),
(void*)&EwtCanAnalysis_obj1800_SYNC_start_value }
};
3、PDO映射参数
映射的数据分解
31-16位:索引
15-8位:子索引
7-0位:长度
例如将其分解:0x20000008
要修改的源程序位置如下:
/* index 0x1A00 : Transmit PDO 1 Mapping. */
UNS8 EwtCanAnalysis_highestSubIndex_obj1A00 = 8; /* number of subindex - 1*/
UNS32 EwtCanAnalysis_obj1A00[] =
{
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0, /* 0 */
0x0 /* 0 */
};
subindex EwtCanAnalysis_Index1A00[] =
{
{ RW, uint8, sizeof (UNS8),
(void*)&EwtCanAnalysis_highestSubIndex_obj1A00 },
{ RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[0] },
{ RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[1] },
{ RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[2] },
{ RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[3] },
{ RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[4] },
{ RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[5] },
{ RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[6] },
{ RW, uint32, sizeof (UNS32), (void*)&EwtCanAnalysis_obj1A00[7] }
};
4、从机发送PDO的应用
_sendPDOevent():启动所有需要触发的PDO事件
pTransmissionType:触发方式
isSyncEvent:同步触发
state5:发送报文
state11:下一个
if (offsetObjdict):通讯参数被设置
/*!
**
**
** @param d
** @param isSyncEvent
**
** @return
**/
UNS8
_sendPDOevent (CO_Data * d, UNS8 isSyncEvent)
{
UNS8 pdoNum = 0x00; /* number of the actual processed pdo-nr. */
UNS8 *pTransmissionType = NULL;
UNS8 status = state3;
UNS16 offsetObjdict = d->firstIndex->PDO_TRS;
UNS16 offsetObjdictMap = d->firstIndex->PDO_TRS_MAP;
UNS16 lastIndex = d->lastIndex->PDO_TRS;
if (!d->CurrentCommunicationState.csPDO)
{
return 0;
}
/* study all PDO stored in the objects dictionary */
if (offsetObjdict)
{
Message pdo;/* = Message_Initializer;*/
memset(&pdo, 0, sizeof(pdo));
while (offsetObjdict <= lastIndex)
{
switch (status)
{
case state3:
if ( /* bSubCount always 5 with objdictedit -> check disabled */
/*d->objdict[offsetObjdict].bSubCount < 5 ||*/
/* check if TPDO is not valid */
*(UNS32 *) d->objdict[offsetObjdict].pSubindex[1].pObject & 0x80000000)
{
MSG_WAR (0x3960, "Not a valid PDO ", 0x1800 + pdoNum);
/*Go next TPDO */
status = state11;
break;
}
/* get the PDO transmission type */
pTransmissionType =
(UNS8 *) d->objdict[offsetObjdict].pSubindex[2].pObject;
MSG_WAR (0x3962, "Reading PDO at index : ", 0x1800 + pdoNum);
/* check if transmission type is SYNCRONOUS */
/* message transmited every n SYNC with n=TransmissionType */
if (isSyncEvent &&
(*pTransmissionType >= TRANS_SYNC_MIN) &&
(*pTransmissionType <= TRANS_SYNC_MAX) &&
(++d->PDO_status[pdoNum].transmit_type_parameter ==
*pTransmissionType))
{
/*Reset count of SYNC */
d->PDO_status[pdoNum].transmit_type_parameter = 0;
MSG_WAR (0x3964, " PDO is on SYNCHRO. Trans type : ",
*pTransmissionType);
memset(&pdo, 0, sizeof(pdo));
/*{
Message msg_init = Message_Initializer;
pdo = msg_init;
}*/
if (buildPDO (d, pdoNum, &pdo))
{
MSG_ERR (0x1906, " Couldn't build TPDO number : ",
pdoNum);
status = state11;
break;
}
status = state5;
/* If transmission RTR, with data sampled on SYNC */
}
else if (isSyncEvent && (*pTransmissionType == TRANS_RTR_SYNC))
{
if (buildPDO
(d, pdoNum, &d->PDO_status[pdoNum].last_message))
{
MSG_ERR (0x1966, " Couldn't build TPDO number : ",
pdoNum);
d->PDO_status[pdoNum].transmit_type_parameter &=
~PDO_RTR_SYNC_READY;
}
else
{
d->PDO_status[pdoNum].transmit_type_parameter |=
PDO_RTR_SYNC_READY;
}
status = state11;
break;
/* If transmission on Event and not inhibited, check for changes */
}
else
if ( (isSyncEvent && (*pTransmissionType == TRANS_SYNC_ACYCLIC))
||
(!isSyncEvent && (*pTransmissionType == TRANS_EVENT_PROFILE || *pTransmissionType == TRANS_EVENT_SPECIFIC)
&& !(d->PDO_status[pdoNum].transmit_type_parameter & PDO_INHIBITED)))
{
sendOnePDOevent(d, pdoNum);
status = state11;
}
else
{
MSG_WAR (0x306C,
" PDO is not on EVENT or synchro or not at this SYNC. Trans type : ",
*pTransmissionType);
status = state11;
}
break;
case state5: /*Send the pdo */
sendPdo(d, pdoNum, &pdo);
status = state11;
break;
case state11: /*Go to next TPDO */
pdoNum++;
offsetObjdict++;
offsetObjdictMap++;
MSG_WAR (0x3970, "next pdo index : ", pdoNum);
status = state3;
break;
default:
MSG_ERR (0x1972, "Unknown state has been reached :", status);
return 0xFF;
} /* end switch case */
} /* end while */
}
return 0;
}
buildPDO:构建PDO
pdo->cob_id:ID
pdo->rtr:数据帧
index:索引
subIndex:子索引
getODentry (d, index, subIndex, tmp, &ByteSize, &dataType, 0)
UNS8 buildPDO (CO_Data * d, UNS8 numPdo, Message * pdo)
{
const indextable *TPDO_com = d->objdict + d->firstIndex->PDO_TRS + numPdo;
const indextable *TPDO_map = d->objdict + d->firstIndex->PDO_TRS_MAP + numPdo;
UNS8 prp_j = 0x00;
UNS32 offset = 0x00000000;
const UNS8 *pMappingCount = (UNS8 *) TPDO_map->pSubindex[0].pObject;
pdo->cob_id = (UNS16) UNS16_LE(*(UNS32*)TPDO_com->pSubindex[1].pObject & 0x7FF);
pdo->rtr = NOT_A_REQUEST;
MSG_WAR (0x3009, " PDO CobId is : ",
*(UNS32 *) TPDO_com->pSubindex[1].pObject);
MSG_WAR (0x300D, " Number of objects mapped : ", *pMappingCount);
do
{
UNS8 dataType; /* Unused */
UNS8 tmp[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; /* temporary space to hold bits */
/* pointer fo the var which holds the mapping parameter of an mapping entry */
UNS32 *pMappingParameter =
(UNS32 *) TPDO_map->pSubindex[prp_j + 1].pObject;
UNS16 index = (UNS16) ((*pMappingParameter) >> 16);
UNS32 Size = (UNS32) (*pMappingParameter & (UNS32) 0x000000FF); /* Size in bits */
/* get variable only if Size != 0 and Size is lower than remaining bits in the PDO */
if (Size && ((offset + Size) <= 64))
{
UNS32 ByteSize = 1 + ((Size - 1) >> 3); /*1->8 => 1 ; 9->16 => 2, ... */
UNS8 subIndex =
(UNS8) (((*pMappingParameter) >> (UNS8) 8) & (UNS32) 0x000000FF);
MSG_WAR (0x300F, " got mapping parameter : ", *pMappingParameter);
MSG_WAR (0x3050, " at index : ", TPDO_map->index);
MSG_WAR (0x3051, " sub-index : ", prp_j + 1);
if (getODentry (d, index, subIndex, tmp, &ByteSize, &dataType, 0) !=
OD_SUCCESSFUL)
{
MSG_ERR (0x1013,
" Couldn't find mapped variable at index-subindex-size : ",
(UNS32) (*pMappingParameter));
return 0xFF;
}
/* copy bit per bit in little endian */
CopyBits ((UNS8) Size, ((UNS8 *) tmp), 0, 0,
(UNS8 *) & pdo->data[offset >> 3], (UNS8)(offset % 8), 0);
offset += Size;
}
prp_j++;
}
while (prp_j < *pMappingCount);
pdo->len = (UNS8)(1 + ((offset - 1) >> 3));
MSG_WAR (0x3015, " End scan mapped variable", 0);
return 0;
}
UNS32 _getODentry( CO_Data* d,
UNS16 wIndex,
UNS8 bSubindex,
void * pDestData,
UNS32 * pExpectedSize,
UNS8 * pDataType,
UNS8 checkAccess,
UNS8 endianize)
{ /* DO NOT USE MSG_ERR because the macro may send a PDO -> infinite
loop if it fails. */
UNS32 errorCode;
UNS32 szData;
const indextable *ptrTable;
ODCallback_t *Callback;
ptrTable = (*d->scanIndexOD)(wIndex, &errorCode, &Callback);
if (errorCode != OD_SUCCESSFUL)
return errorCode;
if( ptrTable->bSubCount <= bSubindex ) {
/* Subindex not found */
accessDictionaryError(wIndex, bSubindex, 0, 0, OD_NO_SUCH_SUBINDEX);
return OD_NO_SUCH_SUBINDEX;
}
if (checkAccess && (ptrTable->pSubindex[bSubindex].bAccessType & WO)) {
MSG_WAR(0x2B30, "Access Type : ", ptrTable->pSubindex[bSubindex].bAccessType);
accessDictionaryError(wIndex, bSubindex, 0, 0, OD_READ_NOT_ALLOWED);
return OD_READ_NOT_ALLOWED;
}
if (pDestData == 0) {
return SDOABT_GENERAL_ERROR;
}
if (ptrTable->pSubindex[bSubindex].size > *pExpectedSize) {
/* Requested variable is too large to fit into a transfer line, inform *
* the caller about the real size of the requested variable. */
*pExpectedSize = ptrTable->pSubindex[bSubindex].size;
return SDOABT_OUT_OF_MEMORY;
}
*pDataType = ptrTable->pSubindex[bSubindex].bDataType;
szData = ptrTable->pSubindex[bSubindex].size;
# ifdef CANOPEN_BIG_ENDIAN
if(endianize && *pDataType > boolean && !(
*pDataType >= visible_string &&
*pDataType <= domain)) {
/* data must be transmited with low byte first */
UNS8 i, j = 0;
MSG_WAR(boolean, "data type ", *pDataType);
MSG_WAR(visible_string, "data type ", *pDataType);
for ( i = szData ; i > 0 ; i--) {
MSG_WAR(i," ", j);
((UNS8*)pDestData)[j++] =
((UNS8*)ptrTable->pSubindex[bSubindex].pObject)[i-1];
}
*pExpectedSize = szData;
}
else /* no endianisation change */
# endif
if(*pDataType != visible_string) {
memcpy(pDestData, ptrTable->pSubindex[bSubindex].pObject,szData);
*pExpectedSize = szData;
}else{
/* TODO : CONFORM TO DS-301 :
* - stop using NULL terminated strings
* - store string size in td_subindex
* */
/* Copy null terminated string to user, and return discovered size */
UNS8 *ptr = (UNS8*)ptrTable->pSubindex[bSubindex].pObject;
UNS8 *ptr_start = ptr;
/* *pExpectedSize IS < szData . if null, use szData */
UNS8 *ptr_end = ptr + (*pExpectedSize ? *pExpectedSize : szData) ;
UNS8 *ptr_dest = (UNS8*)pDestData;
while( *ptr && ptr < ptr_end){
*(ptr_dest++) = *(ptr++);
}
*pExpectedSize = (UNS32) (ptr - ptr_start);
/* terminate string if not maximum length */
if (*pExpectedSize < szData)
*(ptr) = 0;
}
return OD_SUCCESSFUL;
}
从机使用TPDO1发送数值1到主机
700:上文中的心跳包
上一篇: 成功解决Windows10环境下运行Linux系统下的.sh文件
下一篇: USB工业摄像头模块选择