本帖最后由 PippenWang 于 2018-1-5 15:39 编辑
参照楼主的移植方法,目前基本解决了心跳的问题(可以通过修改对象字典中参数0x1017的值设置producer心跳),心跳问题也困扰了我好几天。由于也没有深究,仅仅分享一下经验。心跳不准可以尝试以下内容:
1. 确定定时器调用时间,即确定 timerForCan(void) 函数多长时间调用一次。这个主要与硬件定时器的配置有关,楼主在1楼建议说的是:"另外还要开一个1毫秒的定时器,每1毫秒调用一下 timerForCan(void) 这个函数”。canFestival是用一个定时器A模拟多个浮动定时器B,我们在移植canFestival到不同平台上时,所实现的“每1毫秒调用一下 timerForCan(void)”的硬件定时器即定时器A。
2. 定时器A与定时器B的时间转换,主要与#define MS_TO_TIMEVAL(ms) 的宏定义有关。MS_TO_TIMEVAL(ms)的定义在canFestival协议栈的“timerscfg.h”文件中,含义为:定时器A的1ms转换成浮动定时器B的1ms所对应的时间值。如上述1中,硬件定时器时间间隔为1ms,则#define MS_TO_TIMEVAL(ms) ((ms) * 1);从协议栈MS_TO_TIMEVAL的注释“// The timer is incrementing every 8 us.”来看,协议栈中的原硬件定时器A的时间间隔为8us,所以协议栈中的宏定义为#define MS_TO_TIMEVAL(ms) ((ms) * 125)。
3.“timerscfg.h”文件中还要注意#define TIMEVAL_MAX这个宏定义值,这个值表示硬件定时器的最大值,16位定时器对应 #define TIMEVAL_MAX 0xFFFF;32位定时器则对应 #define TIMEVAL_MAX 0xFFFFFFFF。上述2.3两点内容具体可参考作者softwind在帖子中的说明。
4. 楼主在1楼中,定义了unsigned int TIMER_MAX_COUNT = 70000; //最大时间计数。 这个值在 timerForCan(void)函数中,作为变量TimeCNT计数的判断条件,当超过TIMER_MAX_COUNT的值,TimeCNT的计数值归零。由于我使用的是32位定时器,当我把硬件定时器A的时间间隔设为8us时,TIMER_MAX_COUNT = 70000在心跳值很大时不够用,从而导致心跳值不准确。因此可根据使用要求将TIMER_MAX_COUNT 定义值相应增大(如定时器A时间间隔为8us,设心跳时间为1s,此时TIMER_MAX_COUNT 最小需为125*1000)。
5. 函数TIMEVAL getElapsedTime(void) 的实现。getElapsedTime()在TimeDispatch()函数中被调用,用来获取自上次心跳以来经过的时间。将1楼中getElapsedTime()函数替换如下:TIMEVAL getElapsedTime(void) {
int ret = 0;
ret = TimeCNT >= last_time_set ?
TimeCNT - last_time_set : TimeCNT + TIMEVAL_MAX - last_time_set;
last_time_set = TimeCNT;
return ret;
},72楼所述“心跳报文,改了宏定义之后,心跳报文正常100ms,一旦发送sdo之后变成20ms,80ms交替的”应该是跟这个函数有关。
6. 参数0x1017所设置的心跳时间,是在协议栈中heartbeatInit()函数中,赋给ProducerHeartBeatTime这个变量的,然后再通过调用SetAlarm()函数,赋给浮动定时器B(当0x1017为0时,不发送心跳帧)。
7.若以上仍未能解决心跳不准的问题,建议静下心来找一找,再分享给大家。
目前我这边PDO,SDO通讯还没有完全调通,欢迎大家分享这方面的经验。
最后感谢楼主和softwind。 |