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

  1. /***********************************************************************
  2.  
  3. FILE
  4.     pwm.c  -  Pulse Width Modulation using timer and parallel port
  5.  
  6. ENTRY ROUTINES
  7.     pulse      -  interrupt service routine
  8.     setpfreq   -  set pulse frequency
  9.     setdcycle  -  set duty cycle
  10.  
  11. INITIALIZATION ROUTINE
  12.     pwm_init   -  initialize for pwm
  13.  
  14. REMARKS
  15.     This module uses the IBM-PC's parallel printer port to send out
  16.     pulse width modulated motor control pulses.  One timer is needed
  17.     to time the pulses.  Since the overall control program probably
  18.     needs a timer also, it must tell the initialization routine
  19.     which timer this module can use.  The time2.c module is assumed.
  20.  
  21.     The maximum pulse frequency is limited by the timer resolution
  22.     and execution speed.
  23.  
  24. LAST UPDATE
  25.     26 January 1988
  26.         
  27.     Copyright(c) 1984-1988, D.M.Auslander and C.H. Tham
  28.     
  29. ***********************************************************************/
  30.  
  31. /***********************************************************************
  32.                             I M P O R T S
  33. ***********************************************************************/
  34.  
  35. #include <stdio.h>
  36.  
  37. #include "envir.h"          /* environment definitions */
  38. #include "inout.h"          /* in() and out() mapping */
  39. #include "time2.h"          /* time2.c module declarations */
  40.  
  41. #include "pwm.h"            /* exported declarations */
  42.  
  43. #ifdef ANSI
  44. extern int enable(void);
  45. extern int disable(void);
  46. #else
  47. extern int enable();
  48. extern int disable();
  49. #endif
  50.  
  51.  
  52. /***********************************************************************
  53.             P R I V A T E    D A T A    V A R I A B L E S
  54. ***********************************************************************/
  55.  
  56. #define OUTPORT     0x3BC   /* parallel port address */
  57. #define PULSEON     0x01    /* pulse on output byte */
  58. #define PULSEOFF    0x00    /* pulse off output byte */
  59. #define FORWARD     0x10    /* direction bit OR mask for forward */
  60. #define REVERSE     0x00    /* direction bit OR mask for reverse */
  61.  
  62. static int ptimer;          /* timer number to use with this module */
  63. static long period;         /* cycle period in milliseconds */
  64. static long ontime;         /* on period in milliseconds */
  65. static long offtime;        /* off period in milliseconds */
  66. static int state;           /* current output state, 0 - off, 1 - on */
  67. static int direction;       /* direction, FORWARD or REVERSE */
  68. static double dcycle;       /* PWM duty cycle */
  69.  
  70.  
  71. /***********************************************************************
  72.                     E N T R Y    R O U T I N E S
  73. /***********************************************************************
  74.  
  75. /*----------------------------------------------------------------------
  76. PROCEDURE
  77.     SETPFREQ  -  set pulse frequency in hertz
  78.  
  79. SYNOPSIS
  80.     void setpfreq(f)
  81.     double f;
  82.  
  83. PARAMETER
  84.     f  -  pulse frequency
  85.  
  86. REMARKS
  87.     Adjust ontime and offtime to new cycle period.  Since they are
  88.     accessed asynchronously by pulse(), they must be modifed with
  89.     interrupts disabled.  To minimize the interval with interrupts
  90.     disabled, the calculations are stored in temporary variables,
  91.     only assignment is performed with interrupts disabled.
  92.  
  93. LAST UPDATE
  94.     25 January 1988
  95. ----------------------------------------------------------------------*/
  96.  
  97. void setpfreq(f)
  98. double f;
  99. {
  100.     int istat;              /* interrupt status */
  101.     long on, off;           /* temporary for ontime and offtime */
  102.  
  103.  
  104.     period = (long)(1000.0 / f  +  0.5);        /* cycle time in ms */
  105.  
  106.     on = (long)(dcycle * period  +  0.5);
  107.     off = period - ontime;
  108.  
  109.     istat = disable();      /* begin critical section */
  110.  
  111.     ontime = on;
  112.     offtime = off;
  113.  
  114.     if (istat)              /* end critical section */
  115.         enable();
  116.  
  117. }
  118.  
  119.  
  120.  
  121. /*----------------------------------------------------------------------
  122. PROCEDURE
  123.     SETDCYCLE  -  set duty cycle
  124.  
  125. SYNOPSIS
  126.     void setdcycle(dc)
  127.     double dc;
  128.  
  129. PARAMETER
  130.     dc  -  duty cycle, between 0.0 and 1.0
  131.  
  132. REMARKS
  133.     Adjust ontime and offtime to new duty cycle.  Since they are
  134.     accessed asynchronously by pulse(), they must be modifed with
  135.     interrupts disabled.
  136.  
  137.     To minimize the time where interrupts are disabled, the new on
  138.     and off times are calculated and stored in temporary variables;
  139.     only the assignment to ontime and offtime takes place in the
  140.     critical section.
  141.  
  142. LAST UPDATE
  143.     25 January 1988
  144. ----------------------------------------------------------------------*/
  145.  
  146. void setdcycle(dc)
  147. double dc;
  148. {
  149.     long on, off;       /* temporary copies of ontime and offtime */
  150.     int istat;          /* interrupt status */
  151.  
  152.  
  153.     if ((dc >= -1.0) && (dc <= 1.0))    /* range check */
  154.     {
  155.         if (dc < 0.0)
  156.         {
  157.             direction = REVERSE;        /* set direction mask */
  158.             dcycle = -dc;               /* record absolute duty cycle */
  159.         }
  160.         else
  161.         {
  162.             direction = FORWARD;
  163.             dcycle = dc;
  164.         }
  165.  
  166.         on = (long)(dcycle * period  +  0.5);
  167.         off = period - on;
  168.  
  169.         istat = disable();
  170.  
  171.         ontime = on;
  172.         offtime = off;
  173.  
  174.         if (istat)
  175.             enable();
  176.     }
  177.     else
  178.         fprintf(stderr, "setdcycle: invalid duty cycle %lf\n", dc);
  179.  
  180. }
  181.  
  182.  
  183. /***********************************************************************
  184.                   P R I V A T E    R O U T I N E
  185. ***********************************************************************/
  186.  
  187. /*----------------------------------------------------------------------
  188. PROCEDURE
  189.     PULSE  -  pulse control timeout routine
  190.  
  191. SYNOPSIS
  192.     static void pulse(), called by timer service routine when timeout.
  193.  
  194. REMARKS
  195.     The timer is reset as soon as possible to reduce timing offsets.
  196.  
  197. LAST UPDATE
  198.     25 January 1988
  199. ----------------------------------------------------------------------*/
  200.  
  201. static void pulse()
  202. {
  203.  
  204.     if (state == PULSEOFF)                  /* is in pulse off state */
  205.     {
  206.         SetDTimer(ptimer, ontime);          /* set timer for on interval */
  207.  
  208.         out(OUTPORT, PULSEON | direction);  /* pulse on */
  209.  
  210.         state = PULSEON;                    /* record current state */
  211.     }
  212.     else
  213.     {
  214.         SetDTimer(ptimer, offtime);
  215.  
  216.         out(OUTPORT, PULSEOFF | direction);
  217.  
  218.         state = PULSEOFF;
  219.     }
  220.  
  221. }
  222.  
  223.  
  224.  
  225. /***********************************************************************
  226.             I N I T I A L I Z A T I O N    R O U T I N E
  227. ***********************************************************************/
  228.  
  229. /*----------------------------------------------------------------------
  230. PROCEDURE
  231.     PWM_INIT  -  initialize and start PWM pulses
  232.  
  233. SYNOPSIS
  234.     void pwm_init(timer)
  235.     int timer;
  236.  
  237. PARAMETER
  238.     timer  -  which timer to use
  239.  
  240. REMARKS
  241.     Assumes timing is done using time2.c and install pulse() as the
  242.     timeout routine for the specified timer.  Defaults initial duty
  243.     cycle to 0.5 and pulse frequency to quarter MAXFREQ.
  244.  
  245. LAST UPDATE
  246.     25 January 1988
  247. ----------------------------------------------------------------------*/
  248.  
  249. void pwm_init(timer)
  250. int timer;
  251. {
  252.  
  253.     ptimer = timer;             /* record timer number */
  254.  
  255.     period = 1000L;             /* default 1 second */
  256.  
  257.     setdcycle(0.0);             /* direction is set in setdcycle() */
  258.  
  259.     out(OUTPORT, PULSEOFF);     /* make sure outputs are off */
  260.     state = PULSEOFF;
  261.  
  262.     SetTsr(timer, pulse, (void *)NULL);
  263.  
  264. }
  265.  
  266.  
  267.