encoder.c

来自「CNC 的开放码,EMC2 V2.2.8版」· C语言 代码 · 共 537 行 · 第 1/2 页

C
537
字号
/************************************************************************            REALTIME ENCODER COUNTING AND UPDATE FUNCTIONS            *************************************************************************/static void update(void *arg, long period){    counter_t *cntr;    atomic *buf;    int n;    unsigned char state;    cntr = arg;    for (n = 0; n < num_chan; n++) {	buf = (atomic *) cntr->bp;	/* get state machine current state */	state = cntr->state;	/* add input bits to state code */	if (*(cntr->phaseA)) {	    state |= SM_PHASE_A_MASK;	}	if (*(cntr->phaseB)) {	    state |= SM_PHASE_B_MASK;	}	/* look up new state */	if ( cntr->counter_mode ) {	    state = lut_ctr[state & (SM_LOOKUP_MASK & ~SM_PHASE_B_MASK)];	} else if ( cntr->x4_mode ) {	    state = lut_x4[state & SM_LOOKUP_MASK];	} else {	    state = lut_x1[state & SM_LOOKUP_MASK];	}	/* should we count? */	if (state & SM_CNT_UP_MASK) {	    cntr->raw_counts++;	    buf->raw_count = cntr->raw_counts;	    buf->timestamp = timebase;	    buf->count_detected = 1;	} else if (state & SM_CNT_DN_MASK) {	    cntr->raw_counts--;	    buf->raw_count = cntr->raw_counts;	    buf->timestamp = timebase;	    buf->count_detected = 1;	}	/* save state machine state */	cntr->state = state;	/* get old phase Z state, make room for new bit value */	state = cntr->oldZ << 1;	/* add new value of phase Z */	if (*(cntr->phaseZ)) {	    state |= 1;	}	cntr->oldZ = state & 3;	/* test for index enabled and rising edge on phase Z */	if ((state & cntr->Zmask) == 1) {	    /* capture counts, reset Zmask */	    buf->index_count = cntr->raw_counts;	    buf->index_detected = 1;	    cntr->Zmask = 0;	}	/* move on to next channel */	cntr++;    }    /* increment main timestamp counter */    timebase += period;    /* done */}/* if no edges in 100mS time, force vel to zero */#define TIMEOUT 100000000static void capture(void *arg, long period){    counter_t *cntr;    atomic *buf;    int n;    __s32 delta_counts;    __u32 delta_time;    double vel;    cntr = arg;    for (n = 0; n < num_chan; n++) {	/* point to active buffer */	buf = (atomic *) cntr->bp;	/* tell update() to use the other buffer */	if ( buf == &(cntr->buf[0]) ) {	    cntr->bp = &(cntr->buf[1]);	} else {	    cntr->bp = &(cntr->buf[0]);	}	/* handle index */	if ( buf->index_detected ) {	    buf->index_detected = 0;	    cntr->index_count = buf->index_count;	    *(cntr->index_ena) = 0;	}	/* update Zmask based on index_ena */	if (*(cntr->index_ena)) {	    cntr->Zmask = 3;	} else {	    cntr->Zmask = 0;	}	/* done interacting with update() */	/* check for change in scale value */	if ( cntr->pos_scale != cntr->old_scale ) {	    /* save new scale to detect future changes */	    cntr->old_scale = cntr->pos_scale;	    /* scale value has changed, test and update it */	    if ((cntr->pos_scale < 1e-20) && (cntr->pos_scale > -1e-20)) {		/* value too small, divide by zero is a bad thing */		cntr->pos_scale = 1.0;	    }	    /* we actually want the reciprocal */	    cntr->scale = 1.0 / cntr->pos_scale;	}	/* check reset input */	if (*(cntr->reset)) {	    /* reset is active, reset the counter */	    /* note: we NEVER reset raw_counts, that is always a		running count of edges seen since startup.  The		public "count" is the difference between raw_count		and index_count, so it will become zero. */	    cntr->raw_count = cntr->raw_counts;	    cntr->index_count = cntr->raw_count;	}	/* process data from update() */	if ( buf->count_detected ) {	    buf->count_detected = 0;	    delta_counts = buf->raw_count - cntr->raw_count;	    delta_time = buf->timestamp - cntr->timestamp;	    cntr->raw_count = buf->raw_count;	    cntr->timestamp = buf->timestamp;	    if ( cntr->counts_since_timeout < 2 ) {		cntr->counts_since_timeout++;	    } else {		vel = (delta_counts * cntr->scale ) / (delta_time * 1e-9);		*(cntr->vel) = vel;	    }	} else {	    /* no count */	    if ( cntr->counts_since_timeout ) {		/* calc time since last count */		delta_time = timebase - cntr->timestamp;		if ( delta_time < TIMEOUT ) {		    /* not to long, estimate vel if a count arrived now */		    vel = ( cntr->scale ) / (delta_time * 1e-9);		    /* make vel positive, even if scale is negative */		    if ( vel < 0.0 ) vel = -vel;		    /* use lesser of estimate and previous value */		    /* use sign of previous value, magnitude of estimate */		    if ( vel < *(cntr->vel) ) {			*(cntr->vel) = vel;		    }		    if ( -vel > *(cntr->vel) ) {			*(cntr->vel) = -vel;		    }		} else {		    /* its been a long time, stop estimating */		    cntr->counts_since_timeout = 0;		    *(cntr->vel) = 0;		}	    } else {		/* we already stopped estimating */		*(cntr->vel) = 0;	    }	}	/* compute net counts */	*(cntr->count) = cntr->raw_count - cntr->index_count;	/* scale count to make floating point position */	*(cntr->pos) = *(cntr->count) * cntr->scale;	/* move on to next channel */	cntr++;    }    /* done */}/************************************************************************                   LOCAL FUNCTION DEFINITIONS                         *************************************************************************/static int export_counter(int num, counter_t * addr){    int retval, msg;    char buf[HAL_NAME_LEN + 2];    /* This function exports a lot of stuff, which results in a lot of       logging if msg_level is at INFO or ALL. So we save the current value       of msg_level and restore it later.  If you actually need to log this       function's actions, change the second line below */    msg = rtapi_get_msg_level();    rtapi_set_msg_level(RTAPI_MSG_WARN);    /* export pins for the quadrature inputs */    rtapi_snprintf(buf, HAL_NAME_LEN, "encoder.%d.phase-A", num);    retval = hal_pin_bit_new(buf, HAL_IN, &(addr->phaseA), comp_id);    if (retval != 0) {	return retval;    }    rtapi_snprintf(buf, HAL_NAME_LEN, "encoder.%d.phase-B", num);    retval = hal_pin_bit_new(buf, HAL_IN, &(addr->phaseB), comp_id);    if (retval != 0) {	return retval;    }    /* export pin for the index input */    rtapi_snprintf(buf, HAL_NAME_LEN, "encoder.%d.phase-Z", num);    retval = hal_pin_bit_new(buf, HAL_IN, &(addr->phaseZ), comp_id);    if (retval != 0) {	return retval;    }    /* export pin for the index enable input */    rtapi_snprintf(buf, HAL_NAME_LEN, "encoder.%d.index-enable", num);    retval = hal_pin_bit_new(buf, HAL_IO, &(addr->index_ena), comp_id);    if (retval != 0) {	return retval;    }    /* export pin for the reset input */    rtapi_snprintf(buf, HAL_NAME_LEN, "encoder.%d.reset", num);    retval = hal_pin_bit_new(buf, HAL_IN, &(addr->reset), comp_id);    if (retval != 0) {	return retval;    }    /* export parameter for raw counts */    rtapi_snprintf(buf, HAL_NAME_LEN, "encoder.%d.rawcounts", num);    retval = hal_param_s32_new(buf, HAL_RO, &(addr->raw_counts), comp_id);    if (retval != 0) {	return retval;    }    /* export pin for counts captured by capture() */    rtapi_snprintf(buf, HAL_NAME_LEN, "encoder.%d.counts", num);    retval = hal_pin_s32_new(buf, HAL_OUT, &(addr->count), comp_id);    if (retval != 0) {	return retval;    }    /* export pin for scaled position captured by capture() */    rtapi_snprintf(buf, HAL_NAME_LEN, "encoder.%d.position", num);    retval = hal_pin_float_new(buf, HAL_OUT, &(addr->pos), comp_id);    if (retval != 0) {	return retval;    }    /* export pin for scaled velocity captured by capture() */    rtapi_snprintf(buf, HAL_NAME_LEN, "encoder.%d.velocity", num);    retval = hal_pin_float_new(buf, HAL_OUT, &(addr->vel), comp_id);    if (retval != 0) {	return retval;    }    /* export parameter for scaling */    rtapi_snprintf(buf, HAL_NAME_LEN, "encoder.%d.position-scale", num);    retval = hal_param_float_new(buf, HAL_RW, &(addr->pos_scale), comp_id);    if (retval != 0) {	return retval;    }    /* export parameter for x4 mode */    rtapi_snprintf(buf, HAL_NAME_LEN, "encoder.%d.x4-mode", num);    retval = hal_param_bit_new(buf, HAL_RW, &(addr->x4_mode), comp_id);    if (retval != 0) {	return retval;    }    /* export parameter for counter mode */    rtapi_snprintf(buf, HAL_NAME_LEN, "encoder.%d.counter-mode", num);    retval = hal_param_bit_new(buf, HAL_RW, &(addr->counter_mode), comp_id);    if (retval != 0) {	return retval;    }    /* restore saved message level */    rtapi_set_msg_level(msg);    return 0;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?