Hi,
We have a magnetic encoder that measures angle... We use PACNT counter to measure the pulse width. The values are between 0 and 20000. After each angle reading, we want to store the value of PACNT into an unsigned integer. But something is wrong... The value of the variable is just around 30 whereas PACNT is around 4900. We see 4900 in the memory but when we try to copy it into the variable (D register), we encounter this problem. Can you help me?
Regards,
Mehmedean
Dear Mehmedean,
I can't explain the symptom you are describing. The dissassembly of your code looks correct in terms of reading the PACNT register.
However there a couple of things that may be leading to problems.
You appear to be clearing the PAIF flag manually as well as automatically using the FFC option. This can cause problems (or at least confuse me!)
The PACNT should be cleared immediately after reading - not before the flag clearing. I think the way your code is set up it would be possible for incomplete counts since the delay through your SCI code could be quite long and overlap the next period measurement. Essentially you would get a random value depending on the timing of when you clear the register before the end of capture time.
Alternativley just omit clearing the flag and wait for it to be set twice in the busy-wait loop. Save the PACNT value from the 1st edge and use subtraction to determine the change in count. The second measurement would be guaranteed to be complete. Better still - have an interrupt handler save the difference value in a glabal var instead.
You enable PA interrupts. What does you PA interrupt handler do anyway?
One last comment - Personally, I would use the IC hardware instead.
bye
Dear mehmedean,
Can you describe the device you are trying to interface to?
Some example code using input capture - This routine measures duty cycle and period. It should be adaptable to your requirements (if I understand what you are trying to do correctly).
#include <hidef.h> /* common defines and macros */
#include <mc9s12c32.h> /* derivative information */
#pragma LINK_INFO DERIVATIVE "mc9s12c32"
#include <stdio.h>
#include "LCD.h"
typedef unsigned char U8;
typedef unsigned int U16;
/*
** Information for M68HC11 Timer
*/
#define PR210 (0x04) /* Prescale value for TSCR2 reg */
#define PRESCALE (1<<PR210) /* Actual division factor (1,2,4,..,128) */
/* TIOS, TIE & TFLG1 masks */
#define IC3 (0x08)
/* TCTL4 masks */
#define IC3EDGE (0xC0)
#define IC3RISING (0x40)
#define IC3FALLING (0x80)
int highTime, period; /* globals updated by IC3 routine */
interrupt VectorNumber_Vtimch3
void IC3Handler(void) {
/*
** Handler for IC3 interrupts.
** This handler alternates between looking for rising and
** falling edges of IC3. From these events it
** calculates the high time and period of the waveform in
** the global variables highTime and period.
** Note that highTime and period are updated on the same
** rising edge interrupt so that they are always a
** consistent pair of values.
** This falls in a heap if the waveform is too fast or slow!!
*/
static int risingEdge; /* times of last edges */
static int fallingEdge;
if ((TCTL4 & IC3EDGE) == IC3RISING) {
/* handling int for IC3 rising edge */
/* calculate period & high time */
highTime = fallingEdge - risingEdge;
period = TC3 - risingEdge;
risingEdge = TC3; /* save time of edge for next time */
/* set for next falling edge on IC3 */
TCTL4 &= ~IC3EDGE;
TCTL4 |= IC3FALLING;
}
else {
/* handling int for IC3 falling edge */
fallingEdge = TC3; /* save time of edge */
/* set for next rising edge on IC3 */
TCTL4 &= ~IC3EDGE;
TCTL4 |= IC3RISING;
}
TFLG1 = IC3; /* clear pending IC3 int */
} /* IC3Handler(void) */
void q8_1(void) {
char lineBuff[100];
EnableInterrupts;
initLCD();
/* Set timer prescale value */
TSCR2 = PR210;
/* Enable timer, stop in freeze or wait mode */
TSCR1 = TSCR1_TEN_MASK|TSCR1_TSWAI_MASK|TSCR1_TSFRZ_MASK;
TIOS &= ~IC3; /* set ECT3 as IC3 */
/* set for next rising edge on IC3 */
TCTL4 &= ~IC3EDGE;
TCTL4 |= IC3RISING;
TFLG1 = IC3; /* clear pending IC3 int */
TIE |= IC3; /* enable IC3 int */
for( ; ; ) { /* continuous loop updating the display */
int lHighTime, lPeriod;
/* enter critical region */
DisableInterrupts;
/* make local copy of globals
** - minimises time that ints are off
** This is important since the division and putsLCD()
** are verrrrry SLOW and we don't want to miss edges.
** We disable ints as we need a consistent pair of
** values from highTime and period without any ints
** between.
*/
lHighTime = highTime;
lPeriod = period;
/* leave critical region */
EnableInterrupts;
(void)sprintf( lineBuff,
"Duty Cycle =%3d%%", (int)((100UL*lHighTime)/lPeriod) );
gotoXY(0,0);
putsLCD( lineBuff );
} /* for(..) */
} /* main() */
bye
both didn't work...
the counter should start counting when a rising edge comes and should stop when a falling edge comes. Should it stop until the next rising edge? Or does the value resetted when a falling edge comes or does it stay the same until the next rising edge?
Do you have any other suggestions to measure the pulsewidth?
Is there any possibility that the problem arises from wrong assignment? Should I merge PACNT(hi) and PACNT(lo) after direct reading from the memory? I tried the code below, but it is not correct...
0x0062 - Address of PACNT(hi)
0x0063 - Address of PACNT(lo)
instead of "angle = PACNT;", I used "angle = ((*(int *)(0x0062)) * 256) + (*(int *)(0x0063));"...