home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 15 / 15.iso / s / s300 / 1.ddi / CHAP3 / PFM1.C < prev    next >
Encoding:
C/C++ Source or Header  |  1988-05-02  |  9.1 KB  |  280 lines

  1. /***********************************************************************
  2.  
  3. FILE
  4.     pfm1.c  -  unidirectional velocity measurement using
  5.                Pulse Frequency Modulation with adaptive pulse group size.
  6.  
  7. ENTRY ROUTINES
  8.     pfm_getv   -  read velocity value
  9.     pfm_group  -  set pulse group size
  10.  
  11. PRIVATE ROUTINE
  12.     pulse      -  pulse interrupt service routine
  13.  
  14. INITIALIZATION ROUTINE
  15.     pfm_init  -  initialize this module
  16.  
  17. REMARKS
  18.     This differs from pfm0.c in that the group size used in velocity 
  19.     calculation adapts to the arrival rate of the pulses.
  20.  
  21.     If the pulses arrive too slowly, as determined by MAXPERIOD and
  22.     the sampling time, the group size is halved since we do not want 
  23.     the group interval to exceed the sampling time.  If the problem
  24.     persists, the group size is reduced again until the lower limit
  25.     of one, in which case velocity is based on the interval between
  26.     consecutive pulses.
  27.     
  28.     However, if the pulses are arriving too rapidly, then the group 
  29.     size should be increased as the interval timer cannot accurately 
  30.     measure small intervals.  The minimum period, MINPERIOD criteria 
  31.     to determine if we should increase the group size is based on the 
  32.     resolution of the interval timer.  In this case, the interval timer
  33.     has a poor resolution and MINPERIOD reflects this.
  34.  
  35. LAST UPDATE
  36.     26 January 1988
  37.         change names and eliminate getgroup()
  38.  
  39.     Copyright(c) 1985-1988  D.M. Auslander and C.H. Tham
  40.  
  41. ***********************************************************************/
  42.  
  43. /***********************************************************************
  44.                             I M P O R T S
  45. ***********************************************************************/
  46.  
  47. #include "envir.h"          /* environmemnt */
  48.  
  49. #include "inout.h"          /* in() and out() mapping */
  50. #include "time.h"           /* timer module declarations */
  51. #include "xignal.h"         /* xignal package declarations */
  52.  
  53.  
  54. /***********************************************************************
  55.                         P R I V A T E    D A T A
  56. ***********************************************************************/
  57.  
  58. #define MINPERIOD   50L     /* minimum group period, timer limit */
  59. #define MAXPERIOD   200L    /* max group period, sampling time limit */
  60.  
  61. #define INPORT  0x3BE       /* parallel input port address */
  62. #define INMASK  0x01        /* mask for pulse bit */
  63.  
  64. #define MAXINT  0x7FFF      /* max value for 16-bit integer */
  65.  
  66. static double pscale;       /* pulses per unit displacement */
  67. static int itimer;          /* interval timer number */
  68. static int pflag = 0;       /* a group has arrived */
  69. static long period = 0L;    /* time period for last group */
  70. static int pcount = 0;      /* pulse count */
  71. static int group = 1;       /* number of pulses per group */
  72.  
  73.  
  74. /***********************************************************************
  75.                     E N T R Y    R O U T I N E S
  76. ***********************************************************************/
  77.  
  78. /*----------------------------------------------------------------------
  79. FUNCTION
  80.     PFM_GETV  -  get velocity reading, adaptive version
  81.  
  82. SYNOPSIS
  83.     double pfm_getv()
  84.  
  85. RETURNS
  86.     displacement per second
  87.  
  88. REMARKS
  89.     This version differs from that in pfm0.c in that the group size
  90.     is adjusted to keep the period (i.e. the time interval needed to
  91.     collect the number of pulses forming a group) between MINPERIOD
  92.     and MAXPERIOD.
  93.     
  94.     If the group period is less than MINPERIOD, pulses are arriving
  95.     too fast for the resolution of the timer.  The group size is
  96.     doubled.
  97.  
  98.     If the group period is greater than MAXPERIOD, pulses are
  99.     arriving too slowly to form a group when a velocity reading is
  100.     required.  The group size is halved (with a floor of 1).
  101.  
  102. LAST UPDATE
  103.     26 January 1988
  104.         name change and other minor modifications
  105. ----------------------------------------------------------------------*/
  106.     
  107. double pfm_getv()
  108. {
  109.     long time;          /* time period - copy of global period */
  110.     int count;          /* copy of pcount */
  111.     int istat;          /* interrupt status */
  112.  
  113.  
  114.     istat = disable();                  /* begin critical section */
  115.  
  116.     if (pflag)                          /* data available */
  117.     {
  118.         pflag = 0;                      /* reset immediately */
  119.         time = period;
  120.         count = group;
  121.  
  122.         /*---------------------------------------------------------
  123.             If the period is less than some predefined minimum,
  124.             pulses are arriving too fast.  Double the group size.
  125.         ---------------------------------------------------------*/
  126.  
  127.         if (period <= MINPERIOD)        /* pulses arriving too fast, */
  128.             group <<= 1;                /*  double the group size.   */
  129.         
  130.         if (group < 0)                  /* group variable overflow! */
  131.             group = MAXINT;             /* set to max integer value */
  132.     }
  133.     else    /* not enough pulses for a group since last pfm_getv() */
  134.     {
  135.         /*-------------------------------------------------------------
  136.             Base velocity on the current pulse count instead of the
  137.             group count.  This is more accurate than returning the
  138.             previous velocity value.  If the current pulse count is
  139.             zero, then the velocity is too low for the resolution
  140.             of this routine; it is effectively zero.
  141.         --------------------------------------------------------------*/
  142.         
  143.         time = ReadITimer(itimer);
  144.         count = pcount;
  145.  
  146.         /*------------------------------------------------------------
  147.             If the elasped time since the start of the current group
  148.             exceeds MAXPERIOD, either the pulses are arriving too
  149.             slowly or the group size is too big, or both.  The group
  150.             size is halved.
  151.         ------------------------------------------------------------*/
  152.  
  153.         if (time > MAXPERIOD)       /* pulses are arriving too slowly */
  154.             if (group > 1)
  155.                 group >>= 1;        /* halve group size, floor of 1 */
  156.     }
  157.  
  158.     if (istat)                      /* exit critical section */
  159.         enable();
  160.  
  161.     return(count * pscale / time);
  162. }
  163.  
  164.  
  165.  
  166. /*---------------------------------------------------------------------
  167. ROUTINES
  168.     PFM_GROUP  -  set pulse group size
  169.  
  170. SYNOPSIS
  171.     void pfm_group(size)
  172.     int size;
  173.  
  174. PARAMETER
  175.     size  -  number of pulses in a group
  176.  
  177. LAST UPDATE
  178.     26 January 1988
  179.         name change
  180. ----------------------------------------------------------------------*/
  181.  
  182. void pfm_group(size)
  183. int size;
  184. {
  185.     int istat;      /* interrupt status */
  186.  
  187.  
  188.     istat = disable();
  189.  
  190.     group = size;
  191.  
  192.     if (istat)
  193.         enable();
  194.  
  195. }
  196.  
  197.  
  198. /***********************************************************************
  199.                   P R I V A T E    R O U T I N E
  200. ***********************************************************************/
  201.  
  202. /*----------------------------------------------------------------------
  203. PROCEDURE
  204.     PULSE  -  pulse interrupt service routine
  205.  
  206. SYNOPSIS
  207.     static void pulse()  -  called by lower level interrupt service routine
  208.  
  209. REMARKS
  210.     If pulse count enough for a group, reset interval timer and record
  211.     the time interval for the group.
  212.  
  213. LAST UPDATE
  214.     8 April 1985
  215. ----------------------------------------------------------------------*/
  216.     
  217. static void pulse()
  218. {
  219.  
  220.     if (in(INPORT) & INMASK)        /* verify pulse */
  221.     {
  222.         ++pcount;
  223.  
  224.         if (pcount >= group)                /* enough for a group */
  225.         {
  226.             period = ReadITimer(itimer);    /* record group period */
  227.  
  228.             SetITimer(itimer);              /* reset interval timer */
  229.             pcount = 0;                     /* reset pulse count */
  230.             pflag = 1;                      /* indicate data available */
  231.         }
  232.     }
  233.  
  234. }
  235.  
  236.  
  237.  
  238. /***********************************************************************
  239.             I N I T I A L I Z A T I O N    R O U T I N E S
  240. ***********************************************************************/
  241.  
  242. /*----------------------------------------------------------------------
  243. PROCEDURE
  244.     PFM_INIT  -  initialize
  245.  
  246. SYNOPSIS
  247.     void pfm_init(scale)
  248.     double scale;
  249.  
  250. PARAMETERS
  251.     scale  -  pulse scaling factor: displacement per pulse
  252.  
  253. REMARKS
  254.     The scale is multiplied by 1000 because the interval timer
  255.     readings are in milliseconds.
  256.  
  257. LAST UPDATE
  258.     28 January 1988
  259.         allocate interval timer here instead of externally
  260. ----------------------------------------------------------------------*/
  261.  
  262. void pfm_init(scale)
  263. double scale;
  264. {
  265.  
  266.     pscale = scale * 1000.0;
  267.  
  268.     itimer = NewITimer();   /* allocate an interval timer */
  269.  
  270.     group = 100;            /* default to 100 pulses in a group */
  271.  
  272.     SetITimer(itimer);      /* initialize interval timer */
  273.  
  274.     xignal(XIGPRN, pulse);  /* set pulse() as parallel port isr */
  275.  
  276.     out(INPORT, 0x14);      /* enable parallel port interrupts */
  277. }
  278.  
  279.  
  280.